def fit_rings(file, trim_rad=470, disp=None): """ main routine to take a FITS file, read it in, azimuthally average it, find the rings, and then fit voigt profiles to them. Parameters ---------- file : string filename of FITS file to analyze trim_rad : int maximum radial extent of profile disp : boolean to control DS9 display of image Returns ------- list containing: boolean - success of finding peaks or not numpy array - wavelengths of profile numpy array - radial flux profile data numpy array - best-fit radial flux profile dict - parameters of best-fit """ hdu = pyfits.open(file) (data, header) = (hdu[0].data, hdu[0].header) etalon = int(header['ET-STATE'].split()[3]) etwave_key = "ET%dWAVE0" % etalon name_key = "ET%dMODE" % etalon etname = header[name_key] cenwave = float(header[etwave_key]) binning = int(header['CCDSUM'].split()[0]) if header['OBSMODE'] != 'FABRY-PEROT': return False, np.empty(1), np.empty(1), np.empty(1), np.empty(1) ysize, xsize = data.shape # cut FP image down to square fp_im = data[:, (xsize - ysize) / 2: (xsize + ysize) / 2] if disp: disp.set_np2arr(fp_im, dtype=np.int32) # mask those gaps fp_im = ma.masked_less_equal(data[:, (xsize - ysize) / 2: (xsize + ysize) / 2], 0.0) # define center based on FP ghost imaging with special mask xc = 2054 / binning yc = 2008 / binning # print "FP ring centre should be at x= %.1f y= %.1f" % (xc+280, yc) #Find the list of rings: ring_list=findrings(data, thresh=5, niter=5, minsize=10) print "%1d ring(s) found" % (len(ring_list)) sxc=syc=0 for i in range(len(ring_list)): ring_list[i]=findcenter(data, ring_list[i], method='center') print "Ring number %1d: centre at X= %.1f, Y=%.1f, Radius= %.1f" % (i+1, ring_list[i].xc, ring_list[i].yc,ring_list[i].prad) if ring_list[i].prad > 250 and ring_list[i].prad < 390: sxc=ring_list[i].xc syc=ring_list[i].yc # xcn,ycn=find_center(fp_im,xc,yc) if sxc >0 and syc > 0: print "Found ring centre at x= %.1f y= %.1f" % (sxc, syc) xc=sxc-280 yc=syc #Xc0 and Yc0 is the ring centre for a good ring # Ted's values: xc0=802 yc0=503 #From Tim's: # xc0=800 # yc0=500 deltaX=int(3.6*(syc-yc0)) deltaY=int(4.7*((sxc)-xc0)) # print "With this new centre, recommend dX= %1d, dY=%1d" % (deltaX, deltaY) else: print "Found ring centre at x= %.1f y= %.1f" % (sxc, syc) print "Using FP ghost ring centre at x= %.1f y= %.1f" % (xc+280, yc) # we use the 4x4 version of trim_rad since the vast majority of FP # data is taken with 4x4 binning trim_rad *= 4 / binning mask_val = 0.0 f = {} if cenwave < 5200: f['MR'] = 22149.6 f['LR'] = 22795.92 f['TF'] = 24360.32 if cenwave > 6500 and cenwave < 6600: f['MR'] = 22713.0 f['LR'] = 24191.40 f['TF'] = 24360.32 if cenwave >= 6600 and cenwave < 6700: f['MR'] = 22848.0 f['LR'] = 24169.32 f['TF'] = 23830.20 if cenwave >= 6700 and cenwave < 6900: f['MR'] = 22828.92 f['LR'] = 24087.68 f['TF'] = 24553.32 if cenwave >= 7300 and cenwave < 7700: f['MR'] = 22864.06 f['LR'] = 24087.68 f['TF'] = 24553.32 else: f['MR'] = 22828.92 f['LR'] = 24400.32 f['TF'] = 24553.32 # get the radial profile and flatten it with a default QTH flat profile prof, r = FP_profile(fp_im, xc, yc, trim_rad=trim_rad, mask=mask_val) # Not flatfielding the profile as ring already flat-fielded using saltflat. # prof = flatprof(prof, binning) wave = cenwave / np.sqrt(1.0 + (r * binning / f[etname]) ** 2) # find the peaks and bail out if none found npeaks, peak_list = find_peaks(prof, width=40) if npeaks < 1: print "No peaks found." return False, np.empty(1), np.empty(1), np.empty(1), np.empty(1) print "Found %d rings at:" % npeaks cenwidth = 20 for peak in peak_list: cen_peak = centroid(prof, peak, cenwidth) if np.isnan(cen_peak): cen_peak = peak print "\t R %f" % cen_peak if disp: disp.set("regions command {circle %f %f %f # color=red}" % (xc, yc, cen_peak)) # max_r = peak_list[0] # pmax = prof[max_r] back = 250.0 fwhm = 5.0 gam = 1.0 init = [back] bounds = [(0.0, 2.0e8)] # keep brightest peak = peak_list[0] # position init.append(cenwave / np.sqrt(1.0 + (peak * binning / f[etname]) ** 2)) bounds.append((cenwave - 30, cenwave + 30)) # amplitude init.append(prof[peak]) bounds.append((0.0, 1.0e8)) # FWHM init.append(fwhm) bounds.append((0.1, 20.0)) # gamma init.append(gam) bounds.append((0.0, 5.0)) ### keep these around in case we want to try again someday # #fit = opt.fmin_slsqp(fit_func, init, args=(prof, wave), # bounds=bounds) #fit, nfeval, rc = opt.fmin_tnc(fit_func, init, args=(prof, wave), # epsilon=0.0001, # bounds=bounds, # approx_grad=True, # disp=0, # maxfun=5000) # good ol' powell method FTW fit = opt.fmin_powell(fit_func, init, args=(prof, wave), ftol=0.00001, full_output=False, disp=False) #print "Return code: %s" % opt.tnc.RCSTRINGS[rc] pars = {} fit_v = fit[0] print "\nBackground = %f" % fit[0] pars['Background'] = fit[0] pars['R'] = [] pars['Amplitude'] = [] pars['Gauss FWHM'] = [] pars['Gamma'] = [] pars['FWHM'] = [] for i in range(1, len(fit), 4): fwhm = voigt_fwhm(fit[i + 2], fit[i + 3]) pars['R'].append(fit[i]) pars['Amplitude'].append(fit[i + 1]) pars['Gauss FWHM'].append(fit[i + 2]) pars['Gamma'].append(fit[i + 3]) pars['FWHM'].append(fwhm) fit_v = fit_v + qvoigt(wave, fit[i + 1], fit[i], fit[i + 2], fit[i + 3]) return True, wave, prof, fit_v, pars
def fit_rings(file, flatfile=None, disp=None): if flatfile: flat = np.loadtxt(flatfile) hdu = pyfits.open(file) (data, header) = (hdu[1].data, hdu[0].header) etalon = int(header['ET-STATE'].split()[3]) etwave_key = "ET%dWAVE0" % etalon name_key = "ET%dMODE" % etalon etname = header[name_key] cenwave = float(header[etwave_key]) binning = int(header['CCDSUM'].split()[0]) if header['OBSMODE'] != 'FABRY-PEROT': return False, np.empty(1), np.empty(1), np.empty(1), np.empty(1) ysize, xsize = data.shape # cut FP image down to square fp_im = data[:, (xsize - ysize) / 2:(xsize + ysize) / 2] if disp: disp.set_np2arr(fp_im, dtype=np.int32) # mask those gaps fp_im = ma.masked_less_equal( data[:, (xsize - ysize) / 2:(xsize + ysize) / 2], 0.0) # first guess is the center of the aperture (assume 4x4 binning here) xc = 4 * 513.5 / binning yc = 4 * 514.5 / binning mask_val = 0.0 f = {} f['MR'] = 22848.0 f['LR'] = 24169.32 # find brightest ring and refine center cenwidth = 20 if flatfile: prof, r = FP_profile(fp_im, xc, yc, trim_rad=len(flat), mask=mask_val) prof = prof / flat else: prof, r = FP_profile(fp_im, xc, yc, trim_rad=4 * 450.0 / binning, mask=mask_val) wave = cenwave / np.sqrt(1.0 + (r * binning / f[etname]) ** 2) npeaks, peak_list = find_peaks(prof, width=40) if npeaks < 1: print "No peaks found." return False, np.empty(1), np.empty(1), np.empty(1), np.empty(1) print "Found %d rings at:" % npeaks for peak in peak_list: cen_peak = centroid(prof, peak, cenwidth) if np.isnan(cen_peak): cen_peak = peak print "\t R %f" % cen_peak if disp: disp.set( "regions command {circle %f %f %f # color=red}" % (xc, yc, cen_peak)) back = 100.0 fwhm = 1.0 gam = 1.0 init = [back] # keep brightest if len(peak_list) > 1: peaks = peak_list[0:1] else: peaks = peak_list for peak in peaks: # position init.append(cenwave / np.sqrt(1.0 + (peak * binning / f[etname]) ** 2)) # amplitude init.append(prof[peak]) # FWHM init.append(fwhm) # gamma init.append(gam) #fit = opt.fmin_slsqp(fit_func, init, # args=(prof, rsq), bounds=bounds) #fit = opt.fmin_tnc(fit_func, init, # args=(prof, rsq), bounds=bounds, approx_grad=True) fit = opt.fmin_powell(fit_func, init, args=(prof, wave), ftol=0.00001, full_output=False, disp=False) pars = {} fit_v = fit[0] print "Background = %f" % fit[0] pars['Background'] = fit[0] pars['R'] = [] pars['Amplitude'] = [] pars['Gauss FWHM'] = [] pars['Gamma'] = [] pars['FWHM'] = [] for i in range(1, len(fit), 4): fwhm = voigt_fwhm(fit[i + 2], fit[i + 3]) pars['R'].append(fit[i]) pars['Amplitude'].append(fit[i + 1]) pars['Gauss FWHM'].append(fit[i + 2]) pars['Gamma'].append(fit[i + 3]) pars['FWHM'].append(fwhm) fit_v = fit_v + qvoigt(wave, fit[i + 1], fit[i], fit[i + 2], fit[i + 3]) return True, wave, prof, fit_v, pars
def fit_rings(file, trim_rad=470, disp=None): """ main routine to take a FITS file, read it in, azimuthally average it, find the rings, and then fit voigt profiles to them. Parameters ---------- file : string filename of FITS file to analyze trim_rad : int maximum radial extent of profile disp : boolean to control DS9 display of image Returns ------- list containing: boolean - success of finding peaks or not numpy array - wavelengths of profile numpy array - radial flux profile data numpy array - best-fit radial flux profile dict - parameters of best-fit """ hdu = pyfits.open(file) (data, header) = (hdu[1].data, hdu[0].header) etalon = int(header['ET-STATE'].split()[3]) etwave_key = "ET%dWAVE0" % etalon name_key = "ET%dMODE" % etalon etname = header[name_key] cenwave = float(header[etwave_key]) binning = int(header['CCDSUM'].split()[0]) if header['OBSMODE'] != 'FABRY-PEROT': return False, np.empty(1), np.empty(1), np.empty(1), np.empty(1) ysize, xsize = data.shape # cut FP image down to square fp_im = data[:, (xsize - ysize) / 2:(xsize + ysize) / 2] if disp: disp.set_np2arr(fp_im, dtype=np.int32) # mask those gaps fp_im = ma.masked_less_equal( data[:, (xsize - ysize) / 2:(xsize + ysize) / 2], 0.0) # define center based on FP ghost imaging with special mask xc = 2054 / binning yc = 2008 / binning # we use the 4x4 version of trim_rad since the vast majority of FP # data is taken with 4x4 binning trim_rad *= 4 / binning mask_val = 0.0 f = {} if cenwave < 5200: f['MR'] = 22149.6 f['LR'] = 22795.92 f['TF'] = 24360.32 if cenwave > 6500 and cenwave < 6600: f['MR'] = 22713.0 f['LR'] = 24191.40 f['TF'] = 24360.32 if cenwave >= 6600 and cenwave < 6700: f['MR'] = 22848.0 f['LR'] = 24169.32 f['TF'] = 23830.20 if cenwave >= 6700 and cenwave < 6900: f['MR'] = 22828.92 f['LR'] = 24087.68 f['TF'] = 24553.32 else: f['MR'] = 22828.92 f['LR'] = 24400.32 f['TF'] = 24553.32 # get the radial profile and flatten it with a default QTH flat profile prof, r = FP_profile(fp_im, xc, yc, trim_rad=trim_rad, mask=mask_val) prof = flatprof(prof, binning) wave = cenwave / np.sqrt(1.0 + (r * binning / f[etname])**2) # find the peaks and bail out if none found npeaks, peak_list = find_peaks(prof, width=40) if npeaks < 1: print "No peaks found." return False, np.empty(1), np.empty(1), np.empty(1), np.empty(1) print "Found %d rings at:" % npeaks cenwidth = 20 for peak in peak_list: cen_peak = centroid(prof, peak, cenwidth) if np.isnan(cen_peak): cen_peak = peak print "\t R %f" % cen_peak if disp: disp.set("regions command {circle %f %f %f # color=red}" % (xc, yc, cen_peak)) # max_r = peak_list[0] # pmax = prof[max_r] back = 250.0 fwhm = 5.0 gam = 1.0 init = [back] bounds = [(0.0, 2.0e8)] # keep brightest peak = peak_list[0] # position init.append(cenwave / np.sqrt(1.0 + (peak * binning / f[etname])**2)) bounds.append((cenwave - 30, cenwave + 30)) # amplitude init.append(prof[peak]) bounds.append((0.0, 1.0e8)) # FWHM init.append(fwhm) bounds.append((0.1, 20.0)) # gamma init.append(gam) bounds.append((0.0, 5.0)) ### keep these around in case we want to try again someday # #fit = opt.fmin_slsqp(fit_func, init, args=(prof, wave), # bounds=bounds) #fit, nfeval, rc = opt.fmin_tnc(fit_func, init, args=(prof, wave), # epsilon=0.0001, # bounds=bounds, # approx_grad=True, # disp=0, # maxfun=5000) # good ol' powell method FTW fit = opt.fmin_powell(fit_func, init, args=(prof, wave), ftol=0.00001, full_output=False, disp=False) #print "Return code: %s" % opt.tnc.RCSTRINGS[rc] pars = {} fit_v = fit[0] print "\nBackground = %f" % fit[0] pars['Background'] = fit[0] pars['R'] = [] pars['Amplitude'] = [] pars['Gauss FWHM'] = [] pars['Gamma'] = [] pars['FWHM'] = [] for i in range(1, len(fit), 4): fwhm = voigt_fwhm(fit[i + 2], fit[i + 3]) pars['R'].append(fit[i]) pars['Amplitude'].append(fit[i + 1]) pars['Gauss FWHM'].append(fit[i + 2]) pars['Gamma'].append(fit[i + 3]) pars['FWHM'].append(fwhm) fit_v = fit_v + qvoigt(wave, fit[i + 1], fit[i], fit[i + 2], fit[i + 3]) return True, wave, prof, fit_v, pars
def fit_rings(file, trim_rad=470, disp=None): """ main routine to take a FITS file, read it in, azimuthally average it, find the rings, and then fit voigt profiles to them. Parameters ---------- file : string filename of FITS file to analyze trim_rad : int maximum radial extent of profile disp : boolean to control DS9 display of image Returns ------- list containing: boolean - success of finding peaks or not numpy array - wavelengths of profile numpy array - radial flux profile data numpy array - best-fit radial flux profile dict - parameters of best-fit """ hdu = pyfits.open(file) (data, header) = (hdu[1].data, hdu[0].header) etalon = int(header["ET-STATE"].split()[3]) etwave_key = "ET%dWAVE0" % etalon name_key = "ET%dMODE" % etalon etname = header[name_key] cenwave = float(header[etwave_key]) binning = int(header["CCDSUM"].split()[0]) if header["OBSMODE"] != "FABRY-PEROT": return False, np.empty(1), np.empty(1), np.empty(1), np.empty(1) ysize, xsize = data.shape # cut FP image down to square fp_im = data[:, (xsize - ysize) / 2 : (xsize + ysize) / 2] if disp: disp.set_np2arr(fp_im, dtype=np.int32) # mask those gaps fp_im = ma.masked_less_equal(data[:, (xsize - ysize) / 2 : (xsize + ysize) / 2], 0.0) # define center based on FP ghost imaging with special mask xc = 2054 / binning yc = 2008 / binning # we use the 4x4 version of trim_rad since the vast majority of FP # data is taken with 4x4 binning trim_rad *= 4 / binning mask_val = 0.0 f = {} if cenwave < 5200: f["MR"] = 22149.6 f["LR"] = 22795.92 f["TF"] = 24360.32 if cenwave > 6500 and cenwave < 6600: f["MR"] = 22713.0 f["LR"] = 24191.40 f["TF"] = 24360.32 if cenwave >= 6600 and cenwave < 6700: f["MR"] = 22848.0 f["LR"] = 24169.32 f["TF"] = 23830.20 if cenwave >= 6700 and cenwave < 6900: f["MR"] = 22828.92 f["LR"] = 24087.68 f["TF"] = 24553.32 else: f["MR"] = 22828.92 f["LR"] = 24400.32 f["TF"] = 24553.32 # get the radial profile and flatten it with a default QTH flat profile prof, r = FP_profile(fp_im, xc, yc, trim_rad=trim_rad, mask=mask_val) prof = flatprof(prof, binning) wave = cenwave / np.sqrt(1.0 + (r * binning / f[etname]) ** 2) # find the peaks and bail out if none found npeaks, peak_list = find_peaks(prof, width=40) if npeaks < 1: print "No peaks found." return False, np.empty(1), np.empty(1), np.empty(1), np.empty(1) print "Found %d rings at:" % npeaks cenwidth = 20 for peak in peak_list: cen_peak = centroid(prof, peak, cenwidth) if np.isnan(cen_peak): cen_peak = peak print "\t R %f" % cen_peak if disp: disp.set("regions command {circle %f %f %f # color=red}" % (xc, yc, cen_peak)) # max_r = peak_list[0] # pmax = prof[max_r] back = 250.0 fwhm = 5.0 gam = 1.0 init = [back] bounds = [(0.0, 2.0e8)] # keep brightest peak = peak_list[0] # position init.append(cenwave / np.sqrt(1.0 + (peak * binning / f[etname]) ** 2)) bounds.append((cenwave - 30, cenwave + 30)) # amplitude init.append(prof[peak]) bounds.append((0.0, 1.0e8)) # FWHM init.append(fwhm) bounds.append((0.1, 20.0)) # gamma init.append(gam) bounds.append((0.0, 5.0)) ### keep these around in case we want to try again someday # # fit = opt.fmin_slsqp(fit_func, init, args=(prof, wave), # bounds=bounds) # fit, nfeval, rc = opt.fmin_tnc(fit_func, init, args=(prof, wave), # epsilon=0.0001, # bounds=bounds, # approx_grad=True, # disp=0, # maxfun=5000) # good ol' powell method FTW fit = opt.fmin_powell(fit_func, init, args=(prof, wave), ftol=0.00001, full_output=False, disp=False) # print "Return code: %s" % opt.tnc.RCSTRINGS[rc] pars = {} fit_v = fit[0] print "\nBackground = %f" % fit[0] pars["Background"] = fit[0] pars["R"] = [] pars["Amplitude"] = [] pars["Gauss FWHM"] = [] pars["Gamma"] = [] pars["FWHM"] = [] for i in range(1, len(fit), 4): fwhm = voigt_fwhm(fit[i + 2], fit[i + 3]) pars["R"].append(fit[i]) pars["Amplitude"].append(fit[i + 1]) pars["Gauss FWHM"].append(fit[i + 2]) pars["Gamma"].append(fit[i + 3]) pars["FWHM"].append(fwhm) fit_v = fit_v + qvoigt(wave, fit[i + 1], fit[i], fit[i + 2], fit[i + 3]) return True, wave, prof, fit_v, pars