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
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
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)
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)