def main(args): """ Parameters ---------- args Returns ------- """ import numpy as np from pypit import pyputils msgs = pyputils.get_dummy_logger() from pypit import arqa from linetools.utils import loadjson # Read JSON fdict = loadjson(args.wave_soln) for key in fdict.keys(): if isinstance(fdict[key], list): fdict[key] = np.array(fdict[key]) # Generate QA arqa.arc_fit_qa(None, fdict, outfil=args.outfile, ids_only=True, title=args.title) print("Wrote {:s}".format(args.outfile))
def tst_unknwn_wvcen(spec, lines, wv_cen, disp, siglev=20., min_ampl=300., swv_uncertainty=350., pix_tol=2, plot_fil=None, wvoff=1000.): """ As named """ dcen = swv_uncertainty * 0.8 wvcens = np.arange(wv_cen - wvoff, wv_cen + wvoff + dcen, dcen) # Best best_dict = dict(nmatch=0, nID=0, rms=0., ibest=-1, bwv=0.) # Loop for ss, iwv_cen in enumerate(wvcens): print('wv_cen guess = {:g}'.format(iwv_cen)) stuff = grail.basic(spec, lines, iwv_cen, disp, siglev=siglev, min_ampl=min_ampl, swv_uncertainty=swv_uncertainty, pix_tol=pix_tol, plot_fil=None) if stuff[0] == -1: print("Solution failed for iwv_cen={:g}. Nmatch={:d}".format( iwv_cen, stuff[1])) elif stuff[0] == 1: # Unpack status, nmatch, match_idx, scores, final_fit = stuff print("Fit finished for iwv_cen={:g}".format(iwv_cen)) # Metrics -- nmatch, nID, RMS nID = len(final_fit['xfit']) print(" Nmatch={:d}, nID={:d}, RMS={:g}".format( nmatch, nID, final_fit['rms'])) # Best? if nID > best_dict['nID']: best_dict['nmatch'] = nmatch best_dict['nID'] = nID best_dict['rms'] = final_fit['rms'] best_dict['ibest'] = ss best_dict['bwv'] = iwv_cen best_dict['fit'] = final_fit # Report print("Here is the best:") print(best_dict) # QA if plot_fil is not None: from pypit import pyputils msgs = pyputils.get_dummy_logger() from pypit import arqa arqa.arc_fit_qa(None, best_dict['fit'], outfil=plot_fil)
def calib_with_arclines(slf, det, get_poly=False, use_method="general"): """Simple calibration algorithm for longslit wavelengths Uses slf._arcparam to guide the analysis Parameters ---------- get_poly : bool, optional Pause to record the polynomial pix = b0 + b1*lambda + b2*lambda**2 Returns ------- final_fit : dict Dict of fit info """ from arclines.holy.grail import basic, semi_brute, general # Parameters (just for convenience) aparm = slf._arcparam[det - 1] # Extract the arc msgs.work("Detecting lines") tampl, tcent, twid, w, satsnd, spec = detect_lines(slf, det, slf._msarc[det - 1]) if use_method == "semi-brute": best_dict, final_fit = semi_brute(spec, aparm['lamps'], aparm['wv_cen'], aparm['disp'], fit_parm=aparm, min_ampl=aparm['min_ampl']) elif use_method == "basic": stuff = basic(spec, aparm['lamps'], aparm['wv_cen'], aparm['disp']) status, ngd_match, match_idx, scores, final_fit = stuff else: # Now preferred best_dict, final_fit = general(spec, aparm['lamps'], fit_parm=aparm, min_ampl=aparm['min_ampl']) arqa.arc_fit_qa(slf, final_fit) # return final_fit
def simple_calib(slf, det, get_poly=False): """Simple calibration algorithm for longslit wavelengths Uses slf._arcparam to guide the analysis Parameters ---------- get_poly : bool, optional Pause to record the polynomial pix = b0 + b1*lambda + b2*lambda**2 Returns ------- final_fit : dict Dict of fit info """ # Extract the arc msgs.work("Detecting lines..") tampl, tcent, twid, w, satsnd, yprep = detect_lines( slf, det, slf._msarc[det - 1]) # Cut down to the good ones tcent = tcent[w] tampl = tampl[w] msgs.info('Detected {:d} lines in the arc spectrum.'.format(len(w[0]))) # Parameters (just for convenience) aparm = slf._arcparam[det - 1] # Read Arc linelist llist = aparm['llist'] # IDs were input by hand if len(settings.argflag['arc']['calibrate']['IDpixels']) > 0: # Check that there are at least 5 values pixels = np.array(settings.argflag['arc']['calibrate']['IDpixels']) if np.sum(pixels > 0.) < 5: msgs.error("Need to give at least 5 pixel values!") # msgs.info("Using input lines to seed the wavelength solution") # Calculate median offset mdiff = [ np.min(np.abs(tcent - pix)) for pix in settings.argflag['arc']['calibrate']['IDpixels'] ] med_poff = np.median(np.array(mdiff)) msgs.info("Will apply a median offset of {:g} pixels".format(med_poff)) # Match input lines to observed spectrum nid = len(settings.argflag['arc']['calibrate']['IDpixels']) idx_str = np.ones(nid).astype(int) ids = np.zeros(nid) idsion = np.array([' '] * nid) gd_str = np.arange(nid).astype(int) for jj, pix in enumerate( settings.argflag['arc']['calibrate']['IDpixels']): diff = np.abs(tcent - pix - med_poff) if np.min(diff) > 2.: debugger.set_trace() msgs.error("No match with input pixel {:g}!".format(pix)) else: imn = np.argmin(diff) # Set idx_str[jj] = imn # Take wavelength from linelist instead of input value wdiff = np.abs(llist['wave'] - settings.argflag['arc']['calibrate']['IDwaves'][jj]) imnw = np.argmin(wdiff) if wdiff[imnw] > 0.015: # Arbitrary tolerance msgs.error( "Input IDwaves={:g} is not in the linelist. Fix".format( settings.argflag['arc']['calibrate']['IDwaves'][jj])) else: ids[jj] = llist['wave'][imnw] idsion[jj] = llist['Ion'][imnw] msgs.info("Identifying arc line: {:s} {:g}".format( idsion[jj], ids[jj])) else: # Generate dpix pairs msgs.info("Using pair algorithm for wavelength solution") nlist = len(llist) dpix_list = np.zeros((nlist, nlist)) for kk, row in enumerate(llist): #dpix_list[kk,:] = (np.array(row['wave'] - llist['wave']))/disp dpix_list[kk, :] = slf._msarc[det - 1].shape[0] * ( aparm['b1'] * (np.array(row['wave'] - llist['wave'])) + aparm['b2'] * np.array(row['wave']**2 - llist['wave']**2)) # Lambda pairs for the strongest N lines srt = np.argsort(tampl) idx_str = srt[-aparm['Nstrong']:] idx_str.sort() dpix_obs = np.zeros((aparm['Nstrong'], aparm['Nstrong'])) for kk, idx in enumerate(idx_str): dpix_obs[kk, :] = np.array(tcent[idx] - tcent[idx_str]) # Match up (ugly loops) ids = np.zeros(aparm['Nstrong']) idsion = np.array([' '] * aparm['Nstrong']) for kk in range(aparm['Nstrong']): med_off = np.zeros(nlist) for ss in range(nlist): dpix = dpix_list[ss] min_off = [] for jj in range(aparm['Nstrong']): min_off.append(np.min(np.abs(dpix_obs[kk, jj] - dpix))) med_off[ss] = np.median(min_off) # Set by minimum idm = np.argmin(med_off) ids[kk] = llist['wave'][idm] idsion[kk] = llist['Ion'][idm] # Calculate disp of the strong lines disp_str = np.zeros(aparm['Nstrong']) for kk in range(aparm['Nstrong']): disp_val = (ids[kk] - ids) / (tcent[idx_str[kk]] - tcent[idx_str]) isf = np.isfinite(disp_val) disp_str[kk] = np.median(disp_val[isf]) # Consider calculating the RMS with clipping gd_str = np.where( np.abs(disp_str - aparm['disp']) / aparm['disp'] < aparm['disp_toler'])[0] msgs.info('Found {:d} lines within the dispersion threshold'.format( len(gd_str))) if len(gd_str) < 5: if msgs._debug['arc']: msgs.warn('You should probably try your best to ID lines now.') debugger.set_trace() debugger.plot1d(yprep) else: msgs.error('Insufficient lines to auto-fit.') # Debug #debug=True if msgs._debug['arc']: #tmp = list(gd_str) #tmp.pop(1) #gd_str = np.array(tmp) #xdb.xpcol(tcent[idx_str[gd_str]],ids[gd_str]) #xdb.xplot(tcent[idx_str[gd_str]],ids[gd_str],scatter=True) # debugger.xplot(yprep) debugger.set_trace() msgs.work('Cross correlate here?') # Setup for fitting ifit = idx_str[gd_str] sv_ifit = list(ifit) # Keep the originals all_ids = -999. * np.ones(len(tcent)) all_idsion = np.array(['12345'] * len(tcent)) all_ids[ifit] = ids[gd_str] all_idsion[ifit] = idsion[gd_str] # Fit n_order = aparm['n_first'] flg_quit = False fmin, fmax = -1., 1. msgs.info('Iterative wavelength fitting..') while (n_order <= aparm['n_final']) and (flg_quit is False): #msgs.info('n_order={:d}'.format(n_order)) # Fit with rejection xfit, yfit = tcent[ifit], all_ids[ifit] mask, fit = arutils.robust_polyfit(xfit, yfit, n_order, function=aparm['func'], sigma=aparm['nsig_rej'], minv=fmin, maxv=fmax) # Reject but keep originals (until final fit) ifit = list(ifit[mask == 0]) + sv_ifit # Find new points (should we allow removal of the originals?) twave = arutils.func_val(fit, tcent, aparm['func'], minv=fmin, maxv=fmax) for ss, iwave in enumerate(twave): mn = np.min(np.abs(iwave - llist['wave'])) if mn / aparm['disp'] < aparm['match_toler']: imn = np.argmin(np.abs(iwave - llist['wave'])) #if msgs._debug['arc']: # print('Adding {:g} at {:g}'.format(llist['wave'][imn],tcent[ss])) # Update and append all_ids[ss] = llist['wave'][imn] all_idsion[ss] = llist['Ion'][imn] ifit.append(ss) # Keep unique ones ifit = np.unique(np.array(ifit, dtype=int)) #if msgs._debug['arc']: # debugger.set_trace() # Increment order if n_order < aparm['n_final']: n_order += 1 else: # This does 2 iterations at the final order flg_quit = True # Final fit (originals can now be rejected) fmin, fmax = 0., 1. xfit, yfit = tcent[ifit] / (slf._msarc[det - 1].shape[0] - 1), all_ids[ifit] mask, fit = arutils.robust_polyfit(xfit, yfit, n_order, function=aparm['func'], sigma=aparm['nsig_rej_final'], minv=fmin, maxv=fmax) #, debug=True) irej = np.where(mask == 1)[0] if len(irej) > 0: xrej = xfit[irej] yrej = yfit[irej] for imask in irej: msgs.info('Rejecting arc line {:g}'.format(yfit[imask])) else: xrej = [] yrej = [] xfit = xfit[mask == 0] yfit = yfit[mask == 0] ions = all_idsion[ifit][mask == 0] # if msgs._debug['arc']: msarc = slf._msarc[det - 1] wave = arutils.func_val(fit, np.arange(msarc.shape[0]) / float(msarc.shape[0]), 'legendre', minv=fmin, maxv=fmax) debugger.set_trace() #debugger.xplot(xfit, np.ones(len(xfit)), scatter=True, # xtwo=np.arange(msarc.shape[0]),ytwo=yprep) #debugger.xplot(xfit,yfit, scatter=True, xtwo=np.arange(msarc.shape[0]), # ytwo=wave) #debugger.set_trace() #wave = arutils.func_val(fit, np.arange(msarc.shape[0])/float(msarc.shape[0]), # 'legendre', min=fmin, max=fmax) # 2nd order Poly fit for archival #get_poly=True if get_poly: poly_fit = arutils.func_fit(yfit, xfit, 'polynomial', 2, minv=fmin, maxv=fmax) print(' Most likely you with to record these values:') print(poly_fit) debugger.set_trace() # Pack up fit final_fit = dict(fitc=fit, function=aparm['func'], xfit=xfit, yfit=yfit, ions=ions, fmin=fmin, fmax=fmax, xnorm=float(slf._msarc[det - 1].shape[0]), xrej=xrej, yrej=yrej, mask=mask, spec=yprep, nrej=aparm['nsig_rej_final'], shift=0., tcent=tcent) # QA arqa.arc_fit_qa(slf, final_fit) # RMS rms_ang = arutils.calc_fit_rms(xfit, yfit, fit, aparm['func'], minv=fmin, maxv=fmax) wave = arutils.func_val(fit, np.arange(slf._msarc[det - 1].shape[0]) / float(slf._msarc[det - 1].shape[0]), aparm['func'], minv=fmin, maxv=fmax) rms_pix = rms_ang / np.median(np.abs(wave - np.roll(wave, 1))) msgs.info("Fit RMS = {} pix".format(rms_pix)) # Return return final_fit
def iterative_fitting(spec, tcent, ifit, IDs, llist, disp, plot_fil=None, verbose=False, load_pypit=False, aparm=None): if aparm is None: aparm = dict( llist='', disp=disp, # Ang/unbinned pixel disp_toler=0.1, # 10% tolerance match_toler=3., # Matcing tolerance (pixels) func='legendre', # Function for fitting n_first=3, # Order of polynomial for first fit n_final=4, # Order of polynomial for final fit nsig_rej=2., # Number of sigma for rejection nsig_rej_final=3.0) # Number of sigma for rejection (final fit) # PYPIT if load_pypit: from pypit import pyputils msgs = pyputils.get_dummy_logger() from pypit import arutils from pypit import arqa if load_pypit: arutils.dummy_settings() npix = spec.size # Setup for fitting sv_ifit = list(ifit) # Keep the originals all_ids = -999. * np.ones(len(tcent)) all_idsion = np.array(['UNKNWN'] * len(tcent)) all_ids[ifit] = IDs # Fit n_order = aparm['n_first'] flg_quit = False fmin, fmax = -1., 1. while (n_order <= aparm['n_final']) and (flg_quit is False): # Fit with rejection xfit, yfit = tcent[ifit], all_ids[ifit] mask, fit = arutils.robust_polyfit(xfit, yfit, n_order, function=aparm['func'], sigma=aparm['nsig_rej'], minv=fmin, maxv=fmax) rms_ang = arutils.calc_fit_rms(xfit[mask == 0], yfit[mask == 0], fit, aparm['func'], minv=fmin, maxv=fmax) rms_pix = rms_ang / disp if verbose: print("RMS = {:g}".format(rms_pix)) # DEBUG # Reject but keep originals (until final fit) ifit = list(ifit[mask == 0]) + sv_ifit # Find new points (should we allow removal of the originals?) twave = arutils.func_val(fit, tcent, aparm['func'], minv=fmin, maxv=fmax) for ss, iwave in enumerate(twave): mn = np.min(np.abs(iwave - llist['wave'])) if mn / aparm['disp'] < aparm['match_toler']: imn = np.argmin(np.abs(iwave - llist['wave'])) #if verbose: # print('Adding {:g} at {:g}'.format(llist['wave'][imn],tcent[ss])) # Update and append all_ids[ss] = llist['wave'][imn] all_idsion[ss] = llist['ion'][imn] ifit.append(ss) # Keep unique ones ifit = np.unique(np.array(ifit, dtype=int)) # Increment order if n_order < (aparm['n_final'] + 2): n_order += 1 else: # This does 2 iterations at the final order flg_quit = True # Final fit (originals can now be rejected) fmin, fmax = 0., 1. xfit, yfit = tcent[ifit] / (npix - 1), all_ids[ifit] mask, fit = arutils.robust_polyfit(xfit, yfit, n_order, function=aparm['func'], sigma=aparm['nsig_rej_final'], minv=fmin, maxv=fmax) #, debug=True) irej = np.where(mask == 1)[0] if len(irej) > 0: xrej = xfit[irej] yrej = yfit[irej] if verbose: for kk, imask in enumerate(irej): wave = arutils.func_val(fit, xrej[kk], aparm['func'], minv=fmin, maxv=fmax) print('Rejecting arc line {:g}; {:g}'.format( yfit[imask], wave)) else: xrej = [] yrej = [] xfit = xfit[mask == 0] yfit = yfit[mask == 0] ions = all_idsion[ifit][mask == 0] # Final RMS rms_ang = arutils.calc_fit_rms(xfit, yfit, fit, aparm['func'], minv=fmin, maxv=fmax) rms_pix = rms_ang / disp # ''' if msgs._debug['arc']: msarc = slf._msarc[det-1] wave = arutils.func_val(fit, np.arange(msarc.shape[0])/float(msarc.shape[0]), 'legendre', minv=fmin, maxv=fmax) debugger.xplot(xfit,yfit, scatter=True, xtwo=np.arange(msarc.shape[0])/float(msarc.shape[0]), ytwo=wave) debugger.xpcol(xfit*msarc.shape[0], yfit) debugger.set_trace() ''' #debugger.xplot(xfit, np.ones(len(xfit)), scatter=True, # xtwo=np.arange(msarc.shape[0]),ytwo=yprep) #debugger.xplot(xfit,yfit, scatter=True, xtwo=np.arange(msarc.shape[0]), # ytwo=wave) #debugger.set_trace() #wave = arutils.func_val(fit, np.arange(msarc.shape[0])/float(msarc.shape[0]), # 'legendre', min=fmin, max=fmax) # Pack up fit final_fit = dict(fitc=fit, function=aparm['func'], xfit=xfit, yfit=yfit, ions=ions, fmin=fmin, fmax=fmax, xnorm=float(npix), xrej=xrej, yrej=yrej, mask=mask, spec=spec, nrej=aparm['nsig_rej_final'], shift=0., tcent=tcent, rms=rms_pix) # QA if plot_fil is not None: arqa.arc_fit_qa(None, final_fit, outfil=plot_fil) # Return return final_fit