def id(self, wave, feature): # Get closest feature to input value lines = scipy.asarray(self.linelist) diff = abs(lines - feature) if diff.min() < 3.: feature = lines[diff.argmin()] disp = self.wave[1] - self.wave[0] indx = scipy.where(abs(wave - self.wave) < disp)[0][0] if indx < 5 or indx > self.wave.size - 4: self.lineid(wave, feature) return fitdata = scipy.empty((11, 2)) fitdata[:, 0] = self.wave[indx - 5:indx + 6] fitdata[:, 1] = self.current[indx - 5:indx + 6] fit = scipy.zeros(4) fit[1] = self.current[indx] fit[2] = wave fit[3] = 2. fit, chi2 = special_functions.ngaussfit(fitdata, fit) if abs(fit[2] - wave) > 5.: self.lineid(wave, feature) else: self.lineid(fit[2], feature) self.collect.append(self.z)
def get_line_resolution(line, file): import pyfits from mostools import spectools as st spec = pyfits.open(file)[3].data.copy() wave = st.wavelength(file, 1) data = spec.astype(scipy.float64) data[scipy.isnan(data)] = 0. size = data.size bg = ndimage.percentile_filter(data, 20, 55) bg = ndimage.gaussian_filter(bg, 7) data -= bg pos = abs(wave - line).argmin() fitdata = scipy.zeros((15, 2)) fitdata[:, 0] = wave[pos - 7:pos + 8] fitdata[:, 1] = data[pos - 7:pos + 8] par = scipy.zeros(4) par[1] = data[pos] par[2] = line par[3] = 1. fit, chi2 = special_functions.ngaussfit(fitdata, par) pixsize = wave[pos] - wave[pos - 1] if fit[3] > 5. * pixsize or fit[3] < 0.8 * pixsize or abs( fit[2] - wave[pos]) > 1.5 * fit[3]: print 'Could not fit for resolution of spectral line' print fit return 0 v = fit[2] / fit[3] return 299792. / v
def get_ap(slit, B, R, apcent, apnum, wid, order): xproj = np.median(slit[:, B:R], 1) m, s = clip(xproj) smooth = ndimage.gaussian_filter(xproj, 1) if order == 3.: smooth = ndimage.gaussian_filter(xproj[:-30], 1) x = np.arange(xproj.size) * 1. """ The four parameters immediately below are the initial guesses bkgd, amplitude, mean location, and sigma for a Gaussian fit """ fit = np.array([0., smooth.max(), smooth.argmax(), 1.]) fit = sf.ngaussfit(xproj, fit)[0] cent = fit[2] + apcent[apnum] / arcsecperpix[order - 1] print cent apmax = 0.1 * xproj.max() ap = np.where(abs(x - cent) < wid / arcsecperpix[order - 1], 1., 0.) if order < 60.: plt.subplot(2, 5, order) plt.plot(x, apmax * ap) # Scale the aperture to easily see it plt.plot(x, xproj) plt.ylim(-apmax, 1.1 * xproj.max()) ap = ap.repeat(slit.shape[1]).reshape(slit.shape) return ap, fit
def measure(spectrum, num=25): """ measure(spectrum,num=25) Deterines the spectral resolution for a spectrum by measuring the width of arc or skylines. Inputs: spectrum - 1d spectrum num - maximum number of lines to measure (not implemented) Outputs: median resolution of all lines extracted """ data = spectrum.astype(scipy.float64) size = data.size pixels = scipy.arange(size) * 1. avg, std = clipped(data, 3.) thresh = avg + 30. * std # Only measure 30 sigma lines """ Identify peaks. """ mask = ndimage.maximum_filter(data, 13) mask = scipy.where(mask == data, data, 0) lines = scipy.where((mask > thresh) & (mask < 50000.))[0] count = 0 vals = [] for pos in lines: """ Don't use lines near the edges. """ if pos < 5 or pos + 6 > size: continue fitdata = scipy.zeros((11, 2)) fitdata[:, 0] = pixels[pos - 5:pos + 6] fitdata[:, 1] = data[pos - 5:pos + 6] par = scipy.zeros(4) par[1] = data[pos] par[2] = pixels[pos] par[3] = 1. fit, chi2 = special_functions.ngaussfit(fitdata, par) fit[2] -= fitdata[0, 0] """ Reject fits that were 'too' wide or narrow, or not near the expected center. """ if fit[3] > 4. or fit[3] < 0.8 or fit[2] < 2 or fit[2] > 9: continue vals.append(fit[3]) count += 1 vals = scipy.asarray(vals) if vals.size == 0: return 1. return scipy.median(vals)
def measure(file,num=25): f = pyfits.open(file) data = f[0].data.astype(scipy.float64)/1000. size = data.size wave = spectools.wavelength(file) sorted = scipy.sort(data) zero = sorted[size/20:size/10].mean() sigma = sorted[size/20:size/10].std() thresh = zero+100*sigma count = 0 search = data.copy() vals = scipy.zeros(num) place = scipy.zeros(num) while count<num: max = search.max() if max<thresh: break pos = search.argmax() search[pos-5:pos+6] = 0. if pos<5 or pos+6>size: continue fitdata = scipy.zeros((11,2)) fitdata[:,0] = wave[pos-5:pos+6] fitdata[:,1] = data[pos-5:pos+6] par = scipy.zeros(4) par[1] = max par[2] = wave[pos] par[3] = wave[pos]-wave[pos-1] fit,chi2 = special_functions.ngaussfit(fitdata,par) if chi2>4: continue model = special_functions.ngauss(fitdata[:,0],fit) pylab.plot(wave[pos-5:pos+6],model) feature = wave[pos] width = fit[3]*299800/feature vals[count] = width place[count] = feature count += 1 args = place.argsort() vals = vals[args] place = place[args] return scipy.median(vals)
def find_peak(data): size = data.shape[0] fit_data = scipy.reshape(scipy.arange(0, size, 0.5), (size, 2)) fit_data[:, 1] = data.copy() fit = scipy.zeros(4) fit[0] = 0. fit[1] = data.max() fit[2] = data.argmax() fit[3] = 2. fit, val = special_functions.ngaussfit(fit_data, fit) return fit
def findlines(x,z,sigma=5.): """ Peak finding """ tmp = ndimage.maximum_filter(z,9) peaks = scipy.where(tmp==z,z,0) """ Only choose >sigma lines """ avg = ndimage.percentile_filter(z,30.,55) tmp = scipy.where(peaks>0.)[0] peaks = [] for i in tmp: start = i-150 end = i+150 if start<0: start = 0 if end>z.size: end = z.size mean,std = clipped_std(z[start:end],3.5) if z[i]>avg[i]+sigma*std: peaks.append(i) """ Centroid the lines, fixing the zeropoint of the gaussians to avg """ fit = scipy.ones(8) fit[4] = 0. datalines = [] for i in peaks: if i-14<0 or i+15>x.size: continue fit[0] = avg[i] fit[1] = z[i] fit[2] = x[i] fit[3] = 1. """ Deal with saturated lines appropriately (ie skipping the non-linear pixels) """ if z[i]<SATURATED: fitdata = scipy.empty((9,2)) fitdata[:,0] = x[i-4:i+5].copy() fitdata[:,1] = z[i-4:i+5].copy() else: fitdata = scipy.empty((25,2)) fitdata[:,0] = x[i-12:i+13].copy() fitdata[:,1] = z[i-12:i+13].copy() fitdata = fitdata[fitdata[:,1]<SATURATED*0.8] """ A simple weighted sum would probably be robust.... """ gfit,chi2 = special_functions.ngaussfit(fitdata,fit) datalines.append(gfit[2]) return scipy.asarray(datalines)
def medsubtract(image,outname): data = pyfits.open(image)[0].data.copy() if data.ndim==3: data = data[0].copy() tmp = data.copy() tmp[numpy.isnan(tmp)] = 0. tmp -= numpy.sort(tmp,0)[tmp.shape[0]/5] trace = tmp.sum(1) peak = trace.argmax() center = numpy.empty(data.shape[1]) w = center.copy() for i in range(1+center.size/100): b = i*100 e = b+100 if e>center.size: e = center.size if b==e: continue center[b:e] = tmp[:,b:e].sum(1).argmax() bg = center.copy() x = numpy.arange(data.shape[0]) for i in range(center.size): d = tmp[:,i].copy() peak = center[i] if numpy.isnan(d[peak]): center[i] = peak continue fit = numpy.array([0.,d[peak],peak,1.]) cond = ~numpy.isnan(d) input = numpy.empty((d[cond].size,2)) input[:,0] = x[cond].copy() input[:,1] = d[cond].copy() fit,chi = sf.ngaussfit(input,fit) center[i] = fit[2] w[i] = fit[3] fit = sf.lsqfit(ndimage.median_filter(center,17),'polynomial',5) centroid = sf.genfunc(numpy.arange(bg.size),0.,fit) w = numpy.median(w) for i in range(bg.size): d = data[:,i].copy() d[centroid[i]-w*4:centroid[i]+w*4] = numpy.nan data[:,i] -= stats.nanmedian(d) hdu = pyfits.open(image)[0] hdu.data = data.copy() hdu.writeto(outname,clobber=True)
def findoffset(scidata,coord,offset,slice=None): straight = spectools.resampley(scidata,coord,offset,slice=slice) slice = straight.mean(axis=1) p = scipy.zeros(4) p[0] = slice.min() p[1] = slice.max() p[2] = slice.argmax() p[3] = 1. fit,val = special_functions.ngaussfit(slice,p) chi2 = val/(slice.size-4.) if fit[2]>0 and fit[2]<slice.size: return fit[2] else: return scipy.nan
def fitline(self, xpos): # Find local maximum to start fitting if self.solution == None: point = round(xpos) else: point = sf.genfunc(xpos, 0., self.inverse) point = point[0].round() print(point) center = self.data[point - 5:point + 6].argmax() + point - 5 print(self.data[point - 5:point + 6]) print(self.data[point - 5:point + 6].argmax()) max = self.data[center] fit = scipy.empty(4) fit[0] = 0. fit[1] = max fit[2] = 7. fit[3] = 2. fit, chi = sf.ngaussfit(self.data[center - 7:center + 8], fit) centroid = fit[2] + center - 7 print("Press enter to input wavelength") wave = float(input("Wavelength: ")) max = self.data[centroid - 2:centroid + 3].max() try: indx = self.lines.index(centroid) self.ids[indx] = wave except: self.lines.append(centroid) self.ids.append(wave) axis = self.ax.axis() fudge = 0.05 * (axis[3] - axis[2]) if self.solution == None: wave = centroid else: wave = sf.genfunc(centroid, 0., self.solution) mark = mpl.patches.Polygon([(wave, max + fudge), (wave, max + 2 * fudge)]) self.ax.add_patch(mark) self.markers[centroid] = mark pylab.draw()
def get_ap_oldham(self, slit, apcent, nsig, ordinfo, doplot=True): """ Defines a uniform aperture as in the example ESI extraction scripts from Lindsay """ B = ordinfo['pixmin'] R = ordinfo['pixmax'] xproj = np.median(slit[:, B:R], 1) m, s = df.sigclip(xproj) smooth = ndimage.gaussian_filter(xproj, 1) if ordinfo['name'] == 'Order 3': smooth = ndimage.gaussian_filter(xproj[:-30], 1) x = np.arange(xproj.size) * 1. """ The four parameters immediately below are the initial guesses bkgd, amplitude, mean location, and sigma for a Gaussian fit """ fit = np.array([0., smooth.max(), smooth.argmax(), 1.]) fit = sf.ngaussfit(xproj, fit)[0] cent = fit[2] + apcent / ordinfo['pixscale'] apymax = 0.1 * xproj.max() ap = np.where(abs(x - cent) < nsig / ordinfo['pixscale'], 1., 0.) # slit.apmin = cent - nsig # slit.apmax = cent + nsig if doplot: plt.subplot(2, 5, (ordinfo['order'])) plt.plot(x, apymax * ap) # Scale the aperture to easily see it plt.plot(x, xproj) plt.ylim(-apymax, 1.1 * xproj.max()) plt.axvline(cent, color='k', ls='dotted') ap = ap.repeat(slit.shape[1]).reshape(slit.shape) return ap, fit
def measure(spectrum, wave, nsig=30., num=25, show=False): """ measure(spectrum,num=25) Deterines the spectral resolution for a spectrum by measuring the width of arc or skylines. Inputs: spectrum - 1d spectrum wave - array containing wavelengths of points in file num - maximum number of lines to measure (not implemented) Outputs: median resolution of all lines extracted """ data = spectrum.astype(scipy.float64) data[scipy.isnan(data)] = 0. size = data.size bg = ndimage.percentile_filter(data, 20, 35) bg = ndimage.gaussian_filter(bg, 7) data -= bg avg, std = clipped(data, 2.0) thresh = avg + nsig * std # Only measure 30 sigma lines """ Identify isolated peaks. """ mask = ndimage.maximum_filter(data, 15) lines = scipy.where((mask == data) & (mask > thresh) & (mask < 50000.))[0] count = 0 vals = [] locs = [] for pos in lines: """ Don't use lines near the edges. """ if pos < 7 or pos + 8 > size: continue fitdata = scipy.zeros((15, 2)) fitdata[:, 0] = wave[pos - 7:pos + 8] fitdata[:, 1] = data[pos - 7:pos + 8] par = scipy.zeros(4) par[1] = data[pos] par[2] = wave[pos] par[3] = 1. fit, chi2 = special_functions.ngaussfit(fitdata, par) """ Reject fits that were 'too' wide or narrow, or not near the expected center. """ pixsize = wave[1] - wave[0] if fit[3] > 5. * pixsize or fit[3] < 0.8 * pixsize or abs( fit[2] - wave[pos]) > 1.5 * fit[3]: continue locs.append(fit[2]) vals.append(fit[2] / fit[3]) count += 1 vals = scipy.asarray(vals) if vals.size == 0: return 1. if show: import pylab pylab.plot(locs, vals) pylab.show() return scipy.median(vals), vals.size
def solve(d,orders): path = os.path.split(__file__)[0] lines = {} lines['cuar'] = numpy.loadtxt(path+"/data/cuar.lines") lines['hgne'] = numpy.loadtxt(path+"/data/hgne.lines") lines['xe'] = numpy.loadtxt(path+"/data/xe.lines") #startsoln = numpy.load(path+"/data/test_wavesol.dat", # allow_pickle=True) startsoln = numpy.load(path+"/data/esi_wavesolution.dat", allow_pickle=True) #arclist = d.keys() # Under python 3 this does not produce a list # and so arclist[0] below fails arclist = list(d) arclist.sort() soln = [] if d[arclist[0]].shape[1]>3000: xvals = numpy.arange(4096.) cuslice = slice(3860,3940) fw1 = 75. fw2 = 9 else: xvals = numpy.arange(1.,4096.,2.) cuslice = slice(1930,1970) fw1 = 37. fw2 = 5 """ Do a temporary kludge. In some cases, the finding of the orders fails, and only 9 orders are found. In this case, we need to skip the first of the orders """ if len(orders) == 9: ordstart = 1 dord = 1 else: ordstart = 0 dord = 0 for i in range(ordstart, 10): solution = startsoln[i] start,end = orders[(i-dord)] peaks = {} trace = {} fitD = {} WIDTH = 4 import pylab for arc in arclist: data = numpy.nanmedian(d[arc][start:end],axis=0) data[scipy.isnan(data)] = 0. if i==0 and arc=='cuar': data[cuslice] = numpy.median(data) trace[arc] = data.copy() bak = ndimage.percentile_filter(data,50.,int(fw1)) bak = getContinuum(bak,40.) data -= bak fitD[arc] = data/d[arc][start:end].std(0) p = ndimage.maximum_filter(data,fw2) std = clip(scipy.trim_zeros(data),3.)[1] nsig = ndimage.uniform_filter((data>7.*std)*1.,3) peak = scipy.where((nsig==1)&(p>10.*std)&(p==data))[0] peaks[arc] = [] for p in peak: if p-WIDTH<0 or p+WIDTH+1>xvals.size: continue x = xvals[p-WIDTH:p+WIDTH+1].copy()#-xvals[p] f = data[p-WIDTH:p+WIDTH+1].copy() fitdata = scipy.array([x,f]).T fit = scipy.array([0.,f.max(),xvals[p],1.]) fit,chi = sf.ngaussfit(fitdata,fit,weight=1) peaks[arc].append(fit[2])#+xvals[p]) for converge in range(15): wave = 10**sf.genfunc(xvals,0.,solution) refit = [] corrA = {} err = wave[int(wave.size/2)]-wave[int(wave.size/2-1)] for arc in arclist: corr = [] p = 10.**sf.genfunc(peaks[arc],0.,solution) for k in range(p.size): cent = p[k] diff = cent-lines[arc] corr.append(diff[abs(diff).argmin()]) corr = numpy.array(corr) if corr.size<4: continue m,s = clip(corr) corr = numpy.median(corr[abs(corr-m)<5.*s]) print(corr) corrA[arc] = corr # corr = m #for arc in arclist: p = 10.**sf.genfunc(peaks[arc],0.,solution) for k in range(p.size): pos = peaks[arc][k] cent = p[k] diff = abs(cent-lines[arc]-corr) if diff.min()<2.*err: refit.append([pos,lines[arc][diff.argmin()]]) refit = scipy.asarray(refit) solution = sf.lsqfit(refit,'polynomial',3) refit = [] err = solution['coeff'][1] for arc in arclist: data = trace[arc] for pos in peaks[arc]: cent = sf.genfunc(pos,0.,solution) delta = 1e9 match = None for j in lines[arc]: diff = abs(cent-j) if diff<delta and diff<1.*err: delta = diff match = j if match is not None: refit.append([pos,match]) refit = scipy.asarray(refit) refit[:,1] = numpy.log10(refit[:,1]) solution = sf.lsqfit(refit,'chebyshev',3) #refit[:,0],refit[:,1] = refit[:,1].copy(),refit[:,0].copy() #refit = numpy.array([refit[:,1],refit[:,0]]).T #refit = refit[:,::-1] solution2 = sf.lsqfit(refit[:,::-1],'chebyshev',3) #soln.append([solution,solution2]) w = 10**sf.genfunc(xvals,0.,solution) if (w==wave).all() or converge>8: print("Order %d converged in %d iterations"%(i,converge)) soln.append([solution,solution2]) break for arc in arclist: pylab.plot(w,trace[arc]) pylab.plot(w,fitD[arc]) pp = 10**sf.genfunc(peaks[arc],0.,solution) for p in pp: pylab.axvline(p,c='k') for j in 10**refit[:,1]: if j>w[0] and j<w[-1]: pylab.axvline(j) pylab.show() break return soln
def jointSolve(d,orders): import pylab path = __path__[0] lines = {} lines['cuar'] = numpy.loadtxt(path+"/data/cuar.lines") lines['hgne'] = numpy.loadtxt(path+"/data/hgne.lines") lines['xe'] = numpy.loadtxt(path+"/data/xe.lines") startsoln = numpy.load(path+"/data/esi_wavesolution.dat") startsoln = numpy.load(path+'/data/shao_wave.dat') startsoln = [i for i,j in startsoln] alldata = d['arc'] arclist = d.keys() arclist.remove('arc') soln = [] if alldata.shape[1]>3000: xvals = numpy.arange(4096.) resolve = False cuslice = slice(3860,3940) fw1 = 75. fw2 = 9 WIDTH = 4 else: xvals = numpy.arange(2048.) resolve = True cuslice = slice(1930,1970) fw1 = 37. fw2 = 7 WIDTH = 3 for i in range(10): solution = startsoln[i] start,end = orders[i] if resolve==True: tmp = numpy.arange(0.5,4096.,2.) w = sf.genfunc(tmp,0.,solution) solution = sf.lsqfit(numpy.array([xvals,w]).T,'chebyshev',3) data = numpy.nanmedian(alldata[start:end],axis=0) data[numpy.isnan(data)] = 0. if i==0: data[cuslice] = numpy.median(data) bak = ndimage.percentile_filter(data,50.,int(fw1)) data -= bak peaks = [] p = ndimage.maximum_filter(data,fw2) std = clip(numpy.trim_zeros(data),3.)[1] peak = numpy.where((p>30.*std)&(p==data))[0] for p in peak: if p-WIDTH<0 or p+WIDTH+1>xvals.size: continue x = xvals[p-WIDTH:p+WIDTH+1].copy() f = data[p-WIDTH:p+WIDTH+1].copy() fitdata = numpy.array([x,f]).T fit = numpy.array([0.,f.max(),xvals[p],1.]) fit,chi = sf.ngaussfit(fitdata,fit,weight=1) peaks.append(fit[2]) for converge in range(10): wave = 10**sf.genfunc(xvals,0.,solution) refit = [] corr = [] err = wave[wave.size/2]-wave[wave.size/2-1] p = 10.**sf.genfunc(peaks,0.,solution) for arc in arclist: for k in range(p.size): if i==0 and p[k]>4344.: continue cent = p[k] diff = cent-lines[arc] corr.append(diff[abs(diff).argmin()]) corr = numpy.array(corr) corr = corr[abs(corr)<5*err] m,s = clip(corr) corr = numpy.median(corr[abs(corr-m)<5.*s]) for arc in arclist: for k in range(p.size): if i==0 and p[k]>4344.: continue pos = peaks[k] cent = p[k] diff = abs(cent-lines[arc]-corr) if diff.min()<2.*err: refit.append([pos,lines[arc][diff.argmin()]]) refit = numpy.asarray(refit) solution = sf.lsqfit(refit,'polynomial',3) refit = [] err = solution['coeff'][1] p = sf.genfunc(peaks,0.,solution) for k in range(p.size): delta = 1e9 match = None for arc in arclist: for j in lines[arc]: if i==0 and j>4344.: continue diff = abs(p[k]-j) if diff<delta and diff<1.*err: delta = diff match = j if match is not None: refit.append([peaks[k],match]) refit = numpy.asarray(refit) refit[:,1] = numpy.log10(refit[:,1]) solution = sf.lsqfit(refit,'chebyshev',3) solution2 = sf.lsqfit(refit[:,::-1],'chebyshev',3) g = 10**sf.genfunc(peaks,0.,solution) g2 = 10**sf.genfunc(peak,0.,solution) w = 10**sf.genfunc(xvals,0.,solution) if (w==wave).all(): print("Order %d converged in %d iterations"%(i,converge)) soln.append([solution,solution2]) break pylab.plot(w,data) for arc in arclist: for j in lines[arc]: if j>w[0] and j<w[-1]: pylab.axvline(j,c='b') for j in 10**refit[:,1]: if j>w[0] and j<w[-1]: pylab.axvline(j,c='r') for j in g: pylab.axvline(j,c='g') for j in g2: pylab.axvline(j,c='c') pylab.show() break return soln
def extract(image, varimage, outname, width=2., offset=0., pos=None, minwave=None, maxwave=None, response_image=None, response_model=None, regions=[], centroid=None): if outname.lower().find('fits') < 1: outname = "%s.fits" % outname resp = None respwave = None if response_image is not None: if response_model is None: # print "No response model included; not performing response correction." import cPickle resp = cPickle.load(open(response_image)) else: resp = get_response(response_image, response_model, regions) elif response_model is not None: print "No response image included; not performing response correction." if minwave is None: minwave = -10. if maxwave is None: maxwave = 1e99 data = pyfits.open(image)[0].data.copy() if data.ndim == 3: if data.shape[0] > 1: print "Only working on first image plane of 3D image." data = data[0].copy() wave = st.wavelength(image) indx = scipy.where((wave > minwave) & (wave < maxwave))[0] minx, maxx = indx.min(), indx.max() wave = wave[minx:maxx] data = data[:, minx:maxx] tmp = data.copy() tmp[numpy.isnan(data)] = 0. ospec = wave * 0. ovar = wave * 0. x = numpy.arange(data.shape[0]) if centroid is None: n = tmp.shape[1] / 100 peaks = [] bounds = numpy.linspace(0, tmp.shape[1], n + 1) for i in range(n): a, b = bounds[i], bounds[i + 1] p = tmp[:, a:b].sum(1).argmax() peaks.append([(a + b) / 2., p]) peak = sf.lsqfit(numpy.asarray(peaks), 'polynomial', 3) if pos is not None: peak['coeff'][0] = pos peaks = sf.genfunc(numpy.arange(tmp.shape[1]), 0., peak) center = wave * 0. for i in range(center.size): d = data[:, i].copy() peak = peaks[i] if peak < 0: peak = 0 if peak >= d.shape: peak = d.shape - 1. fit = numpy.array([0., d[peak], peak, 1.]) cond = ~numpy.isnan(d) input = numpy.empty((d[cond].size, 2)) input[:, 0] = x[cond].copy() input[:, 1] = d[cond].copy() fit = sf.ngaussfit(input, fit)[0] center[i] = fit[2] fit = sf.lsqfit(ndimage.median_filter(center, 17), 'polynomial', 5) centroid = sf.genfunc(scipy.arange(wave.size), 0., fit) #import pylab #pylab.plot(center-centroid) #pylab.show() xvals = scipy.arange(data.shape[0]) var = pyfits.open(varimage)[0].data.copy() if var.ndim == 3: var = var[0].copy() var = var[:, minx:maxx] cond = (numpy.isnan(var)) | (numpy.isnan(data)) for i in range(ovar.size): c = centroid[i] + offset wid = width mask = xvals * 0. mask[(xvals - c < wid) & (xvals - c > 0.)] = wid - (xvals[ (xvals - c < wid) & (xvals - c > 0.)] - c) mask[(xvals - c < wid - 1) & (xvals - c > 0.)] = 1. mask[(c - xvals < wid + 1) & (c - xvals > 0.)] = (wid + 1) - ( c - xvals[(c - xvals < wid + 1) & (c - xvals > 0.)]) mask[(c - xvals < wid) & (c - xvals > 0.)] = 1. mask[cond[:, i]] = 0. mask /= mask.sum() ospec[i] = (mask[~cond[:, i]] * data[:, i][~cond[:, i]]).sum() ovar[i] = ((mask[~cond[:, i]]**2) * var[:, i][~cond[:, i]]).sum() badpix = numpy.where(numpy.isnan(ospec))[0] ospec[badpix] = 0. ovar[badpix] = ovar[~numpy.isnan(ovar)].max() * 1e6 med = numpy.median(ospec) ospec /= med ovar /= med**2 if resp is not None: # if respwave is None: # resp = sf.genfunc(wave,0,resp) # else: # resp = interpolate.splrep(respwave,resp) resp = interpolate.splev(wave, resp) ospec *= resp ovar *= resp**2 st.make_spec(ospec, ovar, wave, outname, clobber=True) return centroid
def extract(data, varimg, fitwidth=10., extractwidth=1.5, thresh=5.): """ extract(data,varimg,width=WIDTH,nsig=NSIG,noise=NOISE) From an input 2d array, find and extract spectral traces. Inputs: data - 2d science spectrum varimg - 2d variance spectrum fitwidth - width to fit profile to in pixels extractwidth - width to extract (in sigma) thresh - signal/noise threshold for extraction Outputs: a list containing the [profile, extracted spectrum, a smoothed spectrum, the extracted variance spectrum] for each extracted trace """ WIDTH = fitwidth NSIG = extractwidth NOISE = thresh FILTSIZE = 7 data = data.copy() spectra = [] # Replace nan with zero data[scipy.isnan(data)] = 0. varimg[scipy.isnan(varimg)] = 0. data[scipy.isinf(data)] = 0. varimg[scipy.isinf(varimg)] = 0. # Create model of real flux. We ignore the slit ends, which may have # artifacts from the resampling. slit = data[:, 8:-8].astype(scipy.float32) var = varimg[:, 8:-8] # OK...so negative-variance also isn't good; set these pixels to zero var[var < 0] = 0 # Create noise models sigmaimg = slit / scipy.sqrt(var) highpix = scipy.where(sigmaimg > 1.5, sigmaimg, 0.) source_columns = highpix.sum(axis=0) # MASKING DISABLED (this would take only columns with lotsa flux...) # mask = scipy.where(source_columns>4.,1.,scipy.nan) mask = source_columns * 0. # Condition 1, dealing with bad pixels if (var == 0).any(): cond = var == 0 var[cond] = scipy.nan slit[cond] = scipy.nan mask = scipy.where(cond, 0, 1) flux = scipy.nansum(slit / var, axis=1) / scipy.nansum(1. / var, axis=1) noise = scipy.sqrt(scipy.nansum(var, axis=1)) / mask.sum(axis=1) # Condition 2, no masking elif scipy.nansum(mask) == 0: flux = (slit / var).sum(axis=1) / (1. / var).sum(axis=1) noise = scipy.sqrt(var.sum(axis=1)) / mask.size # Condition 3, masking else: fluxmodel = slit * mask noisemodel = var * mask noise = scipy.sqrt(scipy.nansum(noisemodel, axis=1)) / scipy.nansum(mask) flux = stats.stats.nanmean(fluxmodel, axis=1) # A smooth S/N estimate for the slit # sig2noise = ndimage.gaussian_filter1d(flux,1)/noise row = scipy.arange(flux.size) model = flux.copy() nspec = 10 # Maximum number of attempts while nspec: nspec -= 1 # Fit a gaussian around the peak of the S/N model start = model.argmax() - WIDTH end = model.argmax() + WIDTH + 1 if start < 0: start = 0. if end > model.size: end = model.size fitarr = model[start:end] p = scipy.zeros(4) p[1] = fitarr.max() p[2] = fitarr.argmax() p[3] = 2. fit, val = special_functions.ngaussfit(fitarr, p) chi2 = val / (fitarr.size - 3) fit[2] += start # If the centroid doesn't lie on the slit, get use the edge pix midcol = fit[2].round() if midcol >= flux.size: midcol = flux.size - 1 elif midcol < 0: midcol = 0 # Require a reasonable S/N and width if fit[3] > fitarr.size / 2. or fit[3] < 0.85: break elif fit[0] > 0 and fit[1] < NOISE * noise[midcol]: break elif fit[0] < 0 and fit[1] - fit[0] < NOISE * noise[midcol]: break else: fit[1] += fit[0] fit[0] = 0. # Subtract away a model of the source source = special_functions.ngauss(row, fit) model -= scipy.where(source > noise, source, 0.) # Skip Slits off the edge if fit[2] < 0 or fit[2] >= flux.size: continue # Skip residuals! if fit[1] < scipy.sqrt(flux[fit[2]]): continue fit[1] = 1. weight = special_functions.ngauss(row, fit) cond = (row > fit[2] - fit[3] * NSIG) & (row < fit[2] + fit[3] * NSIG) weight = scipy.where(cond, weight, 0) weight /= weight.sum() spec = weight * data.T spec = spec.sum(axis=1) varspec = weight * varimg.T varspec = varspec.sum(axis=1) spec[varspec == 0] = 0. smooth = signal.wiener(spec, FILTSIZE, varspec) smooth[scipy.isnan(smooth)] = 0. spectra.append([fit, spec, smooth, varspec]) return spectra