示例#1
0
def derivative(x):
    """
    This computes the simple numerical derivative of x by convolving with kernel [-1,0,1].

    Parameters
    ----------
    x : list, np.ndarray
        The array from which the derivative is required.

    Returns
    -------
    derivative : np.array
        The numerical derivative of x.

    Example
    -------
    >>> import numpy as np
    >>> x=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
    >>> dx=derivative(x)
    """
    import numpy as np
    from tayph.vartests import typetest, dimtest
    typetest(x, [list, np.ndarray], 'x in derivative()')
    dimtest(x, [0], 'x in derivative()')
    x = np.array(x)
    d_kernel = np.array([-1, 0, 1]) / 2.0
    return (convolve(x, d_kernel, fit_width=3))
示例#2
0
def end(start, id='', silent=False):
    """
    Short-hand for ending a timing measurement and printing the elapsed time.

    Parameters
    ----------
    start : float
        Generated by time.time()

    id : str
        Description or numeral to identify the clock associated with the start time.

    Returns
    -------
    elapsed : float
        The time elapsed since start.
    """

    from tayph.vartests import typetest
    typetest(start, float, 'start time in utils.end()')
    typetest(id, str, 'id/descriptor in utils.end()')
    import time
    end = time.time()
    if not silent:
        print('Elapsed %s: %s' % ('on timer ' + id, end - start))
    return end - start
示例#3
0
def dRV(dp):
    """This program calculates the change in radial velocity in km/s for the
    planet in the data sequence provided in dp, the data-path. dp starts in the
    root folder,i.e. it starts with data/projectname/, and it ends with a slash.

    Example: dv=dRV('data/Kelt-9/night1/')
    The output is an array with length N, corresponding to N exposures.
    The change in radial velocity is calculated using the first derivative of the
    formula for RV, multiplied by the exposure time provided in obs_times.
    The answer is provided in units of km/s change within each exposure."""
    from tayph.vartests import typetest
    import numpy as np
    import astropy.units as u
    from astropy.io import ascii
    import pdb
    import tayph.util as ut
    dp=ut.check_path(dp,exists=True)
    obsp=ut.check_path(dp/'obs_times',exists=True)

    d=ascii.read(obsp,comment="#")
    #Texp=d['exptime'].astype('float')
    Texp=d['col3'].data#astype('float')
    vorb=v_orb(dp)
    p=phase(dp)
    P=paramget('P',dp)
    i=paramget('inclination',dp)
    typetest(P,float,'P in dRV()')
    typetest(i,float,'i in dRV()')

    dRV=vorb*np.cos(2.0*np.pi*p)*2.0*np.pi/((P*u.d).to('s').value)*np.sin(np.radians(i))
    return abs(dRV*Texp)
示例#4
0
def t_eff(M,R):
    """This function computes the mass and radius of a star given its mass and radius relative to solar."""
    from tayph.vartests import typetest
    import numpy as np
    import astropy.constants as const

    typetest(M,[int,float],'M in t_eff()')
    typetest(R,[int,float],'R in t_eff()')
    M=float(M)
    R=float(R)

    Ms = const.M_sun
    Rs = const.R_sun
    Ls = const.L_sun
    sb = const.sigma_sb

    if M < 0.43:
        a = 0.23
        b = 2.3
    elif M < 2:
        a = 1.0
        b = 4.0
    elif M < 55:
        a = 1.4
        b = 3.5
    else:
        a = 32000.0
        b = 1.0

    T4 = a*M**b * Ls / (4*np.pi*R**2*Rs**2*sb)
    return(T4**0.25)
示例#5
0
def airtovac(wlnm):
    """
    This converts air wavelengths to vaccuum wavelengths.

    Parameters
    ----------
    wlnm : float, np.ndarray
        The wavelength that is to be converted.

    Returns
    -------
    wlnm : float, np.array
        wavelengths in vaccuum.

    Example
    -------
    >>> import numpy as np
    >>> wlA=np.array([500.0,510.0,600.0,700.0])
    >>> wlV=airtovac(wlA)
    """
    import numpy as np
    from tayph.vartests import typetest
    typetest(wlnm, [float, np.ndarray], 'wlmn in airtovac()')
    wlA = wlnm * 10.0
    s = 1e4 / wlA
    n = 1 + 0.00008336624212083 + 0.02408926869968 / (
        130.1065924522 - s**2) + 0.0001599740894897 / (38.92568793293 - s**2)
    return (wlA * n / 10.0)
示例#6
0
def load_columns_from_file(dp,maskname,mode='strict'):
    """
    This loads the list of lists of columns back into memory after having been
    saved by a call of write_columns_to_file() below.
    """
    import tayph.util as ut
    from tayph.vartests import typetest
    import pickle
    import os
    from pathlib import Path
    ut.check_path(dp)
    typetest(maskname,str,'maskname in load_columns_from_file()')
    typetest(mode,str,'mode in load_columns_from_file()')
    outpath=Path(dp)/(maskname+'_columns.pkl')

    if os.path.isfile(outpath) ==  False:
         if mode == 'strict':
             raise Exception('FileNotFoundError in reading columns from file: Column file named %s do not exist at %s.' % (maskname,dp))
         else:
             print('---No previously saved manual mask exists. User will start a new mask.')
             return([])
    else:
        print(f'------Loading previously saved manual mask {str(outpath)}.')
        pickle_in = open(outpath,"rb")
        return(pickle.load(pickle_in))
示例#7
0
def vactoair(wlnm):
    """
    This converts vaccuum wavelengths to air wavelengths.

    Parameters
    ----------
    wlnm : float, np.ndarray
        The wavelength that is to be converted.

    Returns
    -------
    wlnm : float, np.array
        wavelengths in air.

    Example
    -------
    >>> import numpy as np
    >>> wlV=np.array([500.0,510.0,600.0,700.0])
    >>> wlA=vactoair(wlV)
    """
    import numpy as np
    from tayph.vartests import typetest
    typetest(wlnm, [float, np.ndarray], 'wlmn in vactoair()')
    wlA = wlnm * 10.0
    s = 1e4 / wlA
    f = 1.0 + 5.792105e-2 / (238.0185e0 - s**2) + 1.67917e-3 / (57.362e0 -
                                                                s**2)
    return (wlA / f / 10.0)
示例#8
0
def running_MAD_2D(z, w, verbose=False, parallel=False):
    """Computers a running standard deviation of a 2-dimensional array z.
    The stddev is evaluated over the vertical block with width w pixels.
    The output is a 1D array with length equal to the width of z.
    This is very slow on arrays that are wide in x (hundreds of thousands of points)."""
    import astropy.stats as stats
    import numpy as np
    from tayph.vartests import typetest, dimtest, postest
    import tayph.util as ut
    if parallel: from joblib import Parallel, delayed
    typetest(z, np.ndarray, 'z in fun.running_MAD_2D()')
    dimtest(z, [0, 0], 'z in fun.running_MAD_2D()')
    typetest(w, [int, float], 'w in fun.running_MAD_2D()')
    postest(w, 'w in fun.running_MAD_2D()')
    size = np.shape(z)
    ny = size[0]
    nx = size[1]
    s = np.arange(0, nx, dtype=float) * 0.0
    dx1 = int(0.5 * w)
    dx2 = int(int(0.5 * w) + (w % 2))  #To deal with odd windows.
    for i in range(nx):
        minx = max([0, i - dx1])  #This here is only a 3% slowdown.
        maxx = min([nx, i + dx2])
        s[i] = stats.mad_std(
            z[:, minx:maxx],
            ignore_nan=True)  #This is what takes 97% of the time.
        if verbose: ut.statusbar(i, nx)
    return (s)
示例#9
0
def astropyberv(dp):
    """
    This does the same as berv(dp), but uses astropy to compute the BERV for the
    dates of observation given a data parameter file.
    Useful if the BERV keyword was somehow wrong or missing, or if you wish to
    cross-validate. Requires latitude, longitude, ra, dec and elevation to be provided in
    the config file as lat, long, RA, DEC and elev in units of degrees and meters.
    Date should be provided as mjd.
    """
    from tayph.vartests import typetest
    from pathlib import Path
    import numpy as np
    from astropy.io import ascii
    from astropy.time import Time
    from astropy import units as u
    from astropy.coordinates import SkyCoord, EarthLocation
    dp=check_dp(dp)#Path object
    d=ascii.read(dp/'obs_times',comment="#")#,names=['mjd','time','exptime','airmass'])
    #Not using named columns because I may not know for sure how many columns
    #there are, and read-ascii breaks if only some columns are named.
    #The second column has to be an MJD date array though.
    dates = d['col1']
    RA=paramget('RA',dp)
    DEC=paramget('DEC',dp)
    typetest(RA,str,'RA in sp.astropyberv()')
    typetest(DEC,str,'DEC in sp.astropyberv()')
    berv = []
    observatory = EarthLocation.from_geodetic(lat=paramget('lat',dp)*u.deg, lon=paramget('long',dp)*u.deg, height=paramget('elev',dp)*u.m)
    sc = SkyCoord(RA+' '+DEC, unit=(u.hourangle, u.deg))
    for date in dates:
        barycorr = sc.radial_velocity_correction(obstime=Time(date,format='mjd'), location=observatory).to(u.km/u.s)
        berv.append(barycorr.value)
    return berv
示例#10
0
def envelope(wlm, fxm, binsize, selfrac=0.05, mode='top', threshold=''):
    """
    This program measures the top or bottom envelope of a spectrum (wl,fx), by
    chopping it up into bins of size binsze (unit of wl), and measuring the mean
    of the top n % of values in that bin. Setting the mode to 'bottom' will do the
    oppiste: The mean of the bottom n% of values. The output is the resulting wl
    and flux points of these bins.

    Example: wle,fxe = envelope(wl,fx,1.0,selfrac=3.0,mode='top')
    """
    import numpy as np
    import tayph.util as ut
    import tayph.functions as fun
    from tayph.vartests import typetest, dimtest, nantest, postest
    from matplotlib import pyplot as plt
    typetest(wlm, np.ndarray, 'wlm in ops.envelope()')
    typetest(fxm, np.ndarray, 'fxm in ops.envelope()')
    dimtest(wlm, [len(fxm)])
    typetest(binsize, [int, float], 'binsize in ops.envelope()')
    typetest(selfrac, float, 'percentage in ops.envelope()')
    typetest(mode, str, 'mode in envelope')
    nantest(fxm, 'fxm in ops.envelope()')
    nantest(wlm, 'wlm in ops.envelope()')
    postest(wlm, 'wlm in ops.envelope()')
    postest(binsize, 'binsize in ops.envelope()')

    if mode not in ['top', 'bottom']:
        raise Exception(
            f'RuntimeError in ops.envelope(): Mode should be set to "top" or "bottom" ({mode}).'
        )

    binsize = float(binsize)
    if mode == 'bottom':
        fxm *= -1.0

    wlcs = np.array([])  #Center wavelengths
    fxcs = np.array([])  #Flux at center wavelengths
    i_start = 0
    wlm_start = wlm[i_start]
    for i in range(0, len(wlm) - 1):
        if wlm[i] - wlm_start >= binsize:
            wlsel = wlm[i_start:i]
            fxsel = fxm[i_start:i]
            maxsel = fun.selmax(fxsel, selfrac)
            wlcs = np.append(wlcs, np.mean(wlsel[maxsel]))
            fxcs = np.append(fxcs, np.mean(fxsel[maxsel]))
            i_start = i + 1
            wlm_start = wlm[i + 1]

    if isinstance(threshold, float) == True:
        #This means that the threshold value is set, and we set all bins less than
        #that threshold to the threshold value:
        if mode == 'bottom':
            threshold *= -1.0
        fxcs[(fxcs < threshold)] = threshold

    if mode == 'bottom':
        fxcs *= -1.0
        fxm *= -1.0
    return wlcs, fxcs
示例#11
0
    def set_order(self,i):
        """
        This modifies the currently active order to be plotted.
        """
        import numpy as np
        import tayph.functions as fun
        import warnings
        import tayph.util as ut
        import copy
        from tayph.vartests import typetest
        typetest(i,int,'i in mask_maker.set_order()',)

        self.wl = self.list_of_wls[i]
        self.order = self.list_of_orders[i]

        #Measure the shape of the current order
        self.nexp = np.shape(self.order)[0]
        self.npx = np.shape(self.order)[1]

        #Compute the meanspec and the residuals, ignoring runtime warnings related to NaNs:
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", category=RuntimeWarning)
            self.meanspec = np.nanmean(self.list_of_orders[i],axis=0)
            self.residual = self.order / self.meanspec
        self.img_max = np.nanmean(self.meanspec[fun.selmax(self.meanspec,0.02,s=0.02)])*1.3
        self.vmin = np.nanmedian(self.residual)-3.0*np.nanstd(self.residual)
        self.vmax = np.nanmedian(self.residual)+3.0*np.nanstd(self.residual)
示例#12
0
def get_model(name, library='models/library', root='models'):
    """This program queries a model from a library file, with predefined models
    for use in model injection, cross-correlation and plotting. These models have
    a standard format. They are 2 rows by N points, where N corresponds to the
    number of wavelength samples. The first row contains the wavelengths, the
    second the associated flux values. The library file has two columns that are
    formatted as follows:

    modelname  modelpath
    modelname  modelpath
    modelname  modelpath

    modelpath starts in the models/ subdirectory.
    Set the root variable if a location is required other than the ./models directory.

    Example call:
    wlm,fxm = get_model('WASP-121_TiO',library='models/testlib')
    """

    from tayph.vartests import typetest, dimtest
    from tayph.util import check_path
    from astropy.io import fits
    from pathlib import Path
    import errno
    import os
    typetest(name, str, 'name in mod.get_model()')
    library = check_path(library, exists=True)

    #First open the library file.
    f = open(library, 'r')
    x = f.read().splitlines()  #Read everything into a big string array.
    f.close()
    n_lines = len(x)  #Number of models in the library.
    models = {}  #This will contain the model names.

    for i in range(0, n_lines):
        line = x[i].split()
        value = (line[1])
        models[line[0]] = value

    try:
        modelpath = Path(models[name])
    except KeyError:
        raise KeyError(
            f'Model {name} is not present in library at {str(library)}'
        ) from None
    if str(modelpath)[0] != '/':  #Test if this is an absolute path.
        root = check_path(root, exists=True)
        modelpath = root / modelpath
    try:
        modelarray = fits.getdata(
            modelpath
        )  #Two-dimensional array with wl on the first row and flux on the second row.
    except FileNotFoundError:
        raise FileNotFoundError(
            f'Model file {modelpath} from library {str(library)} does not exist.'
        )
    dimtest(modelarray, [2, 0])
    return (modelarray[0, :], modelarray[1, :])
示例#13
0
def apply_mask_from_file(dp,maskname,list_of_orders):
    import astropy.io.fits as fits
    import numpy as np
    import os.path
    import sys
    import tayph.util as ut
    from tayph.vartests import typetest,dimtest
    from pathlib import Path
    import pickle
    ut.check_path(dp)
    typetest(maskname,str,'maskname in write_mask_to_file()')
    typetest(list_of_orders,list,'list_of_orders in apply_mask_from_file()')

    N = len(list_of_orders)

    inpath_auto = Path(dp)/(maskname+'_auto.pkl')
    inpath_man = Path(dp)/(maskname+'_manual.pkl')

    if os.path.isfile(inpath_auto) ==  False and os.path.isfile(inpath_man) == False:
        raise Exception(f'FileNotFoundError in apply_mask_from_file: Both mask files named '
        f'{maskname} do not exist at {str(dp)}. Rerun with make_maske = True.')

    #At this point either of the mask files is determined to exist.
    #Apply the masks to the orders, by adding. This works because the mask is zero
    #everywhere, apart from the NaNs, and x+0=x, while x+NaN = NaN.


    if os.path.isfile(inpath_auto) ==  True:
        print(f'------Applying sigma_clipped mask from {inpath_auto}')
        # cube_of_masks_auto = fits.getdata(inpath_auto)
        with open(inpath_auto,"rb") as f:
            list_of_masks_auto = pickle.load(f)
        Nm = len(list_of_masks_auto)
        err = f'ERROR in apply_mask_from_file: List_of_orders and list_of_masks_auto do not have '
        f'the same length ({N} vs {Nm}), meaning that the number of orders provided and the number '
        'of orders onto which the masks were created are not the same. This could have happened if '
        'you copy-pased mask_auto from one dataset to another. This is not recommended anyway, as '
        'bad pixels / outliers are expected to be in different locations in different datasets.'
        if Nm != N:
            raise Exception(err)
        #Checks have passed. Add the mask to the list of orders.
        for i in range(N):
            list_of_orders[i]+=list_of_masks_auto[i]

    if os.path.isfile(inpath_man) ==  True:
        print(f'------Applying manually defined mask from {inpath_man}')
        # cube_of_masks_man = fits.getdata(inpath_man)
        with open(inpath_man,"rb") as f:
            list_of_masks_man = pickle.load(f)
        Nm = len(list_of_masks_man)
        err = f'ERROR in apply_mask_from_file: List_of_orders and list_of_masks_auto do not have the same length ({N} vs {Nm}), meaning that the number of orders provided and the number of orders onto which the masks were created are not the same. This could have happened if you copy-pased mask_auto from one dataset to another. This is not recommended anyway, as bad pixels / outliers are expected to be in different locations in different datasets.'
        if Nm != N:
            raise Exception(err)
        for i in range(N):
            list_of_orders[i]+=list_of_masks_man[i]
    return(list_of_orders)
示例#14
0
def running_mean_2D(D, w):
    """This computes a running mean on a 2D array in a window with width w that
    slides over the array in the horizontal (x) direction."""
    import numpy as np
    from tayph.vartests import typetest, dimtest, postest
    typetest(D, np.ndarray, 'z in fun.running_mean_2D()')
    typetest(w, [int, float], 'w in fun.running_mean_2D()')
    postest(w, 'w in fun.running_mean_2D()')
    ny, nx = D.shape
    m2 = strided_window(D, w, pad=True)
    s = np.nanmean(m2, axis=(1, 2))
    return (s)
示例#15
0
    def set_spectrum(self, i):
        """This modifies the currently active spectrum to be plotted."""
        import numpy as np
        import tayph.functions as fun
        from tayph.vartests import typetest
        import matplotlib.pyplot as plt

        typetest(i, int, 'i in molecfit_gui/set_order')
        self.wl = self.wls[i]
        self.spectrum = self.fxc[i]
        self.Tspectrum = self.trans[i]
        self.img_max = np.nanmean(self.spectrum[fun.selmax(
            self.spectrum, 0.02, s=0.02)]) * 1.3
示例#16
0
def findgen(n,integer=False):
    """This is basically IDL's findgen function.
    a = findgen(5) will return an array with 5 elements from 0 to 4:
    [0,1,2,3,4]
    """
    import numpy as np
    from tayph.vartests import typetest,postest
    typetest(n,[int,float],'n in findgen()')
    typetest(integer,bool,'integer in findgen()')
    postest(n,'n in findgen()')
    n=int(n)
    if integer:
        return np.linspace(0,n-1,n).astype(int)
    else:
        return np.linspace(0,n-1,n)
示例#17
0
def write_columns_to_file(dp,maskname,list_of_selected_columns):
    """
    This dumps the list of list of columns that are manually selected by the
    user to a pkl file for loading at a later time. This is done to allow the user
    to resume work on a saved mask.
    """
    import pickle
    from pathlib import Path
    import tayph.util as ut
    from tayph.vartests import typetest
    ut.check_path(dp)
    typetest(maskname,str,'maskname in write_columns_to_file()')
    typetest(list_of_selected_columns,list,'list_of_selected_columns in write_columns_to_file()')
    outpath=Path(dp)/(maskname+'_columns.pkl')
    print(f'---Saving list of masked columns to {str(outpath)}')
    with open(outpath, 'wb') as f: pickle.dump(list_of_selected_columns, f)
示例#18
0
def phase(dp):
    """
    Calculates the orbital phase of the planet in the data
    sequence provided using the parameters in dp/config and the timings in
    dp/obstimes.

    The output is an array with length N, corresponding to N exposures.

    Be CAREFUL: This program provides a time difference of ~1 minute compared
    to IDL/calctimes. This likely has to do with the difference between HJD
    and BJD, and the TDB timescale. In the future you should have a thorough
    look at the time-issue, because you should be able to get this right to the
    second. At the very least, make sure that the time conventions are ok.

    More importantly: The transit center time needs to be provided in config
    in BJD.
    """
    from tayph.vartests import typetest
    import numpy as np
    from astropy.io import ascii
    from astropy.time import Time
    from astropy import units as u, coordinates as coord
    import tayph.util as ut
    dp=check_dp(dp)#Path object
    d=ascii.read(dp/'obs_times',comment="#")#,names=['mjd','time','exptime','airmass'])
    #Not using the named columns because I may not know for sure how many columns
    #there are, and read-ascii breaks if only some columns are named.
    #The second column has to be a date array though.

    # t = Time(d['col2'],scale='utc', location=coord.EarthLocation.of_site('paranal'))# I determined that the difference between this and geodetic 0,0,0 is zero.
    t = Time(d['col2'],scale='utc', location=coord.EarthLocation.from_geodetic(0,0,0))

    jd = t.jd
    P=paramget('P',dp)
    RA=paramget('RA',dp)
    DEC=paramget('DEC',dp)
    Tc=paramget('Tc',dp)#Needs to be given in BJD!

    typetest(P,float,'P in sp.phase()')
    typetest(Tc,float,'Tc in sp.phase()')
    typetest(RA,str,'RA in sp.phase()')
    typetest(DEC,str,'DEC in sp.phase()')

    ip_peg = coord.SkyCoord(RA,DEC,unit=(u.hourangle, u.deg), frame='icrs')
    ltt_bary = t.light_travel_time(ip_peg)

    n=0.0
    Tc_n=Time(Tc,format='jd',scale='tdb')
    while Tc_n.jd >= min(jd):
        Tc_n=Time(Tc-100.0*n*P,format='jd',scale='tdb')#This is to make sure that the Transit central time PRECEDES the observations (by tens or hundreds or thousands of years). Otherwise, the phase could pick up a minus sign somewhere and be flipped. I wish to avoid that.
        n+=1
    BJD = t.tdb + ltt_bary
    diff = BJD-Tc_n
    phase=((diff.jd) % P)/P
    return phase
示例#19
0
def RV_star(dp):
    """
    This calculates the radial velocity in km/s for the star in the
    data sequence provided in dp. The output is an array with length N,
    corresponding to N exposures. The radial velocity is provided in km/s.
    This is meant to be used to correct (align) the stellar spectra to the same
    reference frame. It requires K (the RV-semi amplitude to be provided in the
    config file, in km/s as well. Often this value is given in discovery papers.
    Like all my routines, this assumes a circular orbit.
    """
    from tayph.vartests import typetest
    import numpy as np
    dp=check_dp(dp)
    p=phase(dp)
    K=paramget('K',dp)
    typetest(K,float,'K in sp.RV_star()')
    rv=K*np.sin(2.0*np.pi*p) * (-1.0)
    return(rv)
示例#20
0
def running_MAD(z,w):
    """Computers a running standard deviation of a 1-dimensional array z.
    The stddev is evaluated over a range with width w pixels.
    The output is a 1D array with length equal to the width of z."""
    import astropy.stats as stats
    import numpy as np
    from tayph.vartests import typetest,dimtest,postest
    typetest(z,np.ndarray,'z in fun.running_MAD()')
    typetest(w,[int,float],'w in fun.running_MAD()')
    postest(w,'w in fun.running_MAD_2D()')
    nx = len(z)
    s = np.arange(0,nx,dtype=float)*0.0
    dx1=int(0.5*w)
    dx2=int(int(0.5*w)+(w%2))#To deal with odd windows.
    for i in range(nx):
        minx = max([0,i-dx1])
        maxx = min([nx,i+dx2])
        s[i] = stats.mad_std(z[minx:maxx],ignore_nan=True)
    return(s)
示例#21
0
def running_MAD_2D(z,w):
    """Computers a running standard deviation of a 2-dimensional array z.
    The stddev is evaluated over the vertical block with width w pixels.
    The output is a 1D array with length equal to the width of z."""
    import astropy.stats as stats
    import numpy as np
    from tayph.vartests import typetest,dimtest,postest
    typetest(z,np.ndarray,'z in fun.running_MAD_2D()')
    dimtest(z,[0,0],'z in fun.running_MAD_2D()')
    typetest(w,[int,float],'w in fun.running_MAD_2D()')
    postest(w,'w in fun.running_MAD_2D()')
    size = np.shape(z)
    ny = size[0]
    nx = size[1]
    s = findgen(nx)*0.0
    for i in range(nx):
        minx = max([0,i-int(0.5*w)])
        maxx = min([nx-1,i+int(0.5*w)])
        s[i] = stats.mad_std(z[:,minx:maxx],ignore_nan=True)
    return(s)
示例#22
0
def sigma_clip(array,nsigma=3.0,MAD=False):
    """This returns the n-sigma boundaries of an array, mainly used for scaling plots.

    Parameters
    ----------
    array : list, np.ndarray
        The array from which the n-sigma boundaries are required.

    nsigma : int, float
        The number of sigma's away from the mean that need to be provided.

    MAD : bool
        Use the true standard deviation or MAD estimator of the standard deviation
        (works better in the presence of outliers).

    Returns
    -------
    vmin,vmax : float
        The bottom and top n-sigma boundaries of the input array.
    """
    from tayph.vartests import typetest
    import numpy as np
    typetest(array,[list,np.ndarray],'array in fun.sigma_clip()')
    typetest(nsigma,[int,float],'nsigma in fun.sigma_clip()')
    typetest(MAD,bool,'MAD in fun.sigma_clip()')
    m = np.nanmedian(array)
    if MAD:
        from astropy.stats import mad_std
        s = mad_std(array,ignore_nan=True)
    else:
        s = np.nanstd(array)
    vmin = m-nsigma*s
    vmax = m+nsigma*s
    return vmin,vmax
示例#23
0
def write_mask_to_file(dp,maskname,list_of_masks_auto,list_of_masks_manual=[]):
    import sys
    from pathlib import Path
    import pickle
    import tayph.util as ut
    from tayph.vartests import typetest,dimtest,lentest
    import pdb
    import numpy as np
    ut.check_path(dp)
    typetest(maskname,str,'maskname in write_mask_to_file()')
    typetest(list_of_masks_auto,list,'list_of_masks_auto in write_mask_to_file()')
    typetest(list_of_masks_manual,list,'list_of_masks_manual in write_mask_to_file()')
    lentest(list_of_masks_auto,len(list_of_masks_manual),'list_of_masks_auto in '
    'write_mask_to_file()')


    for i in range(len(list_of_masks_auto)):
        dimtest(list_of_masks_auto[i],np.shape(list_of_masks_manual[i]),'list_of_masks_auto in '
        'write_mask_to_file()')
    outpath=Path(dp)/maskname
    if len(list_of_masks_auto) == 0 and len(list_of_masks_manual) == 0:
        print('RuntimeError in write_mask_to_file: Both lists of masks are emtpy!')
        sys.exit()

    print(f'---Saving lists of auto and manual masks to {str(outpath)}')

    if len(list_of_masks_auto) > 0:
        with open(str(outpath)+'_auto.pkl', 'wb') as f: pickle.dump(list_of_masks_auto,f)
        # ut.save_stack(str(outpath)+'_auto.fits',list_of_masks_auto)
    if len(list_of_masks_manual) > 0:
        with open(str(outpath)+'_manual.pkl', 'wb') as f: pickle.dump(list_of_masks_manual,f)
示例#24
0
def save_stack(filename, list_of_2D_frames):
    """This code saves a stack of fits-files to a 3D cube, that you can play
    through in DS9. For diagnostic purposes.

    Parameters
    ----------
    filename : str, Path
        Output filename/path.

    list_of_2D-frames : list
        A list with 2D arrays

    Returns
    -------
    elapsed : float
        The time elapsed since start.

    """
    import astropy.io.fits as fits
    import numpy as np
    import pathlib
    from tayph.vartests import typetest
    from tayph.vartests import dimtest
    import warnings

    filename = check_path(filename, 'filename in save_stack()')
    typetest(list_of_2D_frames, list,
             'list_of_2D_frames in save_stack()')  #Test that its a list
    typetest(list_of_2D_frames[0], [list, np.ndarray],
             'list_of_2D_frames in save_stack()')
    for i, f in enumerate(list_of_2D_frames):
        typetest(f, [list, np.ndarray],
                 'frame %s of list_of_2D_frames in save_stack()' % i)

    base = np.shape(list_of_2D_frames[0])
    N = len(list_of_2D_frames)

    dimtest(base, [2], 'shape of list_of_2D_frames in save_stack()'
            )  #Test that its 2-dimensional
    for i, f in enumerate(list_of_2D_frames):
        dimtest(f,
                base,
                varname='frame %s of list_of_2D_frames in save_stack()' %
                i)  #Test that all have the same shape.

    N = len(list_of_2D_frames)

    if N > 0:
        out = np.zeros((base[0], base[1], N))
        for i in range(N):
            out[:, :, i] = list_of_2D_frames[i]
        fits.writeto(filename,
                     np.swapaxes(np.swapaxes(out, 2, 0), 1, 2),
                     overwrite=True)
    else:
        warnings.warn(
            "List_of_2D_frames has length zero. No output was generated by save_stack().",
            RuntimeWarning)
示例#25
0
def RV(dp,vorb=None,vsys=False):
    """This program calculates the radial velocity in km/s for the planet in the
    data sequence provided in dp, the data-path. dp starts in the root folder,
    i.e. it starts with data/projectname/, and it ends with a slash.

    Example: v=RV('data/Kelt-9/night1/')
    The output is an array with length N, corresponding to N exposures.
    The radial velocity is provided in km/s."""
    import tayph.util as ut
    import numpy as np
    from tayph.vartests import typetest
    dp=ut.check_path(dp)
    p=phase(dp)
    i=paramget('inclination',dp)
    typetest(i,float,'i')
    if vorb == None:
        vorb=v_orb(dp)
    typetest(vorb,float,'vorb in sp.RV')
    rv=vorb*np.sin(2.0*np.pi*p)*np.sin(np.radians(i))

    if vsys == True:
        vs=paramget('vsys',dp)
        rv+=vs
    return rv#In km/s.
示例#26
0
def bin(x, y, n, err=[]):
    """
    A simple function to quickly bin a spectrum by a certain number of points.

    Parameters
    ----------
    x : list, np.ndarray
        The horizontal axis.

    y : list, np.ndarray
        The array corresponding to x.

    n : int, float
        The number of points by which to bin. Int is recommended, and it is converted
        to int if a float is provided, with the consequence of the rounding that int() does.

    err : list, np.array, optional
        If set, errors corresponding to the flux points.

    Returns
    -------
    x_bin : np.array
        The binned x-axis.
    y_bin : np.array
        The binned y-axis.
    e_bin : np.array
        Only if err is set to an array with non-zero length.
    """

    from tayph.vartests import typetest, dimtest, minlength
    import numpy as np

    typetest(x, [list, np.ndarray], 'x in ops.bin()')
    typetest(y, [list, np.ndarray], 'y in ops.bin()')
    typetest(n, [int, float], 'n in ops.bin()')
    dimtest(x, [0], 'x in ops.bin()')
    dimtest(y, [len(x)], 'y in ops.bin()')
    minlength(x, 0, 'x in ops.bin()')
    minlength(x, 100, 'x in ops.bin()', warning_only=True)

    x_bin = []
    y_bin = []
    et = False
    if len(err) > 0:
        e_bin = []
        et = True
    for i in range(0, int(len(x) - n - 1), n):
        x_bin.append(np.nanmean(x[i:i + n]))
        y_bin.append(np.nanmean(y[i:i + n]))
        if et:
            e_bin.append(
                np.sqrt(np.nansum(err[i:i + n]**2)) / len(err[i:i + n]))
    if et:
        return (np.array(x_bin), np.array(y_bin), np.array(e_bin))
    else:
        return (np.array(x_bin), np.array(y_bin))
示例#27
0
def v_orb(dp):
    """
    This program calculates the orbital velocity in km/s for the planet in the
    data sequence provided in dp, the data-path. dp starts in the root folder,
    i.e. it starts with data/projectname/. This assumes a circular orbit.

    The output is a number in km/s.

    Parameters
    ----------
    dp : str, path like
        The path to the dataset containing the config file.

    Returns
    -------
    v_orb : float
        The planet's orbital velocity.

    list_of_sigmas_corrected : list
        List of 2D error matrices, telluric corrected.

    """
    import numpy as np
    import pdb
    import astropy.units as u
    from tayph.vartests import typetest,postest

    dp=check_dp(dp)#Path object
    P=paramget('P',dp)
    r=paramget('a',dp)
    typetest(P,float,'P in sp.v_orb()')
    typetest(r,float,'r in sp.v_orb()')
    postest(P,'P in sp.v_orb()')
    postest(r,'r in sp.v_orb()')

    return (2.0*np.pi*r*u.AU/(P*u.d)).to('km/s').value
示例#28
0
def read_shadow(dp, shadowname, rv, ccf):
    """
    This reads  shadow parameters from a pickle file generated by the fit_doppler_
    model class below, and evaluates it on the user-supplied rv and ccf (the latter of which is
    just for shape-purposes and the mask defined during the creation of the shadow model.
    """
    import pickle
    import os.path
    import sys
    from pathlib import Path
    import tayph.util as ut
    from tayph.vartests import typetest, dimtest
    import tayph.system_parameters as sp
    import numpy as np
    typetest(shadowname, str, 'shadowname in read_shadow().')
    typetest(rv, np.ndarray, 'rv in read_shadow()')
    typetest(ccf, np.ndarray, 'ccf in read_shadow()')

    dp = ut.check_path(dp, exists=True)
    inpath = dp / (shadowname + '.pkl')
    ut.check_path(inpath, exists=True)
    RVp = sp.RV(dp)
    pickle_in = open(inpath, "rb")
    d = pickle.load(pickle_in)
    params = d["fit_params"]
    T = d["Transit"]
    p = d["Phases"]
    aRstar = d["aRstar"]
    vsys = d["vsys"]
    i = d["inclination"]
    n_c = d["n_components"]
    maskHW = d["maskHW"]
    offset = d["offset"]  #Offset of second component.
    S = d["S"]
    D = d["D"]
    RVp = sp.RV(dp) + vsys
    mask = mask_ccf_near_RV(rv, ccf, RVp, maskHW)
    return (evaluate_shadow(params,
                            rv,
                            ccf,
                            T,
                            p,
                            aRstar,
                            vsys,
                            i,
                            n_c,
                            offset,
                            S,
                            D,
                            leastsq=False), mask)
示例#29
0
def transit(dp):
    """This code uses Ians astro python routines for the approximate Mandel &
    Agol transit lightcurve to produce the predicted transit lightcurve for the
    planet described by the configfile located at dp/config.
    This all assumes a circular orbit.
    ===========
    Derivation:
    ===========
    occultnonlin_small(z,p, cn) is the algorithm of the Mandel&Agol derivation.
    z = d/R_star, where d is the distance of the planet center to the LOS to the
    center of the star.
    sin(alpha) = d/a, with a the orbital distance (semi-major axis).
    so sin(alpha)*a/Rstar = d/a*a/Rstar = d/Rstar = z.
    a/Rstar happens to be a quantity that is well known from the transit light-
    curve. So z = sin(2pi phase)*a/Rstar. But this is in the limit of i = 90.

    From Cegla 2016 it follows that z = sqrt(xp^2 + yp^2). These are given
    as xp = a/Rstar sin(2pi phase) and yp = -a/Rstar * cos(2pi phase) * cos(i).

    The second quantity, p, is Rp/Rstar, also well known from the transit light-
    curve.

    cn is a four-element vector with the nonlinear limb darkening coefficients.
    If a shorter sequence is entered, the later values will be set to zero.
    By default I made it zero; i.e. the injected model does not take into
    account limb-darkening.
    """
    from tayph.vartests import typetest
    import tayph.util as ut
    import tayph.iansastropy as iap
    import numpy as np
    import pdb
    dp=ut.check_path(dp)
    p=phase(dp)
    a_Rstar=paramget('aRstar',dp)
    Rp_Rstar=paramget('RpRstar',dp)
    i=paramget('inclination',dp)
    typetest(a_Rstar,float,'Rp_Rstar')
    typetest(a_Rstar,float,'a_Rstar')
    typetest(i,float,'i')

    xp=np.sin(p*2.0*np.pi)*a_Rstar
    yp=np.cos(p*2.0*np.pi)*np.cos(np.radians(i))*a_Rstar
    z=np.sqrt(xp**2.0 + yp**2.0)
    transit=iap.occultnonlin_small(z,Rp_Rstar,[0.0,0.0])
    return transit
示例#30
0
def write_mask_to_file(dp,maskname,list_of_masks_auto,list_of_masks_manual=[]):
    import sys
    from pathlib import Path
    import tayph.util as ut
    from tayph.vartests import typetest,dimtest
    import pdb
    ut.check_path(dp)
    typetest(maskname,str,'maskname in write_mask_to_file()')
    typetest(list_of_masks_auto,list,'list_of_masks_auto in write_mask_to_file()')
    typetest(list_of_masks_manual,list,'list_of_masks_manual in write_mask_to_file()')
    dimtest(list_of_masks_auto,[len(list_of_masks_manual),0,0],'list_of_masks_auto in write_mask_to_file()')
    outpath=Path(dp)/maskname
    if len(list_of_masks_auto) == 0 and len(list_of_masks_manual) == 0:
        print('RuntimeError in write_mask_to_file: Both lists of masks are emtpy!')
        sys.exit()

    print(f'---Saving lists of auto and manual masks to {str(outpath)}')
    if len(list_of_masks_auto) > 0:
        ut.save_stack(str(outpath)+'_auto.fits',list_of_masks_auto)
    if len(list_of_masks_manual) > 0:
        ut.save_stack(str(outpath)+'_manual.fits',list_of_masks_manual)