def invert(self, domain=None, coeff=None, deg=None): """ Utility to return a traceset modeling x vs. y instead of y vs. x """ if domain is None: domain = [self.wmin, self.wmax] ispec = np.arange(self.nspec) # Doing for all spectra if coeff is None: coeff = self.ycoeff # doing y-wavelength map ytmp = list() for ii in ispec: fit_dict = dufits.mk_fit_dict(coeff[ii, :], coeff.shape[1], 'legendre', domain[0], domain[1]) xtmp = np.array((domain[0], domain[1])) yfit = dufits.func_val(xtmp, fit_dict) ytmp.append(yfit) ymin = np.min(ytmp) ymax = np.max(ytmp) x = np.linspace(domain[0], domain[1], 1000) if deg is None: deg = self.ncoeff + 2 #- Now get the coefficients for inverse mapping c = np.zeros((coeff.shape[0], deg + 1)) for ii in ispec: fit_dict = dufits.mk_fit_dict(coeff[ii, :], coeff.shape, 'legendre', domain[0], domain[1]) y = dufits.func_val(x, fit_dict) yy = 2.0 * (y - ymin) / (ymax - ymin) - 1.0 c[ii] = legfit(yy, x, deg) return c, ymin, ymax
def invert(self, domain=None, coeff=None, deg=None): """ Utility to return a traceset modeling x vs. y instead of y vs. x """ if domain is None: domain=[self.wmin,self.wmax] ispec=np.arange(self.nspec) # Doing for all spectra if coeff is None: coeff=self.ycoeff # doing y-wavelength map ytmp=list() for ii in ispec: fit_dict=dufits.mk_fit_dict(coeff[ii,:],coeff.shape[1],'legendre',domain[0],domain[1]) xtmp=np.array((domain[0],domain[1])) yfit = dufits.func_val(xtmp, fit_dict) ytmp.append(yfit) ymin = np.min(ytmp) ymax = np.max(ytmp) x = np.linspace(domain[0], domain[1], 1000) if deg is None: deg = self.ncoeff+2 #- Now get the coefficients for inverse mapping c = np.zeros((coeff.shape[0], deg+1)) for ii in ispec: fit_dict=dufits.mk_fit_dict(coeff[ii,:],coeff.shape,'legendre',domain[0],domain[1]) y = dufits.func_val(x,fit_dict) yy = 2.0 * (y-ymin) / (ymax-ymin) - 1.0 c[ii] = legfit(yy, x, deg) return c,ymin,ymax
def y(self,ispec=None,wavelength=None): """ returns CCD y centroids for the spectra ispec can be None, scalar or a vector wavelength can be a vector but not allowing None #- similar as in specter.psf.PSF.y """ if wavelength is None: raise ValueError, "PSF.y requires wavelength 1D vector" wavelength = np.asarray(wavelength) if ispec is None: ispec=np.arange(self.nspec) y=list() for ii in ispec: fit_dicty=dufits.mk_fit_dict(self.ycoeff[ii],self.ncoeff,'legendre',self.wmin,self.wmax) yfit=dufits.func_val(wavelength,fit_dicty) y.append(yfit) return np.array(y) if isinstance(ispec,(np.ndarray,list,tuple)): y=list() for ii in ispec: fit_dicty=dufits.mk_fit_dict(self.ycoeff[ii],self.ncoeff,'legendre',self.wmin,self.wmax) yfit=dufits.func_val(wavelength,fit_dicty) y.append(yfit) return np.array(y) if isinstance(ispec,int): # int ispec fit_dicty=dufits.mk_fit_dict(self.ycoeff[ispec],self.ncoeff,'legendre',self.wmin,self.wmax) y=dufits.func_val(wavelength,fit_dicty) return np.array(y)
def wavelength(self, ispec=None, y=None): """ returns wavelength evaluated at y """ if y is None: y = np.arange(0, self.npix_y) if ispec is None: ispec = np.arange(self.nspec) c = self.icoeff ymin = self.ymin ymax = self.ymax if isinstance(ispec, numbers.Integral): new_dict = dufits.mk_fit_dict(c[ispec, :], c[ispec, :].shape, 'legendre', ymin, ymax) wfit = dufits.func_val(y, new_dict) return wfit else: ww = list() for ii in ispec: new_dict = dufits.mk_fit_dict(c[ii, :], c[ii, :].shape, 'legendre', ymin, ymax) wfit = dufits.func_val(y, new_dict) ww.append(wfit) return np.array(ww)
def y(self,ispec=None,wavelength=None): """ returns CCD y centroids for the spectra ispec can be None, scalar or a vector wavelength can be a vector but not allowing None #- similar as in specter.psf.PSF.y """ if wavelength is None: raise ValueError("PSF.y requires wavelength 1D vector") wavelength = np.asarray(wavelength) if ispec is None: ispec=np.arange(self.nspec) y=list() for ii in ispec: fit_dicty=dufits.mk_fit_dict(self.ycoeff[ii],self.ncoeff,'legendre',self.wmin,self.wmax) yfit=dufits.func_val(wavelength,fit_dicty) y.append(yfit) return np.array(y) if isinstance(ispec,(np.ndarray,list,tuple)): y=list() for ii in ispec: fit_dicty=dufits.mk_fit_dict(self.ycoeff[ii],self.ncoeff,'legendre',self.wmin,self.wmax) yfit=dufits.func_val(wavelength,fit_dicty) y.append(yfit) return np.array(y) if isinstance(ispec, numbers.Integral): # int ispec fit_dicty=dufits.mk_fit_dict(self.ycoeff[ispec],self.ncoeff,'legendre',self.wmin,self.wmax) y=dufits.func_val(wavelength,fit_dicty) return np.array(y)
def x(self, ispec=None, wavelength=None): """ returns CCD x centroids for the spectra ispec can be None, scalar or a vector wavelength can be None or a vector """ if wavelength is None: #- ispec = None -> all the spectra if ispec is None: ispec = np.arange(self.nspec) x = list() #x=np.array((len(ispec),len(wavelength))) for ii in ispec: wave = self.wavelength(ii) fit_dictx = dufits.mk_fit_dict(self.xcoeff[ii], self.ncoeff, 'legendre', self.wmin, self.wmax) xfit = dufits.func_val(wave, fit_dictx) x.append(xfit) return np.array(x) if isinstance(ispec, (np.ndarray, list, tuple)): x = list() for ii in ispec: wave = self.wavelength(ii) fit_dictx = dufits.mk_fit_dict(self.xcoeff[ii], self.ncoeff, 'legendre', self.wmin, self.wmax) xfit = dufits.func_val(wave, fit_dictx) x.append(xfit) return np.array(x) else: # int ispec wave = self.wavelength(ispec) fit_dictx = dufits.mk_fit_dict(self.xcoeff[ispec], self.ncoeff, 'legendre', self.wmin, self.wmax) x = dufits.func_val(wave, fit_dictx) return np.array(x) #- wavelength not None but a scalar or 1D-vector here and below wavelength = np.asarray(wavelength) if isinstance(ispec, numbers.Integral): fit_dictx = dufits.mk_fit_dict(self.xcoeff[ispec], self.ncoeff, 'legendre', self.wmin, self.wmax) x = dufits.func_val(wavelength, fit_dictx) return np.array(x) if ispec is None: ispec = np.arange(self.nspec) x = list() for ii in ispec: #- for a None or a np.ndarray or anything that can be iterated case fit_dictx = dufits.mk_fit_dict(self.xcoeff[ii], self.ncoeff, 'legendre', self.wmin, self.wmax) xfit = dufits.func_val(wavelength, fit_dictx) x.append(xfit) return np.array(x)
def x(self,ispec=None,wavelength=None): """ returns CCD x centroids for the spectra ispec can be None, scalar or a vector wavelength can be None or a vector """ if wavelength is None: #- ispec = None -> all the spectra if ispec is None: ispec=np.arange(self.nspec) wavelength=self.wavelength x=list() for ii in ispec: wave=self.wavelength(ii) fit_dictx=dufits.mk_fit_dict(self.xcoeff[ii],self.ncoeff,'legendre',self.wmin,self.wmax) xfit=dufits.func_val(wave,fit_dictx) x.append(xfit) return np.array(x) if isinstance(ispec,(np.ndarray,list,tuple)): x=list() for ii in ispec: wave=self.wavelength(ii) fit_dictx=dufits.mk_fit_dict(self.xcoeff[ii],self.ncoeff,'legendre',self.wmin,self.wmax) xfit=dufits.func_val(wave,fit_dictx) x.append(xfit) return np.array(x) else: # int ispec wave=self.wavelength(ispec) fit_dictx=dufits.mk_fit_dict(self.xcoeff[ispec],self.ncoeff,'legendre',self.wmin,self.wmax) x=dufits.func_val(wave,fit_dictx) return np.array(x) #- wavelength not None but a scalar or 1D-vector here and below wavelength = np.asarray(wavelength) if isinstance(ispec,int): fit_dictx=dufits.mk_fit_dict(self.xcoeff[ispec],self.ncoeff,'legendre',self.wmin,self.wmax) x=dufits.func_val(wavelength,fit_dictx) return np.array(x) if ispec is None: ispec=np.arange(self.nspec) x=list() for ii in ispec: #- for a None or a np.ndarray or anything that can be iterated case fit_dictx=dufits.mk_fit_dict(self.xcoeff[ii],self.ncoeff,'legendre',self.wmin,self.wmax) xfit=dufits.func_val(wavelength,fit_dictx) x.append(xfit) return np.array(x)
def wavelength(self,ispec=None,y=None): """ returns wavelength evaluated at y """ if y is None: y=np.arange(0,self.npix_y) if ispec is None: ispec=np.arange(self.nspec) #- First get the inversion map y --> wavelength dictionary c,ymin,ymax=self.invert(coeff=self.ycoeff) if isinstance(ispec,int): new_dict=dufits.mk_fit_dict(c[ispec,:],c[ispec,:].shape,'legendre',ymin,ymax) wfit=dufits.func_val(y,new_dict) return wfit else: ww=list() for ii in ispec: new_dict=dufits.mk_fit_dict(c[ii,:],c[ii,:].shape,'legendre',ymin,ymax) wfit=dufits.func_val(y,new_dict) ww.append(wfit) return np.array(ww)
def main(args): log=get_logger() log.info("Starting") if args.triplet_matching : log.warning("triplet_matching option deprecated, this algorithm is now used for all cases") lamps=None if args.lamps : lamps=np.array(args.lamps.split(",")) log.info("Using lamps = %s"%str(lamps)) else : log.info("Using default set of lamps") if args.fiberflat is not None and args.contfile is None : args.contfile=args.fiberflat log.warning("Please use --contfile instead of --fiberflat") if (args.psffile is None) and (args.contfile is None): raise IOError("Must provide either a PSF file or a contfile") # Start QA try: pp = PdfPages(args.qafile) except ValueError: QA = False else: QA = True contfile_header = None if args.psffile is None: ########### # Read continuum cont_hdu = fits.open(args.contfile) contfile_header = cont_hdu[0].header header = cont_hdu[0].header if len(cont_hdu)>=3 : cont = cont_hdu[0].data*(cont_hdu[1].data>0)*(cont_hdu[2].data==0) else : cont = cont_hdu[0].data log.warning("found only %d HDU in cont, do not use ivar"%len(cont_hdu)) ny = cont.shape[0] ########### # Find fibers log.info("Finding the fibers") xpk, ypos, cut = desiboot.find_fiber_peaks(cont) if QA: desiboot.qa_fiber_peaks(xpk, cut, pp) # Test? if args.test: log.warning("cutting down fibers for testing..") #xpk = xpk[0:100] xpk = xpk[0:50] #xpk = xpk[0:5] ########### # Trace the fiber cont spectra log.info("Tracing the continuum spectra") # Crude first log.info("Crudely..") xset, xerr = desiboot.trace_crude_init(cont,xpk,ypos) # Polynomial fits log.info("Fitting the traces") xfit, fdicts = desiboot.fit_traces(xset,xerr) # QA if QA: desiboot.qa_fiber_Dx(xfit, fdicts, pp) ########### # Model the PSF with Gaussian log.info("Modeling the PSF with a Gaussian, be patient..") gauss = desiboot.fiber_gauss(cont,xfit,xerr) if QA: desiboot.qa_fiber_gauss(gauss, pp) XCOEFF = None else: # Load PSF file and generate trace info log.warning("Not tracing the continuum. Using the PSF file.") psf_hdu = fits.open(args.psffile) psf_head = psf_hdu[0].header # Gaussians gauss = psf_hdu[2].data # Traces WAVEMIN = psf_head['WAVEMIN'] WAVEMAX = psf_head['WAVEMAX'] XCOEFF = psf_hdu[0].data xfit = None fdicts = None arc_header = None # ARCS if not args.trace_only: ########### # Read arc log.info("Reading arc") arc_hdu = fits.open(args.arcfile) arc_header = arc_hdu[0].header if len(arc_hdu)>=3 : # set to zero ivar of masked pixels, force positive or null ivar arc_ivar = arc_hdu[1].data*(arc_hdu[2].data==0)*(arc_hdu[1].data>0) # and mask pixels below -5 sigma (cures unmasked dead columns in sims.) arc_ivar *= (arc_hdu[0].data*np.sqrt(arc_hdu[1].data)>-5.) # set to zero pixel values with null ivar arc = arc_hdu[0].data*(arc_ivar>0) else : arc = arc_hdu[0].data arc_ivar = np.ones(arc.shape) log.warning("found only %d HDU in arc, do not use ivar"%len(arc_hdu)) header = arc_hdu[0].header ny = arc.shape[0] ##################################### # Extract arc spectra (one per fiber) log.info("Extracting arcs") if xfit is None: wv_array = np.linspace(WAVEMIN, WAVEMAX, num=arc.shape[0]) nfiber = XCOEFF.shape[0] ncoeff = XCOEFF.shape[1] xfit = np.zeros((arc.shape[0], nfiber)) # Generate a fit_dict fit_dict = dufits.mk_fit_dict(XCOEFF[:,0], ncoeff, 'legendre', WAVEMIN, WAVEMAX) for ii in range(nfiber): fit_dict['coeff'] = XCOEFF[ii,:] xfit[:,ii] = dufits.func_val(wv_array, fit_dict) all_spec = desiboot.extract_sngfibers_gaussianpsf(arc, arc_ivar, xfit, gauss) ############################ # Line list camera = header['CAMERA'].lower() log.info("Loading line list") llist = desiboot.load_arcline_list(camera,vacuum=True,lamps=lamps) dlamb, gd_lines = desiboot.load_gdarc_lines(camera,llist,vacuum=True,lamps=lamps,good_lines_filename=args.good_lines) ##################################### # Loop to solve for wavelengths all_wv_soln = [] all_dlamb = [] debug=False id_dict_of_fibers=[] # first loop to find arc lines and do a first matching for ii in range(all_spec.shape[1]): spec = all_spec[:,ii] id_dict={} id_dict["fiber"] = ii id_dict["status"] = "none" id_dict['id_pix'] = [] id_dict['id_idx'] = [] id_dict['id_wave'] = [] pixpk, flux = desiboot.find_arc_lines(spec) id_dict["pixpk"] = pixpk id_dict["flux"] = flux try: desiboot.id_arc_lines_using_triplets(id_dict, gd_lines, dlamb,ntrack=args.ntrack,nmax=args.nmax,toler=args.toler) except : log.warning(sys.exc_info()) log.warning("fiber {:d} ID_ARC failed".format(ii)) id_dict['status'] = "failed" id_dict_of_fibers.append(id_dict) continue # Add lines if len(id_dict['pixpk'])>len(id_dict['id_pix']) : desiboot.id_remainder(id_dict, llist, deg=args.legendre_degree) log.info("Fiber #{:d} n_match={:d} n_detec={:d}".format(ii,len(id_dict['id_pix']),len(id_dict['pixpk']))) # Save id_dict_of_fibers.append(id_dict) # now record the list of waves identified in several fibers matched_lines=np.array([]) for ii in range(all_spec.shape[1]): matched_lines = np.append(matched_lines,id_dict_of_fibers[ii]['id_wave']) matched_lines = np.unique(matched_lines) number_of_detections = [] for line in matched_lines : ndet=0 for ii in range(all_spec.shape[1]): if np.sum(id_dict_of_fibers[ii]['id_wave']==line) >0 : ndet += 1 print(line,"ndet=",ndet) number_of_detections.append(ndet) # choose which lines are ok and # ok if 5 detections (coincidental error very low) min_number_of_detections=min(5,all_spec.shape[1]) number_of_detections=np.array(number_of_detections) good_matched_lines = matched_lines[number_of_detections>=min_number_of_detections] bad_matched_lines = matched_lines[number_of_detections<min_number_of_detections] log.info("good matched lines = {:s}".format(str(good_matched_lines))) log.info("bad matched lines = {:s}".format(str(bad_matched_lines))) # loop again on all fibers for ii in range(all_spec.shape[1]): spec = all_spec[:,ii] id_dict = id_dict_of_fibers[ii] n_matched_lines=len(id_dict['id_wave']) n_detected_lines=len(id_dict['pixpk']) # did we find any bad line for this fiber? n_bad = np.intersect1d(id_dict['id_wave'],bad_matched_lines).size # how many good lines did we find n_good = np.intersect1d(id_dict['id_wave'],good_matched_lines).size if id_dict['status']=="ok" and ( n_bad>0 or (n_good < good_matched_lines.size-1 and n_good<30) ) and n_good<40 : log.info("Try to refit fiber {:d} with n_bad={:d} and n_good={:d} when n_good_all={:d} n_detec={:d}".format(ii,n_bad,n_good,good_matched_lines.size,n_detected_lines)) try: desiboot.id_arc_lines_using_triplets(id_dict, good_matched_lines, dlamb,ntrack=args.ntrack,nmax=args.nmax) except: log.warning(sys.exc_info()) log.warning("ID_ARC failed on fiber {:d}".format(ii)) id_dict["status"]="failed" if id_dict['status']=="ok" and len(id_dict['pixpk'])>len(id_dict['id_pix']) : desiboot.id_remainder(id_dict, llist, deg=args.legendre_degree) else : log.info("Do not refit fiber {:d} with n_bad={:d} and n_good={:d} when n_good_all={:d} n_detec={:d}".format(ii,n_bad,n_good,good_matched_lines.size,n_detected_lines)) if id_dict['status'] != 'ok': all_wv_soln.append(id_dict) all_dlamb.append(0.) log.warning("Fiber #{:d} failed, no final fit".format(ii)) continue # Final fit wave vs. pix too id_wave=np.array(id_dict['id_wave']) id_pix=np.array(id_dict['id_pix']) deg=max(1,min(args.legendre_degree,id_wave.size-2)) final_fit, mask = dufits.iter_fit(id_wave,id_pix, 'polynomial', deg, xmin=0., xmax=1., sig_rej=3.) rms = np.sqrt(np.mean((dufits.func_val(id_wave[mask==0], final_fit)-id_pix[mask==0])**2)) final_fit_pix,mask2 = dufits.iter_fit(id_pix[mask==0],id_wave[mask==0],'legendre',deg , sig_rej=100000000.) rms_pix = np.sqrt(np.mean((dufits.func_val(id_pix[mask==0], final_fit_pix)-id_wave[mask==0])**2)) # Append wave = dufits.func_val(np.arange(spec.size),final_fit_pix) idlamb = np.median(np.abs(wave-np.roll(wave,1))) all_dlamb.append(idlamb) # Save id_dict['final_fit'] = final_fit id_dict['rms'] = rms id_dict['final_fit_pix'] = final_fit_pix id_dict['wave_min'] = dufits.func_val(0,final_fit_pix) id_dict['wave_max'] = dufits.func_val(ny-1,final_fit_pix) id_dict['mask'] = mask log.info("Fiber #{:d} final fit rms(y->wave) = {:g} A ; rms(wave->y) = {:g} pix ; nlines = {:d}".format(ii,rms,rms_pix,id_pix.size)) all_wv_soln.append(id_dict) if QA: desiboot.qa_arc_spec(all_spec, all_wv_soln, pp) desiboot.qa_fiber_arcrms(all_wv_soln, pp) desiboot.qa_fiber_dlamb(all_spec, all_wv_soln, pp) else: all_wv_soln = None ########### # Write PSF file log.info("Writing PSF file") desiboot.write_psf(args.outfile, xfit, fdicts, gauss, all_wv_soln, legendre_deg=args.legendre_degree , without_arc=args.trace_only, XCOEFF=XCOEFF,fiberflat_header=contfile_header,arc_header=arc_header) log.info("Successfully wrote {:s}".format(args.outfile)) if ( not args.trace_only ) and args.out_line_list : log.info("Writing list of lines found in {:s}".format(args.out_line_list)) desiboot.write_line_list(args.out_line_list,all_wv_soln,llist) log.info("Successfully wrote {:s}".format(args.out_line_list)) ########### # All done if QA: log.info("Successfully wrote {:s}".format(args.qafile)) pp.close() log.info("end") return
def wdisp(self,ispec,wave): #- wave: scalar or vector, ispec: scalar integer TODO: make useful for other permutations if hasattr(self,'wcoeff'): new_dict=dufits.mk_fit_dict(self.wcoeff[ispec],self.wcoeff.shape[1],'legendre',self.wmin,self.wmax) wsigma=dufits.func_val(wave,new_dict) return wsigma