def make_pseudoslits(sigma=67., nfib=19):
    """
    This routine creates random-normal-sampled offsets for the stellar fibres that make up the Veloce pseudoslit. The user has the option to supply the desired level of scatter 
    in the fibre offsets, which is used to draw from a random-normal distribution the offsets (in steps of 10 m/s). Default value is 67 m/s, based on the considerations 
    in "WORD DOCUMENT HERE". Maximum offset is +/- 200 m/s, which corresponds to ~3 default sigmas, or a probability of ~0.27% that the offset more than that (in which case 
    the maximum offset is still used).
    NOTE: Alignment inaccuracies in the spatial directions are NOT treated here, as they should not influence the RV measurements.
    
    INPUT:
    'sigma'   : RMS of the fibre offsets (in m/s)
    'nfib'    : number of fibres (default for Veloce is 19 stellar fibres)
    
    OUTPUT:
    'offsets' : an nfib-element array of the individual fibre offsets (in m/s)
    
    MODHIST:
    15/05/2018 - CMB create
    """

    #For random samples from N(mu, sigma^2), use:   "sigma * np.random.randn(dimensions) + mu"
    pos = sigma * np.random.randn(nfib)

    #divide into discreet bins
    bins = np.arange(-200, 201, 10)

    #which bin is the right one?
    offsets = np.array([])
    for x in pos:
        offsets = np.append(offsets, find_nearest(bins, x))

    return offsets
Example #2
0
def make_gaussmask_from_linelist(refwl, relint=None, step=0.01, gauss_sigma=1):
    
    #sigma in units of steps
    #steps should be adjusted depending on np.min(np.diff(refwl)), and spectrograph resolving power
    
    ### input could be sth like this:
#     from readcol import readcol
#     #read in master line list
#     linelist = readcol('/Users/christoph/OneDrive - UNSW/linelists/thar_mm.arc', twod=False, skipline=8)
#     refwl = linelist[0]
#     relint = 10**linelist[2]

    if relint is None:
        relint = np.ones(len(refwl))

    refgrid = np.arange(np.floor(np.min(refwl)), np.ceil(np.max(refwl)), step)
    refspec = np.zeros(len(refgrid))
    for i,pos in enumerate(refwl):
        #print('Line '+str(i+1)+'/'+str(len(refwl)))
        ix = find_nearest(refgrid, pos, return_index=True)
        #print('ix = ',ix)
        if relint is None:
            amp = 1
        else:
            amp = relint[i]
        peak = CMB_pure_gaussian(refgrid[ix-20:ix+21], pos, gauss_sigma * step, amp)
        refspec[ix-20:ix+21] = refspec[ix-20:ix+21] + peak * relint[i]
        
    return refgrid,refspec


# step = 0.01
# refgrid,refspec = make_gaussmask_from_linelist(refwl, relint=relint, step=step)
# lam_found = lam[x.astype(int)]
# grid,spec = make_gaussmask_from_linelist(lam_found, step=step)
# rebinned_refspec = np.interp(grid,refgrid,refspec)
# xc = np.correlate(spec,rebinned_refspec, mode='same')
# #peakix = find maximum...
# shift = (peakix - len(spec)//2) * step   #that's how many Angstroms the detected peaks are shifted wrt the "master" line list



    
Example #3
0
def make_binmask_from_linelist(refwl, relint=None, step=0.01):
    
    ### input could be sth like this:
#     from readcol import readcol
#     #read in master line list
#     linelist = readcol('/Users/christoph/OneDrive - UNSW/linelists/thar_mm.arc', twod=False, skipline=8)
#     refwl = linelist[0]

    if relint is None:
        relint = np.ones(len(refwl))

    refgrid = np.arange(np.floor(np.min(refwl)), np.ceil(np.max(refwl)), step)
    refspec = np.zeros(len(refgrid))
    for i,pos in enumerate(refwl):
        #print('Line '+str(i+1)+'/'+str(len(refwl)))
        ix = find_nearest(refgrid, pos, return_index=True)
        #print('ix = ',ix)
        refspec[np.max([0,ix-1]) : np.min([ix+2,len(refspec)])] = relint[i]
        
    return refgrid,refspec
Example #4
0
def check_transformation_scatter_daophot(
        lfc_files,
        M_list=None,
        nx=4112,
        ny=4202,
        wrt='centre',
        n_sub=1,
        eps=0.5,
        return_residuals=True,
        ref_obsname='21sep30019',
        return_M_list=False,
        return_pixel_phase=False,
        lfc_path='/Users/christoph/OneDrive - UNSW/lfc_peaks/'):
    # INPUT:
    # 'lfc_files' - list of lfc files for which to check
    # 'M_list'    - corresponding list of calculated transformation matrices

    # WARNING: They obviously need to be in the same order. See how it's done at the start of "check_all_shifts_with_telemetry"

    if M_list is not None:
        assert len(lfc_files) == len(
            M_list
        ), 'ERROR: list of files and list of matrices have different lengths!!!'
    else:
        M_list_new = []

    # read reference LFC peak positions
    _, yref, xref, _, _, _, _, _, _, _, _ = readcol(lfc_path + ref_obsname +
                                                    'olc.nst',
                                                    twod=False,
                                                    skipline=2)
    xref = nx - xref
    yref = yref - 54.  # or 53??? but does not matter for getting the transformation matrix
    if wrt == 'centre':
        xref -= nx // 2
        yref -= ny // 2
    ref_peaks_xy_list = [(xpos, ypos) for xpos, ypos in zip(xref, yref)]

    all_delta_x_list = []
    all_delta_y_list = []
    if return_pixel_phase:
        xphi_list = []
        yphi_list = []

    # loop over all files
    for i, lfc_file in enumerate(lfc_files):

        print('Processing observation ' + str(i + 1) + '/' +
              str(len(lfc_files)) + '...')

        # read observation LFC peak positions
        try:
            _, y, x, _, _, _, _, _, _, _, _ = readcol(lfc_file,
                                                      twod=False,
                                                      skipline=2)
        except:
            _, y, x, _, _, _, _, _, _ = readcol(lfc_file,
                                                twod=False,
                                                skipline=2)
        del _
        x = nx - x
        y = y - 54.  # or 53??? but does not matter for getting the transformation matrix
        if wrt == 'centre':
            x -= nx // 2
            y -= ny // 2
        obs_peaks_xy_list = [(xpos, ypos) for xpos, ypos in zip(x, y)]
        obs_peaks_xy = np.array(obs_peaks_xy_list).T

        if M_list is None:
            # NOTE that we do not want to shift to the centre twice, so we hard-code 'corner' here!!! (xref, yref, x, y) are already transformed above!!!
            M = find_affine_transformation_matrix(
                xref, yref, x, y, timit=True, eps=2., wrt='corner'
            )  # note that within "wavelength_solution" this is called "Minv"
            M_list_new.append(M)
        else:
            M = M_list[i]

        # now we need to match the peaks so we can compare the reference peaks with the (back-)transformed obs peaks
        good_ref_peaks = []
        good_obs_peaks = []
        for n, refpeak in enumerate(ref_peaks_xy_list):
            # print(n)
            shifted_obs_peaks = obs_peaks_xy - np.expand_dims(
                np.array(refpeak), axis=1)
            distance = np.sqrt(shifted_obs_peaks[0, :]**2 +
                               shifted_obs_peaks[1, :]**2)

            if np.sum(distance < eps) > 0:
                if np.sum(distance < eps) > 1:
                    print('FUGANDA: ', refpeak)
                    print(
                        'There is probably a cosmic really close to an LFC peak - skipping this peak...'
                    )
                else:
                    good_ref_peaks.append(refpeak)
                    good_obs_peaks.append((obs_peaks_xy[0, distance < eps],
                                           obs_peaks_xy[1, distance < eps]))
            # print(n, refpeak, np.sum(distance < eps))

        # calculate pixel phase as defined by Anderson & King, 2000, PASP, 112:1360
        if return_pixel_phase:
            x_pixel_phase = np.squeeze(good_obs_peaks)[:, 0] - np.round(
                np.squeeze(good_obs_peaks)[:, 0], 0)
            y_pixel_phase = np.squeeze(good_obs_peaks)[:, 1] - np.round(
                np.squeeze(good_obs_peaks)[:, 1], 0)

        # divide good_ref_peaks into several subsections for a more detailed investigation
        x_step = nx / np.sqrt(n_sub).astype(int)
        y_step = ny / np.sqrt(n_sub).astype(int)
        x_centres = np.arange(0.5 * x_step,
                              (np.sqrt(n_sub).astype(int) + 0.5) * x_step,
                              x_step)
        y_centres = np.arange(0.5 * y_step,
                              (np.sqrt(n_sub).astype(int) + 0.5) * y_step,
                              y_step)
        if wrt == 'centre':
            x_centres -= nx // 2
            y_centres -= ny // 2
        peak_subsection_id = []
        for refpeak in good_ref_peaks:
            # first, figure out which subsection this particular peak falls into
            xpos = refpeak[0]
            ypos = refpeak[1]
            nearest_x_ix = find_nearest(x_centres, xpos, return_index=True)
            nearest_y_ix = find_nearest(y_centres, ypos, return_index=True)
            # then save that information
            peak_subsection_id.append((nearest_x_ix, nearest_y_ix))

        # give each subsection a label
        subsection_id = []
        for j in range(np.sqrt(n_sub).astype(int)):
            for i in range(np.sqrt(n_sub).astype(int)):
                subsection_id.append((i, j))  # (x,y)

        # # divide chip into several subsections for a more detailed investigation
        # section_masks = []
        # section_indices = []
        # x_step = nx / np.sqrt(n_sub).astype(int)
        # y_step = ny / np.sqrt(n_sub).astype(int)
        # for j in range(np.sqrt(n_sub).astype(int)):
        #     for i in range(np.sqrt(n_sub).astype(int)):
        #         q = np.zeros((ny, nx), dtype='bool')
        #         q[j * y_step : (j+1) * y_step, i * x_step : (i+1) * x_step] = True
        #         section_masks.append(q)
        #         section_indices.append((i,j))   # (x,y)

        # go to homogeneous coordinates (ie add a z-component equal to 1, so that we can include translation into the matrix)
        good_ref_peaks_xyz = np.hstack(
            (np.array(good_ref_peaks),
             np.expand_dims(np.repeat(1, len(good_ref_peaks)), axis=1)))
        good_obs_peaks_xyz = np.hstack(
            (np.squeeze(np.array(good_obs_peaks)),
             np.expand_dims(np.repeat(1, len(good_obs_peaks)), axis=1)))

        # calculate transformed co-ordinates (ie the observed peaks transformed back to match the reference peaks)
        xyz_prime = np.dot(good_obs_peaks_xyz, M)
        delta_x = good_ref_peaks_xyz[:, 0] - xyz_prime[:, 0]
        delta_y = good_ref_peaks_xyz[:, 1] - xyz_prime[:, 1]

        delta_x_list = []
        delta_y_list = []
        # loop over all subsections
        for tup in subsection_id:
            # find indices of peaks falling in each subsection
            ix = [i for i, x in enumerate(peak_subsection_id) if x == tup]
            if return_residuals:
                delta_x_list.append(delta_x[ix])
                delta_y_list.append(delta_y[ix])
            else:
                # return difference between ref and obs
                delta_x_list.append(good_ref_peaks_xyz[ix, 0] -
                                    good_obs_peaks_xyz[ix, 0])
                delta_y_list.append(good_ref_peaks_xyz[ix, 1] -
                                    good_obs_peaks_xyz[ix, 1])


#####   DO THIS IF YOU WANT TO GET A TRANSFORMATION MATRIX FOR EVERY SUBSECTION OF THE CHIP   #####
#                 M = find_affine_transformation_matrix(np.squeeze(good_ref_peaks)[ix,0], np.squeeze(good_ref_peaks)[ix,1], np.squeeze(good_obs_peaks)[ix,0], np.squeeze(good_obs_peaks)[ix,1], timit=True, eps=2., wrt='corner')
#                 good_ref_peaks_xyz = np.hstack((np.array(good_ref_peaks)[ix], np.expand_dims(np.repeat(1, len(ix)), axis=1)))
#                 good_obs_peaks_xyz = np.hstack((np.squeeze(np.array(good_obs_peaks)[ix]), np.expand_dims(np.repeat(1, len(ix)), axis=1)))
#                 xyz_prime = np.dot(good_obs_peaks_xyz, M)
#                 delta_x = good_ref_peaks_xyz[:, 0] - xyz_prime[:, 0]
#                 delta_y = good_ref_peaks_xyz[:, 1] - xyz_prime[:, 1]
#                 plt.plot(delta_x,'.')
#                 print(np.std(delta_x))
#                 sub_M_list.append(M)

# append to all-files list
        all_delta_x_list.append(delta_x_list)
        all_delta_y_list.append(delta_y_list)

    if M_list is None:
        M_list = M_list_new[:]

    if return_pixel_phase:
        if not return_M_list:
            return all_delta_x_list, all_delta_y_list, x_pixel_phase, y_pixel_phase
        else:
            return all_delta_x_list, all_delta_y_list, x_pixel_phase, y_pixel_phase, M_list
    else:
        if not return_M_list:
            return all_delta_x_list, all_delta_y_list
        else:
            return all_delta_x_list, all_delta_y_list, M_list
def get_obstype_lists(pathdict,
                      pattern=None,
                      weeding=True,
                      quick=False,
                      raw_goodonly=True,
                      savefiles=True):
    """
    This routine performs the "INGEST" step, ie for all files in a given night it identifies the type of observation and sorts the files into lists.
    For simcalib exposures it also determines which lamps were actually firing, no matter what the header says, as that can often be wrong (LC / SimTh / LC+SimTh).

    INPUT:
    "pathdict"      : dictionary containing all directories relevant to the reduction
    "pattern"       : if provided, only files containing a certain string pattern will be included
    "weeding"       : boolean - do you want to weed out binned observations?
    "quick"         : boolean - if TRUE, simcalib status in determined from headers alone (not from 2-dim images)
    "raw_goodonly"  : boolean - if TRUE, expect 8-digit date (YYYYMMDD) - if FALSE expect 6-digit date (YYMMDD)
    "savefiles"     : boolean - do you want to save the lists into output files

    OUTPUT:
    lists containing the filenames (incl. directory) of the respective observations of a certain type

    MODHIST:
    20200421 - CMB removed domeflat and skyflat lists (not used with Veloce)
    """

    path = pathdict['raw']
    chipmask_path = pathdict['cm']

    if raw_goodonly:
        date = path[-9:-1]
    else:
        date = '20' + path[-13:-7]

    if pattern is None:
        file_list = glob.glob(path + date[-2:] + "*.fits")
    else:
        file_list = glob.glob(path + '*' + pattern + '*.fits')

    # first weed out binned observations
    if weeding:
        unbinned = []
        binned = []
        for file in file_list:
            xdim = pyfits.getval(file, 'NAXIS2')
            if xdim == 4112:
                unbinned.append(file)
            else:
                binned.append(file)
    else:
        unbinned = file_list

    # prepare output lists
    if weeding:
        acq_list = binned[:]
    else:
        acq_list = []
    bias_list = []
    dark_list = []
    flat_list = []
    # skyflat_list = []
    # domeflat_list = []
    arc_list = []
    thxe_list = []
    laser_list = []
    laser_and_thxe_list = []
    stellar_list = []
    unknown_list = []

    for file in unbinned:
        obj_type = pyfits.getval(file, 'OBJECT')

        if obj_type.lower() == 'acquire':
            if not weeding:
                acq_list.append(file)
        elif obj_type.lower().startswith('bias'):
            bias_list.append(file)
        elif obj_type.lower().startswith('dark'):
            dark_list.append(file)
        elif obj_type.lower().startswith('flat'):
            flat_list.append(file)
        # elif obj_type.lower().startswith('skyflat'):
        #     skyflat_list.append(file)
        # elif obj_type.lower().startswith('domeflat'):
        #     domeflat_list.append(file)
        elif obj_type.lower().startswith('arc'):
            arc_list.append(file)
        elif obj_type.lower() in ["thxe", "thxe-only", "simth"]:
            thxe_list.append(file)
        elif obj_type.lower() in ["lc", "lc-only", "lfc", "lfc-only", "simlc"]:
            laser_list.append(file)
        elif obj_type.lower() in [
                "thxe+lfc", "lfc+thxe", "lc+simthxe", "lc+thxe"
        ]:
            laser_and_thxe_list.append(file)
        elif obj_type.lower().startswith(
            ("wasp", "proxima", "kelt", "toi", "tic", "hd", "hr", "hip", "gj",
             "gl", "ast", "alpha", "beta", "gamma", "delta", "tau", "ksi",
             "ach", "zeta", "ek", '1', '2', '3', '4', '5', '6', '7', '8', '9',
             'mercury', 'bd', 'bps', 'cd', 'he', 'g', 'cs', 'bkt', 'meingast',
             'spangap', 'sarah', 'rm', 'fp', 'vel')):
            stellar_list.append(file)
        else:
            unknown_list.append(file)

    # sort out which calibration lamps were actually on for the exposures tagged as either "SimLC" or "SimTh"
    laser_only_list = []
    simth_only_list = []
    laser_and_simth_list = []
    calib_list = laser_list + thxe_list + laser_and_thxe_list
    calib_list.sort()

    if quick:
        checkdate = date[:]
    else:
        checkdate = '1' + date[1:]

    if int(checkdate) < 20190503:
        # check if chipmask for that night already exists (if not revert to the closest one in time (preferably earlier in time))
        if os.path.isfile(chipmask_path + 'chipmask_' + date + '.npy'):
            chipmask = np.load(chipmask_path + 'chipmask_' + date +
                               '.npy').item()
        else:
            cm_list = glob.glob(chipmask_path + 'chipmask*.npy')
            cm_datelist = [int(cm.split('.')[-2][-8:]) for cm in cm_list]
            cm_datelist.sort(
            )  # need to make sure it is sorted, so that find_nearest finds the earlier one in time if two dates are found that have the same delta_t to date
            cm_dates = np.array(cm_datelist)
            alt_date = find_nearest(cm_dates, int(date))
            chipmask = np.load(chipmask_path + 'chipmask_' + str(alt_date) +
                               '.npy').item()

        # look at the actual 2D image (using chipmasks for LFC and simThXe) to determine which calibration lamps fired
        for file in calib_list:
            img = correct_for_bias_and_dark_from_filename(
                file,
                np.zeros((4096, 4112)),
                np.zeros((4096, 4112)),
                gain=[1., 1.095, 1.125, 1.],
                scalable=False,
                savefile=False,
                path=pathdict['raw'])
            lc = laser_on(img, chipmask)
            thxe = thxe_on(img, chipmask)
            if (not lc) and (not thxe):
                unknown_list.append(file)
            elif (lc) and (thxe):
                laser_and_simth_list.append(file)
            else:
                if lc:
                    laser_only_list.append(file)
                elif thxe:
                    simth_only_list.append(file)
    else:
        # since May 2019 the header keywords are (mostly) correct, so could check for LFC / ThXe in header, as that is MUCH faster
        for file in calib_list:
            lc = 0
            thxe = 0
            h = pyfits.getheader(file)
            if 'LCNEXP' in h.keys(
            ):  # this indicates the latest version of the FITS headers (from May 2019 onwards)
                if ('LCEXP' in h.keys()) or (
                        'LCMNEXP' in h.keys()
                ):  # this indicates the LFC actually was actually exposed (either automatically or manually)
                    lc = 1
            else:  # if not, just go with the OBJECT field
                if file in laser_list + laser_and_thxe_list:
                    lc = 1
            if (h['SIMCALTT'] > 0) and (h['SIMCALN'] > 0) and (h['SIMCALSE'] >
                                                               0):
                thxe = 1
            if lc + thxe == 1:
                if lc == 1:
                    laser_only_list.append(file)
                else:
                    simth_only_list.append(file)
            elif lc + thxe == 2:
                laser_and_simth_list.append(file)
            else:
                unknown_list.append(file)

    # sort all lists
    acq_list.sort()
    bias_list.sort()
    dark_list.sort()
    flat_list.sort()
    arc_list.sort()
    simth_only_list.sort()
    laser_only_list.sort()
    laser_and_simth_list.sort()
    stellar_list.sort()
    unknown_list.sort()

    if savefiles:
        shortfn_acq_list = [fn.split('/')[-1] for fn in acq_list]
        np.savetxt(path + date + '_acquire_list.txt',
                   shortfn_acq_list,
                   fmt='%s')
        shortfn_bias_list = [fn.split('/')[-1] for fn in bias_list]
        np.savetxt(path + date + '_bias_list.txt', shortfn_bias_list, fmt='%s')
        shortfn_dark_list = [fn.split('/')[-1] for fn in dark_list]
        np.savetxt(path + date + '_dark_list.txt', shortfn_dark_list, fmt='%s')
        shortfn_flat_list = [fn.split('/')[-1] for fn in flat_list]
        np.savetxt(path + date + '_flat_list.txt', shortfn_flat_list, fmt='%s')
        shortfn_arc_list = [fn.split('/')[-1] for fn in arc_list]
        np.savetxt(path + date + '_arc_list.txt', shortfn_arc_list, fmt='%s')
        shortfn_simth_only_list = [fn.split('/')[-1] for fn in simth_only_list]
        np.savetxt(path + date + '_simth_only_list.txt',
                   shortfn_simth_only_list,
                   fmt='%s')
        shortfn_laser_only_list = [fn.split('/')[-1] for fn in laser_only_list]
        np.savetxt(path + date + '_lfc_only_list.txt',
                   shortfn_laser_only_list,
                   fmt='%s')
        shortfn_laser_and_simth_list = [
            fn.split('/')[-1] for fn in laser_and_simth_list
        ]
        np.savetxt(path + date + '_lfc_and_simth_list.txt',
                   shortfn_laser_and_simth_list,
                   fmt='%s')
        shortfn_stellar_list = [fn.split('/')[-1] for fn in stellar_list]
        np.savetxt(path + date + '_stellar_list.txt',
                   shortfn_stellar_list,
                   fmt='%s')
        shortfn_unknown_list = [fn.split('/')[-1] for fn in unknown_list]
        np.savetxt(path + date + '_unknown_list.txt',
                   shortfn_unknown_list,
                   fmt='%s')

    # return acq_list, bias_list, dark_list, flat_list, skyflat_list, domeflat_list, arc_list, simth_only_list, laser_only_list, laser_and_simth_list, stellar_list, unknown_list
    return acq_list, bias_list, dark_list, flat_list, arc_list, simth_only_list, laser_only_list, laser_and_simth_list, stellar_list, unknown_list
Example #6
0
def lfc_peak_diffs(ref_obsname='25jun30256',
                   ref_date='20190625',
                   ref_year='2019',
                   degpol=7,
                   nx=4112,
                   ny=4096):
    """check LFC shifts from DAOPHOT files"""

    from readcol import readcol
    from mpl_toolkits import mplot3d
    import matplotlib.pyplot as plt

    from veloce_reduction.veloce_reduction.lfc_peaks import divide_lfc_peaks_into_orders
    from veloce_reduction.veloce_reduction.helper_functions import find_nearest
    from veloce_reduction.veloce_reduction.helper_functions import sigma_clip, single_sigma_clip

    red_path = '/Volumes/BERGRAID/data/veloce/reduced/'
    root = '/Users/christoph/OneDrive - UNSW/'
    lfc_path = '/Volumes/BERGRAID/data/veloce/lfc_peaks/'
    outpath = root + 'dispsol_tests/diff_tests/'

    # read in LFC vac wls (f0 = 9.56 GHz   &   f_rep = 25 GHz)
    lfc_vac_wls = np.squeeze(
        np.array(readcol(root + 'dispsol/lfc_vac_wls_nm.txt',
                         twod=False))) * 10.  # in Angstroms

    # read reference LFC peak positions
    try:
        _, yref, xref, _, _, _, _, _, _, _, _ = readcol(
            lfc_path + 'all/' + ref_year + '/' + ref_obsname + 'olc.nst',
            twod=False,
            skipline=2)
    except:
        _, yref, xref, _, _, _, _, _, _ = readcol(
            lfc_path + 'all/' + ref_year + '/' + ref_obsname + 'olc.nst',
            twod=False,
            skipline=2)
    xref = nx - xref
    yref = yref - 54.  # or 53??? but does not matter for getting the transformation matrix
    ref_peaks_xy_list = [(xpos, ypos) for xpos, ypos in zip(xref, yref)]
    ref_peaks = divide_lfc_peaks_into_orders(xref, yref)
    ref_vac_wl = pyfits.getdata(
        red_path + ref_date + '/' + ref_date + '_thxe_dispsol.fits', 1)

    # read in list of files to be investigated from file
    obsnames, dates = readcol(outpath + 'filelist.txt', twod=False)

    # loop over all observations to analyze
    for obsname, obs_date in zip(obsnames, dates):
        fail = False
        print('Cross-matching LFC peaks for ' + obsname)

        obs_date = str(obs_date)
        year = obs_date[:4]
        obsname = obsname.split('.')[0]

        # read obs. LFC peak positions
        if os.path.isfile(lfc_path + 'all/' + year + '/' + obsname +
                          'olc.nst'):
            try:
                _, y, x, _, _, _, _, _, _, _, _ = readcol(
                    lfc_path + 'all/' + year + '/' + obsname + 'olc.nst',
                    twod=False,
                    skipline=2)
            except:
                _, y, x, _, _, _, _, _, _ = readcol(lfc_path + 'all/' + year +
                                                    '/' + obsname + 'olc.nst',
                                                    twod=False,
                                                    skipline=2)
            x = nx - x
            y = y - 54.  # or 53??? but does not matter for getting the transformation matrix
            obs_peaks_xy_list = [(xpos, ypos) for xpos, ypos in zip(x, y)]
            obs_peaks = divide_lfc_peaks_into_orders(x, y)
            obs_vac_wl = pyfits.getdata(
                red_path + obs_date + '/' + obs_date + '_thxe_dispsol.fits', 1)
        else:
            print('ERROR: no LFC peaks measured for ' + obsname)
            fail = True

        # prepare arrays for 3D-plotting
        x_points = []
        y_points = []
        zx_points = []
        zy_points = []
        ord_points = []

        if not fail:
            # LOOP OVER ORDERS
            for ord in sorted(ref_peaks.keys()):
                # print('Processing ' + ord)
                o = int(ord[-2:]) - 1

                # divide DAOPHOT LFC peaks into orders
                ord_xref = np.array(ref_peaks[ord])[:, 0]
                ord_yref = np.array(ref_peaks[ord])[:, 1]
                ord_yref = ord_yref[ord_xref.argsort()]
                ord_xref = ord_xref[ord_xref.argsort()]
                ord_x = np.array(obs_peaks[ord])[:, 0]
                ord_y = np.array(obs_peaks[ord])[:, 1]
                ord_y = ord_y[ord_x.argsort()]
                ord_x = ord_x[ord_x.argsort()]

                # this just recovers the 7th order polynomial used in the 2-dim ThXe dispsol for the fibre closest to the LFC for this order (almost perfect)
                xx = np.arange(nx)
                ref_ord_wlfit = np.poly1d(
                    np.polyfit(xx, ref_vac_wl[o, -2, :], degpol))
                obs_ord_wlfit = np.poly1d(
                    np.polyfit(xx, obs_vac_wl[o, -2, :], degpol))
                ref_peak_thxe_wls = ref_ord_wlfit(ord_xref)
                obs_peak_thxe_wls = obs_ord_wlfit(ord_x)

                # find the nearest entries in the array of theoretical wavelengths for each peak based on the ThXe dispsol
                maxwl = np.max(ref_ord_wlfit(xx))
                minwl = np.min(ref_ord_wlfit(xx))
                ord_lfc_vac_wls = lfc_vac_wls[(lfc_vac_wls >= minwl)
                                              & (lfc_vac_wls <= maxwl)]
                thresh = (1. / 3.) * np.max(np.abs(np.diff(ord_lfc_vac_wls)))
                refpeaks_theo_wls = np.array([
                    find_nearest(lfc_vac_wls, ref_ord_wlfit(peak_x))
                    for peak_x in ord_xref
                ])
                obspeaks_theo_wls = np.array([
                    find_nearest(lfc_vac_wls, obs_ord_wlfit(peak_x))
                    for peak_x in ord_x
                ])
                refdiffs = np.abs(
                    np.array(refpeaks_theo_wls) - ref_peak_thxe_wls)
                obsdiffs = np.abs(
                    np.array(obspeaks_theo_wls) - obs_peak_thxe_wls)
                refpeaks_theo_wls = refpeaks_theo_wls[refdiffs < thresh]
                ord_xref = ord_xref[refdiffs < thresh]
                ord_yref = ord_yref[refdiffs < thresh]
                obspeaks_theo_wls = obspeaks_theo_wls[obsdiffs < thresh]
                ord_x = ord_x[obsdiffs < thresh]
                ord_y = ord_y[obsdiffs < thresh]

                # remove obvious outliers from reference observation (in both x-y-fit, and x-lambda-fit)
                # in the x-y-space
                pix_fit = np.poly1d(np.polyfit(ord_xref, ord_yref, degpol))
                pixres = ord_yref - pix_fit(ord_xref)
                clipped, goodboolix, goodix, badix = single_sigma_clip(
                    pixres, 3, return_indices=True)
                new_outies = len(badix)
                while new_outies > 0:
                    ord_xref = ord_xref[goodboolix]
                    ord_yref = ord_yref[goodboolix]
                    refpeaks_theo_wls = refpeaks_theo_wls[goodboolix]
                    pix_fit = np.poly1d(np.polyfit(ord_xref, ord_yref, degpol))
                    pixres = ord_yref - pix_fit(ord_xref)
                    clipped, goodboolix, goodix, badix = single_sigma_clip(
                        pixres, 3, return_indices=True)
                    new_outies = len(badix)
                # in the x-lambda-space
                lam_fit = np.poly1d(
                    np.polyfit(ord_xref, refpeaks_theo_wls, degpol))
                wlres = refpeaks_theo_wls - lam_fit(ord_xref)
                clipped, goodboolix, goodix, badix = single_sigma_clip(
                    wlres, 5, return_indices=True)
                new_outies = len(badix)
                while new_outies > 0:
                    ord_xref = ord_xref[goodboolix]
                    ord_yref = ord_yref[goodboolix]
                    refpeaks_theo_wls = refpeaks_theo_wls[goodboolix]
                    lam_fit = np.poly1d(
                        np.polyfit(ord_xref, refpeaks_theo_wls, degpol))
                    wlres = refpeaks_theo_wls - lam_fit(ord_xref)
                    clipped, goodboolix, goodix, badix = single_sigma_clip(
                        wlres, 5, return_indices=True)
                    new_outies = len(badix)

                # remove obvious outliers from observation
                # in the x-y-space
                pix_fit = np.poly1d(np.polyfit(ord_x, ord_y, degpol))
                pixres = ord_y - pix_fit(ord_x)
                clipped, goodboolix, goodix, badix = single_sigma_clip(
                    pixres, 3, return_indices=True)
                new_outies = len(badix)
                while new_outies > 0:
                    ord_x = ord_x[goodboolix]
                    ord_y = ord_y[goodboolix]
                    obspeaks_theo_wls = obspeaks_theo_wls[goodboolix]
                    pix_fit = np.poly1d(np.polyfit(ord_x, ord_y, degpol))
                    pixres = ord_y - pix_fit(ord_x)
                    clipped, goodboolix, goodix, badix = single_sigma_clip(
                        pixres, 3, return_indices=True)
                    new_outies = len(badix)
                # in the x-lambda-space
                lam_fit = np.poly1d(
                    np.polyfit(ord_x, obspeaks_theo_wls, degpol))
                wlres = obspeaks_theo_wls - lam_fit(ord_x)
                clipped, goodboolix, goodix, badix = single_sigma_clip(
                    wlres, 5, return_indices=True)
                new_outies = len(badix)
                while new_outies > 0:
                    ord_x = ord_x[goodboolix]
                    ord_y = ord_y[goodboolix]
                    obspeaks_theo_wls = obspeaks_theo_wls[goodboolix]
                    lam_fit = np.poly1d(
                        np.polyfit(ord_x, obspeaks_theo_wls, degpol))
                    wlres = obspeaks_theo_wls - lam_fit(ord_x)
                    clipped, goodboolix, goodix, badix = single_sigma_clip(
                        wlres, 5, return_indices=True)
                    new_outies = len(badix)

                # remove duplicate entries from the theo wls, which must correspond to false positive peaks (but we don't know which one, so let's remove all occurrences)
                refpeaks_theo_wls = list(refpeaks_theo_wls)
                ord_xref = list(ord_xref)
                ord_yref = list(ord_yref)
                obspeaks_theo_wls = list(obspeaks_theo_wls)
                ord_x = list(ord_x)
                ord_y = list(ord_y)
                if len(refpeaks_theo_wls) != len(set(refpeaks_theo_wls)):
                    dups = set([
                        dumx for dumx in refpeaks_theo_wls
                        if list(refpeaks_theo_wls).count(dumx) > 1
                    ])
                    dupix_ll = [
                        np.squeeze(
                            np.argwhere(refpeaks_theo_wls == dup)).tolist()
                        for dup in dups
                    ]
                    dupix = [item for sublist in dupix_ll for item in sublist]
                    for ix in dupix:
                        del refpeaks_theo_wls[ix]
                        del ord_xref[ix]
                        del ord_yref[ix]
                if len(obspeaks_theo_wls) != len(set(obspeaks_theo_wls)):
                    dups = set([
                        dumx for dumx in obspeaks_theo_wls
                        if list(obspeaks_theo_wls).count(dumx) > 1
                    ])
                    dupix_ll = [
                        np.squeeze(
                            np.argwhere(obspeaks_theo_wls == dup)).tolist()
                        for dup in dups
                    ]
                    dupix = [item for sublist in dupix_ll for item in sublist]
                    for ix in dupix:
                        del obspeaks_theo_wls[ix]
                        del ord_x[ix]
                        del ord_y[ix]

                # cross-match the two peak lists
                matching_ord_xref = [
                    xdum for xdum, rp in zip(ord_xref, refpeaks_theo_wls)
                    if rp in obspeaks_theo_wls
                ]
                matching_ord_yref = [
                    ydum for ydum, rp in zip(ord_yref, refpeaks_theo_wls)
                    if rp in obspeaks_theo_wls
                ]
                matching_ord_x = [
                    xdum for xdum, op in zip(ord_x, obspeaks_theo_wls)
                    if op in refpeaks_theo_wls
                ]
                matching_ord_y = [
                    ydum for ydum, op in zip(ord_y, obspeaks_theo_wls)
                    if op in refpeaks_theo_wls
                ]
                assert len(matching_ord_xref) == len(
                    matching_ord_yref
                ), 'ERROR: len(matching_ord_xref) != len(matching_ord_yref)'
                assert len(matching_ord_x) == len(
                    matching_ord_y
                ), 'ERROR: len(matching_ord_x) != len(matching_ord_y)'
                # assert len(matching_ord_xref) == len(matching_ord_x), 'ERROR: len(matching_ord_xref) != len(matching_ord_x)'
                if len(matching_ord_xref) != len(matching_ord_x):
                    print(
                        'ERROR: len(matching_ord_xref) != len(matching_ord_x)')
                    print('Skipping this file...')
                    fail = True
                else:
                    # now we can finally compare them
                    xdiff = np.array(matching_ord_x) - np.array(
                        matching_ord_xref)
                    ydiff = np.array(matching_ord_y) - np.array(
                        matching_ord_yref)

                    # fill output arrays for 3D-plotting
                    x_points.append(matching_ord_xref)
                    y_points.append(matching_ord_yref)
                    ord_points.append(
                        list((np.ones(len(matching_ord_xref)) *
                              (o + 1)).astype(int)))
                    zx_points.append(list(xdiff))
                    zy_points.append(list(ydiff))

        if not fail:
            # now bring to 1-dim format for 3D-plotting
            x_points = np.sum(x_points)
            y_points = np.sum(y_points)
            zx_points = np.sum(zx_points)
            zy_points = np.sum(zy_points)
            ord_points = np.sum(ord_points)

            # # PLOT
            # fig = plt.figure()
            # ax = fig.add_subplot(111, projection='3d')
            # ax.scatter3D(x_points, ord_points, zx_points, marker='.', s=0.5, color='b')
            # ax.set_xlabel('pixel')
            # ax.set_ylabel('order')
            # ax.set_zlabel('pixel shift')
            # plt.title(obsname)

            # save diffs to output file
            print('Saving results for a total of ' + str(len(ord_points)) +
                  ' LFC peaks!')
            results = np.array(
                [ord_points, x_points, y_points, zx_points, zy_points]).T
            outfn = outpath + obsname + '_lfc_peak_diffs.txt'
            np.savetxt(outfn,
                       results,
                       fmt='%2i   %4.8f   %4.8f   %4.8f   %4.8f')

    return
Example #7
0
def make_LFC_linelist(delta_f=25., wlmin=550., wlmax=950., shift=0., savefile=True, outpath = '/Users/christoph/OneDrive - UNSW/linelists/'):
    """
    PURPOSE:
    make fake laser-comb line-list for JS's Echelle++
    
    INPUT:
    'delta_f'  : line spacing in GHz
    'wlmin'    : minimum wavelength in nm
    'wlmax'    : maximum wavelength in nm
    'shift'    : apply this RV shift (negative for blueshift)
    'savefile' : boolean - do you want to save the linelist to a file?
    'outpath'  : directory for outpuf file 
    
    OUTPUT:
    'wl'     : wl of lines in microns
    'relint' : relative intensities (should be all equal for the LFC)
    
    MODHIST:
    15/06/2018 - CMB create
    """
    
    veloce_grating_constant = 61.4   # m*lambda_c in microns for Veloce (only approximately)
    
    if shift % np.floor(shift) != 0:
        print('WARNING: non-integer RV shift provided!!! It will be rounded to the nearest integer [in m/s]!')
        shift = np.round(shift,0)
        
    c = 2.99792458E8    #speed of light in m/s
    #convert delta_f to Hertz
    delta_f *= 1e9    
    #min and max frequency in Hz
    fmin = c / (wlmax*1e-9)         
    fmax = c / (wlmin*1e-9)

    #all the frequencies
    f0 = np.arange(fmin,fmax,delta_f)
    
    #calculate the "Doppler" shift (it really is just an offset in pixel space)
    fshift = fmin * (shift/c)
    
    #apply shift to frequencies (WARNING: don't Doppler-shift all frequencies, as this is not actually a Doppler shift, but is supposed to simulate a shift in pixels)
    f = f0 - fshift   #the minus sign is because the shift is applied to frequencies rather than to wavelengths

    #convert to the wavelengths
    wl = np.flip((c / f) / 1e-6, axis=0)     #wavelength in microns (from shortest to longest wavelength)
    relint = [1]*len(wl)

    #make one line near the order centres a different intensity so that it is easier to identify the lines
    for o in np.arange(1,44):
        m = 65 + o
        ordcen = veloce_grating_constant / m
        ordcen_ix = find_nearest(wl,ordcen,return_index=True)
        relint[ordcen_ix] = 2.
    
    if savefile:
        #string manipulations for the output file name
        if shift > 0:
            redblue = '_red'
        elif shift < 0:
            redblue = '_blue'
        else:
            redblue = ''
        np.savetxt(outpath + 'laser_linelist_25GHz'+redblue+'_'+str(int(shift))+'ms.dat', np.c_[wl, relint], delimiter=';', fmt='%12.10f; %i')
        return
    else:
        return wl, relint