Exemple #1
0
def run(path0, silent=False, verbose=True):
    '''
    Main function to run for a given path containing the raw GNIRS data

    Parameters
    ----------
    path0 : str
     Path to raw FITS file. Must include '/' at the end

    silent : boolean
      Turns off stdout messages. Default: False

    verbose : boolean
      Turns on additional stdout messages. Default: True

    Returns
    -------

    Notes
    -----
    Created by Chun Ly, 22 March 2017
    Modified by Chun Ly, 23 March 2017
     - Call dir_check.main() to handle multiple date directories
    Modified by Chun Ly, 8 January 2018
     - Import glog and call for stdout and ASCII logging
     - Pass mylogger to get_files()
    Modified by Chun Ly, 7 May 2018
     - Bug fix: Call check_path() to add '/' in path0
    '''

    rawdir = check_path(path0) # + on 07/05/2018

    # + on 08/01/2018
    logfile  = path0+'symlink.log'
    mylogger = glog.log0(logfile)._get_logger()

    if silent == False: mylogger.info('### Begin run : '+systime())

    # + on 23/03/2017
    dir_list, list_path = dir_check.main(path0, mylogger=mylogger,
                                         silent=silent, verbose=verbose)

    # Mod on 23/03/2017
    for path in list_path:
        files, n_files = get_files(path, mylogger=mylogger, silent=silent,
                                   verbose=verbose)

        for nn in xrange(n_files):
            c_file = path+'c'+files[nn]
            if exists(c_file):
                mylogger.warn('File exists : '+c_file)
            else:
                cmd0 = 'ln -fs '+files[nn]+' '+c_file
                if silent == False:
                    mylogger.info(cmd0)
                os.system(cmd0)
        #endfor
    #endfor

    if silent == False: mylogger.info('### End run : '+systime())
def run(path0, clean_file='', out_script='', silent=False, verbose=True,
        overwrite=False):

    '''
    Create a .sh script to run cleanir.py for a set of files

    Parameters
    ----------

    silent : boolean
      Turns off stdout messages. Default: False

    verbose : boolean
      Turns on additional stdout messages. Default: True

    overwrite : boolean
      Overwrite files if they exists. Default: False

    Returns
    -------

    Notes
    -----
    Created by Chun Ly, 7 March 2017
    Modified by Chun Ly, 15 May 2017
     - Call dir_check.main() to handle multiple date directories
    Modified by Chun Ly, 30 May 2017
     - Added overwrite option. Default is to not overwrite .sh files
     - Fix bug when only one file is found
    Modified by Chun Ly, 18 June 2017
     - Fix to work with no date directory
    Modified by Chun Ly, 22 January 2018
     - Import glog and call for stdout and ASCII logging
     - Pass mylogger to dir_check.main()
    Modified by Chun Ly, 20 April 2018
     - Change afq to rfq - row filtering generally produces better results
    '''

    logfile  = path0+'cleanir_script.log'
    mylogger = glog.log0(logfile)._get_logger()
    
    if silent == False: mylogger.info('### Begin run : '+systime())

    if clean_file == '': clean_file = 'clean.lis'

    # + on 15/05/2017
    dir_list, list_path = dir_check.main(path0, mylogger=mylogger, silent=silent,
                                         verbose=verbose)

    # Mod on 15/05/2017
    for date,path in zip(dir_list,list_path):
        clean_file0 = path+clean_file
        if not exists(clean_file0):
            mylogger.warn('File does not exist!!!')
            mylogger.warn(clean_file0)
        else:
            if silent == False: mylogger.info('Reading : '+clean_file0)
            files = np.loadtxt(clean_file0, dtype=type(str)).tolist()
            if type(files) == str: files = [files] # Bug fix. Mod on 30/05/2017

            out_script0 = path+'run_cleanir.sh' if out_script == '' \
                          else out_script

            if date != '': # Mod on 18/06/2017
                out_script0 = out_script0.replace('.sh', '.'+date+'.sh')

            # Mod on 30/05/2017
            if overwrite == False and exists(out_script0):
                log.warn('## File found!!! : '+out_script0)
                log.warn('## Will not overwrite!!!')
            else:
                if silent == False:
                    stat0 = 'Overwriting' if exists(out_script0) else 'Writing'
                    mylogger.info(stat0+' : '+out_script0)
                f = open(out_script0, 'w')
                for ii in xrange(len(files)):
                    cmd1 = cmd0+' -rfqo '+path+'c'+files[ii]+' '+path+files[ii]
                    f.write(cmd1+'\n')
                f.close()
            #endelse
        #endelse
    #endfor

    if silent == False: mylogger.info('End run : '+systime())
Exemple #3
0
def main(path0, out_pdf='', silent=False, verbose=True, overwrite=False):
    '''
    Main function to generate PDF illustrating alignment on target

    Parameters
    ----------
    path0 : str
     Path to FITS file. Must include '/' at the end

    silent : boolean
      Turns off stdout messages. Default: False

    verbose : boolean
      Turns on additional stdout messages. Default: True

    overwrite : boolean
      Overwrite files if they exists. Default: False

    Returns
    -------

    Notes
    -----
    Created by Chun Ly, 24 March 2017
    Modified by Chun Ly, 01 April 2017
     - Handle CRs and bad pixels using cosmicrays_lacosmic
    Modified by Chun Ly, 04 April 2017
     - Use find_gnirs_window_mean to find center
    Modified by Chun Ly, 04-05 April 2017
     - Adjust greyscale limits to handle slit image (make it black),
       and faint sources
     Use find_gnirs_window_mean to find center
    Modified by Chun Ly, 05 April 2017
     - Handle alignment sequences with more than just 4 frames
     - Handle excess subplots for individual PDF pages (remove axes)
     - Compute seeing FWHM for acquisition images
    Modified by Chun Ly, 06 April 2017
     - Get coordinates for slit in cutout
    Modified by Chun Ly, 11 May 2017
     - Use slit image to find center when telluric data is only available
    Modified by Chun Ly, 3 July 2017
     - Add overwrite option to prevent overwriting file
    Modified by Chun Ly, 9 January 2018
     - Import glog and call for stdout and ASCII logging
     - Pass mylogger to find_gnirs_window_mean(), find_gnirs_window()
    Modified by Chun Ly, 20 April 2018
     - Pass mylogger to gauss2d_fit()
     - Switch print statements to mylogger calls
    Modified by Chun Ly, 22 April 2018
     - Bug fix: mylogger calls mistakes
     - Bug fix: mylogger calls mistakes (cont'd)
    '''

    # + on 09/01/2018
    logfile = path0 + 'align_check.log'
    mylogger = glog.log0(logfile)._get_logger()

    if silent == False: mylogger.info('### Begin main : ' + systime())

    dir_list, list_path = dir_check.main(path0,
                                         mylogger=mylogger,
                                         silent=silent,
                                         verbose=verbose)

    out_pdf_default = out_pdf
    for path in list_path:
        infile = path + 'hdr_info.QA.tbl'
        if not exists(infile):
            mylogger.warning('File does not exist : ' + infile)
            mylogger.warning('Exiting!!! ' + systime())
            return

        out_pdf = path + 'align_check.pdf' if out_pdf == '' else path + out_pdf

        # Mod on 03/07/2017
        if overwrite == False and exists(out_pdf):
            mylogger.warn('File exists!! Will not overwrite ' + out_pdf)
        else:
            pp = PdfPages(out_pdf)

            if silent == False: mylogger.info('Reading: ' + infile)
            tab0 = asc.read(infile, format='fixed_width_two_line')

            align = [ii for ii in xrange(len(tab0)) if tab0['QA'][ii] == 'N/A']
            if silent == False:
                mylogger.info('Number of alignment images found : ' +
                              str(len(align)))

            ID = tab0['object'][align]
            ID0 = list(set(ID))  #Unique ID's
            if silent == False:
                mylogger.info('Sources found : ' + ', '.join(ID0))

            # + on 04/04/2017
            win_ref_idx = [
                tt for tt in xrange(len(tab0))
                if (tab0['QA'][tt] == 'N/A') and ('Acq' in tab0['slit'][tt])
                and ('HIP' not in tab0['object'][tt]) and (
                    'HD' not in tab0['object'][tt])
            ]

            # Mod on 11/05/2017
            if len(win_ref_idx) > 0:
                win_ref_file = path + tab0['filename'][win_ref_idx[0]]
                mylogger.info('Reference image for finding GNIRS window : ' +
                              win_ref_file)

                x_min, x_max, y_min, y_max, x_cen, \
                    y_cen = find_gnirs_window_mean(win_ref_file, mylogger=mylogger)
            else:
                mylogger.info('Using telluric image as reference')
                win_ref_file = path + tab0['filename'][0]
                slit_x0, slit_y0_lo, slit_y0_hi = get_slit_trace(win_ref_file)
                x_min, x_max = min(slit_x0), max(slit_x0)
                x_cen = (x_min + x_max) / 2.0
                y_cen = (np.median(slit_y0_lo) + np.median(slit_y0_hi)) / 2.0
                y_min, y_max = y_cen - size2d[0].value / 2.0, y_cen + size2d[
                    0].value / 2.0

            pos_cen = (x_cen, y_cen)
            new_size = u.Quantity((y_max - y_min, x_max - x_min), u.pixel)

            # + on 20/04/2018, Mod on 22/04/2018
            mylogger.info('pos_cen : (%f, %f) ' % (pos_cen[0], pos_cen[1]))
            mylogger.info('new_size : [%f, %f] pix ' %
                          (new_size[0].value, new_size[1].value))

            for ii in xrange(len(ID0)):
                t_idx = [
                    tt for tt in xrange(len(tab0)) if
                    (tab0['object'][tt] == ID0[ii] and tab0['QA'][tt] == 'N/A')
                ]

                t_files = [path + a for a in tab0['filename'][t_idx]]
                ncols = 2.0
                nrows = 2  # np.ceil(len(t_idx)/ncols)
                ncols, nrows = np.int(ncols), np.int(nrows)

                # Mod on 05/04/2017
                if len(t_idx) <= nrows * ncols:
                    fig, ax_arr = plt.subplots(nrows=nrows, ncols=ncols)

                #med0, x_min, x_max, y_min, \
                #    y_max, x_cen, y_cen = find_gnirs_window(t_files[1], mylogger=mylogger)

                # Later + on 24/03/2017 | Mod on 04/04/2017
                xcen, ycen = find_star(t_files[-1],
                                       pos=pos_cen,
                                       find_size2d=new_size)
                # Fix to get relative coordinate for Cutout2D image
                #xcen -= pos_cen[0]-new_size[1].value/2.0
                #ycen -= pos_cen[1]-new_size[0].value/2.0

                slit_x0, slit_y0_lo, slit_y0_hi = get_slit_trace(
                    t_files[0])  #, x_min, x_max)
                # Adjust values for offset that is applied
                # Bug: Mod on 04/04/2017 to get proper coordinate
                slit_x0 -= np.int64(pos_cen[0] - size2d[1].value / 2.0)
                slit_y0_lo -= pos_cen[1] - size2d[0].value / 2.0
                slit_y0_hi -= pos_cen[1] - size2d[0].value / 2.0

                for jj in xrange(len(t_idx)):
                    jj_idx = t_idx[jj]

                    # + on 05/04/2017
                    if len(t_idx) > (nrows * ncols):
                        if jj % (nrows * ncols) == 0:
                            fig, ax_arr = plt.subplots(nrows=nrows,
                                                       ncols=ncols)

                    im0 = fits.getdata(t_files[jj])
                    hdr0 = fits.getheader(t_files[jj], ext=0)  # Get WCS header

                    # + 01/04/2017
                    im0_clean = cosmicray_lacosmic(im0, sigclip=10)[0]

                    cutout = Cutout2D(im0_clean,
                                      pos_cen,
                                      size2d,
                                      mode='partial',
                                      fill_value=np.nan)

                    t_col, t_row = jj % ncols, (jj / ncols) % nrows

                    # Mod on 04/04/2017 to handle bright and faint stars
                    max0 = np.max(cutout.data)

                    # Compute median within GNIRS window
                    # + on 04-05/04/2017
                    temp = im0_clean[-50:-1, :]
                    bgd0, sig0 = np.median(temp), np.std(temp)
                    idx_y, idx_x = np.where(im0_clean > (bgd0 + 5 * sig0))
                    med0 = np.median(im0_clean[idx_y, idx_x])
                    mylogger.info('## max0 : %f   med0 : %f ' % (max0, med0))
                    if max0 > 50000:
                        z1, z2 = zscale.get_limits(cutout.data)
                        z2 = max0  # Change for better stretch for telluric star
                    else:
                        if ('Acq_' not in tab0['slit'][jj_idx]) and \
                           (tab0['exptime'][jj_idx] == 3):
                            # First frame that will show the longslit
                            z1, z2 = 0.0, 0.5 * max0
                        else:
                            # This should handle faint and bright stars
                            z1, z2 = 0.5 * med0, max0

                    norm = ImageNormalize(vmin=z1, vmax=z2)
                    t_ax = ax_arr[t_row, t_col]
                    t_ax.imshow(cutout.data,
                                cmap='Greys',
                                origin='lower',
                                norm=norm)
                    #aplpy.FITSFigure(cutout)

                    # Draw trace of slit
                    t_ax.plot(slit_x0, slit_y0_lo, 'r-')
                    t_ax.plot(slit_x0, slit_y0_hi, 'r-')

                    t_ax.xaxis.set_ticklabels([])
                    t_ax.yaxis.set_ticklabels([])

                    fig.suptitle(path, fontsize=14)

                    txt0 = tab0['filename'][jj_idx] + '\n'
                    txt0 += tab0['datelabel'][jj_idx] + '\n'
                    txt0 += tab0['UT_date'][jj_idx] + '\n'
                    txt0 += tab0['object'][jj_idx]
                    t_ax.annotate(txt0, [0.025, 0.95],
                                  xycoords='axes fraction',
                                  ha='left',
                                  va='top')

                    # Plot inset | Later + on 24/03/2017
                    axins = zoomed_inset_axes(t_ax, 6, loc=4)
                    norm2 = ImageNormalize(vmin=z1, vmax=z2)
                    axins.imshow(cutout.data,
                                 cmap='Greys',
                                 origin='lower',
                                 norm=norm2)

                    # Draw trace of slit
                    axins.plot(slit_x0, slit_y0_lo, 'r-')
                    axins.plot(slit_x0, slit_y0_hi, 'r-')

                    # Mod on 04/04/2017 to get Cutout2d coordinates
                    c_xcen = xcen - (pos_cen[0] - size2d[1].value / 2.0)
                    c_ycen = ycen - (pos_cen[1] - size2d[0].value / 2.0)
                    x1, x2, y1, y2 = c_xcen - 20, c_xcen + 20, c_ycen - 20, c_ycen + 20
                    axins.set_xlim([x1, x2])
                    axins.set_ylim([y1, y2])
                    axins.xaxis.set_ticklabels([])
                    axins.yaxis.set_ticklabels([])
                    mark_inset(t_ax,
                               axins,
                               loc1=1,
                               loc2=3,
                               fc="none",
                               ec="b",
                               ls='dotted',
                               lw=0.5)

                    # Compute FWHM of alignment star | + on 05/04/2017
                    if ('Acq_' not in tab0['slit'][jj_idx]) and \
                       (tab0['exptime'][jj_idx] == 3):
                        mylogger.info('No source in slit : ' +
                                      tab0['filename'][jj_idx])
                    else:
                        # + on 06/04/2017
                        c_size2d = u.Quantity((40, 40), u.pixel)
                        c_slit_x0 = slit_x0 - (c_xcen -
                                               c_size2d[1].value / 2.0)
                        c_slit_y0_lo = slit_y0_lo - (c_ycen -
                                                     c_size2d[0].value / 2.0)
                        c_slit_y0_hi = slit_y0_hi - (c_ycen -
                                                     c_size2d[0].value / 2.0)
                        im0_crop = Cutout2D(cutout.data, (c_xcen, c_ycen),
                                            c_size2d,
                                            mode='partial',
                                            fill_value=np.nan)
                        gauss2d_fit(im0_crop.data,
                                    hdr0,
                                    t_ax,
                                    c_slit_x0,
                                    c_slit_y0_lo,
                                    c_slit_y0_hi,
                                    mylogger=mylogger)  # Mod on 06/04/2017

                    # Write each page separately | + on 05/04/2017
                    if len(t_idx) > (nrows * ncols):
                        # Mod later on 05/04/2017 to handle excess subplots
                        if jj == len(t_idx) - 1:
                            rem0 = len(t_idx) % (nrows * ncols)  # remainder
                            if rem0 != 0:
                                for rr in range(rem0, nrows * ncols, 1):
                                    t_col, t_row = rr % ncols, (rr /
                                                                ncols) % nrows
                                    ax_arr[t_row, t_col].axis('off')

                        if (jj % (nrows * ncols) == nrows*ncols-1) or \
                           (jj == len(t_idx)-1):
                            subplots_adjust(left=0.02,
                                            bottom=0.02,
                                            top=0.95,
                                            right=0.98,
                                            wspace=0.02,
                                            hspace=0.02)
                            fig.set_size_inches(11, 8)
                            fig.savefig(pp, format='pdf')
                #endfor

                # Mod on 05/04/2017
                if len(t_idx) <= nrows * ncols:
                    # Mod later on 05/04/2017 to handle excess subplots
                    for rr in range(len(t_idx), nrows * ncols):
                        t_col, t_row = rr % ncols, (rr / ncols) % nrows
                        ax_arr[t_row, t_col].axis('off')

                    subplots_adjust(left=0.02,
                                    bottom=0.02,
                                    top=0.95,
                                    right=0.98,
                                    wspace=0.02,
                                    hspace=0.02)
                    fig.set_size_inches(11, 8)
                    fig.savefig(pp, format='pdf')
            #endfor

            pp.close()
        #endelse

        out_pdf = out_pdf_default

    if silent == False: mylogger.info('### End main : ' + systime())
def main(rawdir, out_pdf='', gz=False, silent=False, verbose=True):
    '''
    Main function to compute and plot statistics

    Parameters
    ----------
    rawdir : str
      Path to raw files.

    gz : boolean
      Indicate using gz-compressed files (mostly for debugging). Default: False

    silent : boolean
      Turns off stdout messages. Default: False

    verbose : boolean
      Turns on additional stdout messages. Default: True

    Returns
    -------

    Notes
    -----
    Created by Chun Ly, 8 May 2018
     - Change output PDF filename
     - Plot averages of statistic measurements
     - Plot expected Poissonian level
     - Plot aesthetics (legend, limits, x/ylabel)
     - Compute and plot rms of stacked image
    Modified by Chun Ly, 21 May 2018
     - Bug fix: Mistake in computing RMS for combined 2-D data
     - Write RMS to mylogger; Label 'Stack' RMS on right side of plot
     - Add gz keyword option to use with compressed files
    Modified by Chun Ly, 28 May 2018
     - Add '/' after rawdir if not provided
    '''

    if rawdir[-1] != '/': rawdir = rawdir + '/'

    logfile = rawdir + 'image_stats.log'
    mylogger = glog.log0(logfile)._get_logger()

    if silent == False: mylogger.info('### Begin run ! ')

    dir_list, list_path = dir_check.main(rawdir,
                                         mylogger=mylogger,
                                         silent=silent,
                                         verbose=verbose)

    out_pdf_default = out_pdf

    for path in list_path:
        file_lis = path + 'obj.lis'
        if not exists(file_lis):
            if silent == False: mylogger.info('File not found : ' + file_lis)
        else:
            if silent == False: mylogger.info('Reading : ' + file_lis)
            t_files = np.loadtxt(file_lis, dtype=type(str)).tolist()
            files0 = [path + 'tfrbnc' + t_file for t_file in t_files]
            if gz == True:  # + on 21/05/2018
                files0 = [t_file + '.gz' for t_file in files0]

            n_files0 = len(files0)
            avg_arr = np.zeros(n_files0)
            med_arr = np.zeros(n_files0)
            sig_arr = np.zeros(n_files0)

            for nn in range(n_files0):
                im0 = fits.getdata(files0[nn], extname='SCI')

                c_mean, c_med, c_sig = sigma_clipped_stats(im0,
                                                           sigma=2.0,
                                                           iters=10)
                avg_arr[nn] = c_mean
                med_arr[nn] = c_med
                sig_arr[nn] = c_sig
            #endfor

            #print avg_arr, med_arr, sig_arr

            if out_pdf == '':
                out_pdf = path + 'image_stats.pdf'
            else:
                out_pdf = path + out_pdf

            fig, ax_arr = plt.subplots(nrows=2)

            num0 = 1 + np.arange(n_files0)
            ax_arr[0].scatter(num0,
                              avg_arr,
                              marker='o',
                              s=50,
                              facecolor='none',
                              edgecolor='k',
                              label='Mean')
            avg_avg = np.average(avg_arr)
            ax_arr[0].axhline(y=avg_avg, c='k', linestyle='dashed')

            ax_arr[0].scatter(num0,
                              med_arr,
                              marker='x',
                              s=25,
                              color='b',
                              label='Median')
            avg_med = np.average(med_arr)
            ax_arr[0].axhline(y=avg_med, c='b', linestyle='dotted')

            ax_arr[0].legend(loc='lower right', fontsize=8)

            ax_arr[1].scatter(num0,
                              sig_arr,
                              marker='o',
                              s=50,
                              facecolor='none',
                              edgecolor='k')
            avg_sig = np.average(sig_arr)
            ax_arr[1].axhline(y=avg_sig, c='k', linestyle='dashed')

            # Expected Poissionan level
            sig_poisson = avg_sig / np.sqrt(n_files0)
            mylogger.info('Expected (Poisson) RMS : %.4f' %
                          sig_poisson)  # + on 21/05/2018
            ax_arr[1].axhline(y=sig_poisson, c='b', linestyle='dashed')
            ax_arr[1].text(0,
                           sig_poisson,
                           'Poisson',
                           color='b',
                           ha='left',
                           va='bottom')

            ax_arr[0].minorticks_on()
            ax_arr[1].minorticks_on()

            ax_arr[0].set_xticklabels([])
            ax_arr[0].set_xlim([-0.25, n_files0 + 1])
            ax_arr[1].set_xlim([-0.25, n_files0 + 1])
            ax_arr[1].set_ylabel(r'$\sigma$')
            ax_arr[1].set_xlabel('Frame No.')

            # Plot rms of stacked image
            comb_file = glob.glob(path + 'obj_comb.fits')
            if len(comb_file) != 0:
                mylogger.info('Reading : ' + comb_file[0])
                comb_data = fits.getdata(comb_file[0],
                                         extname='SCI')  # Mod on 21/05/2018

                # Mod on 21/05/2018
                c_mean, c_med, c_sig = sigma_clipped_stats(comb_data,
                                                           sigma=2.0,
                                                           iters=10)
                mylogger.info('Measured RMS in stack : %.4f' %
                              c_sig)  # + on 21/05/2018
                ax_arr[1].axhline(y=c_sig, c='g', linestyle='dashed')
                ax_arr[1].text(n_files0 + 1,
                               c_sig,
                               'Stack',
                               color='g',
                               ha='right',
                               va='bottom')  # Mod on 21/05/2018

            #fig, ax_arr = plt.subplots(ncols=2)
            #ax_arr[0].hist(avg_arr, bins=5, align='mid', color='b',
            #               linestyle='solid', alpha=0.5, edgecolor='b',
            #               histtype='step', label='Average')
            #ax_arr[0].hist(med_arr, bins=5, align='mid', # color='g',
            #               linestyle='dashed', edgecolor='k',
            #               histtype='step', label='Median')
            #ax_arr[1].hist(sig_arr, bins=5, align='mid', color='k',
            #               linestyle='solid', alpha=0.5, edgecolor='k',
            #               histtype='step')

            mylogger.info('Writing : ' + out_pdf)
            fig.set_size_inches(8, 4)
            fig.savefig(out_pdf, bbox_inches='tight')
            plt.close()

        out_pdf = out_pdf_default
    #endfor

    if silent == False: mylogger.info('### End run ! ')
def main(path0, targets, outfile=None, silent=False, verbose=True):
    '''
    Generate ASCII file summarizing observations

    Parameters
    ----------
    path0 : str
      Parent path for all files

    silent : boolean
      Turns off stdout messages. Default: False

    verbose : boolean
      Turns on additional stdout messages. Default: True

    Returns
    -------

    Notes
    -----
    Created by Chun Ly, 25 April 2017
    Modified by Chun Ly, 5 May 2017
     - Handle overwriting file
    Modified by Chun Ly, 3 June 2017
     - Bug fix: Check if hdr_info.QA.tbl exists
    '''

    if silent == False: log.info('### Begin main : ' + systime())

    Targets, ObsDate, ObsSet = [], [], []
    TotalTime, gratwave, Airmass = [], [], []
    TellStar, TellSet, TellAM = [], [], []  # Later Mod on 25/04/2017

    for tt in range(len(targets)):
        tt_path = path0 + targets[tt] + '/'
        dir_list, list_path = dir_check.main(tt_path,
                                             silent=True,
                                             verbose=False)

        cnt = 0
        for path in list_path:
            # Mod on 25/04/2017
            txt = targets[tt] if cnt == 0 else '...'
            Targets.append(txt)  #targets[tt])

            QA_file = path + '/hdr_info.QA.tbl'
            # Mod on 03/06/2017
            if not exists(QA_file):
                log.warn('## File not found! ' + QA_file)

                ObsDate.append('N/A')
                gratwave.append('N/A')

                ObsSet.append('N/A')
                TotalTime.append('N/A')
                Airmass.append('N/A')

                TellStar.append('N/A')
                TellSet.append('N/A')
                TellAM.append('N/A')
            else:
                QA_tab = asc.read(QA_file, format='fixed_width_two_line')

                # All science targets
                idx = [
                    xx for xx in range(len(QA_tab))
                    if ('obj' in QA_tab['QA'][xx]) or (
                        'sky' in QA_tab['QA'][xx])
                ]

                # Later Mod on 25/04/2017
                tab_ref = QA_tab[idx][0]
                t_date = tab_ref['UT_date'].split('T')[0]
                exptime = tab_ref['exptime']

                ObsDate.append(t_date)
                gratwave.append(tab_ref['gratwave'])

                ObsSet.append(str(len(idx)) + 'x' + str(exptime) + 's')
                TotalTime.append('%.2f' % (len(idx) * exptime / 60.0))

                AM0 = QA_tab['airmass'][idx]
                Airmass.append('%.3f-%.3f' % (np.min(AM0), np.max(AM0)))

                t_idx = [
                    xx for xx in range(len(QA_tab))
                    if ('telluric' in QA_tab['QA'][xx])
                ]
                t_names = list(set(QA_tab['object'][t_idx]))

                telstar, telset, telAM = get_telluric_info(
                    QA_tab, t_idx, t_names)
                TellStar.append(telstar)
                TellSet.append(telset)
                TellAM.append(telAM)  # Later + on 25/04/2017
                cnt += 1
            #endelse
        #endfor
    #endfor

    arr0 = [
        Targets, ObsDate, ObsSet, TotalTime, gratwave, Airmass, TellStar,
        TellSet, TellAM
    ]
    names0 = ('Name', 'UT_Date', 'Sequence', 'Int_Time', 'Grating_Wave',
              'Airmass', 'Telluric_Star', 'Telluric_Seq', 'Telluric_AM')
    tab0 = Table(arr0, names=names0)

    print tab0

    if outfile == None: outfile = path0 + 'obs_summary.txt'

    # Mod on 06/05/2017
    if silent == False:
        stat0 = 'Overwriting : ' if exists(outfile) else 'Writing : '
        log.info(stat0 + outfile)
    asc.write(tab0,
              output=outfile,
              format='fixed_width_two_line',
              overwrite=True)

    if silent == False: log.info('### End main : ' + systime())
def main(rawdir, silent=False, verbose=True):
    '''
    Main function for distort_trace

    Parameters
    ----------
    rawdir : str
      Path to FITS file. Must include '/' at the end

    silent : boolean
      Turns off stdout messages. Default: False

    verbose : boolean
      Turns on additional stdout messages. Default: True

    Returns
    -------

    Notes
    -----
    Created by Chun Ly, 27 June 2018
     - Write multi-page PDF file
     - Remove center value for middle of spectra
     - Plot offsets
     - Bug fix for curve_fit (use bb_med0); plot aesthetics (legend)
     - Plot aesthetics (axes labeling), margin adjustments
     - Call group() to get matplotlib markers and colors
     - Write npz file using np.savez and np.load when available
     - Do linear regression fit and save to npz file
    Modified by Chun Ly, 28 June 2018
     - Change linear regression to 2nd order, plot fit
    Modified by Chun Ly, 29 June 2018
     - Write PDF file in each datedir
     - Minor changes to mylogger calls
    Modified by Chun Ly, 31 July 2018
     - Use sigma_clipped_stats; Search for multiple peaks
    Modified by Chun Ly,  1 August 2018
     - Smooth median signal (boxcar); mask for peaks
     - Call group_index(); Require at leat 5 pixels for peak identification
     - Handle multiple peaks
     - Compute number of peaks only once
    Modified by Chun Ly,  2 August 2018
     - Use combine stack for peak identification (more sensitive)
     - Get quick peak centers from combine stack
     - Use peak in med0 if no combine stack or telluric spec
     - Handle peak finding for both telluric and science data
     - Handle multiple peaks in plotting
     - Restrict fitting to within 10 pixels
    Modified by Chun Ly,  3 August 2018
     - Simplify code (x0_bb -> x0)
     - Fix ValueError: Invalid rgba arg ""
     - Fix bugs with n_files and use of 'x' datapoints
     - Use median for x_cen_middle to deal with outliers
     - Compute median using sigma_clipped_stats, exclude outliers from polyfit
     - Switch flag to flag0 to avoid conflict
     - Use peak when combine stack has single line
     - Switch from curve_fit to weighted centering
     - Define p_idx for single peak
    Modified by Chun Ly,  7 August 2018
     - Bug fix: Incorrect x0_diff
     - Handle case when not all skysubtracted frames are used
       (check for obj_rev.lis file)
     - Force integer for index
     - Avoid right edge issue (specific hack for one target)
     - Use DQ array to masked bad pixels and edges
     - Limit weighted computation within expected location
     - Shift x0_max1 for sub-indexing
     - Force x-limit range (zoom-in)
     - Plot aesthetics: ax annotation
    Modified by Chun Ly,  8 August 2018
     - Plot fitting results
     - Bug fix with savefig location, change labeling
    Modified by Chun Ly,  9 August 2018
     - Fix typo with wrong ax subplots use (row determination)
     - Annotate plot with center
     - Plot aesthetics: toplabel, white space, ylim
     - Changes for right center for telluric and single peak science data cases
     - Adjust ax.plot xrange
    Modified by Chun Ly, 10 August 2018
     - Compute median of trace_arr in each bin, best fit polynomial fit
     - Plot best fit to median of trace_arr
     - Update npz savefile with best_fit results
     - Annotate plot with best fit
     - Fix IndexError issue (limit v1 >= 0)
     - Change fig suptitle (just the filename)
    '''

    if rawdir[-1] != '/': rawdir += '/'

    logfile = rawdir + 'distort_trace.log'
    mylogger = glog.log0(logfile)._get_logger()

    if silent == False: mylogger.info('### Begin ! ')

    bin_size = 25

    dir_list, list_path = dir_check.main(rawdir,
                                         mylogger=mylogger,
                                         silent=silent,
                                         verbose=verbose)

    for path in list_path:
        mylogger.info('Working on : ' + path.split('/')[-2])
        out_pdf = path + 'distort_trace.pdf'
        out_pdf1 = path + 'distort_trace_fit.pdf'
        npz_file = path + 'distort_trace.npz'
        obj_file = path + 'obj_rev.lis'

        if not exists(npz_file):
            if not exists(obj_file):
                files = glob(path + 'tfrbncN????????S????.fits')
            else:
                mylogger.info('File found : ' + obj_file)
                npfiles = np.loadtxt(obj_file, dtype=type(str))
                files = [path + 'tfrbnc' + t_file for t_file in npfiles]

                npfilesT = np.loadtxt(path + 'telluric.lis', dtype=type(str))
                filesT = [path + 'tfrbnc' + t_file for t_file in npfilesT]

                files += filesT
                files.sort()

            n_files = len(files)

            mylogger.info('Number of files found : %i ' % n_files)
            if n_files > 0:
                pdf_pp = PdfPages(out_pdf1)

                hdr0 = fits.getheader(files[0], extname='SCI')
                n_bins = np.int(np.ceil(np.float(hdr0['NAXIS2'])) / bin_size)

                x0 = np.arange(hdr0['NAXIS1'])
                y0 = bin_size / 2.0 + bin_size * np.arange(n_bins)

                no_c_file = 0
                c_file = glob(path + 'obj_comb.fits')
                if len(c_file) == 0:
                    mylogger.warn('Combine frame not found! Using single peak')
                    no_c_file = 1
                    n_peaks = 1
                else:
                    t_c_im = fits.getdata(c_file[0], extname='SCI')
                    c_med0 = np.median(t_c_im, axis=0)

                    # Find peaks | + on 31/07/2018
                    x0_max = np.argmax(c_med0)
                    x0_min = np.argmin(c_med0)

                    idx_mask = np.where((np.absolute(x0 - x0_max) >= 10)
                                        & (np.absolute(x0 - x0_min) >= 10))[0]
                    sm_c_med0 = convolve(c_med0, box_kernel)

                    t_mean, t_med, t_std = sigma_clipped_stats(
                        sm_c_med0[idx_mask], sigma=2, iters=20)
                    idx_det = np.where((sm_c_med0 - t_med) / t_std >= 5)[0]

                    list_peak = np.array(list(group_index(idx_det)))
                    peak_idx = [
                        xx for xx in range(len(list_peak))
                        if (list_peak[xx][1] -
                            list_peak[xx][0] >= 5 and list_peak[xx][0] < 625)
                    ]  # Avoid right edge issues
                    list_peak = list_peak[peak_idx]

                    n_peaks = len(peak_idx)
                    mylogger.info('Number of peaks found : ' + str(n_peaks))

                    peak_ctr = np.zeros(n_peaks)
                    for pp in range(n_peaks):
                        i1, i2 = list_peak[pp][0], list_peak[pp][1]
                        peak_ctr[pp] = i1 + np.argmax(c_med0[i1:i2])

                trace_arr = np.zeros((n_peaks, n_files, n_bins))
                xcen_arr = np.zeros((n_peaks, n_files))
                fit_arr = np.zeros((n_peaks, n_files, 3))

                for ff in range(n_files):
                    fig, ax = plt.subplots(nrows=nrows, ncols=ncols)

                    t_im0, t_hdr = fits.getdata(files[ff],
                                                extname='SCI',
                                                header=True)
                    t_dq = fits.getdata(files[ff], extname='DQ')

                    t_im = np.ma.array(t_im0, mask=t_dq)
                    med0 = np.ma.median(t_im, axis=0)

                    x0_max0 = np.ma.argmax(med0)

                    h_obj = t_hdr['OBJECT']
                    if no_c_file or ('HIP' in h_obj or 'HD' in h_obj):
                        n_peak, use_peak = 1, 1
                    else:
                        n_peak = n_peaks
                        use_peak = 1 if n_peaks == 1 else 0
                        x0_diff = peak_ctr[0] - x0_max0

                    for bb in range(n_bins):
                        row, col = bb / ncols, bb % ncols

                        ty1, ty2 = (0 + bb) * bin_size, (1 + bb) * bin_size
                        bb_med0 = np.ma.median(t_im[ty1:ty2], axis=0)

                        for pp in range(n_peak):
                            if use_peak == 1:
                                if no_c_file or ('HIP' in h_obj
                                                 or 'HD' in h_obj):
                                    v1, v2 = x0_max0 - 15, x0_max0 + 15
                                else:
                                    v1 = np.max([
                                        np.int(list_peak[0][0] - x0_diff - 15),
                                        0
                                    ])
                                    v2 = np.int(list_peak[0][1] - x0_diff + 15)

                                # print ff, bb, pp, v1, v2, x0_max0

                                x0_max1 = v1 + np.ma.argmax(bb_med0[v1:v2])
                                p_idx = np.arange(x0_max1 - 10, x0_max1 + 10)
                                # print ff, bb, pp, x0_max0, x0_max1, p_idx[0], p_idx[-1]
                            else:
                                p_idx = np.arange(
                                    np.int(list_peak[pp][0] - x0_diff),
                                    np.int(list_peak[pp][1] - x0_diff))

                            p_med0 = bb_med0[p_idx]

                            x_cen = np.sum(p_med0 * p_idx) / np.sum(p_med0)
                            #p0 = [0.0, y0_max, x0_max, 2.0]
                            #try:
                            #    popt, pcov = curve_fit(gauss1d, x0, bb_med0, p0=p0)
                            #    x_cen = popt[2]
                            #except RuntimeError:
                            #    print 'Runtime error'
                            #    x_cen = p0[2]
                            trace_arr[pp, ff, bb] = x_cen

                            x_off = p_idx[len(p_idx) / 2]
                            ax[row, col].plot(p_idx - x_off,
                                              p_med0 / max(p_med0))
                            ax[row, col].axvline(x=x_cen - x_off)
                            ax[row, col].annotate('%.1f' % x_cen,
                                                  xy=[0.95, 0.95],
                                                  ha='right',
                                                  va='top',
                                                  fontsize=9,
                                                  xycoords='axes fraction')
                            if row != nrows - 1:
                                ax[row, col].set_xticklabels([])
                            if col != 0:
                                ax[row, col].set_yticklabels([])

                            ax[row, col].set_ylim([-0.05, 1.05])
                        #endfor
                    #endfor
                    plt.subplots_adjust(left=0.08,
                                        right=0.99,
                                        bottom=0.05,
                                        top=0.95,
                                        hspace=0.02,
                                        wspace=0.02)
                    fig.suptitle(os.path.basename(files[ff]), fontsize=12)
                    fig.savefig(pdf_pp, format='pdf')
                #endfor
                mylogger.info('Writing : ' + out_pdf1)
                pdf_pp.close()

                flag0 = np.ones((n_peaks, n_files, n_bins))

                for ff in range(n_files):
                    for pp in range(n_peaks):
                        t_me, t_md, t_s = sigma_clipped_stats(trace_arr[pp,
                                                                        ff],
                                                              sigma=3,
                                                              iters=10)
                        x_cen_middle = t_md
                        xcen_arr[pp, ff] = x_cen_middle
                        trace_arr[pp, ff] -= x_cen_middle

                        diff = trace_arr[pp, ff] - ((y0 - 512) * 0.019)
                        use = np.where(np.absolute(diff) <= 5)[0]
                        if len(use) > 0: flag0[pp, ff, use] = 0

                        fit = np.polyfit(y0[use], trace_arr[pp, ff][use], 2)
                        fit_arr[pp, ff] = fit
                    #endfor
                #endfor

                mylogger.info('Writing : ' + npz_file)
                np.savez(npz_file,
                         trace_arr=trace_arr,
                         xcen_arr=xcen_arr,
                         fit_arr=fit_arr,
                         y0=y0,
                         flag0=flag0)
            else:
                mylogger.warn('Files not found !')
        else:
            mylogger.info('Reading : ' + npz_file)
            npz = np.load(npz_file)
            trace_arr = npz['trace_arr']
            xcen_arr = npz['xcen_arr']
            y0 = npz['y0']
            fit_arr = npz['fit_arr']
            flag0 = npz['flag0']
            n_files = xcen_arr.shape[1]
            n_peaks = xcen_arr.shape[0]

        if n_files > 0:
            fig, ax = plt.subplots()
            xlim = [-10, 10]

            ctype, mtype, labels = group(xcen_arr)

            x_fit0 = np.zeros(len(y0))
            for bb in range(len(y0)):
                use = np.where(flag0[:, :, bb] == 0)
                x_fit0[bb] = np.median(trace_arr[use[0], use[1], bb])
            best_fit = np.polyfit(y0, x_fit0, 2)
            mylogger.info('Best fit : [%f, %f, %f]', best_fit[0], best_fit[1],
                          best_fit[2])

            for pp in range(n_peaks):
                for ff in range(n_files):
                    if labels[pp, ff] != '':
                        fc = ctype[pp, ff] if mtype[pp, ff] == 'x' else 'none'
                        ax.scatter(trace_arr[pp, ff, :],
                                   y0,
                                   marker=mtype[pp, ff],
                                   alpha=0.5,
                                   edgecolor=ctype[pp, ff],
                                   facecolor=fc,
                                   label=labels[pp, ff])
                        ax.scatter(trace_arr[pp, ff, flag0[pp, ff] == 1],
                                   y0[flag0[pp, ff] == 1],
                                   marker='x',
                                   color='r')

                        pd = np.poly1d(fit_arr[pp, ff])
                        ax.plot(pd(y0),
                                y0,
                                color=ctype[pp, ff],
                                linewidth=0.75,
                                alpha=0.5)

            ax.scatter(x_fit0,
                       y0,
                       marker='o',
                       edgecolor='none',
                       facecolor='black',
                       linewidth=2.0,
                       alpha=0.9)
            best_pd = np.poly1d(best_fit)
            ax.plot(best_pd(y0), y0, color='black', linewidth=2.0, alpha=0.9)
            b_txt = r'x = A y$^2$ + B y + C'+\
                    '\nA = %.3e\nB = %.3e\nC = %.3f' % (best_fit[0],best_fit[1],
                                                        best_fit[2])
            ax.annotate(b_txt,
                        xy=(0.05, 0.75),
                        xycoords='axes fraction',
                        ha='left',
                        va='top')

            out_plt = np.where((trace_arr > xlim[1]) | (trace_arr < xlim[0]))
            n_out_plt = len(out_plt[0])
            flagged = np.where(flag0 == 1)
            n_flagged = len(flagged[0])

            a_txt = 'N(exclude) = ' + str(n_out_plt) + '\nN(flagged) = ' + str(
                n_flagged)
            ax.annotate(a_txt,
                        xy=(0.05, 0.95),
                        xycoords='axes fraction',
                        ha='left',
                        va='top')
            ax.legend(loc='lower right')

            ax.set_ylabel('Y [pixels]', fontsize=14)
            ax.set_xlabel('X relative to center [pixels]', fontsize=14)
            ax.set_xlim(xlim)  #[-100,100])
            ax.set_ylim([-10, 1050])
            fig.suptitle(path)
            ax.minorticks_on()

            fig.set_size_inches(8, 8)
            plt.subplots_adjust(left=0.1, right=0.98, bottom=0.07, top=0.98)
            mylogger.info('Writing : ' + out_pdf)
            fig.savefig(out_pdf, format='pdf')

            mylogger.info('Updating : ' + npz_file)
            np.savez(npz_file,
                     trace_arr=trace_arr,
                     xcen_arr=xcen_arr,
                     fit_arr=fit_arr,
                     y0=y0,
                     flag0=flag0,
                     best_fit=best_fit)
    #endfor

    if silent == False: mylogger.info('### End ! ')
Exemple #7
0
def main(path0='',
         out_pdf='',
         check_quality=True,
         skysub=False,
         silent=False,
         verbose=True,
         overwrite=False):
    '''
    main() function to compute natural seeing (image quality) from bright
    alignment star

    Parameters
    ----------
    path0 : str
      Full path to where output PDF and FITS file are located. Must end
      with a '/'

    out_pdf : str
      Filename for output PDF. Do NOT include full path

    check_quality : boolean
      Check whether data meets IQ requirements. Default: True

    silent : boolean
      Turns off stdout messages. Default: False

    verbose : boolean
      Turns on additional stdout messages. Default: True

    overwrite : boolean
      Overwrite files if they exists. Default: False

    Returns
    -------
    multi-page PDF plot

    Notes
    -----
    Created by Chun Ly, 10 March 2017
     - Later modified to include check_quality keyword option
     - Later modified to include inset that shows the stacked line profile
    Modified by Chun Ly, 11 April 2017
     - Call dir_check.main() to handle multiple date directories
    Modified by Chun Ly, 13 April 2017
     - Minor bug: Check if file exists first
    Modified by Chun Ly, 10 May 2017
     - Minor bug: When .lis file contains only one entry, problem for
       appending to list
    Modified by Chun Ly, 1 June 2017
     - Added overwrite keyword option to overwrite file. Default is not to
       overwrite .pdf files
     - Bug found: No longer need sky.lis since obj.lis includes all
    Modified by Chun Ly, 6 June 2017
     - Add skysub keyword option to operate on sky-subtracted images
    Modified by Chun Ly, 14 July 2017
     - Fix tick mark locations
     - Fix y limit range for extreme outliers
    Modified by Chun Ly, 16 November 2017
     - Change prefix: rnc to rbnc
    Modified by Chun Ly, 18 December 2017
     - Import glog and call for stdout and ASCII logging
     - Pass mylogger to compute_fwhm()
    Modified by Chun Ly, 11 January 2018
     - Pass mylogger to dir_check.main()
    Modified by Chun Ly, 18 April 2018
     - Compute and report seeing at zenith
     - Show FWHM @ Zenith on right y-axis
    Modified by Chun Ly, 19 April 2018
     - Include airmass info in plots
    Modified by Chun Ly, 14 May 2018
     - Write ASCII table containing FWHM determination
    Modified by Chun Ly, 18 May 2018
     - Adjust subplots_adjust to avoid labels being cut off
     - Handle case when extra plot window (odd numbers) is available
     - Handle case with extra plot window (cont'd)
    Modified by Chun Ly, 19 May 2018
     - Include QA (PASS/USABLE/FAIL) info in table
    Modified by Chun Ly, 28 June 2018
     - Bug troubleshooting with ValueError
     - Handle ValueError for avg FWHM
    '''

    # + on 18/12/2017
    logfile = path0 + 'IQ_plot.log'
    mylogger = glog.log0(logfile)._get_logger()

    if silent == False: mylogger.info('### Begin main : ' + systime())

    # + on 11/04/2017
    dir_list, list_path = dir_check.main(path0,
                                         mylogger=mylogger,
                                         silent=silent,
                                         verbose=verbose)

    out_pdf_default = out_pdf

    # Mod on 11/04/2017
    for path in list_path:
        files = []
        file_lis = ['obj.lis', 'telluric.lis']  # Minor bug fix on 01/06/2017
        for file0 in file_lis:
            # Mod on 13/04/2017
            if exists(path + file0):
                if silent == False: mylogger.info('Reading : ' + path + file0)
                t_files = np.loadtxt(path + file0, dtype=type(str)).tolist()
                # Bug fix - 10/05/2017
                if type(t_files) == str: t_files = [t_files]
                files += t_files
            else:
                if silent == False:
                    mylogger.info('File not found : ' + path + file0)

        files.sort()

        n_files = len(files)

        # + on 14/05/2018
        FWHM_avg_arr = np.zeros(n_files)  # FWHM from averaging stack0_shift
        FWHM_avg_arr_Z = np.zeros(
            n_files)  # FWHM from averaging stack0_shift at Zenith
        FWHM_avg_QA = [
            ''
        ] * n_files  # QA check from averaging stack0_shift at Zenith
        FWHM_med_arr = np.zeros(n_files)  # FWHM from median along Y
        FWHM_med_arr_Z = np.zeros(
            n_files)  # FWHM from median along Y at Zenith
        FWHM_med_QA = [''] * n_files  # QA check from median along Y at Zenith

        # Mod on 06/06/2017
        if skysub == True:
            files = ['brnc' + file0 for file0 in files]  # Mod on 16/11/2017
            out_pdf = path+'IQ_plot.skysub.pdf' if out_pdf == '' else \
                      path+out_pdf
        else:
            out_pdf = path+'IQ_plot.raw.pdf' if out_pdf == '' else \
                      path+out_pdf

        if overwrite == False and exists(out_pdf):
            mylogger.warn('File exists!! Will not overwrite ' + out_pdf)
        else:
            pp = PdfPages(out_pdf)

            for nn in xrange(n_files):
                if silent == False: mylogger.info('Reading : ' + files[nn])
                hdr0 = fits.getheader(path + files[nn])
                # Mod on 06/06/2017
                if skysub == False:
                    im0 = fits.getdata(path + files[nn])
                else:
                    im0 = fits.getdata(path + files[nn], 'sci')

                airmass = hdr0['AIRMASS']  # + on 18/04/2018

                # Mod on 18/12/2017
                bins, fwhm0, stack0_shift = compute_fwhm(im0,
                                                         mylogger=mylogger)

                row = nn % 2
                if row == 0: fig, ax0 = plt.subplots(2, 1)

                good = np.where(fwhm0 > 0)[0]
                ax0[row].plot(bins[good],
                              fwhm0[good],
                              marker='o',
                              alpha=0.5,
                              mec='none',
                              mfc='b',
                              linestyle='none',
                              zorder=2)

                ax0[row].get_yaxis().set_tick_params(which='both',
                                                     right=True,
                                                     width=1,
                                                     direction='in')
                ax0[row].get_xaxis().set_tick_params(which='both',
                                                     top=True,
                                                     width=1,
                                                     direction='in')

                # Compute average line profile from stack0_shift
                # Later + on 10/03/2017
                avg_stack = np.average(stack0_shift, axis=0)
                x0_avg = np.arange(-25, 25)
                if row == 0: axi = fig.add_axes([0.60, 0.81, 0.25, 0.15])
                if row == 1: axi = fig.add_axes([0.60, 0.36, 0.25, 0.15])
                axi.plot(x0_avg * pscale, avg_stack, 'k-')
                axi.set_ylim([-0.4, 1.1])
                axi.set_xlim([-2.0, 2.0])
                axi.set_xticks(range(-2, 2, 1))
                axi.set_xlabel('X [arcsec]', fontsize=8)
                axi.tick_params(labelsize=8)
                axi.minorticks_on()
                p0 = [0.0, 1.0, 0.0, 2.0]
                try:
                    popt, pcov = curve_fit(gauss1d, x0_avg, avg_stack, p0=p0)
                    fit_good = 1
                except ValueError:
                    print len(np.where(np.isnan(x0_avg))[0])
                    print len(np.where(np.isnan(avg_stack))[0])
                    fit_good = 0

                if fit_good:
                    avg_fwhm0 = popt[3] * 2 * np.sqrt(2 * np.log(2)) * pscale
                    avg_fwhm_Z = avg_fwhm0 / airmass**0.6  # + on 18/04/2018

                    axi.plot(x0_avg * pscale, gauss1d(x0_avg, *popt), 'r--')
                    axi.annotate('FWHM = %.3f" (%.3f")' %
                                 (avg_fwhm0, avg_fwhm_Z), [0.50, 0.025],
                                 xycoords='axes fraction',
                                 ha='center',
                                 va='bottom',
                                 fontsize=8)
                    ax0[row].axhline(y=avg_fwhm0,
                                     linewidth=2,
                                     color='r',
                                     linestyle='--',
                                     zorder=1)

                # Median FWHM | Later + on 10/03/2017
                med_fwhm0 = np.median(fwhm0[good])
                med_fwhm0_Z = med_fwhm0 / airmass**0.6  # + on 18/04/2018
                ax0[row].axhline(y=med_fwhm0,
                                 linewidth=2,
                                 color='g',
                                 linestyle='--',
                                 zorder=1)

                # Axes labeling
                ax0[row].set_ylabel('FWHM [arcsec]')
                if row == 1 or nn == n_files - 1:
                    ax0[row].set_xlabel('Y [pixel]')
                else:
                    ax0[row].set_xticklabels([])

                if nn == n_files - 1:
                    if row == 0:
                        ax0[row + 1].axis('off')

                # Annotation
                txt0 = files[nn] + '\nTarget: ' + hdr0[
                    'OBJECT']  #.split(' ')[0]
                ax0[row].annotate(txt0, [0.025, 0.95],
                                  xycoords='axes fraction',
                                  ha='left',
                                  va='top')

                # + on 19/04/2018
                ax0[row].annotate('AM = %.3f' % airmass, [0.025, 0.025],
                                  xycoords='axes fraction',
                                  ha='left',
                                  va='bottom')

                # Later + on 10/03/2017
                if check_quality:
                    req = hdr0['REQIQ'].replace('-percentile', '%')
                    raw = hdr0['RAWIQ'].replace('-percentile', '%')

                    i_raw = [
                        ii for ii in range(len(FWHM_IQ_C))
                        if raw in FWHM_IQ_C[ii]
                    ][0]
                    i_req = [
                        ii for ii in range(len(FWHM_IQ_C))
                        if raw in FWHM_IQ_C[ii]
                    ][0]

                    txt0 = 'Req. IQ: %s [%.2f"]\n' % (req, FWHM_IQ_J[i_req])
                    txt0 += 'Raw IQ: %s [%.2f"]\n' % (raw, FWHM_IQ_J[i_raw])

                    # Mod on 18/04/2018
                    if med_fwhm0_Z <= FWHM_IQ_J[i_raw]:
                        txt0 += 'PASS'
                        FWHM_med_QA[nn] = 'PASS'  # + on 19/05/2018
                    else:
                        if med_fwhm0_Z <= FWHM_IQ_J[i_raw] * 1.25:
                            txt0 += 'USABLE'
                            FWHM_med_QA[nn] = 'USABLE'  # + on 19/05/2018
                        if med_fwhm0_Z > FWHM_IQ_J[i_raw] * 1.25:
                            txt0 += 'FAIL'
                            FWHM_med_QA[nn] = 'FAIL'  # + on 19/05/2018

                    # + on 19/05/2018
                    if fit_good:
                        if avg_fwhm_Z <= FWHM_IQ_J[i_raw]:
                            FWHM_avg_QA[nn] = 'PASS'
                        else:
                            if avg_fwhm_Z <= FWHM_IQ_J[i_raw] * 1.25:
                                FWHM_avg_QA[nn] = 'USABLE'
                            if avg_fwhm_Z > FWHM_IQ_J[i_raw] * 1.25:
                                FWHM_avg_QA[nn] = 'FAIL'

                    ax0[row].annotate(txt0, [0.975, 0.05],
                                      ha='right',
                                      xycoords='axes fraction',
                                      va='bottom')

                # Aesthetics
                ax0[row].set_xlim([0, 1050])
                if max(fwhm0[good]) > 3:
                    ax0[row].set_ylim([0, 3.0])
                else:
                    ax0[row].set_ylim([min(fwhm0) - 0.025, max(fwhm0) + 0.075])
                ax0[row].minorticks_on()

                # + on 18/04/2018
                ax2 = ax0[row].twinx()
                ax2.set_ylabel(r"FWHM @ Zenith [arcsec]")
                ax2.set_ylim(np.array(ax0[row].get_ylim()) / airmass**0.6)
                ax2.minorticks_on()
                if row != 1:
                    ax2.set_xticklabels([])

                if row == 1 or nn == n_files - 1:
                    subplots_adjust(left=0.11,
                                    bottom=0.10,
                                    top=0.975,
                                    right=0.875,
                                    wspace=0.03,
                                    hspace=0.05)
                    fig.savefig(pp, format='pdf')

                # + on 14/05/2018
                if fit_good:
                    FWHM_avg_arr[nn] = avg_fwhm0
                    FWHM_avg_arr_Z[nn] = avg_fwhm_Z
                FWHM_med_arr[nn] = med_fwhm0
                FWHM_med_arr_Z[nn] = med_fwhm0_Z
            #endfor
            if silent == False: mylogger.info('Writing : ' + out_pdf)
            pp.close()

            # + on 14/05/2018
            fwhm_out_file = out_pdf.replace('.pdf', '.tbl')
            arr0 = [
                files, FWHM_avg_arr, FWHM_avg_arr_Z, FWHM_med_arr,
                FWHM_med_arr_Z, FWHM_avg_QA, FWHM_med_QA
            ]  # Mod on 19/05/2018
            names0 = ('files', 'FWHM_avg', 'FWHM_avg_Z', 'FWHM_med',
                      'FWHM_med_Z', 'FWHM_avg_QA', 'FWHM_med_QA'
                      )  # Mod on 19/05/2018
            tab0 = Table(arr0, names=names0)
            if silent == False: mylogger.info('Writing : ' + fwhm_out_file)
            asc.write(tab0,
                      fwhm_out_file,
                      format='fixed_width_two_line',
                      overwrite=True)
            out_pdf = out_pdf_default
        #endelse
    #endfor

    if silent == False: mylogger.info('### End main : ' + systime())
Exemple #8
0
def get_offsets(path0, mylogger=None, silent=True, verbose=False):
    '''
    Function to get offsets from FITS header and write it to ASCII file

    Parameters
    ----------
    path0 : str
     Path to FITS file. Must include '/' at the end

    silent : boolean
      Turns off stdout messages. Default: False

    verbose : boolean
      Turns on additional stdout messages. Default: True

    Returns
    -------
    tab0 : astropy.table.Table
     Astropy ASCII table written to [path0]+'sci_offsets.tbl'

    Notes
    -----
    Created by Chun Ly, 30 May 2017
    Modified by Chun Ly, 10 December 2017
     - Implement glog logging, allow mylogger keyword input
    Modified by Chun Ly, 17 December 2017
     - Minor fix: log -> clog
     - Call dir_check with mylogger input
    '''

    # + on 10/12/2017
    if type(mylogger) == type(None):
        mylog, clog = 0, log
    else:
        mylog, clog = 1, mylogger

    if silent == False: clog.info('### Begin get_offsets : ' + systime())

    # Mod on 17/12/2017
    if not mylog:
        dir_list, list_path = dir_check.main(path0,
                                             silent=silent,
                                             verbose=verbose)
    else:
        dir_list, list_path = dir_check.main(path0,
                                             silent=silent,
                                             verbose=verbose,
                                             mylogger=clog)

    for path in list_path:
        outfile = path + 'sci_offsets.tbl'

        if exists(outfile):
            # Mod on 10/12/2017
            clog.warning('File exists : ' + outfile)
            clog.warning('Not over-writing!!! ')
        else:
            fits_files = np.loadtxt(path + 'obj.lis', dtype=type(str))
            fits_files = [path + file0 for file0 in fits_files]  # Bug fix
            n_files = len(fits_files)

            names0 = ('filename', 'xoffset', 'yoffset', 'poffset', 'qoffset')
            dtype0 = ('S20', 'f8', 'f8', 'f8', 'f8')
            tab0 = Table(names=names0, dtype=dtype0)

            for nn in xrange(n_files):
                basename = os.path.basename(fits_files[nn])
                if verbose == True: log.info('## Reading : ' + basename)
                h0 = fits.getheader(fits_files[nn])
                vec0 = [
                    basename, h0['XOFFSET'], h0['YOFFSET'], h0['POFFSET'],
                    h0['QOFFSET']
                ]
                tab0.add_row(vec0)

            if silent == False: clog.info('Writing : ' + outfile)
            asc.write(tab0, outfile, format='fixed_width_two_line')
        #endelse
    #endfor

    if silent == False: clog.info('### End get_offsets : ' + systime())
def create_distort_grid(rawdir, silent=False, verbose=True):
    '''
    Create grid (and plot) of distortion for extraction

    Parameters
    ----------
    None

    Returns
    -------
    None

    Notes
    -----
    Created by Chun Ly, 29 June 2018

    Modified by Chun Ly, 10 August 2018
     - Plot best fit

    Modified by Chun Ly, 13 August 2018
     - Rewrite to work for specified rawdir path (instead of all)
     - Fix typo with ax.axhline indexing
     - Re-organize code (handle only one distort_trace.npz file)
     - Minor bug fix: array name
     - Plot aesthetics
    '''

    if rawdir[-1] != '/': rawdir += '/'

    logfile = rawdir + 'distort_trace.log'
    mylogger = glog.log0(logfile)._get_logger()

    if silent == False: mylogger.info('### Begin ! ')

    dir_list, list_path = dir_check.main(rawdir,
                                         mylogger=mylogger,
                                         silent=silent,
                                         verbose=verbose)

    for path in list_path:
        mylogger.info('Working on : ' + path.split('/')[-2])

        npz_files = glob(path + '/distort_trace.npz')

        if len(npz_files) == 0:
            log.warn('No files found!!!')
        else:
            fig, ax = plt.subplots(nrows=3)

            npz = np.load(npz_files[0])
            xcen_arr = npz['xcen_arr']
            fit_arr = npz['fit_arr']
            best_fit = npz['best_fit']
            n_peaks = xcen_arr.shape[0]

            for pp in range(n_peaks):
                ax[0].scatter(xcen_arr[pp],
                              fit_arr[pp, :, 2],
                              marker='o',
                              edgecolor='k',
                              facecolor='none')
                ax[0].axhline(y=best_fit[2], color='b')
                ax[1].scatter(xcen_arr[pp],
                              fit_arr[pp, :, 1],
                              marker='o',
                              edgecolor='k',
                              facecolor='none')
                ax[1].axhline(y=best_fit[1], color='b')
                ax[2].scatter(xcen_arr[pp],
                              fit_arr[pp, :, 0],
                              marker='o',
                              edgecolor='k',
                              facecolor='none')
                ax[2].axhline(y=best_fit[0], color='b')

            ax[0].annotate(r'x = A y$^2$ + B y + C',
                           xy=(0.02, 0.95),
                           xycoords='axes fraction',
                           ha='left',
                           va='top')
            ax[0].set_ylabel('C')
            ax[1].set_ylabel('B')
            ax[2].set_ylabel('A')

            ax[0].set_ylim([-10, 0])
            ax[1].set_ylim([-0.025, 0.025])
            ax[2].set_ylim([-0.001, 0.001])

            ax[0].set_xticklabels([])
            ax[1].set_xticklabels([])

            ax[2].set_xlabel('X [pix]')
            plt.subplots_adjust(left=0.15, right=0.99, top=0.99, bottom=0.1)

            out_pdf = path + 'distort_grid.pdf'
            log.info('Writing : ' + out_pdf)
            fig.savefig(out_pdf)
Exemple #10
0
def main(path0, silent=False, verbose=True, overwrite=False):
    '''
    main() function to obtain information from FITS header and write to
    ASCII file

    Parameters
    ----------
    path0 : str
     Path to FITS file. Must include '/' at the end

    silent : boolean
      Turns off stdout messages. Default: False

    verbose : boolean
      Turns on additional stdout messages. Default: True

    Returns
    -------
    tab0 : astropy.table.Table
     Astropy ASCII table written to [path0]+'hdr_info.tbl'

    Notes
    -----
    Created by Chun Ly, 4 March 2017
     - Later re-organized to check for file first
    Modified by Chun Ly, 5 March 2017
     - File exists warning always printed out
     - Include AIRMASS
    Modified by Chun Ly, 23 March 2017
     - Call dir_check.main() to handle multiple date directories
    Modified by Chun Ly, 11 May 2017
     - Handle longer filter1 and filter2 FITS values
    Modified by Chun Ly,  8 December 2017
     - Import glog and call for stdout and ASCII logging
     - Pass mylogger to dir_check.main()
    '''

    # Moved up on 10/12/2017
    logfile = path0 + 'hdr_info.log'
    mylogger = glog.log0(logfile)._get_logger()

    if silent == False: mylogger.info('### Begin main : ' + systime())

    dir_list, list_path = dir_check.main(path0,
                                         mylogger=mylogger,
                                         silent=silent,
                                         verbose=verbose)

    # Mod on 23/03/2017
    for path in list_path:
        outfile = path + 'hdr_info.tbl'

        # Mod later on 04/03/2017 to not overwrite file
        # Mod on 05/03/2017 to always print out this warning
        if overwrite == False and exists(outfile):
            # Mod on 08/12/2017
            mylogger.warning('File exists : ' + outfile)
            mylogger.warning('Not over-writing!!! ')
        else:
            fits_files = glob.glob(path + 'N*fits')
            n_files = len(fits_files)

            # Mod on 05/03/2017 to include airmass
            names0 = ('filename', 'datelabel', 'UT_date', 'obstype', 'object',
                      'exptime', 'airmass', 'grating', 'gratwave', 'filter1',
                      'filter2', 'slit')
            dtype0 = ('S20', 'S30', 'S25', 'S8', 'S100', 'f8', 'f8', 'S15',
                      'f8', 'S20', 'S20', 'S20')
            tab0 = Table(names=names0, dtype=dtype0)

            for nn in xrange(n_files):
                basename = os.path.basename(fits_files[nn])
                if silent == False: mylogger.info('Reading : ' + basename)
                h0 = fits.getheader(fits_files[nn])
                # Mod on 05/03/2017 to include airmass
                vec0 = [
                    basename, h0['DATALAB'], h0['DATE-OBS'] + 'T' + h0['UT'],
                    h0['OBSTYPE'], h0['OBJECT'], h0['EXPTIME'], h0['AIRMASS'],
                    h0['GRATING'], h0['GRATWAVE'], h0['FILTER1'],
                    h0['FILTER2'], h0['SLIT']
                ]
                tab0.add_row(vec0)

            if silent == False:
                mylogger.info('Writing : ' + outfile)  # Mod on 08/12/2017
            asc.write(tab0, outfile, format='fixed_width_two_line')
        #endelse
    #endfor

    if silent == False: mylogger.info('### End main : ' + systime())
Exemple #11
0
def QA_combine(path0, targets0, out_pdf='', silent=False, verbose=True):
    '''
    Display sky-subtracted and shifted combined images for telluric and
    science data

    Parameters
    ----------
    path0 : str
      Full path to where output PDF and FITS file are located. Must end
      with a '/'

    targets0: list or numpy array
      A list or array of source names available through path0

    out_pdf : str
      Filename for output PDF. Do NOT include full path.
      Default: 'QA_combine.pdf'

    silent : boolean
      Turns off stdout messages. Default: False

    verbose : boolean
      Turns on additional stdout messages. Default: True

    Returns
    -------
    multi-page PDF plot, 'QA_combine.pdf'

    Notes
    -----
    Created by Chun Ly, 31 May 2017
    Modified by Chun Ly, 1 June 2017
     - Switch over to pyplot.imshow() since aplpy cannot allow for more customization
    '''

    if silent == False: log.info('### Begin QA_combine : ' + systime())

    out_pdf = path0 + 'QA_combine.pdf' if out_pdf == '' else path0 + out_pdf
    pp = PdfPages(out_pdf)

    for target in targets0:
        t_path = path0 + target + '/'

        dir_list, list_path = dir_check.main(t_path,
                                             silent=silent,
                                             verbose=verbose)

        for dpath in list_path:
            tel_file = glob.glob(dpath + 'tell_comb.fits')
            obj_file = glob.glob(dpath + 'obj_comb.fits')

            if len(tel_file) == 0 and len(obj_file) == 0:
                log.warn('## No tell_comb.fits and obj_comb.fits found in: ')
                log.warn('## ' + dpath)

            if len(tel_file) == 1 and len(obj_file) == 1:
                fig, (ax1, ax2) = plt.subplots(1, 2)  # Mod on 01/06/2017

            # Mod on 01/06/2017
            if len(tel_file) != 0:
                t_im, t_hdr = fits.getdata(tel_file[0], header=True)

                lam_max = t_hdr['CRVAL2'] + t_hdr['CD2_2'] * t_hdr['NAXIS2']
                extent = [0, t_hdr['NAXIS1'], t_hdr['CRVAL2'], lam_max]

                z1, z2 = zscale.get_limits(t_im)
                norm = ImageNormalize(vmin=z2, vmax=z1)
                ax1.imshow(t_im,
                           cmap='Greys',
                           origin='lower',
                           norm=norm,
                           extent=extent)
                yticks = np.array(ax1.get_yticks())
                ax1.set_yticklabels([val / 1e4 for val in yticks])

                ax1.get_yaxis().set_tick_params(which='major',
                                                direction='in',
                                                right=True,
                                                length=5,
                                                width=1)
                ax1.get_yaxis().set_tick_params(which='minor',
                                                direction='in',
                                                right=True,
                                                length=2.5)
                ax1.get_xaxis().set_tick_params(which='major',
                                                direction='in',
                                                top=True,
                                                length=5,
                                                width=1)
                ax1.get_xaxis().set_tick_params(which='minor',
                                                direction='in',
                                                top=True,
                                                length=2.5)
                ax1.minorticks_on()

                ax1.set_xlabel('X [pixels]', fontsize=14)
                ax1.set_ylabel(r'Wavelength ($\mu$m)', fontsize=14)

                ax1.annotate(tel_file[0], [0.025, 0.975],
                             xycoords='axes fraction',
                             ha='left',
                             va='top',
                             bbox=bbox_props)

            # Mod on 01/06/2017
            if len(obj_file) != 0:
                o_im, o_hdr = fits.getdata(obj_file[0], header=True)

                lam_max = o_hdr['CRVAL2'] + o_hdr['CD2_2'] * o_hdr['NAXIS2']
                extent = [0, o_hdr['NAXIS1'], o_hdr['CRVAL2'], lam_max]

                z1, z2 = zscale.get_limits(o_im)
                norm = ImageNormalize(vmin=z2, vmax=z1)
                ax2.imshow(o_im,
                           cmap='Greys',
                           origin='lower',
                           norm=norm,
                           extent=extent)
                yticks = np.array(ax2.get_yticks())
                ax2.set_yticklabels([val / 1e4 for val in yticks])

                ax2.get_yaxis().set_tick_params(which='major',
                                                direction='in',
                                                right=True,
                                                length=5,
                                                width=1)
                ax2.get_yaxis().set_tick_params(which='minor',
                                                direction='in',
                                                right=True,
                                                length=2.5)
                ax2.get_xaxis().set_tick_params(which='major',
                                                direction='in',
                                                top=True,
                                                length=5,
                                                width=1)
                ax2.get_xaxis().set_tick_params(which='minor',
                                                direction='in',
                                                top=True,
                                                length=2.5)
                ax2.minorticks_on()

                ax2.set_xlabel('X [pixels]', fontsize=14)
                ax2.set_ylabel('')
                ax2.set_yticklabels([])

                ax2.annotate(obj_file[0], [0.025, 0.975],
                             xycoords='axes fraction',
                             ha='left',
                             va='top',
                             bbox=bbox_props)

            if len(tel_file) == 1 and len(obj_file) == 1:  # Mod on 01/06/2017
                subplots_adjust(left=0.06,
                                bottom=0.06,
                                top=0.995,
                                right=0.99,
                                hspace=0.00,
                                wspace=0.00)
                fig.set_size_inches(11, 7.3)
                # fig.tight_layout()
                fig.savefig(pp, format='pdf')  #, bbox_inches='tight')

    if silent == False: log.info('## Writing : ' + out_pdf)
    pp.close()
    if silent == False: log.info('### End QA_combine : ' + systime())
Exemple #12
0
def main(file_list,
         path0='',
         out_pdf='',
         silent=False,
         verbose=True,
         overwrite=False):
    '''
    main() function to read in each FITS image and display it on a zscale
    using aplpy

    Parameters
    ----------
    file_list : str
      Filename of ASCII file containing images to be plotted. Use 'all.lis'
      from create_list() since this will include all that will be processed
      Do NOT include full path

    path0 : str
      Full path to where output PDF and FITS file are located. Must end
      with a '/'

    out_pdf : str
      Filename for output PDF. Do NOT include full path

    silent : boolean
      Turns off stdout messages. Default: False

    verbose : boolean
      Turns on additional stdout messages. Default: True

    overwrite : boolean
      Overwrite files if they exists. Default: False

    Returns
    -------
    multi-page PDF plot

    Notes
    -----
    Created by Chun Ly, 6 March 2017
    Modified by Chun Ly, 23 March 2017
     - Call dir_check.main() to handle multiple date directories
    Modified by Chun Ly, 1 June 2017
     - Added overwrite keyword option to overwrite file. Default is not to
       overwrite .pdf files
    Modified by Chun Ly, 8 December 2017
     - Import glog and call for stdout and ASCII logging
    Modified by Chun Ly, 17 December 2017
     - Change glog logging to common path
     - Add begin and end QA_clean logging to glog logfile
     - Pass mylogger to dir_check.main()
    '''

    # Moved up on 17/12/2017
    logfile = path0 + 'QA_plot.log'
    mylogger = glog.log0(logfile)._get_logger()

    if silent == False: mylogger.info('### Begin main : ' + systime())

    # + on 23/03/2017
    dir_list, list_path = dir_check.main(path0,
                                         mylogger=mylogger,
                                         silent=silent,
                                         verbose=verbose)

    out_pdf_default = out_pdf

    # Mod on 23/03/2017
    for path in list_path:
        if silent == False:
            mylogger.info('Reading : ' + path + file_list)  # Mod on 08/12/2017
        files = np.loadtxt(path + file_list, dtype=type(str)).tolist()
        n_files = len(files)

        if out_pdf == '':
            out_pdf = path + 'QA_plot.pdf'
        else:
            out_pdf = path + out_pdf

        hdr_info_file = path + 'hdr_info.tbl'
        if exists(hdr_info_file):
            if silent == False:
                mylogger.info('Reading : ' +
                              hdr_info_file)  # Mod on 08/12/2017
            tab0 = asc.read(hdr_info_file, format='fixed_width_two_line')
            idx1, idx2 = match_nosort_str(files, tab0['filename'])
            tab0 = tab0[idx2]
        else:
            if silent == False:
                mylogger.warn('File not found : ' +
                              hdr_info_file)  # Mod on 08/12/2017

        if overwrite == False and exists(out_pdf):
            mylogger.warn('File exists!! Will not overwrite ' +
                          out_pdf)  # Mod on 08/12/2017
        else:
            pp = PdfPages(out_pdf)

            for nn in xrange(n_files):
                if silent == False:
                    mylogger.info('Reading : ' +
                                  files[nn])  # Mod on 08/12/2017
                # h0  = fits.getheader(path+files[nn], 0)
                # im0 = fits.getdata(path+files[nn], 1)
                hdu0 = fits.open(path + files[nn])
                im0 = hdu0[1].data
                hdu0[1].header = hdu0[0].header  # Copy WCS header over

                gc = aplpy.FITSFigure(hdu0, hdu=1, figsize=(8, 8))

                z1, z2 = zscale.get_limits(im0)
                gc.show_grayscale(invert=True, vmin=z1, vmax=z2)
                gc.set_tick_color('black')

                gc.set_tick_yspacing('auto')
                gc.ticks.set_yspacing(1 / 60.0)  # Every 1 arcmin in Dec
                gc.set_tick_labels_format(xformat='hh:mm:ss', yformat='dd:mm')

                txt0 = files[nn]
                if exists(hdr_info_file):
                    txt0 += '\n'
                    tmp = tab0[nn]
                    txt0 += 'Date Label : ' + tmp['datelabel'] + '\n'
                    txt0 += 'UT Date : ' + tmp['UT_date'] + '\n'
                    txt0 += tmp['object'] + '\n'
                    txt0 += 'EXPTIME=%.1f ' % tmp['exptime']
                    txt0 += 'AIRMASS=%.3f \n' % tmp['airmass']
                    txt0 += '%s %.3f %s' % (tmp['grating'], tmp['gratwave'],
                                            tmp['filter2'])

                    gc.add_label(0.975,
                                 0.115,
                                 txt0,
                                 color='red',
                                 relative=True,
                                 ha='right',
                                 va='bottom',
                                 weight='medium',
                                 size='medium',
                                 bbox=bbox_props)

                    gc.savefig(pp, format='pdf')

            if silent == False:
                mylogger.info('Writing : ' + out_pdf)  # Mod on 08/12/2017
            pp.close()
        #endelse

        out_pdf = out_pdf_default
    #endfor

    if silent == False: mylogger.info('### End main : ' + systime())
Exemple #13
0
def clean_QA(path0='',
             out_pdf='',
             silent=False,
             verbose=True,
             overwrite=False):
    '''
    Visually compare raw and cleanir-fixed FITS images

    Parameters
    ----------
    path0 : str
      Full path to where output PDF and inputs FITS file are located. Must end
      with a '/'

    out_pdf : str
      Filename for output PDF. Do NOT include full path

    silent : boolean
      Turns off stdout messages. Default: False

    verbose : boolean
      Turns on additional stdout messages. Default: True

    overwrite : boolean
      Overwrite files if they exists. Default: False

    Returns
    -------
    multi-page PDF plot

    Notes
    -----
    Created by Chun Ly, 8 March 2017
    Modified by Chun Ly, 10 March 2017
     - Call quadrant_bias_values()
    Modified by Chun Ly, 23 March 2017
     - Call dir_check.main() to handle multiple date directories
    Modified by Chun Ly, 25 April 2017
     - Check cN*fits files if symlink.
    Modified by Chun Ly, 26 April 2017
     - Fix bug with call to dir_check()
     - Change out_pdf default name (include clean suffix)
     - Fix handling of symlink files; Check for False, not True
    Modified by Chun Ly, 2 June 2017
     - Added overwrite keyword option to overwrite file. Default is not to
       overwrite .pdf files
    Modified by Chun Ly, 8 December 2017
     - Import glog and call for stdout and ASCII logging
    Modified by Chun Ly, 17 December 2017
     - Change glog logging to common path
     - Add begin and end QA_clean logging to glog logfile
    Modified by Chun Ly, 11 January 2018
     - Pass mylogger to dir_check.main()
    '''

    # Moved up on 17/12/2017
    logfile = path0 + 'QA_plot.log'
    mylogger = glog.log0(logfile)._get_logger()

    if silent == False: mylogger.info('### Begin clean_QA : ' + systime())

    # + on 23/03/2017 | Mod on 26/04/2017
    dir_list, list_path = dir_check.main(path0,
                                         mylogger=mylogger,
                                         silent=silent,
                                         verbose=verbose)

    out_pdf_default = out_pdf  # + on 15/05/2017

    # Mod on 23/03/2017
    for path in list_path:
        if out_pdf == '':
            out_pdf = path + 'QA_plot.clean.pdf'
        else:
            out_pdf = path + out_pdf

        files = glob.glob(path + 'cN*fits')

        # Limit to non-symlinked files | + on 25/04/2017
        files = [file for file in files if os.path.islink(file) == False]
        n_files = len(files)

        if overwrite == False and exists(out_pdf):
            mylogger.warn('File exists!! Will not overwrite ' + out_pdf)
        else:
            pp = PdfPages(out_pdf)

            for nn in xrange(n_files):
                if silent == False: mylogger.info('Reading : ' + files[nn])
                orig_file = files[nn].replace('cN', 'N')

                im1 = fits.getdata(orig_file)
                im2 = fits.getdata(files[nn])
                #hdu1 = fits.open(orig_file)
                #im1  = hdu1[1].data
                #hdu1[1].header = hdu1[0].header # Copy WCS header over

                #hdu2 = fits.open(files[nn])
                #im2  = hdu2[1].data
                #hdu2[1].header = hdu2[0].header # Copy WCS header over

                fig = plt.figure(figsize=(16, 8))

                gc1 = aplpy.FITSFigure(orig_file,
                                       figure=fig,
                                       subplot=[0.05, 0.055, 0.47, 0.94])
                z1, z2 = zscale.get_limits(im1)
                gc1.show_grayscale(invert=True, vmin=z1, vmax=z2)
                gc1.set_tick_color('black')
                gc1.set_tick_yspacing('auto')
                #gc1.ticks.set_yspacing(1/60.0) # Every 1 arcmin in Dec
                #gc1.set_tick_labels_format(xformat='hh:mm:ss', yformat='dd:mm')
                gc1.add_label(0.025,
                              0.975,
                              orig_file,
                              color='red',
                              relative=True,
                              ha='left',
                              va='top',
                              weight='medium',
                              size='medium',
                              bbox=bbox_props)

                quadrant_bias_values(fits.open(orig_file),
                                     gc1)  # + on 10/03/2017

                gc2 = aplpy.FITSFigure(files[nn],
                                       figure=fig,
                                       subplot=[0.525, 0.055, 0.47, 0.94])
                z1, z2 = zscale.get_limits(im2)
                gc2.show_grayscale(invert=True, vmin=z1, vmax=z2)
                gc2.set_tick_color('black')
                gc2.set_tick_yspacing('auto')
                gc2.hide_ytick_labels()
                gc2.hide_yaxis_label()
                gc2.add_label(0.025,
                              0.975,
                              files[nn],
                              color='red',
                              relative=True,
                              ha='left',
                              va='top',
                              weight='medium',
                              size='medium',
                              bbox=bbox_props)

                quadrant_bias_values(fits.open(files[nn]),
                                     gc2)  # + on 10/03/2017

                #gc2.ticks.set_yspacing(1/60.0) # Every 1 arcmin in Dec
                #gc2.set_tick_labels_format(xformat='hh:mm:ss', yformat='dd:mm')

                fig.savefig(pp, format='pdf')

            if silent == False: mylogger.info('Writing : ' + out_pdf)
            pp.close()
        #endelse
        out_pdf = out_pdf_default
    #endfor

    if silent == False: mylogger.info('### End clean_QA : ' + systime())
def main(path0, silent=False, verbose=True, overwrite=False):
    '''
    main() function to sort through data and create individual lists

    Parameters
    ----------
    path0 : str
     Path to FITS file. Must include '/' at the end

    silent : boolean
      Turns off stdout messages. Default: False

    verbose : boolean
      Turns on additional stdout messages. Default: True
	  
    Returns
    -------
    ASCII files containing the filenames for each set
     obj.lis      - List of science data frames
     sky.lis      - List of science data frames to be used for sky-subtraction
     arc.lis      - List of Arclamp data frames
     flat.lis     - List of Flat data frames
     telluric.lis - List of Telluric data frames
     all.lis      - List of all obj, sky, arc, flat, and telluric data frames

    tab0 : astropy.table.Table
     Astropy ASCII table with QA flag written to [path0]+'hdr_info.QA.tbl'

    Notes
    -----
    Created by Chun Ly, 5 March 2017
     - Later modified to output ASCII table (hdr_info.QA.tbl) containing a
       column called 'QA' with information of how each FITS file was
       classified. This is to enable quick check that each dataset if
       properly classified
     - Later modified to include all.lis output
     - Later modified to define r0 (for slight speed improvement
    Modified by Chun Ly, 23 March 2017
     - Call dir_check.main() to handle multiple date directories
    Modified by Chun Ly, 10 April 2017
     - Handle cases when arc, flat, telluric, and sci data are not available
    Modified by Chun Ly, 11 April 2017
     - Handle case when no data for all.lis are available
       (i.e., the observing sequence was canceled)
    Modified by Chun Ly, 16 May 2017
     - Change obj.lis and sky.lis to include both A-B and B-A sets
     - Avoid QA flag of 'sky'
     - Fix minor bug
    Modified by Chun Ly, 17 May 2017
     - Minor fix for i_sky to handle skipping of frames for i_obj
    Modified by Chun Ly, 31 May 2017
     - Minor fix for when no science data is available
    Modified by Chun Ly, 1 June 2017
     - Added overwrite keyword option to overwrite file
    Modified by Chun Ly, 8 December 2017
     - Import glog and call for stdout and ASCII logging
    Modified by Chun Ly, 10 December 2017
     - Adjust glog logging to a default file in path0, move up mylogger
       definition
     - Minor mylogger text changes
     - Pass mylogger to dir_check.main()
    Modified by Chun Ly, 12 January 2018
     - Handle multiple telluric datasets
    Modified by Chun Ly, 15 January 2018
     - Handle multiple telluric datasets (cont'd) - Get indices for each dataset
    Modified by Chun Ly, 16 January 2018
     - Handle multiple telluric datasets (cont'd) - Update prefix and index lists
    Modified by Chun Ly, 17 January 2018
     - Create telluric.lis even for multi-telluric case
    Modified by Chun Ly, 23 April 2018
     - Handle no telluric data case
    '''

    logfile = path0 + 'create_list.log'
    mylogger = glog.log0(logfile)._get_logger()

    if silent == False: mylogger.info('### Begin main : ' + systime())

    # + on 23/03/2017
    dir_list, list_path = dir_check.main(path0,
                                         mylogger=mylogger,
                                         silent=silent,
                                         verbose=verbose)

    # Mod on 23/03/2017
    for path in list_path:
        infile = path + 'hdr_info.tbl'
        if not exists(infile):
            mylogger.warning('File does not exist : ' + infile)
            mylogger.warning('Exiting!!! ' + systime())
            return

        if silent == False: mylogger.info('Reading: ' + infile)
        tab0 = asc.read(infile, format='fixed_width_two_line')
        len0 = len(tab0)
        r0 = xrange(len0)

        obstype = tab0['obstype']
        object0 = tab0['object']
        filter2 = tab0['filter2']

        i_arc = [ii for ii in r0 if obstype[ii] == 'ARC']
        i_flat = [ii for ii in r0 if obstype[ii] == 'FLAT']

        i_tell = [
            ii for ii in r0 if (obstype[ii] == 'OBJECT' and (
                'HIP' in object0[ii] or 'HD' in object0[ii]) and (
                    'H2_' not in filter2[ii] and 'H_' not in filter2[ii]))
        ]

        # Identify when multiple sets of telluric data is available
        # Broken based on filename | + on 12/01/2018, Mod on 15/01/2018
        # tel_name = list(set(np.array(object0[i_tell])))
        multi_tell = 0

        # Mod on 23/04/2018
        if len(i_tell) != 0:
            seq_tell = np.array([
                np.int(str0.replace('.fits', '')[-4:])
                for str0 in tab0['filename'][i_tell]
            ])
            seq_diff = seq_tell[1:] - seq_tell[0:-1]
            # +1 to factor first skip for seq_diff
            seq_break = [
                ii + 1 for ii in range(len(seq_diff)) if seq_diff[ii] != 1
            ]
            if len(seq_break) > 0:
                multi_tell = 1
                i_tell0 = []
                mylogger.warn('Multiple telluric star detected.')
                mylogger.warn('Will split into separate files.')
                ss_start = [0] + seq_break  # relative to i_tell
                ss_end = seq_break + [len(i_tell)]
                for ss in range(len(ss_start)):
                    ss_idx = i_tell[ss_start[ss]:ss_end[ss]]
                    i_tell0.append(ss_idx)
            else:
                mylogger.info('Only one telluric star detected.')

        i_sci = [
            ii for ii in r0 if (obstype[ii] == 'OBJECT' and (
                'HIP' not in object0[ii] and 'HD' not in object0[ii]) and (
                    'H2_' not in filter2[ii] and 'H_' not in filter2[ii]))
        ]
        i_sci = np.array(i_sci)

        # Note: Assumes that dithering pattern is ABA'B'
        # Mod on 16/05/2017
        # Mod on 17/05/2017 - Minor bug if things skip for sci frames
        # Mod on 31/05/2017 - Minor bug if i_sci is empty
        if len(i_sci) > 0:
            i_obj = i_sci
            i_off = [1, -1] * (len(i_sci) / 2)
            if len(i_sci) % 2 == 1: i_off.append(-1)  # Odd number correction
            i_sky = i_sci[np.arange(len(i_sci)) + np.array(i_off)]
            # i_sky = [a+b for a,b in zip(i_sci,i_off)]

        # Mod on 10/04/2017
        prefix, index = [], []
        if len(i_arc) == 0:
            mylogger.warn('No ARC data found!')
        else:
            prefix.append('arc')
            index.append(i_arc)

        if len(i_flat) == 0:
            mylogger.warn('No FLAT data found!')
        else:
            prefix.append('flat')
            index.append(i_flat)

        if len(i_tell) == 0:
            mylogger.warn('No Telluric data found!')
        else:
            # Mod on 16/01/2018, 17/01/2018
            # Always create telluric.lis for all tellurics
            prefix.append('telluric')
            index.append(i_tell)
            if multi_tell:
                for ii in range(len(i_tell0)):
                    prefix.append('telluric' + str(ii + 1))
                    index.append(i_tell0[ii])

        if len(i_sci) == 0:
            mylogger.warn('No science data found!')
        else:
            prefix.append('obj')
            prefix.append('sky')
            index.append(i_obj)
            index.append(i_sky)

        zip0 = zip(prefix, index)

        QA = ['N/A'] * len0  # Later + on 05/03/2017

        for a, b in zip0:
            if a != 'sky':
                for idx in b:
                    QA[idx] = a  # Mod on 16/05/2017
            outfile = path + a + '.lis'
            if overwrite == False and exists(outfile):
                mylogger.warn('File exists! Will not write ' + outfile + '!!')
            else:
                if silent == False: mylogger.info('Writing : ' + outfile)
                np.savetxt(outfile, tab0['filename'][b], fmt='%s')
                #asc.write will not work. Will not produce single column
                #asc.write(tab0[b], outfile, overwrite=True,
                #          format='no_header')

        # Later + on 05/03/2017 | Mod on 11/04/2017
        i_all = [ii for ii in r0 if QA[ii] != 'N/A']
        if len(i_all) > 0:
            outfile0 = path + 'all.lis'
            if overwrite == False and exists(outfile0):
                mylogger.warn('File exists! Will not write all.lis!!')
            else:
                if silent == False: mylogger.info('Writing : ' + outfile0)
                np.savetxt(outfile0, tab0['filename'][i_all], fmt='%s')
        else:
            mylogger.warn('Will not write all.lis!!')

        # Later + on 05/03/2017
        col0 = Column(QA, name='QA')
        tab0.add_column(col0)

        # Later + on 05/03/2017
        outfile2 = infile.replace('.tbl', '.QA.tbl')
        if silent == False:
            if overwrite == False and exists(outfile2):
                mylogger.warn('File exists! Will not write ' + outfile2 + '!!')
            else:
                if not exists(outfile2):
                    mylogger.info('Writing : ' + outfile2)
                else:
                    mylogger.info('Overwriting : ' + outfile2)
                asc.write(tab0,
                          outfile2,
                          format='fixed_width_two_line',
                          overwrite=True)

    if silent == False: mylogger.info('### End main : ' + systime())