def test_under_fraserMode(self): 'Test ``bgFinder._fraserMode``' data = array(range(0, 255), int) b = bgFinder(data) r = b._fraserMode() self.assertAlmostEqual(4.5, r, places=1)
def test_stats(self): data = array(range(0, 255), int) b = bgFinder(data) r = b._stats() self.assertEqual(8, r[0]) self.assertAlmostEqual(85.1, r[1], places=1)
def test_gaussFit(self): data = array(range(0, 255), int) b = bgFinder(data) r = b._gaussFit() self.assertAlmostEqual(127.0, r, places=1) self.assertAlmostEqual(r, b.gauss[0], places=1) self.assertAlmostEqual(73.61159329, b.gauss[1], places=1)
def fitWithModelPSF(self, x_in, y_in, m_in=-1., fitWidth=7, bg=None, ftol=1.e-8, useLinePSF=False, verbose=False): """ This is still experimental and hasn't been fully vetted yet. Use at your own risk. """ self.useLinePSF = useLinePSF if fitWidth > self.psf.boxSize: raise NotImplementedError('Need to keep the fitWidth <= boxSize.') (A, B) = self.imageData.shape #ai = max(0,int(y_in)-fitWidth) #bi = min(A,int(y_in)+fitWidth+1) #ci = max(0,int(x_in)-fitWidth) #di = min(B,int(x_in)+fitWidth+1) dat = np.copy(self.imageData) if bg == None: bgf = bgFinder.bgFinder(self.imageData) bg = bgf.smartBackground() dmbg = dat - bg print('Subtracting background {}'.format(bg)) else: dmbg = dat - bg if m_in == -1.: if useLinePSF: m_in = self.psf.repFact * self.psf.repFact * np.sum( dat) / np.sum(self.psf.longPSF) else: m_in = self.psf.repFact * self.psf.repFact * np.sum( dat) / np.sum(self.psf.fullPSF) lsqf = opti.leastsq(resid, (x_in, y_in, m_in), args=(dmbg, self.psf, fitWidth, useLinePSF, verbose), maxfev=1000, ftol=ftol) fitPars = lsqf[0] l = likelihood_for_LS(fitPars, dat, bg, self.psf, boxWidth=fitWidth, useLinePSF=useLinePSF) fitPars = np.concatenate([fitPars, np.array([l])]) return fitPars
def __call__(self,moffatWidth,moffatSNR,initAlpha=5.,initBeta=2.,repFact=5,xWidth=51,yWidth=51, includeCheesySaturationCut=True,autoTrim=False,noVisualSelection=False,verbose=False): self.moffatWidth=moffatWidth self.moffatSNR=moffatSNR self.initAlpha=initAlpha self.initBeta=initBeta self.repFact=repFact self.fwhms=[] self.points=[] self.moffs=[] self.moffr=num.linspace(0,30,80) self.starsFlatR=[] self.starsFlatF=[] self.subsecs=[] self.goodStars=[] self.starsScat=None print 'Fitting stars with moffat profiles...' for j in range(len(self.XWIN_IMAGE)): if self.FLUX_AUTO[j]/self.FLUXERR_AUTO[j]>self.moffatSNR: if self.XWIN_IMAGE[j]-1<0 or self.XWIN_IMAGE[j]-1>=self.data.shape[1] or self.YWIN_IMAGE[j]-1<0 or self.YWIN_IMAGE[j]-1>=self.data.shape[0]: continue mpsf=psf.modelPSF(num.arange(xWidth),num.arange(yWidth),alpha=self.initAlpha,beta=self.initBeta,repFact=self.repFact) mpsf.fitMoffat(self.data,self.XWIN_IMAGE[j],self.YWIN_IMAGE[j],boxSize=self.moffatWidth,verbose=verbose) fwhm=mpsf.FWHM(fromMoffatProfile=True) #if includeCheesySaturationCut: # if (mpsf.fDist[0]-mpsf.bg)/(mpsf.moffat(0)*mpsf.A)<0.9: #cheesy saturation cut # #print 'Saturated' # continue #norm=Im.normalise(mpsf.subsec,[self.z1,self.z2]) norm=self.normer(mpsf.subSec) if fwhm<>None and not (num.isnan(mpsf.beta) or num.isnan(mpsf.alpha)): #print self.XWIN_IMAGE[j],self.YWIN_IMAGE[j],mpsf.alpha,mpsf.beta,fwhm print '{: 8.2f} {: 8.2f} {: 5.2f} {: 5.2f} {: 5.2f}'.format(self.XWIN_IMAGE[j],self.YWIN_IMAGE[j],mpsf.alpha,mpsf.beta,fwhm) self.subsecs.append(norm*1.) self.goodStars.append(True) self.moffs.append(mpsf.moffat(self.moffr)*1.) self.starsFlatR.append(psf.downSample2d(mpsf.repRads,mpsf.repFact)) self.starsFlatF.append((mpsf.subSec-mpsf.bg)/(mpsf.moffat(0)*mpsf.A)) self.moffs[len(self.moffs)-1]/=num.max(self.moffs[len(self.moffs)-1]) self.points.append([fwhm,mpsf.chi,mpsf.alpha,mpsf.beta,self.XWIN_IMAGE[j],self.YWIN_IMAGE[j],mpsf.bg]) self.points=num.array(self.points) self.goodStars=num.array(self.goodStars) if autoTrim: bg=bgFinder.bgFinder(self.points[:,0]) mode=bg('fraserMode') w=num.where(num.abs(self.points[:,0]-mode)>0.5) self.goodStars[w]=False self.figPSF=pyl.figure('Point Source Selector') self.sp1=pyl.subplot2grid((4,4),(0,1),colspan=3,rowspan=2) pyl.scatter(self.points[:,0],self.points[:,1],picker=True) pyl.title('Select PSF range with zoom and then close the plot window.') self.sp2=pyl.subplot2grid((4,4),(2,1),colspan=3,sharex=self.sp1,rowspan=1) bins=num.arange(num.min(self.points[:,0]),num.max(self.points[:,0])+0.5,0.5) pyl.hist(self.points[:,0],bins=bins) pyl.xlabel('FWHM (pix)') self.sp3=pyl.subplot2grid((4,4),(0,0),rowspan=2,sharey=self.sp1) pyl.hist(self.points[:,1],bins=30,orientation='horizontal') pyl.ylabel('RMS') self.sp4=pyl.subplot2grid((4,4),(2,0),rowspan=2) self.moffPatchList=[] self.showing=[] for j in range(len(self.moffs)): self.moffPatchList.append(self.sp4.plot(self.moffr,self.moffs[j])) self.showing.append(1) self.sp4.set_xlim(0,30) self.sp4.set_ylim(0,1.02) self.sp5=pyl.subplot2grid((4,4),(3,1)) self.sp5.set_aspect('equal') self.psfPlotLimits=[self.sp1.get_xlim(),self.sp1.get_ylim()] self.conn1=self.sp1.callbacks.connect('ylim_changed',self.PSFrange) self.conn2=pyl.connect('pick_event',self.ScatterPSF) if not noVisualSelection: pyl.show() fwhm_lim=self.sp1.get_xlim() chi_lim=self.sp1.get_ylim() w=num.where((self.points[:,0]>fwhm_lim[0])&(self.points[:,0]<fwhm_lim[1])&(self.points[:,1]>chi_lim[0])&(self.points[:,1]<chi_lim[1])&(self.goodStars==True)) pyl.close() goodFits=self.points[w] goodMeds=num.median(goodFits[:4],axis=0) goodSTDs=num.std(goodFits[:4],axis=0) return (goodFits,goodMeds,goodSTDs)
def fitDoubleWithModelPSF(self, x_in, y_in, X_in, Y_in, bRat_in, m_in=-1., bg=None, fitWidth=20, nWalkers=30, nBurn=50, nStep=100, useErrorMap=False, useLinePSF=False, verbose=False): """ Using emcee (It's hammer time!) two sources are fit using the provided psf to find the best x,y and amplitude, and confidence range on the fitted parameters. x_in, y_in, m_in, X_in, Y_in, bRat - initial guesses on the true centroids, the amplitude and brightness ratio of the two sources fitWidth - the width +- of x_in/y_in of the data used in the fit nWalkers, nBurn, nStep - emcee fitting paramters. If you don't know what these are RTFM bg - the background of the image. Needed for the uncertainty table. **Defaults to None.** When set to default, it will invoke the background measurement and apply that. Otherwise, it assumes you are dealing with background subtracted data already. useErrorMap - if true, a simple pixel uncertainty map is used in the fit. This is adopted as ue_ij=(imageData_ij+bg)**0.5, that is, the poisson noise estimate. Note the fit confidence range is only honest if useErrorMap=True. useLinePSF - use the TSF? If not, use the PSF verbose - if set to true, lots of information printed to screen """ self.useLinePSF = useLinePSF (A, B) = self.imageData.shape ai = max(0, int((y_in + Y_in) / 2) - fitWidth) bi = min(A, int((y_in + Y_in) / 2) + fitWidth + 1) ci = max(0, int((x_in + X_in) / 2) - fitWidth) di = min(B, int((x_in + X_in) / 2) + fitWidth + 1) dat = np.copy(self.imageData) if bg == None: bgf = bgFinder.bgFinder(self.imageData) bg = bgf.smartBackground() dat -= bg if not useErrorMap: ue = dat * 0.0 + 1. else: ue = (dat + bg)**0.5 if m_in == -1.: if useLinePSF: m_in = np.sum(dat) / np.sum(self.psf.longPSF) else: m_in = np.sum(dat) / np.sum(self.psf.fullPSF) nDim = 6 r0 = [] for ii in range(nWalkers): r0.append( np.array([x_in, y_in, m_in, X_in, Y_in, m_in * bRat_in]) + sci.randn(6) * np.array([1., 1., m_in * 0.4, 1., 1., m_in * 0.4 * bRat_in])) r0 = np.array(r0) sampler = emcee.EnsembleSampler(nWalkers, nDim, lnprobDouble, args=[ dat, (ai, bi, ci, di), self.psf, ue, self.useLinePSF, verbose ]) pos, prob, state = sampler.run_mcmc(r0, nBurn) sampler.reset() pos, prob, state = sampler.run_mcmc(pos, nStep, rstate0=state) self.samps = sampler.chain self.probs = sampler.lnprobability self.dat = np.copy(dat) self.fitted = True
def fitWithModelPSF(self, x_in, y_in, m_in=-1., fitWidth=20, nWalkers=20, nBurn=10, nStep=20, bg=None, useErrorMap=False, useLinePSF=False, fitRateAngle=False, rate_in=None, angle_in=None, exptime=None, pixScale=None, verbose=False, rand_pos=0.1): """ Using emcee (It's hammer time!) the provided image is fit using the provided psf to find the best x,y and amplitude, and confidence range on the fitted parameters. x_in, y_in, m_in - initial guesses on the true centroid and amplitude of the object fitWidth - the width +- of x_in/y_in of the data used in the fit nWalkers, nBurn, nStep - emcee fitting paramters. If you don't know what these are RTFM bg - the background of the image. Needed for the uncertainty table. **Defaults to None.** When set to default, it will invoke the background measurement and apply that. Otherwise, it assumes you are dealing with background subtracted data already. useErrorMap - if true, a simple pixel uncertainty map is used in the fit. This is adopted as ue_ij=(imageData_ij+bg)**0.5, that is, the poisson noise estimate. Note the fit confidence range is only honest if useErrorMap=True. useLinePSF - use the TSF? If not, use the PSF verbose - if set to true, lots of information printed to screen """ print "Initializing sampler" self.nForFitting = 0 self.useLinePSF = useLinePSF if fitWidth > self.psf.boxSize: raise NotImplementedError('Need to keep the fitWidth <= boxSize.') (A, B) = self.imageData.shape ai = max(0, int(y_in) - fitWidth) bi = min(A, int(y_in) + fitWidth + 1) ci = max(0, int(x_in) - fitWidth) di = min(B, int(x_in) + fitWidth + 1) dat = np.copy(self.imageData) if bg == None: bgf = bgFinder.bgFinder(self.imageData) bg = bgf.smartBackground() dat -= bg print 'Subtracting background {}'.format(bg) if not useErrorMap: ue = dat * 0.0 + 1. else: ue = (dat + bg)**0.5 self.fitted = True if m_in == -1.: if useLinePSF: m_in = self.psf.repFact * self.psf.repFact * np.sum( dat) / np.sum(self.psf.longPSF) else: m_in = self.psf.repFact * self.psf.repFact * np.sum( dat) / np.sum(self.psf.fullPSF) if not fitRateAngle: nDim = 2 r0 = [] for ii in range(nWalkers): r0.append( np.array([x_in, y_in]) + sci.randn(2) * np.array([rand_pos, rand_pos])) r0 = np.array(r0) #fit first using input best guess amplitude sampler = emcee.EnsembleSampler(nWalkers, nDim, lnprob, args=[ dat, (ai, bi, ci, di), self.psf, ue, useLinePSF, verbose, (-1, -1, m_in) ]) print "Executing xy burn-in... this may take a while." pos, prob, state = sampler.run_mcmc(r0, nBurn) #, 10) sampler.reset() print "Executing xy production run... this will also take a while." pos, prob, state = sampler.run_mcmc(pos, nStep, rstate0=state) self.samps = sampler.chain self.probs = sampler.lnprobability self.dat = np.copy(dat) out = self.fitResults() (x, y, junk) = out[0] dx = (out[1][0][1] - out[1][0][0]) / 2.0 dy = (out[1][1][1] - out[1][1][0]) / 2.0 nDim = 1 # need to put two here rather than one because the fitresults code does a residual subtraction r0 = [] for ii in range(nWalkers): r0.append( np.array([m_in]) + sci.randn(1) * np.array([m_in * 0.25])) r0 = np.array(r0) #now fit the amplitude using the best-fit x,y from above #could probably cut the nBurn and nStep numbers down by a factor of 2 sampler = emcee.EnsembleSampler(nWalkers, nDim, lnprob, args=[ dat, (ai, bi, ci, di), self.psf, ue, useLinePSF, verbose, (x, y, -1) ]) print "Executing amplitude burn-in... this may take a while." pos, prob, state = sampler.run_mcmc(r0, max(nBurn / 2, 10)) sampler.reset() print "Executing amplitude production run... this will also take a while." pos, prob, state = sampler.run_mcmc(pos, max(nStep / 2, 10), rstate0=state) self.samps = sampler.chain self.probs = sampler.lnprobability self.dat = np.copy(dat) out = self.fitResults() amp = out[0][0] damp = (out[1][0][1] - out[1][0][0]) / 2.0 #now do a full 3D fit using a small number of burn and steps. nDim = 3 r0 = [] for ii in range(nWalkers): r0.append( np.array([x, y, amp]) + sci.randn(3) * np.array([dx, dy, damp])) r0 = np.array(r0) sampler = emcee.EnsembleSampler(nWalkers, nDim, lnprob, args=[ dat, (ai, bi, ci, di), self.psf, ue, useLinePSF, verbose ]) print "Executing xy-amp burn-in... this may take a while." pos, prob, state = sampler.run_mcmc(r0, nBurn) sampler.reset() print "Executing xy-amp production run... this will also take a while." pos, prob, state = sampler.run_mcmc(pos, nStep, rstate0=state) else: nDim = 5 r0 = [] for ii in range(nWalkers): r0.append( np.array([x_in, y_in, m_in, rate_in, angle_in]) + sci.randn(nDim) * np.array([0.1, 0.1, m_in * 0.1, rate_in * 0.1, 4.0])) r0 = np.array(r0) #fit first using input best guess amplitude sampler = emcee.EnsembleSampler(nWalkers, nDim, lnprob_varRateAngle_LSSTHACK, args=[ dat, (ai, bi, ci, di), self.psf, ue, useLinePSF, exptime, pixScale, verbose ]) #dat,lims,psf,ue,useLinePSF, exptime, pixScale, verbose=False): print "Executing burn-in... this may take a while." pos, prob, state = sampler.run_mcmc(r0, nBurn, 10) sampler.reset() print "Executing production run... this will also take a while." pos, prob, state = sampler.run_mcmc(pos, nStep, rstate0=state) self.samps = sampler.chain self.probs = sampler.lnprobability self.dat = np.copy(dat) self.samps = sampler.chain self.probs = sampler.lnprobability self.dat = np.copy(dat)
def fitDoubleWithModelPSF(self,x_in,y_in,X_in,Y_in,bRat_in,m_in=-1.,bg=None, fitWidth=20,nWalkers=30,nBurn=50,nStep=100, useErrorMap=False, useLinePSF=False,verbose=False): """ Using emcee (It's hammer time!) two sources are fit using the provided psf to find the best x,y and amplitude, and confidence range on the fitted parameters. x_in, y_in, m_in, X_in, Y_in, bRat - initial guesses on the true centroids, the amplitude and brightness ratio of the two sources fitWidth - the width +- of x_in/y_in of the data used in the fit nWalkers, nBurn, nStep - emcee fitting paramters. If you don't know what these are RTFM bg - the background of the image. Needed for the uncertainty table. **Defaults to None.** When set to default, it will invoke the background measurement and apply that. Otherwise, it assumes you are dealing with background subtracted data already. useErrorMap - if true, a simple pixel uncertainty map is used in the fit. This is adopted as ue_ij=(imageData_ij+bg)**0.5, that is, the poisson noise estimate. Note the fit confidence range is only honest if useErrorMap=True. useLinePSF - use the TSF? If not, use the PSF verbose - if set to true, lots of information printed to screen """ self.useLinePSF=useLinePSF (A,B)=self.imageData.shape ai=max(0,int((y_in+Y_in)/2)-fitWidth) bi=min(A,int((y_in+Y_in)/2)+fitWidth+1) ci=max(0,int((x_in+X_in)/2)-fitWidth) di=min(B,int((x_in+X_in)/2)+fitWidth+1) dat=num.copy(self.imageData) if bg==None: bgf=bgFinder.bgFinder(self.imageData) bg=bgf.smartBackground() dat-=bg if not useErrorMap: ue=dat*0.0+1. else: ue=(dat+bg)**0.5 if m_in==-1.: if useLinePSF: m_in=num.sum(dat)/num.sum(self.psf.longPSF) else: m_in=num.sum(dat)/num.sum(self.psf.fullPSF) nDim=6 r0=[] for ii in range(nWalkers): r0.append(num.array([x_in,y_in,m_in,X_in,Y_in,m_in*bRat_in])+sci.randn(6)*num.array([1.,1., m_in*0.4, 1.,1., m_in*0.4*bRat_in])) r0=num.array(r0) sampler=emcee.EnsembleSampler(nWalkers,nDim,lnprobDouble,args=[dat,(ai,bi,ci,di),self.psf,ue,self.useLinePSF,verbose]) pos, prob, state=sampler.run_mcmc(r0,nBurn) sampler.reset() pos, prob, state = sampler.run_mcmc(pos, nStep, rstate0=state) self.samps=sampler.chain self.probs=sampler.lnprobability self.dat=num.copy(dat) self.fitted=True
def test_gaussLike(self): data = array(range(0, 255), int) b = bgFinder(data) r = b._gaussLike([1.0, 2.0]) self.assertAlmostEqual(679178.581857, r, places=1)
def create_finder(): retval = bgFinder(MagicMock()) retval.data = MagicMock() return retval
def runSex(file, fn, chip, mask_file, svsPath, showProgress=False, verbose=False, includeImageMask=False, kron_cut=-0.5, runSextractor=True): badflags = 1 + 512 + 8 + 64 + 16 + 4 + 256 + 2 + 128 + 4096 if path.isfile(mask_file): mask = mask_file + '[0]' if includeImageMask: with fits.open(mask_file) as han: mask_data = han[0].data #print('Using image mask') else: mask_data = None else: mask = None mask_data = None with fits.open(file) as han: header = han[0].header header1 = han[1].header if includeImageMask: han2 = han[2].data if mask_data is None: mask_data = np.zeros(han2.shape).astype(han2.dtype) #good pixels in sextractor have mask value == 1, bad have mask value==0 """ w = np.where((han2>2080)|(han2==12)|(han2==5)|(han2==1024)) #12 is cosmic rays, everything above 32 seems to be saturation or bad columns try: mask_data[w] = 0.0 """ w = np.where(((han2 & badflags) == 0)) #good pixels try: mask_data[w] = 1 except: print(np.max(w[0]), np.max(w[1])) exit() if runSextractor: fits.writeto(file + '.mask', mask_data, overwrite=True) mask = file + '.mask' if showProgress: data = han[0].data seeing = header['SEEING_MODE'] try: apNum = apertures[round(seeing)] except: #seeing variable is -9999. This apNum variable will be reset based on sextractor output apNum = apertures[2] catObject = catObj() catObject.seeing = header['SEEING_MODE'] catObject.ellip = header['ELL_MED'] catObject.astrms = header['WCS_RMS'] if showProgress: pyl.imshow(data, interpolation='nearest', cmap='gray', origin='lower') pyl.colorbar() pyl.show() if runSextractor: if mask is not None: scamp.runSex('subaru_LDAC.sex', file + '[0]', options={ 'CATALOG_NAME': svsPath + fn.replace('.fits', '.cat'), 'WEIGHT_IMAGE': mask, 'WEIGHT_TYPE': 'map_weight' }, verbose=verbose) else: scamp.runSex('subaru_LDAC.sex', file + '[0]', options={ 'CATALOG_NAME': svsPath + fn.replace('.fits', '.cat') }, verbose=verbose) catalog = scamp.getCatalog(svsPath + fn.replace('.fits', '.cat'), paramFile='sextract.param') #get rid of the flux=0 sources w = np.where((catalog['FLUX_APER(9)'][:,0]>0) & (catalog['FLUX_APER(9)'][:,1]>0) & (catalog['FLUX_APER(9)'][:,2]>0) & (catalog['FLUX_APER(9)'][:,3]>0) & (catalog['FLUX_APER(9)'][:,4]>0)\ & (catalog['FLUX_APER(9)'][:,5]>0) & (catalog['FLUX_APER(9)'][:,6]>0)\ & (catalog['FLUX_AUTO']>0)) for key in catalog: catalog[key] = catalog[key][w] if chip < 100: x_high = 2045 y_high = 4173 else: print('Chip>100') x_high = 4173 y_high = 2045 if catObject.seeing <= 0: #need to estimate seeing because header value is non-sense #use all snr>40 sources, and take the median FWHM_IMAGE value FWHM_IMAGE = np.sort(catalog['FWHM_IMAGE'][np.where( (catalog['X_IMAGE'] > 50) & (catalog['X_IMAGE'] < x_high - 50) & (catalog['Y_IMAGE'] > 50) & (catalog['Y_IMAGE'] < y_high - 50) & (catalog['FLUX_APER(9)'][:, apNum] / catalog['FLUXERR_APER(9)'][:, apNum] > 40))]) #fwhm_mode = FWHM_IMAGE[len(FWHM_IMAGE)/2] fwhm_median = np.median(FWHM_IMAGE) catObject.seeing = fwhm_median apNum = apertures[int(round(catObject.seeing))] #setup cut on Kron magnitude, by getting the median difference between kron and aperture magnitude for star-like objects. #avoid the edges w = np.where((catalog['X_IMAGE'] > 50) & (catalog['X_IMAGE'] < x_high - 50) & (catalog['Y_IMAGE'] > 50) & (catalog['Y_IMAGE'] < y_high - 50) & ((catalog['FLUX_APER(9)'][:, apNum] / catalog['FLUXERR_APER(9)'][:, apNum]) > 40) & (catalog['FWHM_IMAGE'] > 1.5)) mag_aper = -2.5 * np.log10(catalog['FLUX_APER(9)'][:, apNum][w] / header['EXPTIME']) + header['MAGZERO'] mag_auto = -2.5 * np.log10( catalog['FLUX_AUTO'][w] / header['EXPTIME']) + header['MAGZERO'] mag_diff = mag_auto - mag_aper bgf = bgFinder.bgFinder(mag_diff) med_mag_diff = bgf.fraserMode(0.4) #med_mag_diff = getMeanMagDiff(mag_aper,mag_diff) #if np.isnan(med_mag_diff): # med_mag_diff = getMeanMagDiff(mag_aper,mag_diff,returnMax = True) #cut on position, SNR, and FWHM snr = catalog['FLUX_APER(9)'][:, apNum] / catalog['FLUXERR_APER(9)'][:, apNum] if catObject.seeing > 0: w = np.where((catalog['X_IMAGE'] > 3) & (catalog['X_IMAGE'] < x_high) & (catalog['Y_IMAGE'] > 3) & (catalog['Y_IMAGE'] < y_high) & (catalog['FWHM_IMAGE'] < catObject.seeing * 5.0) & (snr > 3) & (catalog['FWHM_IMAGE'] > 1.5) & (catalog['A_IMAGE'] > 1.0) & (catalog['B_IMAGE'] > 1.0)) else: w = np.where( (catalog['X_IMAGE'] > 3) & (catalog['X_IMAGE'] < x_high) & (catalog['Y_IMAGE'] > 3) & (catalog['Y_IMAGE'] < y_high) & (catalog['FWHM_IMAGE'] < 10.0) & (snr > 3) & (catalog['FWHM_IMAGE'] > 1.5) & (catalog['A_IMAGE'] > 1.5) & (catalog['B_IMAGE'] > 1.0)) #now measured in arcseconds rather than in units of FWHM #now cut on difference between kron and aperture magnitudes, assuming there were enough sources for the cut if not np.isnan(med_mag_diff): mag_aper = -2.5 * np.log10(catalog['FLUX_APER(9)'][:, apNum][w] / header['EXPTIME']) + header['MAGZERO'] mag_auto = -2.5 * np.log10( catalog['FLUX_AUTO'][w] / header['EXPTIME']) + header['MAGZERO'] mag_diff = mag_auto - mag_aper - med_mag_diff w = [w[0][np.where(mag_diff > kron_cut)]] #pyl.scatter(mag_aper,mag_diff) #print(len(w[0])) #pyl.scatter(mag_aper[np.where(np.abs(mag_diff)<kron_cut)],mag_diff[np.where(np.abs(mag_diff)<kron_cut)]) #pyl.show() #exit() catObject.fwhm_image = catalog['FWHM_IMAGE'][w] catObject.x = catalog['X_IMAGE'][w] - 1.0 catObject.y = catalog['Y_IMAGE'][w] - 1.0 catObject.flux = catalog['FLUX_APER(9)'][:, apNum][w] catObject.snr = snr[w] catObject.jd = 2400000.5 + header['MJD'] + header['EXPTIME'] / (24.0 * 3600.0) WCS = wcs.WCS(header1) (ra, dec) = WCS.all_pix2world(catObject.x, catObject.y, 0) catObject.ra = ra catObject.dec = dec catObject.mag = 2.5 * np.log10( catObject.flux / header['EXPTIME']) + header['MAGZERO'] pickle.dump(catObject, open(svsPath + fn.replace('.fits', '.sex_save'), 'wb')) if includeImageMask and runSextractor: os.remove(file + '.mask') print(file, len(catObject.ra)) return catObject
def make_trippy_profile(psf_image, stamp): with fits.open(psf_image) as seepsf: # Get pixel values and Gaussian fit value par1 from seepsf image for ext in range(len(seepsf)): try: header = seepsf[ext].header psfdata = seepsf[ext].data # PSF image data par1 = header['PAR1'] except: continue with fits.open(stamp) as stp: # Postage stamp image header = stp[0].header ra_rate = header['RARATE'] # Values placed in header ext 0 previously dec_rate = header['DECRATE'] for ext in range(len(stp)): # Look in each header section for these values try: header = stp[ext].header stampdata = stp[ext].data # Stamp image data exptime = header['EXPTIME'] zpt = header['PHOTZP'] pixscale = header['PIXSCAL1'] except: continue imgdim = 501 # Should be odd number so that we have a central pixel halfdim = (imgdim-1)/2 emptyimg = (np.random.poisson(1000, (imgdim, imgdim)) - 1000).astype('float64') # Create empty array with "noise", place psf in center of larger "image" for giving to trippy leftsize = (psfdata.shape[0]-1)/2 # Pixels left of center rightsize = (psfdata.shape[0]+1)/2 # Pixels right of center emptyimg[halfdim-leftsize : halfdim+rightsize, halfdim-leftsize : halfdim+rightsize] += psfdata # Plant PSF from seepsf in center of empty image fwhm = 2*math.sqrt(2*math.log(2))*par1 # Get full width/half max using par1 of Gaussian PSF rate = math.sqrt(ra_rate**2+dec_rate**2) angle = math.degrees(math.atan2(dec_rate, ra_rate)) # Angle w.r.t. horizontal, between +/-90 if angle>90: # Since angle can only be in range +/-90 angle -= 180 if angle <-90: angle += 180 if dec_rate<0: angle=-1*angle # the center of the source is the center of the image seecen = np.array([emptyimg.shape[1]/2.+0.5]) # Generate model of size 61x61, alpha and beta are moffat fit values, 1.75 determined experimentally when matching moffat to Gaussian shape goodPSF=psf.modelPSF(np.arange(61), np.arange(61), alpha=1.75*par1, beta=2) goodPSF.genLookupTable(emptyimg, seecen, seecen) # Generate lookup table for model PSF, centered at the center of the psf image '''z2 = goodPSF.lookupTable.max() z1 = goodPSF.lookupTable.min() normer=interval.ManualInterval(z1,z2) pyl.imshow(normer(goodPSF.lookupTable)) pyl.show()''' goodPSF.line(rate, angle, exptime/3600., pixScale=pixscale, useLookupTable=True) # Generate trailed/line PSF # Use if you want to save image of the trippy psf model #modelimg = psf_image.replace('seepsf','model') #goodPSF.psfStore(modelimg) stampdata = stampdata.astype('float64') # Stamp data is originally ints bgf=bgFinder.bgFinder(stampdata) # Calculate and subtract background bg=bgf.smartBackground() stampdata-=bg centroid = sep_phot(stampdata, 0.002, 3) # Use Kristi's code to get centroid info using SEP r_close = 1000 # Arbitrary number that will intentionally be too large for i in range(len(centroid['x'])): # For all the objects identified in the stamp by SEP, find the one closest to the center of the image dist = (centroid['x'][i]-stampdata.shape[0]/2)**2 + (centroid['y'][i]-stampdata.shape[1]/2)**2 if dist < r_close: r_close = dist closest = i xcen, ycen = centroid['x'][closest], centroid['y'][closest] # Use the centroid that was closest to the center, since it will correspond to the asteroid print 'Using centroid {} {} (in numpy coordinates)'.format(xcen,ycen) phot=pill.pillPhot(stampdata) # Perform trailed source photometry, calculate SNR, total flux phot(xcen, ycen, radius=1.1*fwhm, l=(exptime/3600.)*rate/pixscale, a=angle, skyRadius=4*fwhm, width=6*fwhm, zpt=zpt, exptime=exptime) phot.SNR(verbose=True) fitter = MCMCfit.MCMCfitter(goodPSF, stampdata) # Fit trailed model to background subtracted stamp image fitter.fitWithModelPSF(xcen, ycen, m_in=-1, bg=bg, useLinePSF=True,fitWidth=15,nWalkers=20,nStep=20,nBurn=20,useErrorMap=True) (fitPars,fitRange)=fitter.fitResults(0.67) # 0.67 = fit to 1 sigma print '1-sigma range on Best Point', fitRange modelImage=goodPSF.plant(fitPars[0],fitPars[1],fitPars[2],stampdata,addNoise=False,useLinePSF=True,returnModel=True) # Model the trailed source pyl.imshow(modelImage) pyl.show() removed=goodPSF.remove(fitPars[0],fitPars[1],fitPars[2],stampdata,useLinePSF=True) # Subtract the model from the stamp HDU=fits.PrimaryHDU(removed) List=fits.HDUList([HDU]) psf_removed = psf_image.replace('seepsf','removed') os.unlink(psf_image) List.writeto(psf_removed,clobber=True) print 'Asteroid PSF source flux: {}'.format(np.sum(modelImage)) z1 = stampdata[stampdata.shape[0]/2-30:stampdata.shape[0]/2 + 30,stampdata.shape[1]/2-30:stampdata.shape[1]/2 + 30].min() z2 = stampdata[stampdata.shape[0]/2-30:stampdata.shape[0]/2 + 30,stampdata.shape[1]/2-30:stampdata.shape[1]/2 + 30].max() normer=interval.ManualInterval(z1,z2) pyl.imshow(normer(stampdata)) pyl.show() pyl.imshow(normer(removed)) pyl.show()
def __call__(self, moffatWidth, moffatSNR, initAlpha=5., initBeta=2., repFact=5, xWidth=51, yWidth=51, includeCheesySaturationCut=False, autoTrim=False, noVisualSelection=False, verbose=False): self.moffatWidth = moffatWidth self.moffatSNR = moffatSNR self.initAlpha = initAlpha self.initBeta = initBeta self.repFact = repFact self.fwhms = [] self.points = [] self.moffs = [] self.moffr = np.linspace(0, self.moffatWidth, self.moffatWidth * 3) self.starsFlatR = [] self.starsFlatF = [] self.subsecs = [] self.goodStars = [] self.starsScat = None print 'Fitting stars with moffat profiles...' print ' X Y chi a b FWHM' for j in range(len(self.XWIN_IMAGE)): if self.FLUX_AUTO[j] / self.FLUXERR_AUTO[j] > self.moffatSNR: if self.XWIN_IMAGE[j] - 1 - ( moffatWidth + 1) < 0 or self.XWIN_IMAGE[j] - 1 + ( moffatWidth + 1 ) >= self.data.shape[1] or self.YWIN_IMAGE[j] - 1 - ( moffatWidth + 1) < 0 or self.YWIN_IMAGE[j] - 1 + ( moffatWidth + 1) >= self.data.shape[0]: continue #this psf object creator has to be here. It's to do with the way PSF objects are initialized. Some time #in the future I will adjust this for a small speed boost. mpsf = psf.modelPSF(np.arange(xWidth), np.arange(yWidth), alpha=self.initAlpha, beta=self.initBeta, repFact=self.repFact) mpsf.fitMoffat(self.data, self.XWIN_IMAGE[j], self.YWIN_IMAGE[j], boxSize=self.moffatWidth, verbose=verbose) fwhm = mpsf.FWHM(fromMoffatProfile=True) #norm=Im.normalise(mpsf.subsec,[self.z1,self.z2]) norm = self.normer(mpsf.subSec) if (fwhm is not None) and not (np.isnan(mpsf.beta) or np.isnan(mpsf.alpha)): print ' {: 8.2f} {: 8.2f} {:3.2f} {: 5.2f} {: 5.2f} {: 5.2f} '.format( self.XWIN_IMAGE[j], self.YWIN_IMAGE[j], mpsf.chiFluxNorm, mpsf.alpha, mpsf.beta, fwhm) self.subsecs.append(norm * 1.) self.goodStars.append(True) self.moffs.append(mpsf.moffat(self.moffr) * 1.) self.starsFlatR.append( psf.downSample2d(mpsf.repRads, mpsf.repFact)) self.starsFlatF.append( (mpsf.subSec - mpsf.bg) / (mpsf.moffat(0) * mpsf.A)) self.moffs[len(self.moffs) - 1] /= np.max( self.moffs[len(self.moffs) - 1]) self.points.append([ fwhm, mpsf.chi, mpsf.alpha, mpsf.beta, self.XWIN_IMAGE[j], self.YWIN_IMAGE[j], mpsf.bg ]) self.points = np.array(self.points) self.goodStars = np.array(self.goodStars) FWHM_mode_width = 1.0 #could be 0.5 just as well ab_std_width = 2.0 if autoTrim: print '\nDoing auto star selection.' #first use Frasermode on the distribution of FWHM to get a good handle on the true FWHM of stars #select only those stars with FWHM of +-1 pixel of the mode. bg = bgFinder.bgFinder(self.points[:, 0]) mode = bg('fraserMode') w = np.where(np.abs(self.points[:, 0] - mode) > FWHM_mode_width) self.goodStars[w] = False #now mean select on both moffat a and b parameters to get only those with common shapes w = np.where(self.goodStars) mean_a = np.mean(self.points[w][:, 2]) std_a = np.std(self.points[w][:, 2]) mean_b = np.mean(self.points[w][:, 3]) std_b = np.std(self.points[w][:, 3]) w = np.where( (np.abs(self.points[:, 0] - mode) > FWHM_mode_width) | (np.abs(self.points[:, 2] - mean_a) > ab_std_width * std_a) | (np.abs(self.points[:, 3] - mean_b) > ab_std_width * std_b)) self.goodStars[w] = False #now eliminate the ones with sources nearby for ii in range(len(self.goodStars)): dist = ((self.XWIN_IMAGE - self.points[ii, 4])**2 + (self.YWIN_IMAGE - self.points[ii, 5])**2)**0.5 args = np.argsort(dist) dist = dist[args] #print self.points[ii,4:6],dist if dist[1] < moffatWidth: self.goodStars[ii] = False """ #now print out the number of pixels that are 3-sigma above the naive expectation of the moffat profile itself mpsf = psf.modelPSF(np.arange(xWidth), np.arange(yWidth), alpha=mean_a, beta=mean_b, repFact=self.repFact) print 'Fitting amplitudes to each good star.' for ii in range(len(self.moffs)): if self.goodStars[ii]: mpsf.fitMoffat(self.data, self.XWIN_IMAGE[ii], self.YWIN_IMAGE[ii], boxSize = self.moffatWidth, fixAB = True) a,b = int(self.YWIN_IMAGE[ii]-yWidth/2),int(self.YWIN_IMAGE[ii]+yWidth/2)+1 c,d = int(self.XWIN_IMAGE[ii]-xWidth/2),int(self.XWIN_IMAGE[ii]+xWidth/2)+1 x,y = self.XWIN_IMAGE[ii]-int(self.XWIN_IMAGE[ii])+xWidth/2+1.0, self.YWIN_IMAGE[ii]-int(self.YWIN_IMAGE[ii])+yWidth/2+1.0 cut = self.data[a:b,c:d] removed = mpsf.remove(self.XWIN_IMAGE[ii]-0.5,self.YWIN_IMAGE[ii]-0.5, mpsf.A, self.data)[a:b,c:d]-mpsf.bg print ii,len(np.where( np.abs(removed/cut**0.5)>3)[0]) exit() """ self.figPSF = pyl.figure('Point Source Selector') self.sp1 = pyl.subplot2grid((4, 4), (0, 1), colspan=3, rowspan=2) pyl.scatter(self.points[:, 0], self.points[:, 1], picker=True) pyl.title( 'Select PSF range with zoom,\n' + 'inspect stars (a = next, d = previous, w = toggle on/off,\n' + 'or left/right click to show/toggle),\n' + 'then close the plot window.') self.sp2 = pyl.subplot2grid((4, 4), (2, 1), colspan=3, sharex=self.sp1, rowspan=1) bins = np.arange(np.min(self.points[:, 0]), np.max(self.points[:, 0]) + 0.5, 0.5) pyl.hist(self.points[:, 0], bins=bins) pyl.xlabel('FWHM (pix)') self.sp3 = pyl.subplot2grid((4, 4), (0, 0), rowspan=2, sharey=self.sp1) pyl.hist(self.points[:, 1], bins=30, orientation='horizontal') pyl.ylabel('RMS') self.sp4 = pyl.subplot2grid((4, 4), (2, 0), rowspan=2) self.moffPatchList = [] self.showing = [] self.selected_star = -1 for j in range(len(self.moffs)): self.moffPatchList.append(self.sp4.plot(self.moffr, self.moffs[j])) self.showing.append(1) self.sp4.set_xlim(0, 30) self.sp4.set_ylim(0, 1.02) self.sp5 = pyl.subplot2grid((4, 4), (3, 1)) self.sp5.set_aspect('equal') self.psfPlotLimits = [self.sp1.get_xlim(), self.sp1.get_ylim()] self.conn1 = self.sp1.callbacks.connect('ylim_changed', self.PSFrange) self.conn2 = pyl.connect('pick_event', self.ScatterPSF) self.conn3 = pyl.connect('key_press_event', self.ScatterPSF_keys) self.conn4 = pyl.connect('close_event', self.HandleClose) self.ScatterPSF(None) if not noVisualSelection: pyl.show() self._fwhm_lim = self.sp1.get_xlim() self._chi_lim = self.sp1.get_ylim() w = np.where((self.points[:, 0] > self._fwhm_lim[0]) & (self.points[:, 0] < self._fwhm_lim[1]) & (self.points[:, 1] > self._chi_lim[0]) & (self.points[:, 1] < self._chi_lim[1]) & (self.goodStars == True)) pyl.clf() pyl.close() goodFits = self.points[w] goodMeds = np.median(goodFits[:4], axis=0) goodSTDs = np.std(goodFits[:4], axis=0) return (goodFits, goodMeds, goodSTDs)
HDU = fits.PrimaryHDU(data, header) IHDU = fits.ImageHDU(bg) RHDU = fits.ImageHDU(rem) List = fits.HDUList([HDU, IHDU, RHDU]) List.writeto(fitsFile.replace('.', '_bgr.'), overwrite=True) sys.exit() div = 50 for i in range(0, B, B / div): f = np.median(data[:, i:i + B / div], axis=1) print poly(np.arange(len(f)) + 1.0, f, skip) continue sys.exit() #g = np.std(data[:,i:i+B/20],axis=1)*(B/20)**-0.5 #print g/f #sys.exit() bgf = bgFinder.bgFinder(f) fraser = bgf.fraserMode() median = np.median(f) pyl.plot([0, len(f)], [fraser, fraser], 'r-') pyl.plot([0, len(f)], [median, median], 'k-') pyl.plot(f) #pyl.plot(f+g,'k--') #pyl.plot(f-g,'k--') pyl.title(i + B / 40) pyl.show()
def fitWithModelPSF(self, x_in, y_in, m_in=-1., fitWidth=20, nWalkers=20, nBurn=10, nStep=20, bg=None, useErrorMap=False, useLinePSF=False, verbose=False): """ Using emcee (It's hammer time!) the provided image is fit using the provided psf to find the best x,y and amplitude, and confidence range on the fitted parameters. :param float x_in: initial guess on the x coordinate of the true centroid of the object :param float y_in: initial guess on the y coordinate of the true centroid of the object :param float m_in: initial guess on the true amplitude of the object :param float fitWidth: the width +- of x_in/y_in of the data used in the fit :param int nWalkers: The number of Goodman & Weare “walkers”. See :class:`emcee.EnsembleSampler`. :param int nBurn: The number of iterations to run the chain during burn-in. See :class:`emcee.EnsembleSampler.run_mcmc`. :param int nStep: The number of iterations to run the chain in the production run. See :class:`emcee.EnsembleSampler.run_mcmc`. :param bg: the background of the image. Needed for the uncertainty table. **Defaults to None.** When set to default, it will invoke the background measurement and apply that. Otherwise, it assumes you are dealing with background subtracted data already. :param boolean useErrorMap: If true, a simple pixel uncertainty map is used in the fit. This is adopted as ue_ij=(imageData_ij+bg)**0.5, that is, the poisson noise estimate. Note the fit confidence range is only honest if useErrorMap=True. :param boolean useLinePSF: If True, use the TSF. If False, use the PSF :param boolean verbose: lots of information printed to screen """ print("Initializing sampler") self.nForFitting = 0 self.useLinePSF = useLinePSF if fitWidth > self.psf.boxSize: raise NotImplementedError('Need to keep the fitWidth <= boxSize.') (A, B) = self.imageData.shape ai = max(0, int(y_in) - fitWidth) bi = min(A, int(y_in) + fitWidth + 1) ci = max(0, int(x_in) - fitWidth) di = min(B, int(x_in) + fitWidth + 1) dat = num.copy(self.imageData) if bg == None: bgf = bgFinder.bgFinder(self.imageData) bg = bgf.smartBackground() dat -= bg if not useErrorMap: ue = dat * 0.0 + 1. else: ue = (dat + bg) ** 0.5 if m_in == -1.: if useLinePSF: m_in = self.psf.repFact * self.psf.repFact * num.sum(dat) / num.sum(self.psf.longPSF) else: m_in = self.psf.repFact * self.psf.repFact * num.sum(dat) / num.sum(self.psf.fullPSF) nDim = 3 r0 = [] for ii in range(nWalkers): r0.append(num.array([x_in, y_in, m_in]) + sci.randn(3) * num.array([0.1, 0.1, m_in * 0.25])) r0 = num.array(r0) sampler = emcee.EnsembleSampler(nWalkers, nDim, lnprob, args=[dat, (ai, bi, ci, di), self.psf, ue, useLinePSF, verbose]) print("Executing burn-in... this may take a while.") pos, prob, state = sampler.run_mcmc(r0, nBurn) sampler.reset() print("Executing production run... this will also take a while.") pos, prob, state = sampler.run_mcmc(pos, nStep, rstate0=state) self.samps = sampler.chain self.probs = sampler.lnprobability self.dat = num.copy(dat) self.fitted = True
def sourceTrim(fn,snr_lim,doBright = True,doBinary = False, aperFWHMmulti = 1.0, medMagDiff = None): split = fn.split('-')[-1].split('.fits')[0] chip = int(float(split[:3])) if doBright : o = fn.replace('.fits','_bright_planted.coords') file = fn.replace('.fits','_bright_planted.fits') elif doBinary : o = fn.replace('.fits','_binary_planted.coords') file = fn.replace('.fits','_binary_planted.fits') else: o = fn.replace('.fits','_faint_planted.coords') file = fn.replace('.fits','_faint_planted.fits') with open(o) as han: d = han.readlines() if doBinary: planted = [] for i in range(len(d)): s = d[i].split() (x,y,z,X,Y,Z) = (float(s[0]),float(s[1]),float(s[2]),float(s[3]),float(s[4]),float(s[5])) xg = (x*z+X*Z)/(z+Z) yg = (y*z+Y*Z)/(z+Z) planted.append([xg,yg,z+Z]) planted = np.array(planted) else: planted = [] for i in range(len(d)): s = d[i].split() planted.append([float(s[0]),float(s[1]),float(s[2])]) planted = np.array(planted) mask_file = '/home/fraserw/idl_progs/hscp9/sextract/mask'+str(chip).zfill(3)+'.fits' runSex(file,file,chip,mask_file,svsPath = '',showProgress = False, verbose = False, includeImageMask = True,runSextractor=True) pcatalog = scamp.getCatalog(file.replace('.fits','.cat'),paramFile='sextract.param') with fits.open(file) as han: header = han[0].header data = han[1].data try: FWHM = header['FWHMplant'] except: FWHM = header['fwhmRobust'] apNum = apertures[round(FWHM*aperFWHMmulti)] w = np.where((pcatalog['FLUX_APER(5)'][:,0]>0) & (pcatalog['FLUX_APER(5)'][:,1]>0) &\ (pcatalog['FLUX_APER(5)'][:,2]>0) & (pcatalog['FLUX_APER(5)'][:,3]>0) &\ (pcatalog['FLUX_APER(5)'][:,4]>0) & (pcatalog['FLUX_AUTO']>0)) for key in pcatalog: pcatalog[key] = pcatalog[key][w] psnr = pcatalog['FLUX_APER(5)'][:,apNum]/pcatalog['FLUXERR_APER(5)'][:,apNum] w = np.where((pcatalog['X_IMAGE']>50) & (pcatalog['X_IMAGE']<1995) & (pcatalog['Y_IMAGE']>50) & (pcatalog['Y_IMAGE']<4123) \ & (psnr>5) & (pcatalog['FWHM_IMAGE']>1.5)) w1 = np.where((psnr[w]>=snr_lim[0])&(psnr[w]<snr_lim[1])) if doBinary: dist_max = 2.5 else: dist_max = 1.5 p = [] planted_x,planted_y = [],[] for i in range(len(planted)): dist = ((planted[i,0]-pcatalog['X_IMAGE'][w][w1]+1)**2 + (planted[i,1]-pcatalog['Y_IMAGE'][w][w1]+1)**2)**0.5 if np.min(dist)<dist_max: arg = np.argmin(dist) p.append(arg) planted_x.append(pcatalog['X_IMAGE'][w][w1][arg]) planted_y.append(pcatalog['Y_IMAGE'][w][w1][arg]) #else: # print(i,planted[i],np.min(dist)) p = np.array(p) planted_x = np.array(planted_x) planted_y = np.array(planted_y) print('Number of planted sources we are making use of:',len(p)) pmag_aper = -2.5*np.log10(pcatalog['FLUX_APER(5)'][:,apNum][w][w1][p]/header['EXPTIME'])+header['MAGZERO'] pmag_auto = -2.5*np.log10(pcatalog['FLUX_AUTO'][w][w1][p]/header['EXPTIME'])+header['MAGZERO'] pmag_diff = pmag_auto - pmag_aper if doBright: bgf = bgFinder.bgFinder(pmag_diff) pmed_mag_diff = bgf.fraserMode(0.4) #pmed_mag_diff = getMeanMagDiff(pmag_aper,pmag_diff) #if np.isnan(pmed_mag_diff): # pmed_mag_diff = getMeanMagDiff(pmag_aper,pmag_diff,returnMax = True) else: #use an input one from the planted single sources pmed_mag_diff = medMagDiff if not np.isnan(pmed_mag_diff): pmag_diff = pmag_auto-pmag_aper-pmed_mag_diff if doBright: plantedMedMagDiff = pmed_mag_diff catalog = scamp.getCatalog(fn.replace('.fits','.cat'),paramFile='sextract.param') with fits.open(fn) as han: header = han[0].header data = han[1].data (A,B) = data.shape w = np.where((catalog['FLUX_APER(5)'][:,0]>0) & (catalog['FLUX_APER(5)'][:,1]>0) &\ (catalog['FLUX_APER(5)'][:,2]>0) & (catalog['FLUX_APER(5)'][:,3]>0) &\ (catalog['FLUX_APER(5)'][:,4]>0) & (catalog['FLUX_AUTO']>0)&\ (catalog['X_IMAGE']>FWHM) & (catalog['X_IMAGE']<B-FWHM) & (catalog['Y_IMAGE']>FWHM) & (catalog['Y_IMAGE']<A-FWHM) ) for key in catalog: catalog[key] = catalog[key][w] snr = catalog['FLUX_APER(5)'][:,apNum]/catalog['FLUXERR_APER(5)'][:,apNum] w = np.where((snr>5) & (catalog['FWHM_IMAGE']>1.5)) w1 = np.where((snr[w]>snr_lim[0])&(snr[w]<snr_lim[1])) mag_aper = -2.5*np.log10(catalog['FLUX_APER(5)'][:,apNum][w][w1]/header['EXPTIME'])+header['MAGZERO'] mag_auto = -2.5*np.log10(catalog['FLUX_AUTO'][w][w1]/header['EXPTIME'])+header['MAGZERO'] if doBright: pyl.scatter(mag_auto,mag_auto-mag_aper) pyl.scatter(pmag_auto,pmag_auto-pmag_aper) pyl.show() exit() mag_diff = mag_auto-mag_aper-pmed_mag_diff if doBright: pred = np.ones(len(mag_diff)) pred[np.where((mag_diff<snr_lim[2])| (mag_diff>np.max(mag_diff)))] = -1 else: args = np.argsort(pmag_auto) x = pmag_auto[args] y = pmag_diff[args] bins = np.zeros(len(x))+abs(snr_lim[2]) old_i = 0 for i in range(len(x)): if bins[i]<y[i]: bins[old_i:] = y[i] old_i = i ww = np.where(bins==np.max(bins)) #generate a quadratic function that encompasses the true sources b = (bins[ww[0][0]]+0.01+snr_lim_f[2])*((x[ww[0][0]]-np.min(x))**-2) X = np.linspace(np.min(mag_auto)-10,np.max(mag_auto)+10,200) Y = -snr_lim[2] + b*(X-np.min(x))**2 ww = np.where(X<np.min(x)) Y[ww] = -snr_lim[2] #now setup the lower limit function with the cutout to include binaries Yn=-Y ww = np.where(Yn>-0.5) Yn[ww]=-0.5 f = interp.interp1d(X,Y) fneg = interp.interp1d(X,Yn) pred = -np.ones(len(mag_diff)) for i in range(len(pred)): if mag_diff[i]<f(mag_auto[i]) and mag_diff[i]>(fneg(mag_auto[i])): pred[i]=1 for k in catalog: catalog[k] = catalog[k][w][w1] if doBright: return (catalog,data,pred,mag_auto,mag_diff,pmag_auto,pmag_diff,p,apNum,plantedMedMagDiff) elif doBinary: return (catalog,data,pred,mag_auto,mag_diff,pmag_auto,pmag_diff,p,apNum) else: return (catalog,data,pred,mag_auto,mag_diff,pmag_auto,pmag_diff,p,f,fneg,apNum)
def fitWithModelPSF(self,x_in,y_in,m_in=-1.,fitWidth=20, nWalkers=20,nBurn=10,nStep=20, bg=None,useErrorMap=False, useLinePSF=False,verbose=False): """ Using emcee (It's hammer time!) the provided image is fit using the provided psf to find the best x,y and amplitude, and confidence range on the fitted parameters. x_in, y_in, m_in - initial guesses on the true centroid and amplitude of the object fitWidth - the width +- of x_in/y_in of the data used in the fit nWalkers, nBurn, nStep - emcee fitting paramters. If you don't know what these are RTFM bg - the background of the image. Needed for the uncertainty table. **Defaults to None.** When set to default, it will invoke the background measurement and apply that. Otherwise, it assumes you are dealing with background subtracted data already. useErrorMap - if true, a simple pixel uncertainty map is used in the fit. This is adopted as ue_ij=(imageData_ij+bg)**0.5, that is, the poisson noise estimate. Note the fit confidence range is only honest if useErrorMap=True. useLinePSF - use the TSF? If not, use the PSF verbose - if set to true, lots of information printed to screen """ print "Initializing sampler" self.nForFitting=0 self.useLinePSF=useLinePSF if fitWidth>self.psf.boxSize: raise NotImplementedError('Need to keep the fitWidth <= boxSize.') (A,B)=self.imageData.shape ai=max(0,int(y_in)-fitWidth) bi=min(A,int(y_in)+fitWidth+1) ci=max(0,int(x_in)-fitWidth) di=min(B,int(x_in)+fitWidth+1) dat=num.copy(self.imageData) if bg==None: bgf=bgFinder.bgFinder(self.imageData) bg=bgf.smartBackground() dat-=bg if not useErrorMap: ue=dat*0.0+1. else: ue=(dat+bg)**0.5 if m_in==-1.: if useLinePSF: m_in=self.psf.repFact*self.psf.repFact*num.sum(dat)/num.sum(self.psf.longPSF) else: m_in=self.psf.repFact*self.psf.repFact*num.sum(dat)/num.sum(self.psf.fullPSF) nDim=2 r0=[] for ii in range(nWalkers): r0.append(num.array([x_in,y_in])+sci.randn(2)*num.array([0.1,0.1])) r0=num.array(r0) #fit first using input best guess amplitude sampler=emcee.EnsembleSampler(nWalkers,nDim,lnprob,args=[dat,(ai,bi,ci,di),self.psf,ue,useLinePSF,verbose,(-1,-1,m_in)]) print "Executing xy burn-in... this may take a while." pos, prob, state=sampler.run_mcmc(r0, nBurn, 10) sampler.reset() print "Executing xy production run... this will also take a while." pos, prob, state = sampler.run_mcmc(pos, nStep, rstate0=state) self.samps=sampler.chain self.probs=sampler.lnprobability self.dat=num.copy(dat) self.fitted=True out = self.fitResults() (x,y,junk) = out[0] dx = (out[1][0][1] - out[1][0][0])/2.0 dy = (out[1][1][1] - out[1][1][0])/2.0 nDim = 1 # need to put two here rather than one because the fitresults code does a residual subtraction r0 = [] for ii in range(nWalkers): r0.append(num.array([m_in]) + sci.randn(1) * num.array([m_in*0.25])) r0 = num.array(r0) #now fit the amplitude using the best-fit x,y from above #could probably cut the nBurn and nStep numbers down by a factor of 2 sampler = emcee.EnsembleSampler(nWalkers, nDim, lnprob, args=[dat, (ai, bi, ci, di), self.psf, ue, useLinePSF, verbose, (x, y, -1)]) print "Executing amplitude burn-in... this may take a while." pos, prob, state = sampler.run_mcmc(r0, max(nBurn/2,10)) sampler.reset() print "Executing amplitude production run... this will also take a while." pos, prob, state = sampler.run_mcmc(pos, max(nStep/2,10), rstate0=state) self.samps = sampler.chain self.probs = sampler.lnprobability self.dat = num.copy(dat) self.fitted = True out = self.fitResults() amp = out[0][0] damp = (out[1][0][1]-out[1][0][0])/2.0 #now do a full 3D fit using a small number of burn and steps. nDim=3 r0=[] for ii in range(nWalkers): r0.append(num.array([x,y,amp])+sci.randn(3)*num.array([dx,dy,damp])) r0=num.array(r0) sampler=emcee.EnsembleSampler(nWalkers,nDim,lnprob,args=[dat,(ai,bi,ci,di),self.psf,ue,useLinePSF,verbose]) print "Executing xy-amp burn-in... this may take a while." pos, prob, state=sampler.run_mcmc(r0,nBurn) sampler.reset() print "Executing xy-amp production run... this will also take a while." pos, prob, state = sampler.run_mcmc(pos, nStep, rstate0=state) self.samps=sampler.chain self.probs=sampler.lnprobability self.dat=num.copy(dat) self.fitted=True
def setUpClass(self): self.rates = [0.4, 1.0, 2.5] self.angles = [37.0, 0.0, -58.7] self.EXPTIME = 360.0 #os.system('gunzip test_image.fits.gz') self.gened_bg = 1000.0 if not (os.path.isfile('test_image.fits') and os.path.isfile('planted_locations.pickle')): print('You may not have the necessary fits files for these tests.') print('Please execute the following two wget commands:') print( 'wget https://www.cadc-ccda.hia-iha.nrc-cnrc.gc.ca/files/vault/fraserw/test_psf.fits' ) print( 'wget https://www.cadc-ccda.hia-iha.nrc-cnrc.gc.ca/files/vault/fraserw/test_image.fits' ) print('') exit() with fits.open('test_image.fits') as han: self.image = han[0].data self.loadedPSF = psf.modelPSF(restore='test_psf.fits') with open('planted_locations.pickle', 'rb') as han: if sys.version_info[0] == 3: x = pickle.load(han, encoding='latin1') elif sys.version_info[0] == 2: x = pickle.load(han) self.planted_locations = np.array(x) self.bg = bgFinder.bgFinder(self.image) scamp.makeParFiles.writeConv() scamp.makeParFiles.writeParam() scamp.makeParFiles.writeSex('test.sex', minArea=2, threshold=2) scamp.runSex('test.sex', 'test_image.fits', verbose=True) self.catalog = scamp.getCatalog('def.cat', paramFile='def.param') os.remove('default.conv') os.remove('def.param') os.remove('test.sex') os.remove('def.cat') #os.system('gzip test_image.fits') starChooser = psfStarChooser.starChooser(self.image, self.catalog['XWIN_IMAGE'], self.catalog['YWIN_IMAGE'], self.catalog['FLUX_AUTO'], self.catalog['FLUXERR_AUTO']) (self.goodFits, self.goodMeds, self.goodSTDs) = starChooser(30, 25, noVisualSelection=True, autoTrim=False, quickFit=False, repFact=5) (self.goodFitsQF, self.goodMedsQF, self.goodSTDsQF) = starChooser(30, 25, noVisualSelection=True, autoTrim=False, quickFit=True, repFact=5) #using manual alpha and beta because the fitting done with the star chooser results in #different answers with the different versions of scipy ALPHA = 29.81210639392963 BETA = 19.32497948470224 self.goodPSF = psf.modelPSF(np.arange(51), np.arange(51), alpha=ALPHA, beta=BETA, repFact=10) #self.goodPSF = psf.modelPSF(np.arange(51),np.arange(51), alpha=self.goodMeds[2],beta=self.goodMeds[3],repFact=10) self.goodPSF.genLookupTable(self.image, self.goodFits[:, 4], self.goodFits[:, 5], verbose=False) self.goodPSF.line(self.rates[0], self.angles[0], self.EXPTIME / 3600., pixScale=0.185, useLookupTable=True) #self.goodPSF.psfStore('test_psf.fits') self.pill = pill.pillPhot(self.image) rads = np.arange(5.0, 25.0, 5) x_test, y_test = 652.4552577047876, 101.62067493726078 #necessray to use custom coordinates to avoid errors due to different sextractor versions self.pill.computeRoundAperCorrFromSource(x_test, y_test, rads, width=60.0, skyRadius=50.0, display=False, displayAperture=False) self.pill(x_test, y_test, 7.0, l=5.0, display=False, enableBGSelection=False) self.pill.SNR(verbose=True) self.distances = {} self.distances[26] = 0.2913793325 self.distances[16] = 0.5179553032 self.distances[7] = 0.1751143336 self.distances[0] = 0.7428739071 self.distances[23] = 0.3347620368 self.distances[18] = 0.7867022753 self.distances[14] = 0.1851933748 self.distances[5] = 0.4436303377 self.distances[28] = 0.3333371580 self.distances[9] = 0.1997155696 self.distances[29] = 0.3528487086 self.distances[22] = 0.4013085365 self.distances[19] = 0.5801378489 self.distances[17] = 0.6873673797 self.distances[1] = 0.1621235311 self.distances[6] = 0.1248580739 self.distances[13] = 2.0296137333 self.distances[24] = 1.3238428831 self.distances[3] = 0.7816261053 self.distances[25] = 0.3067137897 self.distances[6] = 0.8099660873