def __call__( self, xi, yi, radius=4.0, l=5.0, a=0.01, width=20.0, skyRadius=8.0, zpt=27.0, exptime=1.0, enableBGSelection=False, display=False, verbose=False, backupMode="fraserMode", trimBGHighPix=False, zscale=True, ): """ Perform the actual photometry. angle in degrees clockwise +-90 degrees from +x Length in pixels. Coordinates are in iraf coordinates, not numpy. -width is the outer dimension of the image region considered. That is, 2*width*2*width is the image subsection size. set trimBGHighPix to some value ,x, to trim the background -this is done by first estimating the background. Then, it trims all pixels with value v>bg+x*bgstd. That is, it provides a rough sigma cut to get rid of glaringly bright sources that might affect the bg estimate. -the bg is then restimated. """ x = xi - 0.5 y = yi - 0.5 # if l+radius<width or l+skyRadius<width: # raise Exception("Width must be large enough to include both the full aperture, and the sky radius.") if a > 90 or a < -90 or l < 0 or radius < 0: raise Exception( "Keep the angle between -90 and +90 with positive rates please. If you ask me nicely, I may include code to handle this." ) image = self.__lp__(x=x + 1.0, y=y + 1.0, radius=radius, l=l, a=a, w=int(width)) if display and self.l0 <> None: l0 = self.l0 l1 = self.l1 l2 = self.l2 l3 = self.l3 bgstd = -1.0 mask = self.mask if skyRadius == None: skyImage = image * 0.0 bg = 0.0 else: skyImage = self.__lp__(x=x + 1.0, y=y + 1.0, radius=skyRadius, l=l, a=a, w=int(width), retObj=False) bgmask = self.bgmask rebinnedSkyImage = num.zeros(num.array(skyImage.shape) / self.repFact) (aa, bb) = skyImage.shape for ii in range(0, aa, self.repFact): for jj in range(0, bb, self.repFact): n = num.sum(bgmask[ii : ii + self.repFact, jj : jj + self.repFact]) if n == self.repFact * self.repFact: rebinnedSkyImage[ii / self.repFact, jj / self.repFact] = num.sum( skyImage[ii : ii + self.repFact, jj : jj + self.repFact] ) w = num.where(rebinnedSkyImage <> 0.0) bgf = bgFinder.bgFinder(rebinnedSkyImage[w]) if not trimBGHighPix: bg = bgf.smartBackground(display=display, backupMode=backupMode) else: bg = bgf.smartBackground(backupMode=backupMode) bgstd = num.std(rebinnedSkyImage[w]) if trimBGHighPix: W = num.where(rebinnedSkyImage[w] < bg + trimBGHighPix * bgstd) bgf = bgFinder.bgFinder(rebinnedSkyImage[w][W]) bg = bgf.smartBackground(display=display) bgstd = num.std(rebinnedSkyImage[w][W]) W = num.where(mask <> 0.0) flux = num.sum(image) - len(W[0]) * bg / (self.repFact * self.repFact) self.nPix = num.sum(mask) / (self.repFact * self.repFact) self.sourceFlux = flux self.bg = bg self.bgstd = bgstd self.exptime = exptime self.magnitude = zpt - 2.5 * num.log10(self.sourceFlux / self.exptime) if display: if trimBGHighPix: w = num.where(skyImage > (bg + trimBGHighPix * bgstd) / (self.repFact * self.repFact)) skyImage[w] = 0 im = skyImage + image if zscale: (z1, z2) = numdisplay.zscale.zscale(im) norm = interval.ManualInterval(z1, z2) pyl.imshow(norm(im), interpolation="nearest", origin="lower") else: w = num.where(im == 0.0) im[w] += self.bg * 0.7 / (self.repFact * self.repFact) im = num.clip(im, num.min(im), num.max(image)) pyl.imshow(im, interpolation="nearest", origin="lower") if self.l0 <> None: pyl.plot( num.linspace(l0.xlim[0], l0.xlim[1], 100), l0(num.linspace(l0.xlim[0], l0.xlim[1], 100)), "w-", lw=2.0, ) pyl.plot( num.linspace(l2.xlim[0], l2.xlim[1], 100), l2(num.linspace(l2.xlim[0], l2.xlim[1], 100)), "w-", lw=2.0, ) # pyl.text((l0.xlim[0]+l0.xlim[1])/2.-5,(l0(l0.xlim[0])+l0(l0.xlim[1]))/2.+5,'$l$',size=20) # pyl.plot([l0.xlim[0],l0.xlim[0]+50],[l0(l0.xlim[0]),l0(l0.xlim[0])],'k--') mx0 = (l0.xlim[0] + l2.xlim[0]) / 2 my0 = (l0(l0.xlim[0]) + l2(l2.xlim[0])) / 2 a0 = num.arctan2(l0(l0.xlim[0]) - my0, l0.xlim[0] - mx0) a1 = num.arctan2(l2(l2.xlim[0]) - my0, l2.xlim[0] - mx0) a = num.linspace(a0, a1, 25) xxx = mx0 - num.cos(a) * radius * self.repFact yyy = my0 - num.sin(a) * radius * self.repFact pyl.plot(xxx, yyy, "w-", lw=2) pyl.plot([mx0, xxx[-6]], [my0, yyy[-6]], "w:", lw=2) # pyl.text((mx0+xxx[-6])/2.-5,(my0+yyy[-6])/2.-5,'$r$',size=20) mx0 = (l0.xlim[1] + l2.xlim[1]) / 2 my0 = (l0(l0.xlim[1]) + l2(l2.xlim[1])) / 2 a0 = num.arctan2(l0(l0.xlim[1]) - my0, l0.xlim[1] - mx0) a1 = num.arctan2(l2(l2.xlim[1]) - my0, l2.xlim[1] - mx0) a = num.linspace(a0, a1, 25) xxx = mx0 + num.cos(a) * radius * self.repFact yyy = my0 + num.sin(a) * radius * self.repFact pyl.plot(xxx, yyy, "w-", lw=2) if enableBGSelection: print "Current background value: %.3f" % (self.bg) pyl.title("To improve background measurement, zoom on a good\nbackground region, then close.") CA = pyl.gca() (ox0, ox1) = CA.get_xlim() (oy0, oy1) = CA.get_ylim() pyl.show() (A, B) = im.shape (x0, x1) = CA.get_xlim() (y0, y1) = CA.get_ylim() if ox0 == x0 and ox1 == x1 and oy0 == y0 and oy1 == y1: return x0 = max(0, x0) / 10 y0 = max(0, y0) / 10 x1 = min(A, x1) / 10 y1 = min(B, y1) / 10 rebinnedSkyImage = rebinnedSkyImage[y0:y1, x0:x1] w = num.where(rebinnedSkyImage <> 0.0) bgf = bgFinder.bgFinder(rebinnedSkyImage[w]) bg = bgf.smartBackground(display=display) bgstd = num.std(rebinnedSkyImage[w]) W = num.where(mask <> 0.0) flux = num.sum(image) - len(W[0]) * bg / (self.repFact * self.repFact) self.nPix = num.sum(mask) / (self.repFact * self.repFact) self.sourceFlux = flux self.bg = bg self.bgstd = bgstd self.exptime = exptime self.magnitude = zpt - 2.5 * num.log10(self.sourceFlux / self.exptime) else: pyl.show() if verbose: print num.sum(image), self.sourceFlux, self.bg, zpt - 2.5 * num.log10(flux)
def __call__(self, xi, yi, radius=4., l=5., a=0.01, width=20., skyRadius=8., zpt=27.0, exptime=1., enableBGSelection=False, display=False, verbose=False, backupMode='fraserMode', forceBackupMode=False, trimBGHighPix=False, zscale=True, zoomRegion=None): """ Perform the actual photometry. Important note: the background is taken as the output from bgfinder.smartBackground. First a Guassian is fit to the data. If the gaussian standard deviation / gaussian peak is larger than the variable gaussSTDlimit, or if forceBackupMode is set to true, the backup mode background value is returned. Otherwise, the peak of the gaussian fit is returned. angle in degrees clockwise +-90 degrees from +x Length in pixels. Coordinates are in iraf coordinates, not numpy. -width is the outer dimension of the image region considered. That is, 2*width*2*width is the image subsection size. set trimBGHighPix to some value ,x, to trim the background -this is done by first estimating the background. Then, it trims all pixels with value v>bg+x*bgstd. That is, it provides a rough sigma cut to get rid of glaringly bright sources that might affect the bg estimate. -the bg is then restimated. -when zoomRegion is set [x_low,x_high,y_low,y_high], a 4 int/float array, and enableBGSelection = True, the aperture panel will automatically zoom to the region of the image specified by the box coordinates in zoomRegion """ #Single-letter variables = super painful debugging #I'll leave them in the function call for backwards compatibility, #but will remove below. angle = a length = l del (a, l) #Set up some of the True/False statements that gets used repeatedly: singleAperture = isinstance(radius, (float, num.float64)) multipleApertures = isinstance(radius, num.ndarray) if not singleAperture | multipleApertures: raise Exception( 'Aperture size not understood. ' + 'It seems to be neither an array or a single value') if enableBGSelection: if zoomRegion is not None: if isinstance(zoomRegion, (list, num.float64)): if not len(zoomRegion) == 4: raise Exception( 'Need four values to specify the corners of the zoom box.' ) elif len(zoomRegion) == 4 and not isinstance( zoomRegion[0], (float, int)): raise Exception( 'zoomRegion takes floats or ints only.') else: raise Exception( 'zoomRegion is a 4 float/int array or list ') #Check whether aperture(s) is integer: if True convert to float. integerAperture = isinstance(radius, (int, num.integer)) if multipleApertures: integerAperture = issubclass(radius.dtype.type, num.integer) if integerAperture: radius *= 1. integerAperture = False if display: #setup the necessary subplots self.dispFig = pyl.figure('Image Display') if enableBGSelection: #dispFig.subplots_adjust(wspace = 0.0,hspace = 0.0) self.dispGS = gridspec.GridSpec( 1, 2) #, height_ratios = [3.5,1], width_ratios = [3.5,1]) self.dispAx = pyl.subplot(self.dispGS[0]) else: self.dispAx = self.dispFig.add_subplot(111) x = xi - 0.5 y = yi - 0.5 #if l+radius<width or l+skyRadius<width: # raise Exception("Width must be large enough to include both the full aperture, and the sky radius.") # if angle > 90 or angle < -90 or length < 0 or num.min(radius) < 0: if angle > 90 or angle < -90: angle = angle % 180. if verbose: print("Warning! You gave a bad angle. I'll fix it for you.") if length < 0: length = -length if verbose: print("Warning! You gave a bad length. I'll fix it for you.") if num.min(radius) < 0: raise Exception('Aperture radius must be positive!') if singleAperture: image = self.__lp__(x=x + 1., y=y + 1., radius=radius, l=length, a=angle, w=int(width)) mask = self.mask elif multipleApertures: image = [] mask = [] for jj in range(len(radius)): image.append( self.__lp__(x=x + 1., y=y + 1., radius=radius[jj], l=length, a=angle, w=int(width))) mask.append(self.mask) if display and self.l0 <> None: l0 = self.l0 l1 = self.l1 l2 = self.l2 l3 = self.l3 bgstd = -1. if skyRadius == None: if singleAperture: skyImage = image * 0.0 elif multipleApertures: skyImage = image[0] * 0.0 bg = 0.0 else: skyImage = self.__lp__(x=x + 1., y=y + 1., radius=skyRadius, l=length, a=angle, w=int(width), retObj=False) bgmask = self.bgmask rebinnedSkyImage = num.zeros( num.array(skyImage.shape) / self.repFact) (aa, bb) = skyImage.shape for ii in range(0, aa, self.repFact): for jj in range(0, bb, self.repFact): n = num.sum(bgmask[ii:ii + self.repFact, jj:jj + self.repFact]) if n == self.repFact * self.repFact: rebinnedSkyImage[ii / self.repFact, jj / self.repFact] = num.sum( skyImage[ii:ii + self.repFact, jj:jj + self.repFact]) w = num.where(rebinnedSkyImage <> 0.0) bgf = bgFinder.bgFinder(rebinnedSkyImage[w]) if display and enableBGSelection: bgf.plotAxis = self.dispFig.add_subplot(self.dispGS[1]) if not trimBGHighPix: bg = bgf.smartBackground(display=display, backupMode=backupMode, forceBackupMode=forceBackupMode) bgstd = num.std(rebinnedSkyImage[w]) else: #trimming BG high pix bg = bgf.smartBackground(backupMode=backupMode, forceBackupMode=forceBackupMode) bgstd = num.std(rebinnedSkyImage[w]) W = num.where(rebinnedSkyImage[w] < bg + trimBGHighPix * bgstd) bgf = bgFinder.bgFinder(rebinnedSkyImage[w][W]) if display and enableBGSelection: bgf.plotAxis = self.dispFig.add_subplot(self.dispGS[1]) bg = bgf.smartBackground(display=display, backupMode=backupMode, forceBackupMode=forceBackupMode) bgstd = num.std(rebinnedSkyImage[w][W]) if singleAperture: W = num.where(mask != 0.0) flux = num.sum(image) - len(W[0]) * bg / (self.repFact**2) elif multipleApertures: flux = [] for jj in range(len(radius)): W = num.where(mask[jj] != 0.0) flux.append( num.sum(image[jj]) - len(W[0]) * bg / (self.repFact**2)) flux = num.array(flux) self.nPix = num.sum(mask) / (self.repFact**2) self.sourceFlux = flux self.bg = bg self.bgstd = bgstd self.exptime = exptime self.magnitude = zpt - 2.5 * num.log10(self.sourceFlux / self.exptime) if display: if trimBGHighPix: w = num.where( skyImage * (self.repFact * self.repFact) > (bg + trimBGHighPix * bgstd)) skyImage[w] = 0 if multipleApertures: im = skyImage + image[-1] elif singleAperture: im = skyImage + image if self.zscale: (z1, z2) = numdisplay.zscale.zscale(im) norm = interval.ManualInterval(z1, z2) self.dispAx.imshow(norm(im), interpolation='nearest', origin='lower') else: w = num.where(im == 0.0) im[w] += self.bg * 0.7 / (self.repFact * self.repFact) im = num.clip(im, num.min(im), num.max(image)) self.dispAx.imshow(im, interpolation='nearest', origin='lower') if self.l0 is not None: self.dispAx.plot(num.linspace(l0.xlim[0], l0.xlim[1], 100), l0(num.linspace(l0.xlim[0], l0.xlim[1], 100)), 'w-', lw=2.) self.dispAx.plot(num.linspace(l2.xlim[0], l2.xlim[1], 100), l2(num.linspace(l2.xlim[0], l2.xlim[1], 100)), 'w-', lw=2.) mx0 = (l0.xlim[0] + l2.xlim[0]) / 2 my0 = (l0.ylim[0] + l2.ylim[0]) / 2 a0 = num.arctan2(l0.ylim[0] - my0, l0.xlim[0] - mx0) a1 = num.arctan2(l2.ylim[0] - my0, l2.xlim[0] - mx0) a01 = num.linspace(a0, a1, 25) outerRadius = radius if singleAperture else radius[-1] semiCircX = num.cos(a01) * outerRadius * self.repFact semiCircY = num.sin(a01) * outerRadius * self.repFact mx1 = (l0.xlim[1] + l2.xlim[1]) / 2 my1 = (l0.ylim[1] + l2.ylim[1]) / 2 my0, my1 = ((my1, my0) if ((angle < 0) & (angle > -90)) else (my0, my1)) self.dispAx.plot(mx0 - semiCircX, my0 - semiCircY, 'w-', lw=2) self.dispAx.plot(mx1 + semiCircX, my1 + semiCircY, 'w-', lw=2) if enableBGSelection: print 'Current background value: %.3f' % (self.bg) self.dispAx.set_title( 'To improve background measurement, zoom on\na good background region, then close.' ) (ox0, ox1) = self.dispAx.get_xlim() (oy0, oy1) = self.dispAx.get_ylim() (A, B) = im.shape #all of these are needed in _on_lims_change self._bgFind = bgf self._rbsi = rebinnedSkyImage self._AB = im.shape self._bgm = backupMode self._fbgm = forceBackupMode if zoomRegion is not None: # Broad steps to zoom to a specific region self.dispAx.set_xlim(zoomRegion[0] * self.repFact, zoomRegion[1] * self.repFact) self.dispAx.set_ylim(zoomRegion[2] * self.repFact, zoomRegion[3] * self.repFact) self._on_xlims_change(self.dispAx) self._on_ylims_change(self.dispAx) self.dispAx.callbacks.connect('xlim_changed', self._on_xlims_change) self.dispAx.callbacks.connect('ylim_changed', self._on_ylims_change) pyl.show() (x0, x1) = self.dispAx.get_xlim() (y0, y1) = self.dispAx.get_ylim() x0 = max(0, x0) / self.repFact y0 = max(0, y0) / self.repFact x1 = min(B, x1) / self.repFact y1 = min(A, y1) / self.repFact self.bgSamplingRegion = [x0, x1, y0, y1] #need to clear the histogram first #need to update the positions so that the code below this ifstatement actualy fires if ox0 == x0 and ox1 == x1 and oy0 == y0 and oy1 == y1: return rebinnedSkyImage = rebinnedSkyImage[int(y0):int(y1), int(x0):int(x1)] w = num.where(rebinnedSkyImage <> 0.0) W = num.where(rebinnedSkyImage[w] < bg + trimBGHighPix * bgstd) bgf = bgFinder.bgFinder(rebinnedSkyImage[w][W]) bg = bgf.smartBackground(display=False, backupMode=backupMode, forceBackupMode=forceBackupMode, verbose=verbose) bgstd = num.std(rebinnedSkyImage[w]) if singleAperture: W = num.where(mask != 0.0) flux = num.sum(image) - len( W[0]) * bg / (self.repFact * self.repFact) elif multipleApertures: flux = [] for jj in range(len(radius)): W = num.where(mask[jj] != 0.0) flux.append( num.sum(image[jj]) - len(W[0]) * bg / (self.repFact * self.repFact)) flux = num.array(flux) self.nPix = num.sum(mask) / (self.repFact * self.repFact) self.sourceFlux = flux self.bg = bg self.bgstd = bgstd self.exptime = exptime self.magnitude = zpt - 2.5 * num.log10( self.sourceFlux / self.exptime) else: pyl.show() if verbose: print num.sum( image), self.sourceFlux, self.bg, zpt - 2.5 * num.log10(flux)
def fitMoffat(self, imData, centX, centY, boxSize=25, bgRadius=20, verbose=False, mode='smart', fixAB=False, fitXY=False, fitMaxRadius=-1., logRadPlot=False): """ Fit a moffat profile to the input data, imData, at point centX,centY. - boxSize is the width around the centre used in the fitting. - bgRadius is the radius beyond which the background is estimated. - verbose=True to see a lot of fittnig output and a radial plot of each fit. - logRadPlot=True to see the plot in log radius. - mode='smart' is the background determination method used. See bgFinder for details. - fixAB=True to fit only the amplitude. - fitXY=False *** this is currently not implemented*** - fitMaxRadius ***not currently implemented*** """ self.verbose = verbose self.imData = np.copy(imData) self.boxSize = boxSize self._flatRadial(centX - 0.5, centY - 0.5) #set the radial distribution pixels #w = np.where(self.rDist>bgRadius) #bgf = bgFinder.bgFinder(self.fDist[w]) w = np.where(self.rads > bgRadius) bgf = bgFinder.bgFinder(self.subSec[w]) self.bg = bgf(method=mode) #peakGuess = (np.max(self.fDist)-self.bg)/(np.max(self.moffat(self.rDist))) peakGuess = (np.max(self.subSec) - self.bg) / (np.max( self.moffat(self.rads))) if fitXY: print 'This is hacky and really slow. Not yet meant for production.' self.verbose = False best = [1.e8, -1., -1., -1.] print 'Fitting XYA' deltaX = np.arange(-0.2, 0.2 + 1. / self.repFact, 1. / self.repFact / 2.) deltaY = np.arange(-0.2, 0.2 + 1. / self.repFact, 1. / self.repFact / 2.) for ii in range(len(deltaX)): for jj in range(len(deltaY)): self._flatRadial(centX + deltaX[ii], centY + deltaY[jj]) lsqf = opti.leastsq(self._residFAB, (peakGuess), args=(self.alpha, self.beta, fitMaxRadius), maxfev=1000) res = np.sum( self._residFAB((lsqf[0][0]), self.alpha, self.beta, fitMaxRadius)**2) if best[0] >= res: best = [res, lsqf[0], deltaX[ii], deltaY[jj]] return (best[2], best[3]) elif fixAB: lsqf = opti.leastsq(self._residFAB, (peakGuess), args=(self.alpha, self.beta, fitMaxRadius), maxfev=200) else: lsqf = opti.leastsq(self._resid, (peakGuess, self.alpha, self.beta), args=(fitMaxRadius), maxfev=250) if self.verbose: print lsqf self.A = lsqf[0][0] if not fixAB: self.alpha = lsqf[0][1] self.beta = lsqf[0][2] if fixAB: res = self._residFAB((self.A), self.alpha, self.beta, fitMaxRadius) else: res = self._resid((self.A, self.alpha, self.beta), fitMaxRadius) self.chi = np.sqrt(np.sum(res**2) / (len(res) - 1)) self.chiFluxNorm = np.sqrt(np.sum((res / self.A)**2) / (len(res) - 1)) self.fitted = True self.PSF = self.moffat(self.R) self.PSF /= np.sum(self.PSF) self.psf = downSample2d(self.PSF, self.repFact) if self.verbose: print ' A:%s, alpha:%s, beta:%s' % (self.A, self.alpha, self.beta) fig = pyl.figure('Radial Profile') ax = fig.add_subplot(111) pyl.scatter(downSample2d(self.repRads, self.repFact), self.subSec) r = np.linspace(0, np.max(self.rads), 100) pyl.plot(r, self.A * self.moffat(r) + self.bg, 'r--') fw = self.FWHM(fromMoffatProfile=True) print 'FWHM: %.3f' % (fw) pyl.title('FWHM: {.3f} alpha: {.3f} beta: {.3f}'.format( fw, self.alpha, self.beta)) if logRadPlot: ax.set_xscale('log') pyl.show() return res
cut_widthx = widths[i] cut_widthy = widths[i] while (np.max(X[0, :]) - np.min(X[0, :])) > cut_widthx: cut_widthx = widths[i] i += 1 i = 0 while (np.max(Y[0, :]) - np.min(Y[0, :])) > cut_widthy: cut_widthy = widths[i] i += 1 cut_widthx += 50 cut_widthy += 50 for i, im in enumerate(ims): #print(np.median(datas[i][1850:2300,650:1390])) (A, B) = datas[i].shape bgf = bgFinder.bgFinder(datas[i][30:A - 30:10, 30:B - 30:10]) bg = bgf.fraserMode() big = np.zeros((A + cut_widthy * 4 + 1, B + cut_widthx * 4 + 1)).astype('float64') + bg big[cut_widthy * 2:A + cut_widthy * 2, cut_widthx * 2:cut_widthx * 2 + B] = datas[i] cut = big[int(Y[i][0]) + cut_widthy:int(Y[i][0]) + 3 * cut_widthy, int(X[i][0]) + cut_widthx:int(X[i][0]) + 3 * cut_widthx] #cut = big[int(meanPos[1])+cut_width:int(meanPos[1])+3*cut_width,int(meanPos[0])+cut_width:int(meanPos[0])+3*cut_width] cutouts.append(np.copy(cut)) if len(cut) == 0: normers.append([]) normed.append(np.zeros((2 * cut_widthy + 1, 2 * cut_widthx + 1))) else:
def fitMoffat(self,imData,centX,centY, boxSize=25,bgRadius=20, verbose=False,mode='smart',fixAB=False, fitXY=False,fitMaxRadius=-1.,logRadPlot=False): """ Fit a moffat profile to the input data, imData, at point centX,centY. - boxSize is the width around the centre used in the fitting. - bgRadius is the radius beyond which the background is estimated. - verbose=True to see a lot of fittnig output and a radial plot of each fit. - logRadPlot=True to see the plot in log radius. - mode='smart' is the background determination method used. See bgFinder for details. - fixAB=True to fit only the amplitude. - fitXY=False *** this is currently not implemented*** - fitMaxRadius ***not currently implemented*** """ self.verbose = verbose self.imData = imData*1.0 self.boxSize = boxSize self._flatRadial(centX-0.5,centY-0.5)#set the radial distribution pixels #w = num.where(self.rDist>bgRadius) #bgf = bgFinder.bgFinder(self.fDist[w]) w = num.where(self.rads>bgRadius) bgf = bgFinder.bgFinder(self.subSec[w]) self.bg = bgf(method=mode) #peakGuess = (num.max(self.fDist)-self.bg)/(num.max(self.moffat(self.rDist))) peakGuess = (num.max(self.subSec)-self.bg)/(num.max(self.moffat(self.rads))) if fitXY: print 'This is hacky and really slow. Not really meant for production.' self.verbose = False best = [1.e8,-1.,-1.,-1.] print 'Fitting XYA' deltaX = num.arange(-0.2,0.2+1./self.repFact,1./self.repFact/2.) deltaY = num.arange(-0.2,0.2+1./self.repFact,1./self.repFact/2.) for ii in range(len(deltaX)): for jj in range(len(deltaY)): self._flatRadial(centX+deltaX[ii],centY+deltaY[jj]) lsqf = opti.leastsq(self._residFAB,(peakGuess),args=(self.alpha,self.beta,fitMaxRadius),maxfev=1000) res = num.sum(self._residFAB((lsqf[0][0]),self.alpha,self.beta,fitMaxRadius)**2) if best[0]>= res: best = [res,lsqf[0],deltaX[ii],deltaY[jj]] return (best[2],best[3]) elif fixAB: lsqf = opti.leastsq(self._residFAB,(peakGuess),args=(self.alpha,self.beta,fitMaxRadius),maxfev=200) else: lsqf = opti.leastsq(self._resid,(peakGuess,self.alpha,self.beta),args=(fitMaxRadius),maxfev=250) if self.verbose: print lsqf self.A = lsqf[0][0] if not fixAB: self.alpha = lsqf[0][1] self.beta = lsqf[0][2] if fixAB: res=self._residFAB((self.A),self.alpha,self.beta,fitMaxRadius) else: res=self._resid((self.A,self.alpha,self.beta),fitMaxRadius) self.chi = num.sqrt(num.sum(res**2)/(len(res)-1)) self.fitted = True self.PSF = self.moffat(self.R) self.PSF /= num.sum(self.PSF) self.psf = downSample2d(self.PSF,self.repFact) if self.verbose: print ' A:%s, alpha:%s, beta:%s'%(self.A,self.alpha,self.beta) fig = pyl.figure('Radial Profile') ax = fig.add_subplot(111) pyl.scatter(downSample2d(self.repRads,self.repFact),self.subSec) r = num.linspace(0,num.max(self.rads),100) pyl.plot(r,self.A*self.moffat(r)+self.bg,'r--') fw = self.FWHM(fromMoffatProfile=True) print 'FWHM: %.3f'%(fw) pyl.title('FWHM: %.3f alpha: %.3f beta: %.3f'%(fw,self.alpha,self.beta)) if logRadPlot: ax.set_xscale('log') pyl.show() return res