Exemplo n.º 1
0
def filter_ccf(rv, ccf, v_width):
    """
    Performs a high-pass filter on a CCF.
    """
    import copy
    import tayph.operations as ops
    ccf_f = copy.deepcopy(ccf)
    wiggles = copy.deepcopy(ccf) * 0.0
    dv = rv[1] - rv[0]  #Assumes that the RV axis is constant.
    w = v_width / dv
    for i, ccf_row in enumerate(ccf):
        wiggle = ops.smooth(ccf_row, w, mode='gaussian')
        wiggles[i] = wiggle
        ccf_f[i] = ccf_row - wiggle
    return (ccf_f, wiggles)
Exemplo n.º 2
0
def build_template(templatename,
                   binsize=1.0,
                   maxfrac=0.01,
                   mode='top',
                   resolution=0.0,
                   c_subtract=True,
                   twopass=False,
                   template_library='models/library'):
    """This routine reads a specified model from the library and turns it into a
    cross-correlation template by subtracting the top-envelope (or bottom envelope),
    if c_subtract is set to True."""

    import tayph.util as ut
    from tayph.vartests import typetest, postest, notnegativetest
    import numpy as np
    import tayph.operations as ops
    import astropy.constants as const
    from astropy.io import fits
    from matplotlib import pyplot as plt
    from scipy import interpolate
    from pathlib import Path
    typetest(templatename, str, 'templatename mod.build_template()')
    typetest(binsize, [int, float], 'binsize mod.build_template()')
    typetest(maxfrac, [int, float], 'maxfrac mod.build_template()')
    typetest(
        mode,
        str,
        'mode mod.build_template()',
    )
    typetest(resolution, [int, float], 'resolution in mod.build_template()')
    typetest(twopass, bool, 'twopass in mod.build_template()')

    binsize = float(binsize)
    maxfrac = float(maxfrac)
    resolution = float(resolution)
    postest(binsize, 'binsize mod.build_template()')
    postest(maxfrac, 'maxfrac mod.build_template()')
    notnegativetest(resolution, 'resolution in mod.build_template()')
    template_library = ut.check_path(template_library, exists=True)

    c = const.c.to('km/s').value

    if mode not in ['top', 'bottom']:
        raise Exception(
            f'RuntimeError in build_template: Mode should be set to "top" or "bottom" ({mode}).'
        )
    wlt, fxt = get_model(templatename, library=template_library)

    if wlt[-1] <= wlt[0]:  #Reverse the wl axis if its sorted the wrong way.
        wlt = np.flipud(wlt)
        fxt = np.flipud(fxt)

    if c_subtract == True:
        wle, fxe = ops.envelope(
            wlt, fxt - np.median(fxt), binsize, selfrac=maxfrac,
            mode=mode)  #These are binpoints of the top-envelope.
        #The median of fxm is first removed to decrease numerical errors, because the spectrum may
        #have values that are large (~1.0) while the variations are small (~1e-5).
        e_i = interpolate.interp1d(wle, fxe, fill_value='extrapolate')
        envelope = e_i(wlt)
        T = fxt - np.median(fxt) - envelope
        absT = np.abs(T)
        T[(absT < 1e-4 * np.max(absT)
           )] = 0.0  #This is now continuum-subtracted and binary-like.
        #Any values that are small are taken out.
        #This therefore assumes that the model has lines that are deep compared to the numerical
        #error of envelope subtraction (!).
    else:
        T = fxt * 1.0

    if resolution != 0.0:
        dRV = c / resolution
        print(
            f'------Blurring template to resolution of data ({round(resolution,0)}, {round(dRV,2)} km/s)'
        )
        wlt_cv, T_cv, vstep = ops.constant_velocity_wl_grid(wlt,
                                                            T,
                                                            oversampling=2.0)
        print(f'---------v_step is {np.round(vstep,3)} km/s')
        print(
            f'---------So the resolution blurkernel has an avg width of {np.round(dRV/vstep,3)} px.'
        )
        T_b = ops.smooth(T_cv, dRV / vstep, mode='gaussian')
        wlt = wlt_cv * 1.0
        T = T_b * 1.0
    return (wlt, T)
Exemplo n.º 3
0
def inject_model(list_of_wls,
                 list_of_orders,
                 dp,
                 modelname,
                 model_library='library/models'):
    """This function takes a list of spectral orders and injects a model with library
    identifier modelname, and system parameters as defined in dp. The model is blurred taking into
    account spectral resolution and rotation broadening (with an LSF as per Brogi et al.) and
    finite-exposure broadening (with a box LSF).

    It returns a copy of the list of orders with the model injected."""

    import tayph.util as ut
    import tayph.system_parameters as sp
    import tayph.models
    import astropy.constants as const
    import numpy as np
    import scipy
    import tayph.operations as ops
    from tayph.vartests import typetest, dimtest
    import pdb
    import copy
    import matplotlib.pyplot as plt

    # dimtest(order,[0,len(wld)])
    dp = ut.check_path(dp)
    typetest(modelname, str, 'modelname in models.inject_model()')
    typetest(model_library, str, 'model_library in models.inject_model()')

    c = const.c.to('km/s').value  #In km/s
    Rd = sp.paramget('resolution', dp)
    planet_radius = sp.paramget('Rp', dp)
    inclination = sp.paramget('inclination', dp)
    P = sp.paramget('P', dp)
    transit = sp.transit(dp)
    n_exp = len(transit)
    vsys = sp.paramget('vsys', dp)
    rv = sp.RV(dp) + vsys
    dRV = sp.dRV(dp)
    phi = sp.phase(dp)
    dimtest(transit, [n_exp])
    dimtest(rv, [n_exp])
    dimtest(phi, [n_exp])
    dimtest(dRV, [n_exp])

    mask = (transit - 1.0) / (np.min(transit - 1.0))

    wlm, fxm = get_model(modelname, library=model_library)
    if wlm[-1] <= wlm[0]:  #Reverse the wl axis if its sorted the wrong way.
        wlm = np.flipud(wlm)
        fxm = np.flipud(fxm)

    #With the model and the revelant parameters in hand, now only select that
    #part of the model that covers the wavelengths of the order provided.
    #A larger wavelength range would take much extra time because the convolution
    #is a slow operation.

    N_orders = len(list_of_wls)
    if N_orders != len(list_of_orders):
        raise RuntimeError(
            f'in models.inject_model: List_of_wls and list_of_orders are not of the '
            f'same length ({N_orders} vs {len(list_of_orders)})')

    if np.min(wlm) > np.min(list_of_wls) - 1.0 or np.max(
            wlm) < np.max(list_of_wls) + 1.0:
        ut.tprint(
            'WARNING in model injection: Data grid falls (partly) outside of model range. '
            'Setting missing area to 1.0. (meaning, no planet absorption.)')

    modelsel = [
        (wlm >= np.min(list_of_wls) - 1.0) & (wlm <= np.max(list_of_wls) + 1.0)
    ]

    wlm = wlm[tuple(modelsel)]
    fxm = fxm[tuple(modelsel)]

    fxm_b = ops.blur_rotate(wlm, fxm, c / Rd, planet_radius, P,
                            inclination)  #Only do this once per dataset.

    oversampling = 2.5
    wlm_cv, fxm_bcv, vstep = ops.constant_velocity_wl_grid(
        wlm, fxm_b, oversampling=oversampling)

    if np.min(dRV) < c / Rd / 10.0:

        dRV_min = c / Rd / 10.0  #If the minimum dRV is less than 10% of the spectral
        #resolution, we introduce a lower limit to when we are going to blur, because the effect
        #becomes insignificant.
    else:
        dRV_min = np.min(dRV)

    if dRV_min / vstep < 3:  #Meaning, if the smoothing is going to be undersampled by this choice
        #in v_step, it means that the oversampling parameter in ops.constant_velocity_wl_grid was
        #not high enough. Then we adjust it. I choose a value of 3 here to be safe, even though
        #ops.smooth below accepts values as low as 2.
        oversampling_new = 3.0 / (
            dRV_min / vstep) * oversampling  #scale up the oversampling factor.
        wlm_cv, fxm_bcv, vstep = ops.constant_velocity_wl_grid(
            wlm, fxm_b, oversampling=oversampling_new)

    list_of_orders_injected = copy.deepcopy(list_of_orders)

    for i in range(n_exp):
        if dRV[i] >= c / Rd / 10.0:
            fxm_b2 = ops.smooth(fxm_bcv, dRV[i] / vstep, mode='box')
        else:
            fxm_b2 = copy.deepcopy(fxm_bcv)
        shift = 1.0 + rv[i] / c
        fxm_i = scipy.interpolate.interp1d(
            wlm_cv * shift, fxm_b2, fill_value=1.0,
            bounds_error=False)  #This is a class that can be called.
        #Fill_value = 1 because if the model does not fully cover the order, it will be padded with 1.0s,
        #assuming that we are dealing with a model that is in transmission.
        for j in range(len(list_of_orders)):
            list_of_orders_injected[j][i] *= (
                1.0 + mask[i] * (fxm_i(list_of_wls[j]) - 1.0))  #This assumes
            #that the model is in transit radii. This can definitely be vectorised!

        #These are for checking that the broadening worked as expected:
        # injection_total[i,:]= scipy.interpolate.interp1d(wlm_cv*shift,fxm_b2)(wld)
        # injection_rot_only[i,:]=scipy.interpolate.interp1d(wlm*shift,fxm_b)(wld)
        # injection_pure[i,:]=scipy.interpolate.interp1d(wlm*shift,fxm)(wld)

    # ut.save_stack('test.fits',[injection_pure,injection_rot_only,injection_total])
    # pdb.set_trace()
    # ut.writefits('test.fits',injection)
    # pdb.set_trace()

    return (list_of_orders_injected)