signature:
def checkplot_pickle ( lspinfolist , times , mags , errs , fast_mode = False , magsarefluxes = False , nperiodstouse = 3 , objectinfo = None , deredden_object = True , custom_bandpasses = None , gaia_submit_timeout = 10.0 , gaia_submit_tries = 3 , gaia_max_timeout = 180.0 , gaia_mirror = None , complete_query_later = True , varinfo = None , getvarfeatures = True , lclistpkl = None , nbrradiusarcsec = 60.0 , maxnumneighbors = 5 , xmatchinfo = None , xmatchradiusarcsec = 3.0 , lcfitfunc = None , lcfitparams = None , externalplots = None , findercmap = 'gray_r' , finderconvolve = None , findercachedir = '~/.astrobase/stamp-cache' , normto = 'globalmedian' , normmingap = 4.0 , sigclip = 4.0 , varepoch = 'min' , phasewrap = True , phasesort = True , phasebin = 0.002 , minbinelems = 7 , plotxlim = ( - 0.8 , 0.8 ) , xliminsetmode = False , plotdpi = 100 , bestperiodhighlight = None , xgridlines = None , mindet = 99 , verbose = True , outfile = None , outgzip = False , pickleprotocol = None , returndict = False ) :
    '''This writes a multiple lspinfo checkplot to a ( gzipped ) pickle file .
 This function can take input from multiple lspinfo dicts ( e . g . a list of
 output dicts or gzipped pickles of dicts from independent runs of BLS , PDM ,
 AoV , or GLS period - finders in periodbase ) .
 NOTE : if ` lspinfolist ` contains more than one lspinfo object with the same
 lspmethod ( ' pdm ' , ' gls ' , ' sls ' , ' aov ' , ' bls ' ) , the latest one in the list will
 overwrite the earlier ones .
 The output dict contains all the plots ( magseries and phased magseries ) ,
 periodograms , object information , variability information , light curves , and
 phased light curves . This can be written to :
 - a pickle with ` checkplot _ pickle ` below
 - a PNG with ` checkplot . pkl _ png . checkplot _ pickle _ to _ png `
 Parameters
 lspinfolist : list of dicts
 This is a list of dicts containing period - finder results ( ' lspinfo '
 dicts ) . These can be from any of the period - finder methods in
 astrobase . periodbase . To incorporate external period - finder results into
 checkplots , these dicts must be of the form below , including at least
 the keys indicated here : :
 { ' 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 }
 ` nbestperiods ` and ` nbestlspvals ` in each lspinfo dict must have at
 least as many elements as the ` nperiodstouse ` kwarg to this function .
 times , mags , errs : np . arrays
 The magnitude / flux time - series to process for this checkplot along with
 their associated measurement errors .
 fast _ mode : bool or float
 This runs the external catalog operations in a " fast " mode , with short
 timeouts and not trying to hit external catalogs that take a long time
 to respond .
 If this is set to True , the default settings for the external requests
 will then become : :
 skyview _ lookup = False
 skyview _ timeout = 10.0
 skyview _ retry _ failed = False
 dust _ timeout = 10.0
 gaia _ submit _ timeout = 7.0
 gaia _ max _ timeout = 10.0
 gaia _ submit _ tries = 2
 complete _ query _ later = False
 search _ simbad = False
 If this is a float , will run in " fast " mode with the provided timeout
 value in seconds and the following settings : :
 skyview _ lookup = True
 skyview _ timeout = fast _ mode
 skyview _ retry _ failed = False
 dust _ timeout = fast _ mode
 gaia _ submit _ timeout = 0.66 * fast _ mode
 gaia _ max _ timeout = fast _ mode
 gaia _ submit _ tries = 2
 complete _ query _ later = False
 search _ simbad = False
 magsarefluxes : bool
 If True , indicates the input time - series is fluxes and not mags so the
 plot y - axis direction and range can be set appropriately .
 nperiodstouse : int
 This controls how many ' best ' periods to make phased LC plots for . By
 default , this is the 3 best . If this is set to None , all ' best ' periods
 present in each lspinfo dict ' s ' nbestperiods ' key will be processed for
 this checkplot .
 objectinfo : dict or None
 If provided , this is a dict containing information on the object whose
 light curve is being processed . This function will then be able to look
 up and download a finder chart for this object and write that to the
 output checkplotdict . External services such as GAIA , SIMBAD , TIC @ MAST ,
 etc . will also be used to look up this object by its coordinates , and
 will add in information available from those services .
 The ` objectinfo ` dict must be of the form and contain at least the keys
 described below : :
 { ' objectid ' : the name of the object ,
 ' ra ' : the right ascension of the object in decimal degrees ,
 ' decl ' : the declination of the object in decimal degrees ,
 ' ndet ' : the number of observations of this object }
 You can also provide magnitudes and proper motions of the object using
 the following keys and the appropriate values in the ` objectinfo `
 dict . These will be used to calculate colors , total and reduced proper
 motion , etc . and display these in the output checkplot PNG : :
 ' pmra ' - > the proper motion in mas / yr in right ascension ,
 ' pmdecl ' - > the proper motion in mas / yr in the declination ,
 ' 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
 If you have magnitude measurements in other bands , use the
 ` custom _ bandpasses ` kwarg to pass these in .
 If this is None , no object information will be incorporated into the
 checkplot ( kind of making it effectively useless for anything other than
 glancing at the phased light curves at various ' best ' periods from the
 period - finder results ) .
 deredden _ object : bool
 If this is True , will use the 2MASS DUST service to get extinction
 coefficients in various bands , and then try to deredden the magnitudes
 and colors of the object already present in the checkplot ' s objectinfo
 dict .
 custom _ bandpasses : dict
 This is a dict used to provide custom bandpass definitions for any
 magnitude measurements in the objectinfo dict that are not automatically
 recognized by : py : func : ` astrobase . varclass . starfeatures . color _ features ` .
 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 or None
 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 .
 complete _ query _ later : bool
 If this is True , saves the state of GAIA queries that are not yet
 complete when ` gaia _ max _ timeout ` is reached while waiting for the GAIA
 service to respond to our request . A later call for GAIA info on the
 same object will attempt to pick up the results from the existing query
 if it ' s completed . If ` fast _ mode ` is True , this is ignored .
 varinfo : dict
 If this is None , a blank dict of the form below will be added to the
 checkplotdict : :
 { ' objectisvar ' : None - > variability flag ( None indicates unset ) ,
 ' vartags ' : CSV str containing variability type tags from review ,
 ' varisperiodic ' : None - > periodic variability flag ( None - > unset ) ,
 ' varperiod ' : the period associated with the periodic variability ,
 ' varepoch ' : the epoch associated with the periodic variability }
 If you provide a dict matching this format in this kwarg , this will be
 passed unchanged to the output checkplotdict produced .
 getvarfeatures : bool
 If this is True , several light curve variability features for this
 object will be calculated and added to the output checkpotdict as
 checkplotdict [ ' varinfo ' ] [ ' features ' ] . This uses the function
 ` varclass . varfeatures . all _ nonperiodic _ features ` so see its docstring for
 the measures that are calculated ( e . g . Stetson J indices , dispersion
 measures , etc . )
 lclistpkl : dict or str
 If this is provided , must be a dict resulting from reading a catalog
 produced by the ` lcproc . catalogs . make _ lclist ` function or a str path
 pointing to the pickle file produced by that function . This catalog is
 used to find neighbors of the current object in the current light curve
 collection . Looking at neighbors of the object within the radius
 specified by ` nbrradiusarcsec ` is useful for light curves produced by
 instruments that have a large pixel scale , so are susceptible to
 blending of variability and potential confusion of neighbor variability
 with that of the actual object being looked at . If this is None , no
 neighbor lookups will be performed .
 nbrradiusarcsec : flaot
 The radius in arcseconds to use for a search conducted around the
 coordinates of this object to look for any potential confusion and
 blending of variability amplitude caused by their proximity .
 maxnumneighbors : int
 The maximum number of neighbors that will have their light curves and
 magnitudes noted in this checkplot as potential blends with the target
 object .
 xmatchinfo : str or dict
 This is either the xmatch dict produced by the function
 ` load _ xmatch _ external _ catalogs ` above , or the path to the xmatch info
 pickle file produced by that function .
 xmatchradiusarcsec : float
 This is the cross - matching radius to use in arcseconds .
 lcfitfunc : Python function or None
 If provided , this should be a Python function that is used to fit a
 model to the light curve . This fit is then overplotted for each phased
 light curve in the checkplot . This function should have the following
 signature :
 ` def lcfitfunc ( times , mags , errs , period , * * lcfitparams ) `
 where ` lcfitparams ` encapsulates all external parameters ( i . e . number of
 knots for a spline function , the degree of a Legendre polynomial fit ,
 etc . , planet transit parameters ) This function should return a Python
 dict with the following structure ( similar to the functions in
 ` astrobase . lcfit ` ) and at least the keys below : :
 { ' fittype ' : < str : name of fit method > ,
 ' fitchisq ' : < float : the chi - squared value of the fit > ,
 ' fitredchisq ' : < float : the reduced chi - squared value of the fit > ,
 ' fitinfo ' : { ' fitmags ' : < ndarray : model mags / fluxes from fit func > } ,
 ' magseries ' : { ' times ' : < ndarray : times where fitmags are evaluated > } }
 Additional keys in the dict returned from this function can include
 ` fitdict [ ' fitinfo ' ] [ ' finalparams ' ] ` for the final model fit parameters
 ( this will be used by the checkplotserver if present ) ,
 ` fitdict [ ' fitinfo ' ] [ ' fitepoch ' ] ` for the minimum light epoch returned by
 the model fit , among others .
 In any case , the output dict of ` lcfitfunc ` will be copied to the output
 checkplotdict as
 ` checkplotdict [ lspmethod ] [ periodind ] [ ' lcfit ' ] [ < fittype > ] ` for each
 phased light curve .
 lcfitparams : dict
 A dict containing the LC fit parameters to use when calling the function
 provided in ` lcfitfunc ` . This contains key - val pairs corresponding to
 parameter names and their respective initial values to be used by the
 fit function .
 externalplots : list of tuples of str
 If provided , this is a list of 4 - element tuples containing :
 1 . path to PNG of periodogram from an external period - finding method
 2 . path to PNG of best period phased LC from the external period - finder
 3 . path to PNG of 2nd - best phased LC from the external period - finder
 4 . path to PNG of 3rd - best phased LC from the external period - finder
 This can be used to incorporate external period - finding method results
 into the output checkplot pickle or exported PNG to allow for comparison
 with astrobase results . Example of ` externalplots ` : :
 [ ( ' / path / to / external / bls - periodogram . png ' ,
 ' / path / to / external / bls - phasedlc - plot - bestpeak . png ' ,
 ' / path / to / external / bls - phasedlc - plot - peak2 . png ' ,
 ' / path / to / external / bls - phasedlc - plot - peak3 . png ' ) ,
 ( ' / path / to / external / pdm - periodogram . png ' ,
 ' / path / to / external / pdm - phasedlc - plot - bestpeak . png ' ,
 ' / path / to / external / pdm - phasedlc - plot - peak2 . png ' ,
 ' / path / to / external / pdm - phasedlc - plot - peak3 . png ' ) ,
 If ` externalplots ` is provided here , these paths will be stored in the
 output checkplotdict . The ` checkplot . pkl _ png . checkplot _ pickle _ to _ png `
 function can then automatically retrieve these plot PNGs and put
 them into the exported checkplot PNG .
 findercmap : str or matplotlib . cm . ColorMap object
 The Colormap object to use for the finder chart image .
 finderconvolve : astropy . convolution . Kernel object or None
 If not None , the Kernel object to use for convolving the finder image .
 findercachedir : str
 The path to the astrobase cache directory for finder chart downloads
 from the NASA SkyView service .
 normto : { ' globalmedian ' , ' zero ' } or a float
 This specifies the normalization target : :
 ' globalmedian ' - > norms each mag to global median of the LC column
 ' zero ' - > norms each mag to zero
 a float - > norms each mag to this specified float value .
 normmingap : float
 This defines how much the difference between consecutive measurements is
 allowed to be to consider them as parts of different timegroups . By
 default it is set to 4.0 days .
 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 .
 varepoch : ' min ' or float or list of lists or None
 The epoch to use for this phased light curve plot tile . If this is a
 float , will use the provided value directly . If this is ' min ' , will
 automatically figure out the time - of - minimum of the phased light
 curve . If this is None , will use the mimimum value of ` stimes ` as the
 epoch of the phased light curve plot . If this is a list of lists , will
 use the provided value of ` lspmethodind ` to look up the current
 period - finder method and the provided value of ` periodind ` to look up
 the epoch associated with that method and the current period . This is
 mostly only useful when ` twolspmode ` is True .
 phasewrap : bool
 If this is True , the phased time - series will be wrapped around
 phase 0.0.
 phasesort : bool
 If True , will sort the phased light curve in order of increasing phase .
 phasebin : float
 The bin size to use to group together measurements closer than this
 amount in phase . This is in units of phase . If this is a float , a
 phase - binned version of the phased light curve will be overplotted on
 top of the regular phased light curve .
 minbinelems : int
 The minimum number of elements required per phase bin to include it in
 the phased LC plot .
 plotxlim : sequence of two floats or None
 The x - range ( min , max ) of the phased light curve plot . If None , will be
 determined automatically .
 xliminsetmode : bool
 If this is True , the generated phased light curve plot will use the
 values of ` plotxlim ` as the main plot x - axis limits ( i . e . zoomed - in if
 ` plotxlim ` is a range smaller than the full phase range ) , and will show
 the full phased light curve plot as an smaller inset . Useful for
 planetary transit light curves .
 plotdpi : int
 The resolution of the output plot PNGs in dots per inch .
 bestperiodhighlight : str or None
 If not None , this is a str with a matplotlib color specification to use
 as the background color to highlight the phased light curve plot of the
 ' best ' period and epoch combination . If None , no highlight will be
 applied .
 xgridlines : list of floats or None
 If this is provided , must be a list of floats corresponding to the phase
 values where to draw vertical dashed lines as a means of highlighting
 these .
 mindet : int
 The minimum of observations the input object ' s mag / flux time - series must
 have for this function to plot its light curve and phased light
 curve . If the object has less than this number , no light curves will be
 plotted , but the checkplotdict will still contain all of the other
 information .
 verbose : bool
 If True , will indicate progress and warn about problems .
 outfile : str or None
 The name of the output checkplot pickle file . If this is None , will
 write the checkplot pickle to file called ' checkplot . pkl ' in the current
 working directory .
 outgzip : bool
 This controls whether to gzip the output pickle . It turns out that this
 is the slowest bit in the output process , so if you ' re after speed , best
 not to use this . This is False by default since it turns out that gzip
 actually doesn ' t save that much space ( 29 MB vs . 35 MB for the average
 checkplot pickle ) .
 pickleprotocol : int or None
 This sets the pickle file protocol to use when writing the pickle :
 If None , will choose a protocol using the following rules :
 - 4 - > default in Python > = 3.4 - fast but incompatible with Python 2
 - 3 - > default in Python 3.0-3.3 - mildly fast
 - 2 - > default in Python 2 - very slow , but compatible with Python 2/3
 The default protocol kwarg is None , this will make an automatic choice
 for pickle protocol that ' s best suited for the version of Python in
 use . Note that this will make pickles generated by Py3 incompatible with
 Py2.
 returndict : bool
 If this is True , will return the checkplotdict instead of returning the
 filename of the output checkplot pickle .
 Returns
 dict or str
 If returndict is False , will return the path to the generated checkplot
 pickle file . If returndict is True , will return the checkplotdict
 instead .'''

implementation:
# call checkplot _ dict for most of the work
checkplotdict = checkplot_dict ( lspinfolist , times , mags , errs , magsarefluxes = magsarefluxes , nperiodstouse = nperiodstouse , objectinfo = objectinfo , deredden_object = deredden_object , custom_bandpasses = custom_bandpasses , gaia_submit_timeout = gaia_submit_timeout , gaia_submit_tries = gaia_submit_tries , gaia_max_timeout = gaia_max_timeout , gaia_mirror = gaia_mirror , complete_query_later = complete_query_later , varinfo = varinfo , getvarfeatures = getvarfeatures , lclistpkl = lclistpkl , nbrradiusarcsec = nbrradiusarcsec , maxnumneighbors = maxnumneighbors , xmatchinfo = xmatchinfo , xmatchradiusarcsec = xmatchradiusarcsec , lcfitfunc = lcfitfunc , lcfitparams = lcfitparams , externalplots = externalplots , findercmap = findercmap , finderconvolve = finderconvolve , findercachedir = findercachedir , normto = normto , normmingap = normmingap , sigclip = sigclip , varepoch = varepoch , phasewrap = phasewrap , phasesort = phasesort , phasebin = phasebin , minbinelems = minbinelems , plotxlim = plotxlim , xliminsetmode = xliminsetmode , plotdpi = plotdpi , bestperiodhighlight = bestperiodhighlight , xgridlines = xgridlines , mindet = mindet , verbose = verbose , fast_mode = fast_mode )
# for Python > = 3.4 , use v4
if ( ( sys . version_info [ 0 : 2 ] >= ( 3 , 4 ) and not pickleprotocol ) or ( pickleprotocol > 2 ) ) :
    pickleprotocol = 4
elif ( ( sys . version_info [ 0 : 2 ] >= ( 3 , 0 ) and not pickleprotocol ) or ( pickleprotocol > 2 ) ) :
    pickleprotocol = 3
# for Python = = 2.7 ; use v2
elif sys . version_info [ 0 : 2 ] == ( 2 , 7 ) and not pickleprotocol :
    pickleprotocol = 2
# otherwise , if left unspecified , use the slowest but most compatible
# protocol . this will be readable by all ( most ? ) Pythons
elif not pickleprotocol :
    pickleprotocol = 0
# generate the output file path
if outgzip : # generate the outfile filename
    if ( not outfile and len ( lspinfolist ) > 0 and isinstance ( lspinfolist [ 0 ] , str ) ) :
        plotfpath = os . path . join ( os . path . dirname ( lspinfolist [ 0 ] ) , 'checkplot-%s.pkl.gz' % checkplotdict [ 'objectid' ] )
    elif outfile :
        plotfpath = outfile
    else :
        plotfpath = 'checkplot.pkl.gz'
else : # generate the outfile filename
    if ( not outfile and len ( lspinfolist ) > 0 and isinstance ( lspinfolist [ 0 ] , str ) ) :
        plotfpath = os . path . join ( os . path . dirname ( lspinfolist [ 0 ] ) , 'checkplot-%s.pkl' % checkplotdict [ 'objectid' ] )
    elif outfile :
        plotfpath = outfile
    else :
        plotfpath = 'checkplot.pkl'
# write the completed checkplotdict to a gzipped pickle
picklefname = _write_checkplot_picklefile ( checkplotdict , outfile = plotfpath , protocol = pickleprotocol , outgzip = outgzip )
# at the end , return the dict and filename if asked for
if returndict :
    if verbose :
        LOGINFO ( 'checkplot done -> %s' % picklefname )
    return checkplotdict , picklefname
# otherwise , just return the filename
else : # just to make sure : free up space
    del checkplotdict
    if verbose :
        LOGINFO ( 'checkplot done -> %s' % picklefname )
    return picklefname


signature:
def checkplot_pickle_update ( currentcp , updatedcp , outfile = None , outgzip = False , pickleprotocol = None , verbose = True ) :
    '''This updates the current checkplotdict with updated values provided .
 Parameters
 currentcp : dict or str
 This is either a checkplotdict produced by ` checkplot _ pickle ` above or a
 checkplot pickle file produced by the same function . This checkplot will
 be updated from the ` updatedcp ` checkplot .
 updatedcp : dict or str
 This is either a checkplotdict produced by ` checkplot _ pickle ` above or a
 checkplot pickle file produced by the same function . This checkplot will
 be the source of the update to the ` currentcp ` checkplot .
 outfile : str or None
 The name of the output checkplot pickle file . The function will output
 the new checkplot gzipped pickle file to ` outfile ` if outfile is a
 filename . If ` currentcp ` is a file and ` outfile ` , this will be set to
 that filename , so the function updates it in place .
 outgzip : bool
 This controls whether to gzip the output pickle . It turns out that this
 is the slowest bit in the output process , so if you ' re after speed , best
 not to use this . This is False by default since it turns out that gzip
 actually doesn ' t save that much space ( 29 MB vs . 35 MB for the average
 checkplot pickle ) .
 pickleprotocol : int or None
 This sets the pickle file protocol to use when writing the pickle :
 If None , will choose a protocol using the following rules :
 - 4 - > default in Python > = 3.4 - fast but incompatible with Python 2
 - 3 - > default in Python 3.0-3.3 - mildly fast
 - 2 - > default in Python 2 - very slow , but compatible with Python 2/3
 The default protocol kwarg is None , this will make an automatic choice
 for pickle protocol that ' s best suited for the version of Python in
 use . Note that this will make pickles generated by Py3 incompatible with
 Py2.
 verbose : bool
 If True , will indicate progress and warn about problems .
 Returns
 str
 The path to the updated checkplot pickle file . If ` outfile ` was None and
 ` currentcp ` was a filename , this will return ` currentcp ` to indicate
 that the checkplot pickle file was updated in place .'''

implementation:
# break out python 2.7 and > 3 nonsense
if sys . version_info [ : 2 ] > ( 3 , 2 ) : # generate the outfile filename
    if not outfile and isinstance ( currentcp , str ) :
        plotfpath = currentcp
    elif outfile :
        plotfpath = outfile
    elif isinstance ( currentcp , dict ) and currentcp [ 'objectid' ] :
        if outgzip :
            plotfpath = 'checkplot-%s.pkl.gz' % currentcp [ 'objectid' ]
        else :
            plotfpath = 'checkplot-%s.pkl' % currentcp [ 'objectid' ]
    else : # we ' ll get this later below
        plotfpath = None
    if ( isinstance ( currentcp , str ) and os . path . exists ( currentcp ) ) :
        cp_current = _read_checkplot_picklefile ( currentcp )
    elif isinstance ( currentcp , dict ) :
        cp_current = currentcp
    else :
        LOGERROR ( 'currentcp: %s of type %s is not a ' 'valid checkplot filename (or does not exist), or a dict' % ( os . path . abspath ( currentcp ) , type ( currentcp ) ) )
        return None
    if ( isinstance ( updatedcp , str ) and os . path . exists ( updatedcp ) ) :
        cp_updated = _read_checkplot_picklefile ( updatedcp )
    elif isinstance ( updatedcp , dict ) :
        cp_updated = updatedcp
    else :
        LOGERROR ( 'updatedcp: %s of type %s is not a ' 'valid checkplot filename (or does not exist), or a dict' % ( os . path . abspath ( updatedcp ) , type ( updatedcp ) ) )
        return None
# check for unicode in python 2.7
else : # generate the outfile filename
    if ( not outfile and ( isinstance ( currentcp , str ) or isinstance ( currentcp , unicode ) ) ) :
        plotfpath = currentcp
    elif outfile :
        plotfpath = outfile
    elif isinstance ( currentcp , dict ) and currentcp [ 'objectid' ] :
        if outgzip :
            plotfpath = 'checkplot-%s.pkl.gz' % currentcp [ 'objectid' ]
        else :
            plotfpath = 'checkplot-%s.pkl' % currentcp [ 'objectid' ]
    else : # we ' ll get this later below
        plotfpath = None
    # get the current checkplotdict
    if ( ( isinstance ( currentcp , str ) or isinstance ( currentcp , unicode ) ) and os . path . exists ( currentcp ) ) :
        cp_current = _read_checkplot_picklefile ( currentcp )
    elif isinstance ( currentcp , dict ) :
        cp_current = currentcp
    else :
        LOGERROR ( 'currentcp: %s of type %s is not a ' 'valid checkplot filename (or does not exist), or a dict' % ( os . path . abspath ( currentcp ) , type ( currentcp ) ) )
        return None
    # get the updated checkplotdict
    if ( ( isinstance ( updatedcp , str ) or isinstance ( updatedcp , unicode ) ) and os . path . exists ( updatedcp ) ) :
        cp_updated = _read_checkplot_picklefile ( updatedcp )
    elif isinstance ( updatedcp , dict ) :
        cp_updated = updatedcp
    else :
        LOGERROR ( 'updatedcp: %s of type %s is not a ' 'valid checkplot filename (or does not exist), or a dict' % ( os . path . abspath ( updatedcp ) , type ( updatedcp ) ) )
        return None
# do the update using python ' s dict update mechanism
# this requires updated to be in the same checkplotdict format as current
# all keys in current will now be from updated
cp_current . update ( cp_updated )
# figure out the plotfpath if we haven ' t by now
if not plotfpath and outgzip :
    plotfpath = 'checkplot-%s.pkl.gz' % cp_current [ 'objectid' ]
elif ( not plotfpath ) and ( not outgzip ) :
    plotfpath = 'checkplot-%s.pkl' % cp_current [ 'objectid' ]
# make sure we write the correct postfix
if plotfpath . endswith ( '.gz' ) :
    outgzip = True
# write the new checkplotdict
return _write_checkplot_picklefile ( cp_current , outfile = plotfpath , outgzip = outgzip , protocol = pickleprotocol )


signature:
def get_frequency_grid ( times , samplesperpeak = 5 , nyquistfactor = 5 , minfreq = None , maxfreq = None , returnf0dfnf = False ) :
    '''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'''

implementation:
baseline = times . max ( ) - times . min ( )
nsamples = times . size
df = 1. / baseline / samplesperpeak
if minfreq is not None :
    f0 = minfreq
else :
    f0 = 0.5 * df
if maxfreq is not None :
    Nf = int ( npceil ( ( maxfreq - f0 ) / df ) )
else :
    Nf = int ( 0.5 * samplesperpeak * nyquistfactor * nsamples )
if returnf0dfnf :
    return f0 , df , Nf , f0 + df * nparange ( Nf )
else :
    return f0 + df * nparange ( Nf )


signature:
def pwd_phasebin ( phases , mags , binsize = 0.002 , minbin = 9 ) :
    '''This bins the phased mag series using the given binsize .'''

implementation:
bins = np . arange ( 0.0 , 1.0 , binsize )
binnedphaseinds = npdigitize ( phases , bins )
binnedphases , binnedmags = [ ] , [ ]
for x in npunique ( binnedphaseinds ) :
    thisbin_inds = binnedphaseinds == x
    thisbin_phases = phases [ thisbin_inds ]
    thisbin_mags = mags [ thisbin_inds ]
    if thisbin_inds . size > minbin :
        binnedphases . append ( npmedian ( thisbin_phases ) )
        binnedmags . append ( npmedian ( thisbin_mags ) )
return np . array ( binnedphases ) , np . array ( binnedmags )


signature:
def pdw_worker ( task ) :
    '''This is the parallel worker for the function below .
 task [ 0 ] = frequency for this worker
 task [ 1 ] = times array
 task [ 2 ] = mags array
 task [ 3 ] = fold _ time
 task [ 4 ] = j _ range
 task [ 5 ] = keep _ threshold _ 1
 task [ 6 ] = keep _ threshold _ 2
 task [ 7 ] = phasebinsize
 we don ' t need errs for the worker .'''

implementation:
frequency = task [ 0 ]
times , modmags = task [ 1 ] , task [ 2 ]
fold_time = task [ 3 ]
j_range = range ( task [ 4 ] )
keep_threshold_1 = task [ 5 ]
keep_threshold_2 = task [ 6 ]
phasebinsize = task [ 7 ]
try :
    period = 1.0 / frequency
    # use the common phaser to phase and sort the mag
    phased = phase_magseries ( times , modmags , period , fold_time , wrap = False , sort = True )
    # bin in phase if requested , this turns this into a sort of PDM method
    if phasebinsize is not None and phasebinsize > 0 :
        bphased = pwd_phasebin ( phased [ 'phase' ] , phased [ 'mags' ] , binsize = phasebinsize )
        phase_sorted = bphased [ 0 ]
        mod_mag_sorted = bphased [ 1 ]
        j_range = range ( len ( mod_mag_sorted ) - 1 )
    else :
        phase_sorted = phased [ 'phase' ]
        mod_mag_sorted = phased [ 'mags' ]
    # now calculate the string length
    rolledmags = nproll ( mod_mag_sorted , 1 )
    rolledphases = nproll ( phase_sorted , 1 )
    strings = ( ( rolledmags - mod_mag_sorted ) * ( rolledmags - mod_mag_sorted ) + ( rolledphases - phase_sorted ) * ( rolledphases - phase_sorted ) )
    strings [ 0 ] = ( ( ( mod_mag_sorted [ 0 ] - mod_mag_sorted [ - 1 ] ) * ( mod_mag_sorted [ 0 ] - mod_mag_sorted [ - 1 ] ) ) + ( ( phase_sorted [ 0 ] - phase_sorted [ - 1 ] + 1 ) * ( phase_sorted [ 0 ] - phase_sorted [ - 1 ] + 1 ) ) )
    strlen = npsum ( npsqrt ( strings ) )
    if ( keep_threshold_1 < strlen < keep_threshold_2 ) :
        p_goodflag = True
    else :
        p_goodflag = False
    return ( period , strlen , p_goodflag )
except Exception as e :
    LOGEXCEPTION ( 'error in DWP' )
    return ( period , npnan , False )


signature:
def pdw_period_find ( times , mags , errs , autofreq = True , init_p = None , end_p = None , f_step = 1.0e-4 , phasebinsize = None , sigclip = 10.0 , nworkers = None , verbose = False ) :
    '''This is the parallel version of the function above .
 Uses the string length method in Dworetsky 1983 to calculate the period of a
 time - series of magnitude measurements and associated magnitude errors . This
 can optionally bin in phase to try to speed up the calculation .
 PARAMETERS :
 time : series of times at which mags were measured ( usually some form of JD )
 mag : timeseries of magnitudes ( np . array )
 err : associated errs per magnitude measurement ( np . array )
 init _ p , end _ p : interval to search for periods between ( both ends inclusive )
 f _ step : step in frequency [ days ^ - 1 ] to use
 RETURNS :
 tuple of the following form :
 ( periods ( np . array ) ,
 string _ lengths ( np . array ) ,
 good _ period _ mask ( boolean array ) )'''

implementation:
# remove nans
find = npisfinite ( times ) & npisfinite ( mags ) & npisfinite ( errs )
ftimes , fmags , ferrs = times [ find ] , mags [ find ] , errs [ find ]
mod_mags = ( fmags - npmin ( fmags ) ) / ( 2.0 * ( npmax ( fmags ) - npmin ( fmags ) ) ) - 0.25
if len ( ftimes ) > 9 and len ( fmags ) > 9 and len ( ferrs ) > 9 : # get the median and stdev = 1.483 x MAD
    median_mag = np . median ( fmags )
    stddev_mag = ( np . median ( np . abs ( fmags - median_mag ) ) ) * 1.483
    # sigclip next
    if sigclip :
        sigind = ( np . abs ( fmags - median_mag ) ) < ( sigclip * stddev_mag )
        stimes = ftimes [ sigind ]
        smags = fmags [ sigind ]
        serrs = ferrs [ sigind ]
        LOGINFO ( 'sigclip = %s: before = %s observations, ' 'after = %s observations' % ( sigclip , len ( times ) , len ( stimes ) ) )
    else :
        stimes = ftimes
        smags = fmags
        serrs = ferrs
    # make sure there are enough points to calculate a spectrum
    if len ( stimes ) > 9 and len ( smags ) > 9 and len ( serrs ) > 9 : # get the frequencies to use
        if init_p :
            endf = 1.0 / init_p
        else : # default start period is 0.1 day
            endf = 1.0 / 0.1
        if end_p :
            startf = 1.0 / end_p
        else : # default end period is length of time series
            startf = 1.0 / ( stimes . max ( ) - stimes . min ( ) )
        # if we ' re not using autofreq , then use the provided frequencies
        if not autofreq :
            frequencies = np . arange ( startf , endf , stepsize )
            LOGINFO ( 'using %s frequency points, start P = %.3f, end P = %.3f' % ( frequencies . size , 1.0 / endf , 1.0 / startf ) )
        else : # this gets an automatic grid of frequencies to use
            frequencies = get_frequency_grid ( stimes , minfreq = startf , maxfreq = endf )
            LOGINFO ( 'using autofreq with %s frequency points, ' 'start P = %.3f, end P = %.3f' % ( frequencies . size , 1.0 / frequencies . max ( ) , 1.0 / frequencies . min ( ) ) )
        # set up some internal stuff
        fold_time = npmin ( ftimes )
        # fold at the first time element
        j_range = len ( fmags ) - 1
        epsilon = 2.0 * npmean ( ferrs )
        delta_l = 0.34 * ( epsilon - 0.5 * ( epsilon ** 2 ) ) * ( len ( ftimes ) - npsqrt ( 10.0 / epsilon ) )
        keep_threshold_1 = 1.6 + 1.2 * delta_l
        l = 0.212 * len ( ftimes )
        sig_l = len ( ftimes ) / 37.5
        keep_threshold_2 = l + 4.0 * sig_l
        # generate the tasks
        tasks = [ ( x , ftimes , mod_mags , fold_time , j_range , keep_threshold_1 , keep_threshold_2 , phasebinsize ) for x in frequencies ]
        # fire up the pool and farm out the tasks
        if ( not nworkers ) or ( nworkers > NCPUS ) :
            nworkers = NCPUS
            LOGINFO ( 'using %s workers...' % nworkers )
        pool = Pool ( nworkers )
        strlen_results = pool . map ( pdw_worker , tasks )
        pool . close ( )
        pool . join ( )
        del pool
        periods , strlens , goodflags = zip ( * strlen_results )
        periods , strlens , goodflags = ( np . array ( periods ) , np . array ( strlens ) , np . array ( goodflags ) )
        strlensort = npargsort ( strlens )
        nbeststrlens = strlens [ strlensort [ : 5 ] ]
        nbestperiods = periods [ strlensort [ : 5 ] ]
        nbestflags = goodflags [ strlensort [ : 5 ] ]
        bestperiod = nbestperiods [ 0 ]
        beststrlen = nbeststrlens [ 0 ]
        bestflag = nbestflags [ 0 ]
        return { 'bestperiod' : bestperiod , 'beststrlen' : beststrlen , 'bestflag' : bestflag , 'nbeststrlens' : nbeststrlens , 'nbestperiods' : nbestperiods , 'nbestflags' : nbestflags , 'strlens' : strlens , 'periods' : periods , 'goodflags' : goodflags }
    else :
        LOGERROR ( 'no good detections for these times and mags, skipping...' )
        return { 'bestperiod' : npnan , 'beststrlen' : npnan , 'bestflag' : npnan , 'nbeststrlens' : None , 'nbestperiods' : None , 'nbestflags' : None , 'strlens' : None , 'periods' : None , 'goodflags' : None }
else :
    LOGERROR ( 'no good detections for these times and mags, skipping...' )
    return { 'bestperiod' : npnan , 'beststrlen' : npnan , 'bestflag' : npnan , 'nbeststrlens' : None , 'nbestperiods' : None , 'nbestflags' : None , 'strlens' : None , 'periods' : None , 'goodflags' : None }


signature:
def townsend_lombscargle_value ( times , mags , omega ) :
    '''This calculates the periodogram value for each omega ( = 2 * pi * f ) . Mags must
 be normalized to zero with variance scaled to unity .'''

implementation:
cos_omegat = npcos ( omega * times )
sin_omegat = npsin ( omega * times )
xc = npsum ( mags * cos_omegat )
xs = npsum ( mags * sin_omegat )
cc = npsum ( cos_omegat * cos_omegat )
ss = npsum ( sin_omegat * sin_omegat )
cs = npsum ( cos_omegat * sin_omegat )
tau = nparctan ( 2 * cs / ( cc - ss ) ) / ( 2 * omega )
ctau = npcos ( omega * tau )
stau = npsin ( omega * tau )
leftsumtop = ( ctau * xc + stau * xs ) * ( ctau * xc + stau * xs )
leftsumbot = ctau * ctau * cc + 2.0 * ctau * stau * cs + stau * stau * ss
leftsum = leftsumtop / leftsumbot
rightsumtop = ( ctau * xs - stau * xc ) * ( ctau * xs - stau * xc )
rightsumbot = ctau * ctau * ss - 2.0 * ctau * stau * cs + stau * stau * cc
rightsum = rightsumtop / rightsumbot
pval = 0.5 * ( leftsum + rightsum )
return pval


signature:
def parallel_townsend_lsp ( times , mags , startp , endp , stepsize = 1.0e-4 , nworkers = 4 ) :
    '''This calculates the Lomb - Scargle periodogram for the frequencies
 corresponding to the period interval ( startp , endp ) using a frequency step
 size of stepsize cycles / day . This uses the algorithm in Townsend 2010.'''

implementation:
# make sure there are no nans anywhere
finiteind = np . isfinite ( times ) & np . isfinite ( mags )
ftimes , fmags = times [ finiteind ] , mags [ finiteind ]
# renormalize the mags to zero and scale them so that the variance = 1
nmags = ( fmags - np . median ( fmags ) ) / np . std ( fmags )
startf = 1.0 / endp
endf = 1.0 / startp
omegas = 2 * np . pi * np . arange ( startf , endf , stepsize )
# parallel map the lsp calculations
if ( not nworkers ) or ( nworkers > NCPUS ) :
    nworkers = NCPUS
    LOGINFO ( 'using %s workers...' % nworkers )
pool = Pool ( nworkers )
tasks = [ ( ftimes , nmags , x ) for x in omegas ]
lsp = pool . map ( townsend_lombscargle_wrapper , tasks )
pool . close ( )
pool . join ( )
return np . array ( omegas ) , np . array ( lsp )


signature:
def scipylsp_parallel ( times , mags , errs , # ignored but for consistent API
startp , endp , nbestpeaks = 5 , periodepsilon = 0.1 , # 0.1
stepsize = 1.0e-4 , nworkers = 4 , sigclip = None , timebin = None ) :
    '''This uses the LSP function from the scipy library , which is fast as hell . We
 try to make it faster by running LSP for sections of the omegas array in
 parallel .'''

implementation:
# make sure there are no nans anywhere
finiteind = np . isfinite ( mags ) & np . isfinite ( errs )
ftimes , fmags , ferrs = times [ finiteind ] , mags [ finiteind ] , errs [ finiteind ]
if len ( ftimes ) > 0 and len ( fmags ) > 0 : # sigclip the lightcurve if asked to do so
    if sigclip :
        worktimes , workmags , _ = sigclip_magseries ( ftimes , fmags , ferrs , sigclip = sigclip )
        LOGINFO ( 'ndet after sigclipping = %s' % len ( worktimes ) )
    else :
        worktimes = ftimes
        workmags = fmags
    # bin the lightcurve if asked to do so
    if timebin :
        binned = time_bin_magseries ( worktimes , workmags , binsize = timebin )
        worktimes = binned [ 'binnedtimes' ]
        workmags = binned [ 'binnedmags' ]
    # renormalize the working mags to zero and scale them so that the
    # variance = 1 for use with our LSP functions
    normmags = ( workmags - np . median ( workmags ) ) / np . std ( workmags )
    startf = 1.0 / endp
    endf = 1.0 / startp
    omegas = 2 * np . pi * np . arange ( startf , endf , stepsize )
    # partition the omegas array by nworkers
    tasks = [ ]
    chunksize = int ( float ( len ( omegas ) ) / nworkers ) + 1
    tasks = [ omegas [ x * chunksize : x * chunksize + chunksize ] for x in range ( nworkers ) ]
    # map to parallel workers
    if ( not nworkers ) or ( nworkers > NCPUS ) :
        nworkers = NCPUS
        LOGINFO ( 'using %s workers...' % nworkers )
    pool = Pool ( nworkers )
    tasks = [ ( worktimes , normmags , x ) for x in tasks ]
    lsp = pool . map ( parallel_scipylsp_worker , tasks )
    pool . close ( )
    pool . join ( )
    lsp = np . concatenate ( lsp )
    periods = 2.0 * np . pi / omegas
    # find the nbestpeaks for the periodogram : 1 . sort the lsp array by
    # highest value first 2 . go down the values until we find five values
    # that are separated by at least periodepsilon in period
    # make sure we only get finite lsp values
    finitepeakind = npisfinite ( lsp )
    finlsp = lsp [ finitepeakind ]
    finperiods = periods [ finitepeakind ]
    bestperiodind = npargmax ( finlsp )
    sortedlspind = np . argsort ( finlsp ) [ : : - 1 ]
    sortedlspperiods = finperiods [ sortedlspind ]
    sortedlspvals = finlsp [ sortedlspind ]
    prevbestlspval = sortedlspvals [ 0 ]
    # now get the nbestpeaks
    nbestperiods , nbestlspvals , peakcount = ( [ finperiods [ bestperiodind ] ] , [ finlsp [ bestperiodind ] ] , 1 )
    prevperiod = sortedlspperiods [ 0 ]
    # find the best nbestpeaks in the lsp and their periods
    for period , lspval in zip ( sortedlspperiods , sortedlspvals ) :
        if peakcount == nbestpeaks :
            break
        perioddiff = abs ( period - prevperiod )
        bestperiodsdiff = [ abs ( period - x ) for x in nbestperiods ]
        # print ( ' prevperiod = % s , thisperiod = % s , '
        # ' perioddiff = % s , peakcount = % s ' %
        # ( prevperiod , period , perioddiff , peakcount ) )
        # this ensures that this period is different from the last period
        # and from all the other existing best periods by periodepsilon to
        # make sure we jump to an entire different peak in the periodogram
        if ( perioddiff > periodepsilon and all ( x > periodepsilon for x in bestperiodsdiff ) ) :
            nbestperiods . append ( period )
            nbestlspvals . append ( lspval )
            peakcount = peakcount + 1
        prevperiod = period
    return { 'bestperiod' : finperiods [ bestperiodind ] , 'bestlspval' : finlsp [ bestperiodind ] , 'nbestpeaks' : nbestpeaks , 'nbestlspvals' : nbestlspvals , 'nbestperiods' : nbestperiods , 'lspvals' : lsp , 'omegas' : omegas , 'periods' : periods , 'method' : 'sls' }
else :
    LOGERROR ( 'no good detections for these times and mags, skipping...' )
    return { 'bestperiod' : npnan , 'bestlspval' : npnan , 'nbestpeaks' : nbestpeaks , 'nbestlspvals' : None , 'nbestperiods' : None , 'lspvals' : None , 'periods' : None , 'method' : 'sls' }


signature:
def get_periodicfeatures ( pfpickle , lcbasedir , outdir , fourierorder = 5 , # these are depth , duration , ingress duration
transitparams = ( - 0.01 , 0.1 , 0.1 ) , # these are depth , duration , depth ratio , secphase
ebparams = ( - 0.2 , 0.3 , 0.7 , 0.5 ) , pdiff_threshold = 1.0e-4 , sidereal_threshold = 1.0e-4 , sampling_peak_multiplier = 5.0 , sampling_startp = None , sampling_endp = None , starfeatures = None , timecols = None , magcols = None , errcols = None , lcformat = 'hat-sql' , lcformatdir = None , sigclip = 10.0 , verbose = True , raiseonfail = False ) :
    '''This gets all periodic features for the object .
 Parameters
 pfpickle : str
 The period - finding result pickle containing period - finder results to use
 for the calculation of LC fit , periodogram , and phased LC features .
 lcbasedir : str
 The base directory where the light curve for the current object is
 located .
 outdir : str
 The output directory where the results will be written .
 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 .
 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 .
 starfeatures : str or None
 If not None , this should be the filename of the
 ` starfeatures - < objectid > . pkl ` created by
 : py : func : ` astrobase . lcproc . lcsfeatures . get _ starfeatures ` for this
 object . This is used to get the neighbor ' s light curve and phase it with
 this object ' s period to see if this object is blended .
 timecols : list of str or None
 The timecol keys to use from the lcdict in calculating the features .
 magcols : list of str or None
 The magcol keys to use from the lcdict in calculating the features .
 errcols : list of str or None
 The errcol keys to use from the lcdict in calculating the features .
 lcformat : str
 This is the ` formatkey ` associated with your light curve format , which
 you previously passed in to the ` lcproc . register _ lcformat `
 function . This will be used to look up how to find and read the light
 curves specified in ` basedir ` or ` use _ list _ of _ filenames ` .
 lcformatdir : str or None
 If this is provided , gives the path to a directory when you ' ve stored
 your lcformat description JSONs , other than the usual directories lcproc
 knows to search for them in . Use this along with ` lcformat ` to specify
 an LC format JSON file that ' s not currently registered with lcproc .
 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 True , will indicate progress while working .
 raiseonfail : bool
 If True , will raise an Exception if something goes wrong .
 Returns
 str
 Returns a filename for the output pickle containing all of the periodic
 features for the input object ' s LC .'''

implementation:
try :
    formatinfo = get_lcformat ( lcformat , use_lcformat_dir = lcformatdir )
    if formatinfo :
        ( fileglob , readerfunc , dtimecols , dmagcols , derrcols , magsarefluxes , normfunc ) = formatinfo
    else :
        LOGERROR ( "can't figure out the light curve format" )
        return None
except Exception as e :
    LOGEXCEPTION ( "can't figure out the light curve format" )
    return None
# open the pfpickle
if pfpickle . endswith ( '.gz' ) :
    infd = gzip . open ( pfpickle )
else :
    infd = open ( pfpickle )
pf = pickle . load ( infd )
infd . close ( )
lcfile = os . path . join ( lcbasedir , pf [ 'lcfbasename' ] )
objectid = pf [ 'objectid' ]
if 'kwargs' in pf :
    kwargs = pf [ 'kwargs' ]
else :
    kwargs = None
# override the default timecols , magcols , and errcols
# using the ones provided to the periodfinder
# if those don ' t exist , use the defaults from the lcformat def
if kwargs and 'timecols' in kwargs and timecols is None :
    timecols = kwargs [ 'timecols' ]
elif not kwargs and not timecols :
    timecols = dtimecols
if kwargs and 'magcols' in kwargs and magcols is None :
    magcols = kwargs [ 'magcols' ]
elif not kwargs and not magcols :
    magcols = dmagcols
if kwargs and 'errcols' in kwargs and errcols is None :
    errcols = kwargs [ 'errcols' ]
elif not kwargs and not errcols :
    errcols = derrcols
# check if the light curve file exists
if not os . path . exists ( lcfile ) :
    LOGERROR ( "can't find LC %s for object %s" % ( lcfile , objectid ) )
    return None
# check if we have neighbors we can get the LCs for
if starfeatures is not None and os . path . exists ( starfeatures ) :
    with open ( starfeatures , 'rb' ) as infd :
        starfeat = pickle . load ( infd )
    if starfeat [ 'closestnbrlcfname' ] . size > 0 :
        nbr_full_lcf = starfeat [ 'closestnbrlcfname' ] [ 0 ]
        # check for this LC in the lcbasedir
        if os . path . exists ( os . path . join ( lcbasedir , os . path . basename ( nbr_full_lcf ) ) ) :
            nbrlcf = os . path . join ( lcbasedir , os . path . basename ( nbr_full_lcf ) )
        # if it ' s not there , check for this file at the full LC location
        elif os . path . exists ( nbr_full_lcf ) :
            nbrlcf = nbr_full_lcf
        # otherwise , we can ' t find it , so complain
        else :
            LOGWARNING ( "can't find neighbor light curve file: %s in " "its original directory: %s, or in this object's " "lcbasedir: %s, skipping neighbor processing..." % ( os . path . basename ( nbr_full_lcf ) , os . path . dirname ( nbr_full_lcf ) , lcbasedir ) )
            nbrlcf = None
    else :
        nbrlcf = None
else :
    nbrlcf = None
# now , start processing for periodic feature extraction
try : # get the object LC into a dict
    lcdict = readerfunc ( lcfile )
    # this should handle lists / tuples being returned by readerfunc
    # we assume that the first element is the actual lcdict
    # FIXME : figure out how to not need this assumption
    if ( ( isinstance ( lcdict , ( list , tuple ) ) ) and ( isinstance ( lcdict [ 0 ] , dict ) ) ) :
        lcdict = lcdict [ 0 ]
    # get the nbr object LC into a dict if there is one
    if nbrlcf is not None :
        nbrlcdict = readerfunc ( nbrlcf )
        # this should handle lists / tuples being returned by readerfunc
        # we assume that the first element is the actual lcdict
        # FIXME : figure out how to not need this assumption
        if ( ( isinstance ( nbrlcdict , ( list , tuple ) ) ) and ( isinstance ( nbrlcdict [ 0 ] , dict ) ) ) :
            nbrlcdict = nbrlcdict [ 0 ]
    # this will be the output file
    outfile = os . path . join ( outdir , 'periodicfeatures-%s.pkl' % squeeze ( objectid ) . replace ( ' ' , '-' ) )
    # normalize using the special function if specified
    if normfunc is not None :
        lcdict = normfunc ( lcdict )
        if nbrlcf :
            nbrlcdict = normfunc ( nbrlcdict )
    resultdict = { }
    for tcol , mcol , ecol in zip ( timecols , magcols , errcols ) : # dereference the columns and get them from the lcdict
        if '.' in tcol :
            tcolget = tcol . split ( '.' )
        else :
            tcolget = [ tcol ]
        times = _dict_get ( lcdict , tcolget )
        if nbrlcf :
            nbrtimes = _dict_get ( nbrlcdict , tcolget )
        else :
            nbrtimes = None
        if '.' in mcol :
            mcolget = mcol . split ( '.' )
        else :
            mcolget = [ mcol ]
        mags = _dict_get ( lcdict , mcolget )
        if nbrlcf :
            nbrmags = _dict_get ( nbrlcdict , mcolget )
        else :
            nbrmags = None
        if '.' in ecol :
            ecolget = ecol . split ( '.' )
        else :
            ecolget = [ ecol ]
        errs = _dict_get ( lcdict , ecolget )
        if nbrlcf :
            nbrerrs = _dict_get ( nbrlcdict , ecolget )
        else :
            nbrerrs = None
        # filter out nans , etc . from the object and any neighbor LC
        # get the finite values
        finind = np . isfinite ( times ) & np . isfinite ( mags ) & np . isfinite ( errs )
        ftimes , fmags , ferrs = times [ finind ] , mags [ finind ] , errs [ finind ]
        if nbrlcf :
            nfinind = ( np . isfinite ( nbrtimes ) & np . isfinite ( nbrmags ) & np . isfinite ( nbrerrs ) )
            nbrftimes , nbrfmags , nbrferrs = ( nbrtimes [ nfinind ] , nbrmags [ nfinind ] , nbrerrs [ nfinind ] )
        # get nonzero errors
        nzind = np . nonzero ( ferrs )
        ftimes , fmags , ferrs = ftimes [ nzind ] , fmags [ nzind ] , ferrs [ nzind ]
        if nbrlcf :
            nnzind = np . nonzero ( nbrferrs )
            nbrftimes , nbrfmags , nbrferrs = ( nbrftimes [ nnzind ] , nbrfmags [ nnzind ] , nbrferrs [ nnzind ] )
        # normalize here if not using special normalization
        if normfunc is None :
            ntimes , nmags = normalize_magseries ( ftimes , fmags , magsarefluxes = magsarefluxes )
            times , mags , errs = ntimes , nmags , ferrs
            if nbrlcf :
                nbrntimes , nbrnmags = normalize_magseries ( nbrftimes , nbrfmags , magsarefluxes = magsarefluxes )
                nbrtimes , nbrmags , nbrerrs = nbrntimes , nbrnmags , nbrferrs
            else :
                nbrtimes , nbrmags , nbrerrs = None , None , None
        else :
            times , mags , errs = ftimes , fmags , ferrs
        if times . size > 999 : # now we have times , mags , errs ( and nbrtimes , nbrmags , nbrerrs )
            available_pfmethods = [ ]
            available_pgrams = [ ]
            available_bestperiods = [ ]
            for k in pf [ mcol ] . keys ( ) :
                if k in PFMETHODS :
                    available_pgrams . append ( pf [ mcol ] [ k ] )
                    if k != 'win' :
                        available_pfmethods . append ( pf [ mcol ] [ k ] [ 'method' ] )
                        available_bestperiods . append ( pf [ mcol ] [ k ] [ 'bestperiod' ] )
            # process periodic features for this magcol
            featkey = 'periodicfeatures-%s' % mcol
            resultdict [ featkey ] = { }
            # first , handle the periodogram features
            pgramfeat = periodicfeatures . periodogram_features ( available_pgrams , times , mags , errs , sigclip = sigclip , pdiff_threshold = pdiff_threshold , sidereal_threshold = sidereal_threshold , sampling_peak_multiplier = sampling_peak_multiplier , sampling_startp = sampling_startp , sampling_endp = sampling_endp , verbose = verbose )
            resultdict [ featkey ] . update ( pgramfeat )
            resultdict [ featkey ] [ 'pfmethods' ] = available_pfmethods
            # then for each bestperiod , get phasedlc and lcfit features
            for _ind , pfm , bp in zip ( range ( len ( available_bestperiods ) ) , available_pfmethods , available_bestperiods ) :
                resultdict [ featkey ] [ pfm ] = periodicfeatures . lcfit_features ( times , mags , errs , bp , fourierorder = fourierorder , transitparams = transitparams , ebparams = ebparams , sigclip = sigclip , magsarefluxes = magsarefluxes , verbose = verbose )
                phasedlcfeat = periodicfeatures . phasedlc_features ( times , mags , errs , bp , nbrtimes = nbrtimes , nbrmags = nbrmags , nbrerrs = nbrerrs )
                resultdict [ featkey ] [ pfm ] . update ( phasedlcfeat )
        else :
            LOGERROR ( 'not enough finite measurements in magcol: %s, for ' 'pfpickle: %s, skipping this magcol' % ( mcol , pfpickle ) )
            featkey = 'periodicfeatures-%s' % mcol
            resultdict [ featkey ] = None
    # end of per magcol processing
    # write resultdict to pickle
    outfile = os . path . join ( outdir , 'periodicfeatures-%s.pkl' % squeeze ( objectid ) . replace ( ' ' , '-' ) )
    with open ( outfile , 'wb' ) as outfd :
        pickle . dump ( resultdict , outfd , pickle . HIGHEST_PROTOCOL )
    return outfile
except Exception as e :
    LOGEXCEPTION ( 'failed to run for pf: %s, lcfile: %s' % ( pfpickle , lcfile ) )
    if raiseonfail :
        raise
    else :
        return None


signature:
def _periodicfeatures_worker ( task ) :
    '''This is a parallel worker for the drivers below .'''

implementation:
pfpickle , lcbasedir , outdir , starfeatures , kwargs = task
try :
    return get_periodicfeatures ( pfpickle , lcbasedir , outdir , starfeatures = starfeatures , ** kwargs )
except Exception as e :
    LOGEXCEPTION ( 'failed to get periodicfeatures for %s' % pfpickle )


signature:
def serial_periodicfeatures ( pfpkl_list , lcbasedir , outdir , starfeaturesdir = None , fourierorder = 5 , # these are depth , duration , ingress duration
transitparams = ( - 0.01 , 0.1 , 0.1 ) , # these are depth , duration , depth ratio , secphase
ebparams = ( - 0.2 , 0.3 , 0.7 , 0.5 ) , pdiff_threshold = 1.0e-4 , sidereal_threshold = 1.0e-4 , sampling_peak_multiplier = 5.0 , sampling_startp = None , sampling_endp = None , starfeatures = None , timecols = None , magcols = None , errcols = None , lcformat = 'hat-sql' , lcformatdir = None , sigclip = 10.0 , verbose = False , maxobjects = None ) :
    '''This drives the periodicfeatures collection for a list of periodfinding
 pickles .
 Parameters
 pfpkl _ list : list of str
 The list of period - finding pickles to use .
 lcbasedir : str
 The base directory where the associated light curves are located .
 outdir : str
 The directory where the results will be written .
 starfeaturesdir : str or None
 The directory containing the ` starfeatures - < objectid > . pkl ` files for
 each object to use calculate neighbor proximity light curve features .
 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 .
 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 .
 timecols : list of str or None
 The timecol keys to use from the lcdict in calculating the features .
 magcols : list of str or None
 The magcol keys to use from the lcdict in calculating the features .
 errcols : list of str or None
 The errcol keys to use from the lcdict in calculating the features .
 lcformat : str
 This is the ` formatkey ` associated with your light curve format , which
 you previously passed in to the ` lcproc . register _ lcformat `
 function . This will be used to look up how to find and read the light
 curves specified in ` basedir ` or ` use _ list _ of _ filenames ` .
 lcformatdir : str or None
 If this is provided , gives the path to a directory when you ' ve stored
 your lcformat description JSONs , other than the usual directories lcproc
 knows to search for them in . Use this along with ` lcformat ` to specify
 an LC format JSON file that ' s not currently registered with lcproc .
 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 True , will indicate progress while working .
 maxobjects : int
 The total number of objects to process from ` pfpkl _ list ` .
 Returns
 Nothing .'''

implementation:
try :
    formatinfo = get_lcformat ( lcformat , use_lcformat_dir = lcformatdir )
    if formatinfo :
        ( fileglob , readerfunc , dtimecols , dmagcols , derrcols , magsarefluxes , normfunc ) = formatinfo
    else :
        LOGERROR ( "can't figure out the light curve format" )
        return None
except Exception as e :
    LOGEXCEPTION ( "can't figure out the light curve format" )
    return None
# make sure to make the output directory if it doesn ' t exist
if not os . path . exists ( outdir ) :
    os . makedirs ( outdir )
if maxobjects :
    pfpkl_list = pfpkl_list [ : maxobjects ]
LOGINFO ( '%s periodfinding pickles to process' % len ( pfpkl_list ) )
# if the starfeaturedir is provided , try to find a starfeatures pickle for
# each periodfinding pickle in pfpkl _ list
if starfeaturesdir and os . path . exists ( starfeaturesdir ) :
    starfeatures_list = [ ]
    LOGINFO ( 'collecting starfeatures pickles...' )
    for pfpkl in pfpkl_list :
        sfpkl1 = os . path . basename ( pfpkl ) . replace ( 'periodfinding' , 'starfeatures' )
        sfpkl2 = sfpkl1 . replace ( '.gz' , '' )
        sfpath1 = os . path . join ( starfeaturesdir , sfpkl1 )
        sfpath2 = os . path . join ( starfeaturesdir , sfpkl2 )
        if os . path . exists ( sfpath1 ) :
            starfeatures_list . append ( sfpkl1 )
        elif os . path . exists ( sfpath2 ) :
            starfeatures_list . append ( sfpkl2 )
        else :
            starfeatures_list . append ( None )
else :
    starfeatures_list = [ None for x in pfpkl_list ]
# generate the task list
kwargs = { 'fourierorder' : fourierorder , 'transitparams' : transitparams , 'ebparams' : ebparams , 'pdiff_threshold' : pdiff_threshold , 'sidereal_threshold' : sidereal_threshold , 'sampling_peak_multiplier' : sampling_peak_multiplier , 'sampling_startp' : sampling_startp , 'sampling_endp' : sampling_endp , 'timecols' : timecols , 'magcols' : magcols , 'errcols' : errcols , 'lcformat' : lcformat , 'lcformatdir' : lcformatdir , 'sigclip' : sigclip , 'verbose' : verbose }
tasks = [ ( x , lcbasedir , outdir , y , kwargs ) for ( x , y ) in zip ( pfpkl_list , starfeatures_list ) ]
LOGINFO ( 'processing periodfinding pickles...' )
for task in tqdm ( tasks ) :
    _periodicfeatures_worker ( task )


signature:
def parallel_periodicfeatures ( pfpkl_list , lcbasedir , outdir , starfeaturesdir = None , fourierorder = 5 , # these are depth , duration , ingress duration
transitparams = ( - 0.01 , 0.1 , 0.1 ) , # these are depth , duration , depth ratio , secphase
ebparams = ( - 0.2 , 0.3 , 0.7 , 0.5 ) , pdiff_threshold = 1.0e-4 , sidereal_threshold = 1.0e-4 , sampling_peak_multiplier = 5.0 , sampling_startp = None , sampling_endp = None , timecols = None , magcols = None , errcols = None , lcformat = 'hat-sql' , lcformatdir = None , sigclip = 10.0 , verbose = False , maxobjects = None , nworkers = NCPUS ) :
    '''This runs periodic feature generation in parallel for all periodfinding
 pickles in the input list .
 Parameters
 pfpkl _ list : list of str
 The list of period - finding pickles to use .
 lcbasedir : str
 The base directory where the associated light curves are located .
 outdir : str
 The directory where the results will be written .
 starfeaturesdir : str or None
 The directory containing the ` starfeatures - < objectid > . pkl ` files for
 each object to use calculate neighbor proximity light curve features .
 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 .
 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 .
 timecols : list of str or None
 The timecol keys to use from the lcdict in calculating the features .
 magcols : list of str or None
 The magcol keys to use from the lcdict in calculating the features .
 errcols : list of str or None
 The errcol keys to use from the lcdict in calculating the features .
 lcformat : str
 This is the ` formatkey ` associated with your light curve format , which
 you previously passed in to the ` lcproc . register _ lcformat `
 function . This will be used to look up how to find and read the light
 curves specified in ` basedir ` or ` use _ list _ of _ filenames ` .
 lcformatdir : str or None
 If this is provided , gives the path to a directory when you ' ve stored
 your lcformat description JSONs , other than the usual directories lcproc
 knows to search for them in . Use this along with ` lcformat ` to specify
 an LC format JSON file that ' s not currently registered with lcproc .
 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 True , will indicate progress while working .
 maxobjects : int
 The total number of objects to process from ` pfpkl _ list ` .
 nworkers : int
 The number of parallel workers to launch to process the input .
 Returns
 dict
 A dict containing key : val pairs of the input period - finder result and
 the output periodic feature result pickles for each input pickle is
 returned .'''

implementation:
# make sure to make the output directory if it doesn ' t exist
if not os . path . exists ( outdir ) :
    os . makedirs ( outdir )
if maxobjects :
    pfpkl_list = pfpkl_list [ : maxobjects ]
LOGINFO ( '%s periodfinding pickles to process' % len ( pfpkl_list ) )
# if the starfeaturedir is provided , try to find a starfeatures pickle for
# each periodfinding pickle in pfpkl _ list
if starfeaturesdir and os . path . exists ( starfeaturesdir ) :
    starfeatures_list = [ ]
    LOGINFO ( 'collecting starfeatures pickles...' )
    for pfpkl in pfpkl_list :
        sfpkl1 = os . path . basename ( pfpkl ) . replace ( 'periodfinding' , 'starfeatures' )
        sfpkl2 = sfpkl1 . replace ( '.gz' , '' )
        sfpath1 = os . path . join ( starfeaturesdir , sfpkl1 )
        sfpath2 = os . path . join ( starfeaturesdir , sfpkl2 )
        if os . path . exists ( sfpath1 ) :
            starfeatures_list . append ( sfpkl1 )
        elif os . path . exists ( sfpath2 ) :
            starfeatures_list . append ( sfpkl2 )
        else :
            starfeatures_list . append ( None )
else :
    starfeatures_list = [ None for x in pfpkl_list ]
# generate the task list
kwargs = { 'fourierorder' : fourierorder , 'transitparams' : transitparams , 'ebparams' : ebparams , 'pdiff_threshold' : pdiff_threshold , 'sidereal_threshold' : sidereal_threshold , 'sampling_peak_multiplier' : sampling_peak_multiplier , 'sampling_startp' : sampling_startp , 'sampling_endp' : sampling_endp , 'timecols' : timecols , 'magcols' : magcols , 'errcols' : errcols , 'lcformat' : lcformat , 'lcformatdir' : lcformat , 'sigclip' : sigclip , 'verbose' : verbose }
tasks = [ ( x , lcbasedir , outdir , y , kwargs ) for ( x , y ) in zip ( pfpkl_list , starfeatures_list ) ]
LOGINFO ( 'processing periodfinding pickles...' )
with ProcessPoolExecutor ( max_workers = nworkers ) as executor :
    resultfutures = executor . map ( _periodicfeatures_worker , tasks )
results = [ x for x in resultfutures ]
resdict = { os . path . basename ( x ) : y for ( x , y ) in zip ( pfpkl_list , results ) }
return resdict


signature:
def parallel_periodicfeatures_lcdir ( pfpkl_dir , lcbasedir , outdir , pfpkl_glob = 'periodfinding-*.pkl*' , starfeaturesdir = None , fourierorder = 5 , # these are depth , duration , ingress duration
transitparams = ( - 0.01 , 0.1 , 0.1 ) , # these are depth , duration , depth ratio , secphase
ebparams = ( - 0.2 , 0.3 , 0.7 , 0.5 ) , pdiff_threshold = 1.0e-4 , sidereal_threshold = 1.0e-4 , sampling_peak_multiplier = 5.0 , sampling_startp = None , sampling_endp = None , timecols = None , magcols = None , errcols = None , lcformat = 'hat-sql' , lcformatdir = None , sigclip = 10.0 , verbose = False , maxobjects = None , nworkers = NCPUS , recursive = True , ) :
    '''This runs parallel periodicfeature extraction for a directory of
 periodfinding result pickles .
 Parameters
 pfpkl _ dir : str
 The directory containing the pickles to process .
 lcbasedir : str
 The directory where all of the associated light curve files are located .
 outdir : str
 The directory where all the output will be written .
 pfpkl _ glob : str
 The UNIX file glob to use to search for period - finder result pickles in
 ` pfpkl _ dir ` .
 starfeaturesdir : str or None
 The directory containing the ` starfeatures - < objectid > . pkl ` files for
 each object to use calculate neighbor proximity light curve features .
 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 .
 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 .
 timecols : list of str or None
 The timecol keys to use from the lcdict in calculating the features .
 magcols : list of str or None
 The magcol keys to use from the lcdict in calculating the features .
 errcols : list of str or None
 The errcol keys to use from the lcdict in calculating the features .
 lcformat : str
 This is the ` formatkey ` associated with your light curve format , which
 you previously passed in to the ` lcproc . register _ lcformat `
 function . This will be used to look up how to find and read the light
 curves specified in ` basedir ` or ` use _ list _ of _ filenames ` .
 lcformatdir : str or None
 If this is provided , gives the path to a directory when you ' ve stored
 your lcformat description JSONs , other than the usual directories lcproc
 knows to search for them in . Use this along with ` lcformat ` to specify
 an LC format JSON file that ' s not currently registered with lcproc .
 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 True , will indicate progress while working .
 maxobjects : int
 The total number of objects to process from ` pfpkl _ list ` .
 nworkers : int
 The number of parallel workers to launch to process the input .
 Returns
 dict
 A dict containing key : val pairs of the input period - finder result and
 the output periodic feature result pickles for each input pickle is
 returned .'''

implementation:
try :
    formatinfo = get_lcformat ( lcformat , use_lcformat_dir = lcformatdir )
    if formatinfo :
        ( dfileglob , readerfunc , dtimecols , dmagcols , derrcols , magsarefluxes , normfunc ) = formatinfo
    else :
        LOGERROR ( "can't figure out the light curve format" )
        return None
except Exception as e :
    LOGEXCEPTION ( "can't figure out the light curve format" )
    return None
fileglob = pfpkl_glob
# now find the files
LOGINFO ( 'searching for periodfinding pickles in %s ...' % pfpkl_dir )
if recursive is False :
    matching = glob . glob ( os . path . join ( pfpkl_dir , fileglob ) )
else : # use recursive glob for Python 3.5 +
    if sys . version_info [ : 2 ] > ( 3 , 4 ) :
        matching = glob . glob ( os . path . join ( pfpkl_dir , '**' , fileglob ) , recursive = True )
    # otherwise , use os . walk and glob
    else : # use os . walk to go through the directories
        walker = os . walk ( pfpkl_dir )
        matching = [ ]
        for root , dirs , _files in walker :
            for sdir in dirs :
                searchpath = os . path . join ( root , sdir , fileglob )
                foundfiles = glob . glob ( searchpath )
                if foundfiles :
                    matching . extend ( foundfiles )
# now that we have all the files , process them
if matching and len ( matching ) > 0 :
    LOGINFO ( 'found %s periodfinding pickles, getting periodicfeatures...' % len ( matching ) )
    return parallel_periodicfeatures ( matching , lcbasedir , outdir , starfeaturesdir = starfeaturesdir , fourierorder = fourierorder , transitparams = transitparams , ebparams = ebparams , pdiff_threshold = pdiff_threshold , sidereal_threshold = sidereal_threshold , sampling_peak_multiplier = sampling_peak_multiplier , sampling_startp = sampling_startp , sampling_endp = sampling_endp , timecols = timecols , magcols = magcols , errcols = errcols , lcformat = lcformat , lcformatdir = lcformatdir , sigclip = sigclip , verbose = verbose , maxobjects = maxobjects , nworkers = nworkers , )
else :
    LOGERROR ( 'no periodfinding pickles found in %s' % ( pfpkl_dir ) )
    return None


signature:
def _parse_xmatch_catalog_header ( xc , xk ) :
    '''This parses the header for a catalog file and returns it as a file object .
 Parameters
 xc : str
 The file name of an xmatch catalog prepared previously .
 xk : list of str
 This is a list of column names to extract from the xmatch catalog .
 Returns
 tuple
 The tuple returned is of the form : :
 ( infd : the file object associated with the opened xmatch catalog ,
 catdefdict : a dict describing the catalog column definitions ,
 catcolinds : column number indices of the catalog ,
 catcoldtypes : the numpy dtypes of the catalog columns ,
 catcolnames : the names of each catalog column ,
 catcolunits : the units associated with each catalog column )'''

implementation:
catdef = [ ]
# read in this catalog and transparently handle gzipped files
if xc . endswith ( '.gz' ) :
    infd = gzip . open ( xc , 'rb' )
else :
    infd = open ( xc , 'rb' )
# read in the defs
for line in infd :
    if line . decode ( ) . startswith ( '#' ) :
        catdef . append ( line . decode ( ) . replace ( '#' , '' ) . strip ( ) . rstrip ( '\n' ) )
    if not line . decode ( ) . startswith ( '#' ) :
        break
if not len ( catdef ) > 0 :
    LOGERROR ( "catalog definition not parseable " "for catalog: %s, skipping..." % xc )
    return None
catdef = ' ' . join ( catdef )
catdefdict = json . loads ( catdef )
catdefkeys = [ x [ 'key' ] for x in catdefdict [ 'columns' ] ]
catdefdtypes = [ x [ 'dtype' ] for x in catdefdict [ 'columns' ] ]
catdefnames = [ x [ 'name' ] for x in catdefdict [ 'columns' ] ]
catdefunits = [ x [ 'unit' ] for x in catdefdict [ 'columns' ] ]
# get the correct column indices and dtypes for the requested columns
# from the catdefdict
catcolinds = [ ]
catcoldtypes = [ ]
catcolnames = [ ]
catcolunits = [ ]
for xkcol in xk :
    if xkcol in catdefkeys :
        xkcolind = catdefkeys . index ( xkcol )
        catcolinds . append ( xkcolind )
        catcoldtypes . append ( catdefdtypes [ xkcolind ] )
        catcolnames . append ( catdefnames [ xkcolind ] )
        catcolunits . append ( catdefunits [ xkcolind ] )
return ( infd , catdefdict , catcolinds , catcoldtypes , catcolnames , catcolunits )


signature:
def load_xmatch_external_catalogs ( xmatchto , xmatchkeys , outfile = None ) :
    '''This loads the external xmatch catalogs into a dict for use in an xmatch .
 Parameters
 xmatchto : list of str
 This is a list of paths to all the catalog text files that will be
 loaded .
 The text files must be ' CSVs ' that use the ' | ' character as the
 separator betwen columns . These files should all begin with a header in
 JSON format on lines starting with the ' # ' character . this header will
 define the catalog and contains the name of the catalog and the column
 definitions . Column definitions must have the column name and the numpy
 dtype of the columns ( in the same format as that expected for the
 numpy . genfromtxt function ) . Any line that does not begin with ' # ' is
 assumed to be part of the columns in the catalog . An example is shown
 below : :
 # { " name " : " NSVS catalog of variable stars " ,
 # " columns " : [
 # { " key " : " objectid " , " dtype " : " U20 " , " name " : " Object ID " , " unit " : null } ,
 # { " key " : " ra " , " dtype " : " f8 " , " name " : " RA " , " unit " : " deg " } ,
 # { " key " : " decl " , " dtype " : " f8 " , " name " : " Declination " , " unit " : " deg " } ,
 # { " key " : " sdssr " , " dtype " : " f8 " , " name " : " SDSS r " , " unit " : " mag " } ,
 # { " key " : " vartype " , " dtype " : " U20 " , " name " : " Variable type " , " unit " : null }
 # " colra " : " ra " ,
 # " coldec " : " decl " ,
 # " description " : " Contains variable stars from the NSVS catalog " }
 objectid1 | 45.0 | - 20.0 | 12.0 | detached EB
 objectid2 | 145.0 | 23.0 | 10.0 | RRab
 objectid3 | 12.0 | 11.0 | 14.0 | Cepheid
 xmatchkeys : list of lists
 This is the list of lists of column names ( as str ) to get out of each
 ` xmatchto ` catalog . This should be the same length as ` xmatchto ` and
 each element here will apply to the respective file in ` xmatchto ` .
 outfile : str or None
 If this is not None , set this to the name of the pickle to write the
 collected xmatch catalogs to . this pickle can then be loaded
 transparently by the : py : func : ` astrobase . checkplot . pkl . checkplot _ dict ` ,
 : py : func : ` astrobase . checkplot . pkl . checkplot _ pickle ` functions to provide
 xmatch info to the
 : py : func : ` astrobase . checkplot . pkl _ xmatch . xmatch _ external _ catalogs `
 function below .
 If this is None , will return the loaded xmatch catalogs directly . This
 will be a huge dict , so make sure you have enough RAM .
 Returns
 str or dict
 Based on the ` outfile ` kwarg , will either return the path to a collected
 xmatch pickle file or the collected xmatch dict .'''

implementation:
outdict = { }
for xc , xk in zip ( xmatchto , xmatchkeys ) :
    parsed_catdef = _parse_xmatch_catalog_header ( xc , xk )
    if not parsed_catdef :
        continue
    ( infd , catdefdict , catcolinds , catcoldtypes , catcolnames , catcolunits ) = parsed_catdef
    # get the specified columns out of the catalog
    catarr = np . genfromtxt ( infd , usecols = catcolinds , names = xk , dtype = ',' . join ( catcoldtypes ) , comments = '#' , delimiter = '|' , autostrip = True )
    infd . close ( )
    catshortname = os . path . splitext ( os . path . basename ( xc ) ) [ 0 ]
    catshortname = catshortname . replace ( '.csv' , '' )
    # make a kdtree for this catalog
    # get the ra and decl columns
    objra , objdecl = ( catarr [ catdefdict [ 'colra' ] ] , catarr [ catdefdict [ 'coldec' ] ] )
    # get the xyz unit vectors from ra , decl
    cosdecl = np . cos ( np . radians ( objdecl ) )
    sindecl = np . sin ( np . radians ( objdecl ) )
    cosra = np . cos ( np . radians ( objra ) )
    sinra = np . sin ( np . radians ( objra ) )
    xyz = np . column_stack ( ( cosra * cosdecl , sinra * cosdecl , sindecl ) )
    # generate the kdtree
    kdt = cKDTree ( xyz , copy_data = True )
    # generate the outdict element for this catalog
    catoutdict = { 'kdtree' : kdt , 'data' : catarr , 'columns' : xk , 'colnames' : catcolnames , 'colunits' : catcolunits , 'name' : catdefdict [ 'name' ] , 'desc' : catdefdict [ 'description' ] }
    outdict [ catshortname ] = catoutdict
if outfile is not None : # if we ' re on OSX , we apparently need to save the file in chunks smaller
# than 2 GB to make it work right . can ' t load pickles larger than 4 GB
# either , but 3 GB < total size < 4 GB appears to be OK when loading .
# also see : https : / / bugs . python . org / issue24658.
# fix adopted from : https : / / stackoverflow . com / a / 38003910
    if sys . platform == 'darwin' :
        dumpbytes = pickle . dumps ( outdict , protocol = pickle . HIGHEST_PROTOCOL )
        max_bytes = 2 ** 31 - 1
        with open ( outfile , 'wb' ) as outfd :
            for idx in range ( 0 , len ( dumpbytes ) , max_bytes ) :
                outfd . write ( dumpbytes [ idx : idx + max_bytes ] )
    else :
        with open ( outfile , 'wb' ) as outfd :
            pickle . dump ( outdict , outfd , pickle . HIGHEST_PROTOCOL )
    return outfile
else :
    return outdict


signature:
def xmatch_external_catalogs ( checkplotdict , xmatchinfo , xmatchradiusarcsec = 2.0 , returndirect = False , updatexmatch = True , savepickle = None ) :
    '''This matches the current object in the checkplotdict to all of the
 external match catalogs specified .
 Parameters
 checkplotdict : dict
 This is a checkplotdict , generated by either the ` checkplot _ dict `
 function , or read in from a ` _ read _ checkplot _ picklefile ` function . This
 must have a structure somewhat like the following , where the indicated
 keys below are required : :
 { ' objectid ' : the ID assigned to this object
 ' objectinfo ' : { ' objectid ' : ID assigned to this object ,
 ' ra ' : right ascension of the object in decimal deg ,
 ' decl ' : declination of the object in decimal deg } }
 xmatchinfo : str or dict
 This is either the xmatch dict produced by the function
 : py : func : ` astrobase . checkplot . pkl _ xmatch . load _ xmatch _ external _ catalogs `
 above , or the path to the xmatch info pickle file produced by that
 function .
 xmatchradiusarcsec : float
 This is the cross - matching radius to use in arcseconds .
 returndirect : bool
 If this is True , will only return the xmatch results as a dict . If this
 False , will return the checkplotdict with the xmatch results added in as
 a key - val pair .
 updatexmatch : bool
 This function will look for an existing ' xmatch ' key in the input
 checkplotdict indicating that an xmatch has been performed before . If
 ` updatexmatch ` is set to True , the xmatch results will be added onto
 ( e . g . when xmatching to additional catalogs after the first run ) . If
 this is set to False , the xmatch key - val pair will be completely
 overwritten .
 savepickle : str or None
 If this is None , it must be a path to where the updated checkplotdict
 will be written to as a new checkplot pickle . If this is False , only the
 updated checkplotdict is returned .
 Returns
 dict or str
 If ` savepickle ` is False , this returns a checkplotdict , with the xmatch
 results added in . An ' xmatch ' key will be added to this dict , with
 something like the following dict as the value : :
 { ' xmatchradiusarcsec ' : xmatchradiusarcsec ,
 ' catalog1 ' : { ' name ' : ' Catalog of interesting things ' ,
 ' found ' : True ,
 ' distarcsec ' : 0.7,
 ' info ' : { ' objectid ' : . . . , ' ra ' : . . . , ' decl ' : . . . , ' desc ' : . . . } } ,
 ' catalog2 ' : { ' name ' : ' Catalog of more interesting things ' ,
 ' found ' : False ,
 ' distarcsec ' : nan ,
 ' info ' : None } ,
 This will contain the matches of the object in the input checkplotdict
 to all of the catalogs provided in ` xmatchinfo ` .
 If ` savepickle ` is True , will return the path to the saved checkplot
 pickle file .'''

implementation:
# load the xmatch info
if isinstance ( xmatchinfo , str ) and os . path . exists ( xmatchinfo ) :
    with open ( xmatchinfo , 'rb' ) as infd :
        xmatchdict = pickle . load ( infd )
elif isinstance ( xmatchinfo , dict ) :
    xmatchdict = xmatchinfo
else :
    LOGERROR ( "can't figure out xmatch info, can't xmatch, skipping..." )
    return checkplotdict
# generate the xmatch spec
# get our ra , decl
objra = checkplotdict [ 'objectinfo' ] [ 'ra' ]
objdecl = checkplotdict [ 'objectinfo' ] [ 'decl' ]
cosdecl = np . cos ( np . radians ( objdecl ) )
sindecl = np . sin ( np . radians ( objdecl ) )
cosra = np . cos ( np . radians ( objra ) )
sinra = np . sin ( np . radians ( objra ) )
objxyz = np . column_stack ( ( cosra * cosdecl , sinra * cosdecl , sindecl ) )
# this is the search distance in xyz unit vectors
xyzdist = 2.0 * np . sin ( np . radians ( xmatchradiusarcsec / 3600.0 ) / 2.0 )
# now search in each external catalog
xmatchresults = { }
extcats = sorted ( list ( xmatchdict . keys ( ) ) )
for ecat in extcats : # get the kdtree
    kdt = xmatchdict [ ecat ] [ 'kdtree' ]
    # look up the coordinates
    kdt_dist , kdt_ind = kdt . query ( objxyz , k = 1 , distance_upper_bound = xyzdist )
    # sort by matchdist
    mdsorted = np . argsort ( kdt_dist )
    matchdists = kdt_dist [ mdsorted ]
    matchinds = kdt_ind [ mdsorted ]
    if matchdists [ np . isfinite ( matchdists ) ] . size == 0 :
        xmatchresults [ ecat ] = { 'name' : xmatchdict [ ecat ] [ 'name' ] , 'desc' : xmatchdict [ ecat ] [ 'desc' ] , 'found' : False , 'distarcsec' : None , 'info' : None }
    else :
        for md , mi in zip ( matchdists , matchinds ) :
            if np . isfinite ( md ) and md < xyzdist :
                infodict = { }
                distarcsec = _xyzdist_to_distarcsec ( md )
                for col in xmatchdict [ ecat ] [ 'columns' ] :
                    coldata = xmatchdict [ ecat ] [ 'data' ] [ col ] [ mi ]
                    if isinstance ( coldata , str ) :
                        coldata = coldata . strip ( )
                    infodict [ col ] = coldata
                xmatchresults [ ecat ] = { 'name' : xmatchdict [ ecat ] [ 'name' ] , 'desc' : xmatchdict [ ecat ] [ 'desc' ] , 'found' : True , 'distarcsec' : distarcsec , 'info' : infodict , 'colkeys' : xmatchdict [ ecat ] [ 'columns' ] , 'colnames' : xmatchdict [ ecat ] [ 'colnames' ] , 'colunit' : xmatchdict [ ecat ] [ 'colunits' ] , }
                break
# should now have match results for all external catalogs
if returndirect :
    return xmatchresults
else :
    if updatexmatch and 'xmatch' in checkplotdict :
        checkplotdict [ 'xmatch' ] . update ( xmatchresults )
    else :
        checkplotdict [ 'xmatch' ] = xmatchresults
    if savepickle :
        cpf = _write_checkplot_picklefile ( checkplotdict , outfile = savepickle , protocol = 4 )
        return cpf
    else :
        return checkplotdict


signature:
def angle_wrap ( angle , radians = False ) :
    '''Wraps the input angle to 360.0 degrees .
 Parameters
 angle : float
 The angle to wrap around 360.0 deg .
 radians : bool
 If True , will assume that the input is in radians . The output will then
 also be in radians .
 Returns
 float
 Wrapped angle . If radians is True : input is assumed to be in radians ,
 output is also in radians .'''

implementation:
if radians :
    wrapped = angle % ( 2.0 * pi_value )
    if wrapped < 0.0 :
        wrapped = 2.0 * pi_value + wrapped
else :
    wrapped = angle % 360.0
    if wrapped < 0.0 :
        wrapped = 360.0 + wrapped
return wrapped


signature:
def decimal_to_dms ( decimal_value ) :
    '''Converts from decimal degrees ( for declination coords ) to DD : MM : SS .
 Parameters
 decimal _ value : float
 A decimal value to convert to degrees , minutes , seconds sexagesimal
 format .
 Returns
 tuple
 A four element tuple is returned : ( sign , HH , MM , SS . ssss . . . )'''

implementation:
if decimal_value < 0 :
    negative = True
    dec_val = fabs ( decimal_value )
else :
    negative = False
    dec_val = decimal_value
degrees = trunc ( dec_val )
minutes_deg = dec_val - degrees
minutes_mm = minutes_deg * 60.0
minutes_out = trunc ( minutes_mm )
seconds = ( minutes_mm - minutes_out ) * 60.0
if negative :
    degrees = degrees
    return '-' , degrees , minutes_out , seconds
else :
    return '+' , degrees , minutes_out , seconds


signature:
def decimal_to_hms ( decimal_value ) :
    '''Converts from decimal degrees ( for RA coords ) to HH : MM : SS .
 Parameters
 decimal _ value : float
 A decimal value to convert to hours , minutes , seconds . Negative values
 will be wrapped around 360.0.
 Returns
 tuple
 A three element tuple is returned : ( HH , MM , SS . ssss . . . )'''

implementation:
# wrap to 360.0
if decimal_value < 0 :
    dec_wrapped = 360.0 + decimal_value
else :
    dec_wrapped = decimal_value
# convert to decimal hours first
dec_hours = dec_wrapped / 15.0
if dec_hours < 0 :
    negative = True
    dec_val = fabs ( dec_hours )
else :
    negative = False
    dec_val = dec_hours
hours = trunc ( dec_val )
minutes_hrs = dec_val - hours
minutes_mm = minutes_hrs * 60.0
minutes_out = trunc ( minutes_mm )
seconds = ( minutes_mm - minutes_out ) * 60.0
if negative :
    hours = - hours
    return hours , minutes_out , seconds
else :
    return hours , minutes_out , seconds


signature:
def hms_str_to_tuple ( hms_string ) :
    '''Converts a string of the form HH : MM : SS or HH MM SS to a tuple of the form
 ( HH , MM , SS ) .
 Parameters
 hms _ string : str
 A RA coordinate string of the form ' HH : MM : SS . sss ' or ' HH MM SS . sss ' .
 Returns
 tuple
 A three element tuple is returned ( HH , MM , SS . ssss . . . )'''

implementation:
if ':' in hms_string :
    separator = ':'
else :
    separator = ' '
hh , mm , ss = hms_string . split ( separator )
return int ( hh ) , int ( mm ) , float ( ss )


signature:
def dms_str_to_tuple ( dms_string ) :
    '''Converts a string of the form [ + - ] DD : MM : SS or [ + - ] DD MM SS to a tuple of
 the form ( sign , DD , MM , SS ) .
 Parameters
 dms _ string : str
 A declination coordinate string of the form ' [ + - ] DD : MM : SS . sss ' or
 ' [ + - ] DD MM SS . sss ' . The sign in front of DD is optional . If it ' s not
 there , this function will assume that the coordinate string is a
 positive value .
 Returns
 tuple
 A four element tuple of the form : ( sign , DD , MM , SS . ssss . . . ) .'''

implementation:
if ':' in dms_string :
    separator = ':'
else :
    separator = ' '
sign_dd , mm , ss = dms_string . split ( separator )
if sign_dd . startswith ( '+' ) or sign_dd . startswith ( '-' ) :
    sign , dd = sign_dd [ 0 ] , sign_dd [ 1 : ]
else :
    sign , dd = '+' , sign_dd
return sign , int ( dd ) , int ( mm ) , float ( ss )