Example #1
0
def source_to_unknowns(source, write=False, verbose=True, min_ampl=0.):
    """
    Parameters
    ----------
    source
    write
    min_ampl : float (optional)
      Minimum amplitude for a new UNKNOWN

    Returns
    -------

    """

    # Load
    src_dict = load_source.load(source)
    U_lines = src_dict['U_lines']

    # Cut on amplitude
    print("Cutting UNKNOWNs on min_ampl")
    U_lines = U_lines[U_lines['amplitude'] > min_ampl]
    src_dict['U_lines'] = U_lines

    # UNKNWN lines
    if U_lines is None:
        return

    # Unique ions
    uions = arcl_utils.unique_ions(source, src_dict=src_dict)

    # Check against 'complete' NIST and our line lists
    mask, _ = arcl_utils.vette_unkwn_against_lists(U_lines,
                                                   uions,
                                                   verbose=verbose)
    if np.sum(mask) == 0:
        return

    if not os.path.isfile(unk_file):  # Generate?
        if write:
            print("Generating line list:\n   {:s}".format(unk_file))
            unknwn_list = create_line_list(U_lines[mask > 0],
                                           source['File'],
                                           source['Instr'],
                                           unknown=True,
                                           ions=uions)
            arcl_io.write_line_list(unknwn_list, unk_file)
    else:  # Update
        unknwn_list, updated = update_uline_list(U_lines[mask > 0],
                                                 source['File'],
                                                 source['Instr'], uions)
        if write and updated:
            arcl_io.write_line_list(unknwn_list, unk_file)
    # Return
    return unknwn_list
Example #2
0
def show_source(src_dict, line_lists, outfile, title=None, path=None, clobber=False,
                min_unk_ampl=0.):
    """ Plot of an input source for arclines

    Color code:
      blue = Good line
      gray = previously used unknown
      orange = new unknown
      red = Unknown in good line list (this shouldn't happen)
      green = ??
      brown = Unused UNKNOWN

    Parameters
    ----------
    line_lists : Table
      Existing line lists with the lamps of interest
    outfile : str
      Name of output file
    min_unk_ampl : float (optional)
      Cut on Amplitude for UNKNOWNs
    """
    # Path
    if path is None:
        path = plot_path
    iext = outfile.rfind('.')

    # Begin
    if os.path.isfile(plot_path+outfile) and (not clobber):
        print("Plot {:s} exists.  Remove if you wish to remake it".format(outfile))
        return

    # Parse input
    arc_spec = src_dict['spec']

    # In line_list?
    def chk_line_list(wave):
        mtw = np.where(np.abs(line_lists['wave']-wave) < 1e-3)[0]
        if len(mtw) == 0: # Not in the line list
            return 1
        elif len(mtw) != 1:
            pdb.set_trace()
        # Source used?
        if outfile[:iext] in line_lists['Source'][mtw[0]]:
            return 0
        else:
            return 2

    # IDs
    clrs = ['green', 'red', 'blue']  # Used, not used
    if src_dict['xIDs'] is not None:
        xIDs = src_dict['xIDs']
        IDlbls, IDclrs = [], []
        for row in src_dict['ID_lines']:
            IDlbls.append('{:s} {:.4f}'.format(row['ion'], row['wave']))
            # Color
            in_llist = chk_line_list(row['wave'])
            IDclrs.append(clrs[in_llist])
    else:
        xIDs = []

    # Unknowns
    U_lines = src_dict['U_lines']
    clrs = ['red', 'orange', 'green']  # Used, not used, ??
    if U_lines is not None:
        # Match to NIST
        mask, wv_match = arcl_utils.vette_unkwn_against_lists(U_lines, src_dict['uions'])
        xepix = src_dict['epix']
        extras = dict(x=[], IDs=[], clrs=[])
        for ss,row in enumerate(U_lines):
            # Check against minimum amplitude
            if row['amplitude'] < min_unk_ampl:
                continue
            # x
            extras['x'].append(xepix[ss])
            # Lbl
            if mask[ss] == 2:  # Matched to NIST
                lbl = '{:.4f}'.format(row['wave']) + ' [{:s}]'.format(wv_match[ss])
            else:
                lbl = 'UNKNWN {:.4f}'.format(row['wave'])
            extras['IDs'].append(lbl)
            # Color me
            if mask[ss] == 0: # In current line list
                extras['clrs'].append('gray')
            elif mask[ss] == -1: # Assuming Unknowns skipped
                extras['clrs'].append('brown')
            else:
                in_llist = chk_line_list(row['wave'])
                extras['clrs'].append(clrs[in_llist])
    else:
        extras = None

    # Plot
    pp = PdfPages(plot_path+outfile)
    plt.figure(figsize=(11, 8.5))
    plt.clf()
    gs = gridspec.GridSpec(2, 1)
    idfont = 'small'

    # Simple spectrum plot
    for qq in range(2):
        ax_spec = plt.subplot(gs[qq])
        ax_spec.plot(np.arange(len(arc_spec)), arc_spec, 'k')
        ymin, ymax = 0., np.max(arc_spec)
        ysep = ymax*0.03
        mn_yline = 1e9
        # Standard IDs
        for kk, x in enumerate(xIDs):
            yline = np.max(arc_spec[int(x)-2:int(x)+2])
            mn_yline = min(mn_yline, yline)
            # Tick mark
            ax_spec.plot([x,x], [yline+ysep*0.25, yline+ysep], '-', color=IDclrs[kk])
            # label
            ax_spec.text(x, yline+ysep*1.3, '{:s}'.format(IDlbls[kk]), ha='center', va='bottom',
                size=idfont, rotation=90., color=IDclrs[kk])
        # Extras?
        if extras is not None:
            for kk, x in enumerate(extras['x']):
                yline = np.max(arc_spec[int(x)-2:int(x)+2])
                mn_yline = min(mn_yline, yline)
                # Tick mark
                ax_spec.plot([x,x], [yline+ysep*0.25, yline+ysep], '-', color=extras['clrs'][kk])
                # label
                ax_spec.text(x, yline+ysep*1.3, '{:s}'.format(extras['IDs'][kk]), ha='center', va='bottom',
                    size=idfont, rotation=90., color=extras['clrs'][kk])
        # Axes
        ax_spec.set_xlim(0., len(arc_spec))
        if qq==1:
            ax_spec.set_yscale("log", nonposy='clip')
            ax_spec.set_ylim(mn_yline/10., 5*ymax)
        else:
            ax_spec.set_ylim(ymin, ymax*1.3)
        if qq == 0:
            ax_spec.set_xlabel('Pixel')
        ax_spec.minorticks_on()
        ax_spec.set_ylabel('Counts')
        if title is not None:
            ax_spec.text(0.04, 0.93, title, transform=ax_spec.transAxes,
                         size='x-large', ha='left')#, bbox={'facecolor':'white'})
    # Finish
    plt.tight_layout(pad=0.2, h_pad=0.0, w_pad=0.0)
    pp.savefig(bbox_inches='tight')
    pp.close()
    plt.close()
    print("Wrote {:s}".format(outfile))
    return
Example #3
0
def load_pypit(version, src_file, ions, plot=False, **kwargs):
    """ Load from PYPIT output

    Parameters
    ----------
    version : int
      Flag indicating version of PYPIT output
      1 : JSON format from PYPIT v1 -- Before May 2018
      2 : JSON format from PYPIT v2 -- May 2018 (JSON file has one key per slit/order)
    src_file : str
    plot : bool, optional
      Generate a plot?

    Returns
    -------
    ID_lines : Table
      Table of arc lines with IDs
    U_lines : Table or None
      Additional lines

    """
    # Load
    if version not in [1, 2]:
        raise IOError("Unimplemented version!")
    with open(src_path + src_file, 'r') as f:
        pypit_fit = json.load(f)

    if version == 2:
        print(
            "Taking the first slit in your file;  You will need to code to get another one"
        )
        pypit_fit = pypit_fit['0']

    npix = len(pypit_fit['spec'])
    # ID lines -- Assumed in NIST if from PYPIT
    #  Need to avoid dumb byte's here..
    #  The following line may only work with Python3
    #    and should be 'S{:d}' for Python 2
    ions = np.array(pypit_fit['ions'],
                    dtype='U{:d}'.format(str_len_dict['ion']))
    ID_lines = Table()
    ID_lines['ion'] = ions
    ID_lines['wave'] = pypit_fit['yfit']
    ID_lines['NIST'] = 1
    amps = []
    for jj, xfit in enumerate(pypit_fit['xfit']):
        pix = int(np.round(xfit * (npix - 1)))
        amps.append(int(pypit_fit['spec'][pix]))
    ID_lines['amplitude'] = amps

    mn_ID, mx_ID = min(ID_lines['wave']), max(ID_lines['wave'])
    # Unknown
    # Use PYPIT to decode
    wave = arcl_utils.func_val(pypit_fit['fitc'],
                               np.array(pypit_fit['tcent']) / (npix - 1),
                               pypit_fit['function'],
                               minv=pypit_fit['fmin'],
                               maxv=pypit_fit['fmax'])
    eamps, extras, epix = [], [], []
    for kk, iwave in enumerate(wave):
        if (np.min(np.abs(ID_lines['wave'].data - iwave)) > 0.5) and (
                iwave > mn_ID) and (iwave < mx_ID):  # NO EXTRAPOLATION
            extras.append(iwave)
            pix = int(np.round(pypit_fit['tcent'][kk]))
            epix.append(pix)  # For plotting
            eamps.append(int(pypit_fit['spec'][pix]))
    if len(extras) == 0:
        U_lines = None
    else:
        U_lines = Table()
        U_lines['wave'] = extras
        U_lines['ion'] = str('UNKNWN').rjust(str_len_dict['ion'])
        U_lines['NIST'] = 0
        U_lines['amplitude'] = eamps

    # Plot
    if plot:
        # Generate IDs
        IDs = []
        for row in ID_lines:
            IDs.append('{:s} {:.4f}'.format(row['ion'], row['wave']))
        # Extras
        if U_lines is not None:
            # Match to NIST
            mask, wv_match = arcl_utils.vette_unkwn_against_lists(
                U_lines, ions)
            pextras = dict(x=epix, IDs=[])
            for ss, row in enumerate(U_lines):
                if mask[ss] == 2:  # Matched to NIST
                    lbl = '{:.4f}'.format(row['wave']) + ' [{:s}]'.format(
                        wv_match[ss])
                else:
                    lbl = 'UNKNWN {:.4f}'.format(row['wave'])
                pextras['IDs'].append(lbl)
        else:
            pextras = None
        #
        arcl_plots.arc_ids(np.array(pypit_fit['spec']),
                           np.array(pypit_fit['xfit']) * (npix - 1),
                           IDs,
                           src_file.replace('.json', '.pdf'),
                           title=src_file.replace('.json', ''),
                           extras=pextras)

    # Return
    return mk_src_dict(ID_lines=ID_lines,
                       U_lines=U_lines,
                       spec=np.array(pypit_fit['spec']),
                       wave=wave,
                       xIDs=np.array(pypit_fit['xfit']) * (npix - 1),
                       epix=epix)
Example #4
0
def load_low_redux(version,
                   src_file,
                   ions,
                   plot=False,
                   min_hist=10,
                   cut_amp_val=400.,
                   wvmnx=[0., 1e9]):
    """
    Parameters
    ----------
    version : int
      1 : Find extras from set of LowRedux fits
    src_file : str
    plot

    Returns
    -------

    """
    import warnings
    if version != 1:
        raise IOError("Unimplemented version!")

    import h5py
    from scipy.interpolate import interp1d
    from arclines.pypit_utils import find_peaks
    from arclines.io import load_line_lists

    # Load existing line lists
    line_list = load_line_lists(ions, skip=True)
    if line_list is None:  # Should be a 'by scratch case'
        warnings.warn(
            "No line lists found matching your ions: {}".format(ions))
        print("I hope you are building from scratch here..")
        return mk_src_dict()
    wvdata = line_list['wave'].data

    # Open
    hdf = h5py.File(src_path + src_file, 'r')
    mdict = {}
    for key in hdf['meta'].keys():
        mdict[key] = hdf['meta'][key].value

    # Loop on spec
    extras = []
    eamps = []
    for ispec in range(mdict['nspec']):
        spec = hdf['arcs/' + str(ispec) + '/spec'].value
        wave = hdf['arcs/' + str(ispec) + '/wave'].value  # vacuum
        disp = np.median(np.abs(wave - np.roll(wave, 1)))
        npix = wave.size
        # Find peaks for extras
        tampl, tcent, twid, w, yprep = find_peaks(spec)
        all_tcent = tcent[w]

        # Function for more precise wavelengths
        fwv = interp1d(np.arange(npix), wave)  #, kind='cubic')
        #
        amps = []
        for itc in all_tcent:
            pix = int(np.round(itc))
            amps.append(np.max(spec[pix - 1:pix + 2]))
        amps = np.array(amps)

        # Trim tcent on amplitude
        cut_amp = amps > cut_amp_val  # 500.
        tcent = all_tcent[cut_amp]
        nlin = tcent.size

        # init with Truth
        for ii in range(nlin):
            wvt = float(fwv(tcent[ii]))
            mtw = np.where(np.abs(wvdata - wvt) < 4 *
                           disp)[0]  # Deals with bad wavelength solutions
            if len(mtw) == 0:
                if (wvt > wvmnx[0]) & (wvt < wvmnx[1]):  # LRISb only
                    extras.append(wvt)
                    eamps.append(amps[ii])
    # Repackage
    extras = np.array(extras)
    isort = np.argsort(extras)
    extras = extras[isort]
    eamps = np.array(eamps)[isort]
    # Group -- Super-crude friends of friends
    final_extras = []
    final_amps = []
    cnt = 0
    while cnt <= extras.size:
        # First try
        ingroup = np.abs(extras - extras[cnt]) < 2 * disp
        for ii in range(3):  # For some convergence
            # Median
            mngroup = np.median(extras[ingroup])
            ingroup = np.abs(extras - mngroup) < 2 * disp
        if np.sum(ingroup) > min_hist:
            final_extras.append(np.median(extras[ingroup]))
            final_amps.append(np.median(eamps[ingroup]))
        # Step
        newe = mngroup + 5 * disp
        gdcnt = np.where(extras > newe)[0]
        if len(gdcnt) == 0:
            break
        else:
            cnt = gdcnt[0]

    # Table
    U_lines = Table()
    U_lines['wave'] = final_extras
    U_lines['ion'] = str('UNKNWN').rjust(str_len_dict['ion'])
    U_lines['NIST'] = 0
    U_lines['amplitude'] = final_amps

    # Find the best spectrum
    max_nex = 0
    for ispec in range(mdict['nspec']):
        spec = hdf['arcs/' + str(ispec) + '/spec'].value
        wave = hdf['arcs/' + str(ispec) + '/wave'].value  # vacuum
        minwv, maxwv = np.min(wave), np.max(wave)
        nex = np.sum((final_extras > minwv) & (final_extras < maxwv))
        if nex > max_nex:
            svi = ispec
            max_nex = nex
    # Find pixel values
    spec = hdf['arcs/' + str(svi) + '/spec'].value
    wave = hdf['arcs/' + str(svi) + '/wave'].value  # vacuum

    # Extras
    fpix = interp1d(wave, np.arange(npix))  #, kind='cubic')
    epix = fpix(final_extras)

    # Plot??
    if plot:
        # Match to NIST
        mask, wv_match = arcl_utils.vette_unkwn_against_lists(U_lines, ions)
        npix = wave.size
        for ss, fex in enumerate(final_extras):
            if mask[ss] == 2:  # Matched to NIST
                lbl = '{:.4f}'.format(fex) + ' [{:s}]'.format(wv_match[ss])
            else:
                lbl = 'UNKNWN {:.4f}'.format(fex)
            pextras['IDs'].append(lbl)
        # Plot
        arcl_plots.arc_ids(spec, [], [],
                           src_file.replace('.hdf5', '.pdf'),
                           title=src_file.replace('.hdf5', ''),
                           extras=pextras)

    # Return
    return mk_src_dict(U_lines=U_lines, epix=epix, spec=spec, wave=wave)