def run(): imageFile = '/u/jlu/data/w51/09jun26/combo/mag09jun26_w51a_f4_kp.fits' img = pyfits.getdata(imageFile) F = fftpack.fftshift(fftpack.fft2(img)) psd2D = np.abs(F)**2 psd1D = radialProfile.azimuthalAverage(psd2D) py.figure(1) py.clf() py.imshow(np.log10(img), cmap=py.cm.Greys, vmin=math.log10(20), vmax=math.log10(3500)) py.title('Image') py.savefig('image_fft_examp_image.png') py.figure(2) py.clf() py.imshow(np.log10(psd2D), cmap=py.cm.jet) py.title('2D Power Spectrum') py.savefig('image_fft_examp_psd2d.png') py.figure(3) py.clf() py.semilogy(psd1D) py.title('1D Power Spectrum') py.xlabel('Spatial Frequency') py.ylabel('Power Spectrum') py.savefig('image_fft_examp_psd1d.png') py.show()
def run(): imageFile = '/u/jlu/data/w51/09jun26/combo/mag09jun26_w51a_f4_kp.fits' img = pyfits.getdata(imageFile) F = fftpack.fftshift( fftpack.fft2(img) ) psd2D = np.abs(F)**2 psd1D = radialProfile.azimuthalAverage(psd2D) py.figure(1) py.clf() py.imshow(np.log10(img), cmap=py.cm.Greys, vmin=math.log10(20), vmax=math.log10(3500)) py.title('Image') py.savefig('image_fft_examp_image.png') py.figure(2) py.clf() py.imshow(np.log10(psd2D), cmap=py.cm.jet) py.title('2D Power Spectrum') py.savefig('image_fft_examp_psd2d.png') py.figure(3) py.clf() py.semilogy(psd1D) py.title('1D Power Spectrum') py.xlabel('Spatial Frequency') py.ylabel('Power Spectrum') py.savefig('image_fft_examp_psd1d.png') py.show()
def plot_trim_fake_envelope(): """ Plot up the pairwise delta-mag vs. delta-sep plot and overplot the PSF envelope which we have used in trim_fakes. """ rootDir = '/u/jlu/work/testStarfinder/09_06_01/stf_old/' origList = rootDir + 'img_old_0.8_stf_cal.lis' origPSF = rootDir + 'img_old_psf.fits' # ---------- # Starlist # ---------- # Read in the starlist tab = asciidata.open(origList) mag = tab[1].tonumpy() x = tab[3].tonumpy() y = tab[4].tonumpy() starCount = tab.nrows magMatrix = np.tile(mag, (starCount, 1)) xMatrix = np.tile(x, (starCount, 1)) yMatrix = np.tile(y, (starCount, 1)) # Take only the upper matrix in order to not repeat. dm = np.triu(magMatrix.transpose() - magMatrix) dx = np.triu(xMatrix.transpose() - xMatrix) dy = np.triu(yMatrix.transpose() - yMatrix) dr = np.triu(np.hypot(dx, dy)) # Flatten and take all non-zeros idx = np.where(dr.flatten() != 0)[0] dm = -np.abs(dm.flatten()[idx]) dr = dr.flatten()[idx] # ---------- # PSF # ---------- psf2D = pyfits.getdata(origPSF) psf = radialProfile.azimuthalAverage(psf2D) psf = -2.5 * np.log10(psf[0] / psf) # Plot this up py.clf() py.plot(dr, dm, 'k.') py.plot(psf, 'b-') py.xlim(0, 100)
def apertureCorrections( root, plot=True, silent=False, stfDir='/u/jlu/data/w51/10aug14/combo/', mtfDir='/u/jlu/work/w51/photo_calib/10aug14/science_fields/mtf/', outDir='./', innerAper=None, outerAper=None): """ innerAper - (default = None, use filter-dependent dictionary in function). Set to narrow camera pixels (even if image is wide camera). outerAper - (default = None, use filter-dependent dictionary in function). Set to narrow camera pixels (even if image is wide camera). """ aperSTFbyFilter = {'h': 12, 'kp': 12, 'lp': 12} aperSTDbyFilter = {'h': 160, 'kp': 130, 'lp': 20} filter = root.split('_')[-1] if innerAper == None: apSTF = aperSTFbyFilter[filter] else: apSTF = innerAper if outerAper == None: apSTD = aperSTDbyFilter[filter] else: apSTD = outerAper camera = 'narrow' scale = 0.00995 # Correct for wide camera if 'wide' in root: camera = 'wide' scale = 0.04 apSTF /= 4 apSTD /= 4 # ########## # PSF from starfinder # ########## psf2d_stf = pyfits.getdata(stfDir + root + '_psf.fits') foo = radialProfile.azimuthalAverage(psf2d_stf) psf_stf_r = foo[0] psf_stf = foo[1] psf_stf_err = foo[2] / np.sqrt(foo[3]) # error on the mean psf_stf_npix = foo[3] # ########## # PSF from MTF code # ########## pickleFile = open(mtfDir + root + '_mtf.pickle', 'r') obs = pickle.load(pickleFile) fit = pickle.load(pickleFile) psf2d_mtf = fit.psf2d foo = radialProfile.azimuthalAverage(psf2d_mtf) psf_mtf_r = foo[0] psf_mtf = foo[1] psf_mtf_err = foo[2] / np.sqrt(foo[3]) # error on the mean psf_mtf_npix = foo[3] #psf_mtf = fit.psf1d #psf_mtf_r = np.arange(len(psf_mtf), dtype=float) # Normalize MTF PSF, so that it peaks at 1.0 #renorm = psf_mtf[0] #psf_mtf /= renorm #psf_mtf_err /= renorm # Convert radii to arcsec psf_mtf_r *= scale # in arcsec psf_stf_r *= scale # in arcsec # Normalize the Starfinder PSF to the first 3 radial bins # covering the core. r is still in pixels core_radius = 2 * 0.05 min_r = max([psf_stf_r[0], psf_mtf_r[0]]) # Smallest radius to both idx_stf = np.where((psf_stf_r >= min_r) & (psf_stf_r < core_radius))[0] idx_mtf = np.where((psf_mtf_r >= min_r) & (psf_mtf_r < core_radius))[0] core_flux_stf = psf_stf[idx_stf].sum() core_flux_mtf = psf_mtf[idx_mtf].sum() norm_factor = (core_flux_mtf / core_flux_stf) #.mean() psf_stf *= norm_factor psf_stf_err *= norm_factor # ########## # Calc Aperutre Corrections # ########## npix_inner = psf_mtf_npix[0:apSTF] npix_outer = psf_mtf_npix[apSTF:apSTD] # 1. Get the Starfinder flux out to the specified STF aperture flux_stf_inner = (psf_stf[0:apSTF] * npix_inner).sum() # 2. Get the Starfinder flux out to the edge of the PSF flux_stf_all = (psf_stf * psf_stf_npix).sum() # 3. Get the MTF flux out to the specified STF aperture flux_mtf_inner = (psf_mtf[0:apSTF] * npix_inner).sum() flux_mtf_inner_err = ((psf_mtf_err[0:apSTF] * npix_inner)**2).sum() flux_mtf_inner_err = math.sqrt(flux_mtf_inner_err) # 4. Get the MTF flux out to the specified standard star aperture flux_mtf_outer = (psf_mtf[apSTF:apSTD] * npix_outer).sum() flux_mtf_outer_err = ((psf_mtf_err[apSTF:apSTD] * npix_outer)**2).sum() flux_mtf_outer_err = math.sqrt(flux_mtf_outer_err) # 5. Calculate the aperture correction (in magnitudes) to # go from Starfinder total fluxes, to standard star apertures. stf2stfIn_flux = flux_stf_inner / flux_stf_all stf2stan_flux = (1.0 + (flux_mtf_outer / flux_mtf_inner)) * stf2stfIn_flux stf2stan_mags = -2.5 * math.log10(stf2stan_flux) # 5. Calculate errors err1 = (stf2stfIn_flux * flux_mtf_outer_err / flux_mtf_inner)**2 err2 = (stf2stfIn_flux * flux_mtf_outer * flux_mtf_inner_err / flux_mtf_inner**2)**2 stf2stan_flux_err = np.sqrt(err1 + err2) stf2stan_mags_err = 2.5 * math.log10(math.e) stf2stan_mags_err *= stf2stan_flux_err / stf2stan_flux if silent == False: # ########## # Printing # ########## print '' print '*** APERTURE CORRECTIONS FOR %s ***' % root #print 'err1 = ', err1, ' err2 = ', err2 #print 'stf2stfIn_flux = ', stf2stfIn_flux print 'Science Aperture Size = %d %s pixels (%.3f arcsec)' % \ (apSTF, camera, apSTF * scale) print 'Standard Aperture Size = %d %s pixels (%.3f arcsec)' % \ (apSTD, camera, apSTD * scale) print 'PSFs normalized at radius = %.2f arcsec, factor = %.3f' % \ (core_radius, norm_factor) print '' print 'STF Flux within STF Aperture: %f' % (flux_stf_inner) print 'MTF Flux within STF Aperture: %f' % (flux_mtf_inner) print 'MTF Flux within STD Aperture: %f' % \ (flux_mtf_inner + flux_mtf_outer) print '' print 'Aperture Correction to go from Starfinder Magnitudes' print 'to Standard Apparent Magnitudes:' print ' Flux Ratio = %.3f +/- %.3f' % \ (stf2stan_flux, stf2stan_flux_err) print ' Mag Differ = %.3f +/- %.3f' % \ (stf2stan_mags, stf2stan_mags_err) print ' Stan Flux = STF Flux * %.3f' % (stf2stan_flux) print ' Stan Mags = STF Mags + %.3f + ZP' % (stf2stan_mags) if plot == True: # ########## # Plotting # ########## # Plot PSFs py.figure(1) py.clf() py.semilogy(psf_stf_r, psf_stf, 'b-', label='STF', linewidth=2) py.plot(psf_mtf_r, psf_mtf, 'k-', label='MTF', linewidth=2) psf_lo = psf_stf - psf_stf_err psf_hi = psf_stf + psf_stf_err idx = np.where(psf_lo > 0)[0] py.fill_between(psf_stf_r[idx], psf_lo[idx], y2=psf_hi[idx], color='blue', alpha=0.5) # Show where the normalization occurs. py.plot(psf_mtf_r[idx_mtf], psf_mtf[idx_mtf], 'r-', linewidth=2, label='_nolabel_') py.legend() py.xlabel('Radius (arcsec)') py.ylabel('Point Spread Function Intensity') py.xlim(0, 1.0) py.title(root) py.savefig(outDir + 'mtf_' + root + '_psfs.png') # ---------- # Encircled Energy: # Renormalize the MTF PSF such that integrating it gives # us the encircled energy. # ---------- # EE from MTF code ee_mtf2 = fit.encircled_energy ee_mtf2_r = np.arange(0, len(ee_mtf2)) * scale # EE from integrating the MTF PSF ee_mtf = (psf_mtf * psf_mtf_npix).cumsum() ee_mtf_r = psf_mtf_r # Find the radii at which they overlap min_r = ee_mtf_r[0] max_r = min([ee_mtf_r[-1], ee_mtf2_r[-1]]) idx_mtf2 = np.where((ee_mtf2_r >= min_r) & (ee_mtf2_r <= max_r))[0] idx_mtf = np.where((ee_mtf_r >= min_r) & (ee_mtf_r <= max_r))[0] # Calculate a normalization factor assuming the MTF EE is truth norm_factor_mtf = (ee_mtf2[idx_mtf2] / ee_mtf[idx_mtf]).mean() ee_mtf *= norm_factor_mtf # EE from integrating the STF PSF (renormalized also) ee_stf = (psf_stf * psf_stf_npix).cumsum() * norm_factor_mtf ee_stf_r = psf_stf_r py.figure(2) py.clf() py.plot(ee_stf_r, ee_stf, 'b-', label='STF', linewidth=2) py.plot(ee_mtf_r, ee_mtf, 'k-', label='MTF', linewidth=2) py.plot(ee_mtf2_r, ee_mtf2, 'k--', label='MTF2', linewidth=2) py.legend() py.xlabel('Radius (arcsec)') py.ylabel('Encircled Energy') py.xlim(0, 1.0) py.title(root) py.savefig(outDir + 'mtf_' + root + '_ee.png') return (stf2stan_flux, stf2stan_flux_err, stf2stan_mags, stf2stan_mags_err)
def fft_play(imageRoot, dataDir='/u/jlu/data/w51/09jun26/combo/', starsSuffix='_0.8_stf.lis'): ############################## # H-band wide image ############################## img, hdr = pyfits.getdata(dataDir + imageRoot + '.fits', header=True) F = fftpack.fftshift( fftpack.fft2(img) ) psd2D_im = np.abs(F)**2 psd1D_im = radialProfile.azimuthalAverage(psd2D_im) py.figure(1) py.clf() py.imshow(np.log10(img)) py.figure(2) py.clf() py.imshow(np.log10(psd2D_im)) py.figure(3) py.clf() py.semilogy(psd1D_im) py.show() ########## # H-band wide *_sig.fits image ########## img, hdr = pyfits.getdata(dataDir + imageRoot + '_sig.fits', header=True) F = fftpack.fftshift( fftpack.fft2(img) ) psd2D_sig = np.abs(F)**2 psd1D_sig = radialProfile.azimuthalAverage(psd2D_sig) py.figure(2) py.clf() py.semilogy(psd1D_sig) py.show() ########## # Source List ########## stfLis = dataDir + 'starfinder/' + imageRoot + starsSuffix _lis = asciidata.open(stfLis) mag = _lis[1].tonumpy() x = _lis[3].tonumpy() y = _lis[4].tonumpy() flux = 10**((mag[0] - mag)/2.5) sources = np.zeros(img.shape, dtype=float) xpix = np.array(np.round(x), dtype=int) ypix = np.array(np.round(y), dtype=int) sources[xpix, ypix] = flux F = fftpack.fftshift( fftpack.fft2( sources )) psd2D_src = np.abs(F)**2 psd1D_src = radialProfile.azimuthalAverage(psd2D_src) py.figure(1) py.clf() py.imshow(np.log10(psd2D_src)) py.figure(2) py.clf() py.semilogy(psd1D_src) py.show() # Plot all 1D PSDs py.figure(1) py.clf() py.semilogy(psd1D_im - psd1D_sig) py.semilogy(psd1D_sig) py.semilogy(psd1D_src) py.show()
def mtf_plot_results(imageRoot, dataDir='/u/jlu/data/w51/09jun26/combo/', starsSuffix='_0.8_stf.lis'): img, hdr = pyfits.getdata(dataDir + imageRoot + '.fits', header=True) import pidly idl = pidly.IDL() print 'MTF: Restoring IDL variables' mtfData = imageRoot + '_mtfdata.save' mtfFit = imageRoot + '_mtffit.save' idl('restore, "' + mtfData + '"') idl('restore, "' + mtfFit + '"') ########## # Plot the 1D and 2D power spectrum of the source distribution ########## stfLis = dataDir + 'starfinder/' + imageRoot + starsSuffix _lis = asciidata.open(stfLis) mag = _lis[1].tonumpy() x = _lis[3].tonumpy() y = _lis[4].tonumpy() flux = 10**((mag[0] - mag)/2.5) sources = np.zeros(img.shape, dtype=float) xpix = np.array(np.round(x), dtype=int) ypix = np.array(np.round(y), dtype=int) sources[xpix, ypix] = flux F = fftpack.fftshift( fftpack.fft2(sources) ) psd2D = np.abs(F)**2 psd1D = radialProfile.azimuthalAverage(psd2D) # py.figure(1) # py.clf() # py.imshow(np.log10(psd2D)) # py.figure(2) # py.clf() # py.semilogy(psd1D) # py.xlabel('Spatial Frequency') # py.ylabel('Power Spectrum') # py.figure(3) # py.clf() # py.semilogy(idl.nu, idl.spdist) # py.xlabel('Spatial Frequency') # py.ylabel('Power Spectrum') # py.show() ########## # Plot up the best-fit power spectrum ########## print params idl('pspec_fit = mtffunc_keck(nu, params, spdist=spdist)') idl('mtf = mtffunc_keck(nu, params)') nu = idl.nu power = idl.power pspec_fit = idl.pspec_fit mtf = idl.mtf resid = power - pspec_fit print nu.shape print pspec_fit.shape py.clf() # py.semilogy(nu, power) py.semilogy(nu, pspec_fit) # py.semilogy(nu, mtf) # py.semilogy(nu, np.abs(resid)) py.xlabel('Spatial Frequency') py.ylabel('Power Spectrum') py.legend(('Data', 'Best Fit', 'MTF', 'Residuals')) py.show()
def apertureCorrections(root, plot=True, silent=False, stfDir='/u/jlu/data/w51/09jun26/combo/', mtfDir='/u/jlu/work/w51/photo_calib/09jun26/science_fields/mtf/', outDir='./', innerAper=None, outerAper=None): """ innerAper - (default = None, use filter-dependent dictionary in function). Set to narrow camera pixels (even if image is wide camera). outerAper - (default = None, use filter-dependent dictionary in function). Set to narrow camera pixels (even if image is wide camera). """ aperSTFbyFilter = {'h': 12, 'kp': 12, 'lp': 12} aperSTDbyFilter = {'h': 160, 'kp': 130, 'lp': 20} filter = root.split('_')[-1] if innerAper == None: apSTF = aperSTFbyFilter[filter] else: apSTF = innerAper if outerAper == None: apSTD = aperSTDbyFilter[filter] else: apSTD = outerAper camera = 'narrow' scale = 0.00995 # Correct for wide camera if 'wide' in root: camera = 'wide' scale = 0.04 apSTF /= 4 apSTD /= 4 # ########## # PSF from starfinder # ########## psf2d_stf = pyfits.getdata(stfDir + root + '_psf.fits') foo = radialProfile.azimuthalAverage(psf2d_stf) psf_stf_r = foo[0] psf_stf = foo[1] psf_stf_err = foo[2] / np.sqrt(foo[3]) # error on the mean psf_stf_npix = foo[3] # ########## # PSF from MTF code # ########## pickleFile = open(mtfDir + root + '_mtf.pickle', 'r') obs = pickle.load(pickleFile) fit = pickle.load(pickleFile) psf2d_mtf = fit.psf2d foo = radialProfile.azimuthalAverage(psf2d_mtf) psf_mtf_r = foo[0] psf_mtf = foo[1] psf_mtf_err = foo[2] / np.sqrt(foo[3]) # error on the mean psf_mtf_npix = foo[3] #psf_mtf = fit.psf1d #psf_mtf_r = np.arange(len(psf_mtf), dtype=float) # Normalize MTF PSF, so that it peaks at 1.0 #renorm = psf_mtf[0] #psf_mtf /= renorm #psf_mtf_err /= renorm # Convert radii to arcsec psf_mtf_r *= scale # in arcsec psf_stf_r *= scale # in arcsec # Normalize the Starfinder PSF to the first 3 radial bins # covering the core. r is still in pixels core_radius = 2 * 0.05 min_r = max([psf_stf_r[0], psf_mtf_r[0]]) # Smallest radius to both idx_stf = np.where((psf_stf_r >= min_r) & (psf_stf_r < core_radius))[0] idx_mtf = np.where((psf_mtf_r >= min_r) & (psf_mtf_r < core_radius))[0] core_flux_stf = psf_stf[idx_stf].sum() core_flux_mtf = psf_mtf[idx_mtf].sum() norm_factor = (core_flux_mtf / core_flux_stf)#.mean() psf_stf *= norm_factor psf_stf_err *= norm_factor # ########## # Calc Aperutre Corrections # ########## npix_inner = psf_mtf_npix[0:apSTF] npix_outer = psf_mtf_npix[apSTF:apSTD] # 1. Get the Starfinder flux out to the specified STF aperture flux_stf_inner = (psf_stf[0:apSTF] * npix_inner).sum() # 2. Get the Starfinder flux out to the edge of the PSF flux_stf_all = (psf_stf * psf_stf_npix).sum() # 3. Get the MTF flux out to the specified STF aperture flux_mtf_inner = (psf_mtf[0:apSTF] * npix_inner).sum() flux_mtf_inner_err = ((psf_mtf_err[0:apSTF] * npix_inner)**2).sum() flux_mtf_inner_err = math.sqrt(flux_mtf_inner_err) # 4. Get the MTF flux out to the specified standard star aperture flux_mtf_outer = (psf_mtf[apSTF:apSTD] * npix_outer).sum() flux_mtf_outer_err = ((psf_mtf_err[apSTF:apSTD] * npix_outer)**2).sum() flux_mtf_outer_err = math.sqrt(flux_mtf_outer_err) # 5. Calculate the aperture correction (in magnitudes) to # go from Starfinder total fluxes, to standard star apertures. stf2stfIn_flux = flux_stf_inner / flux_stf_all stf2stan_flux = (1.0 + (flux_mtf_outer / flux_mtf_inner)) * stf2stfIn_flux stf2stan_mags = -2.5 * math.log10(stf2stan_flux) # 5. Calculate errors err1 = (stf2stfIn_flux * flux_mtf_outer_err / flux_mtf_inner)**2 err2 = (stf2stfIn_flux * flux_mtf_outer * flux_mtf_inner_err / flux_mtf_inner**2)**2 stf2stan_flux_err = np.sqrt(err1 + err2) stf2stan_mags_err = 2.5 * math.log10(math.e) stf2stan_mags_err *= stf2stan_flux_err / stf2stan_flux if silent == False: # ########## # Printing # ########## print '' print '*** APERTURE CORRECTIONS FOR %s ***' % root #print 'err1 = ', err1, ' err2 = ', err2 #print 'stf2stfIn_flux = ', stf2stfIn_flux print 'Science Aperture Size = %d %s pixels (%.3f arcsec)' % \ (apSTF, camera, apSTF * scale) print 'Standard Aperture Size = %d %s pixels (%.3f arcsec)' % \ (apSTD, camera, apSTD * scale) print 'PSFs normalized at radius = %.2f arcsec, factor = %.3f' % \ (core_radius, norm_factor) print '' print 'STF Flux within STF Aperture: %f' % (flux_stf_inner) print 'MTF Flux within STF Aperture: %f' % (flux_mtf_inner) print 'MTF Flux within STD Aperture: %f' % \ (flux_mtf_inner + flux_mtf_outer) print '' print 'Aperture Correction to go from Starfinder Magnitudes' print 'to Standard Apparent Magnitudes:' print ' Flux Ratio = %.3f +/- %.3f' % \ (stf2stan_flux, stf2stan_flux_err) print ' Mag Differ = %.3f +/- %.3f' % \ (stf2stan_mags, stf2stan_mags_err) print ' Stan Flux = STF Flux * %.3f' % (stf2stan_flux) print ' Stan Mags = STF Mags + %.3f + ZP' % (stf2stan_mags) if plot == True: # ########## # Plotting # ########## # Plot PSFs py.figure(1) py.clf() py.semilogy(psf_stf_r, psf_stf, 'b-', label='STF', linewidth=2) py.plot(psf_mtf_r, psf_mtf, 'k-', label='MTF', linewidth=2) psf_lo = psf_stf-psf_stf_err psf_hi = psf_stf+psf_stf_err idx = np.where(psf_lo > 0)[0] py.fill_between(psf_stf_r[idx], psf_lo[idx], y2=psf_hi[idx], color='blue', alpha=0.5) # Show where the normalization occurs. py.plot(psf_mtf_r[idx_mtf], psf_mtf[idx_mtf], 'r-', linewidth=2, label='_nolabel_') py.legend() py.xlabel('Radius (arcsec)') py.ylabel('Point Spread Function Intensity') py.xlim(0, 1.0) py.title(root) py.savefig(outDir + 'mtf_' + root + '_psfs.png') # ---------- # Encircled Energy: # Renormalize the MTF PSF such that integrating it gives # us the encircled energy. # ---------- # EE from MTF code ee_mtf2 = fit.encircled_energy ee_mtf2_r = np.arange(0, len(ee_mtf2)) * scale # EE from integrating the MTF PSF ee_mtf = (psf_mtf * psf_mtf_npix).cumsum() ee_mtf_r = psf_mtf_r # Find the radii at which they overlap min_r = ee_mtf_r[0] max_r = min([ee_mtf_r[-1], ee_mtf2_r[-1]]) idx_mtf2 = np.where((ee_mtf2_r >= min_r) & (ee_mtf2_r <= max_r))[0] idx_mtf = np.where((ee_mtf_r >= min_r) & (ee_mtf_r <= max_r))[0] # Calculate a normalization factor assuming the MTF EE is truth norm_factor_mtf = (ee_mtf2[idx_mtf2] / ee_mtf[idx_mtf]).mean() ee_mtf *= norm_factor_mtf # EE from integrating the STF PSF (renormalized also) ee_stf = (psf_stf * psf_stf_npix).cumsum() * norm_factor_mtf ee_stf_r = psf_stf_r py.figure(2) py.clf() py.plot(ee_stf_r, ee_stf, 'b-', label='STF', linewidth=2) py.plot(ee_mtf_r, ee_mtf, 'k-', label='MTF', linewidth=2) py.plot(ee_mtf2_r, ee_mtf2, 'k--', label='MTF2', linewidth=2) py.legend() py.xlabel('Radius (arcsec)') py.ylabel('Encircled Energy') py.xlim(0, 1.0) py.title(root) py.savefig(outDir + 'mtf_' + root + '_ee.png') return (stf2stan_flux, stf2stan_flux_err, stf2stan_mags, stf2stan_mags_err)
def plot_pairwise_envelope(imageRoot, comboDir, magCut=100, radCut=10000, drBinSize=5, dmBinSize=0.5, calcArea=False): """ For all pairs of stars in a starlist, plot up the separation and delta-magnitude. Overplot the Starfinder PSF on the plots. imageRoot = e.g. mag06maylgs2_arch_f1_kp comboDir = e.g. /u/ghezgroup/data/gc/06maylgs2/combo/ magCut = Only plot pairs where the primary (brighter star) is brighter than a certain magnitude (default=100). radCut = Only plot pairs where the radius of the primary (brighter star) is less than a certain radius in pixels (default=10,000). """ image_file = comboDir + imageRoot + '.fits' psf_file = comboDir + imageRoot + '_psf.fits' #psf_file = imageRoot + '_psf2d_2asec.fits' lis_file = comboDir + 'starfinder/' + imageRoot + '_rms.lis' outSuffix = '%s_m%g_r%d' % (imageRoot.replace('mag', ''), magCut, radCut) lis = starTables.StarfinderList(lis_file, hasErrors=True) img = pyfits.getdata(image_file) psf2D = pyfits.getdata(psf_file) # Sort by brightness sidx = lis.mag.argsort() mag = lis.mag[sidx] x = lis.x[sidx] y = lis.y[sidx] xe = lis.xerr[sidx] ye = lis.yerr[sidx] asterr = (xe + ye) / 2.0 # # Make a cut based on the astrometric at a given magnitude. # starsPerBin = 30 # numBins = int( math.ceil(len(x) / starsPerBin) ) # keep = np.array([], dtype=int) # for ii in range(numBins): # lo = ii * starsPerBin # hi = (ii+1) * starsPerBin # asterr_median = np.median( asterr[lo:hi] ) # asterr_stddev = asterr[lo:hi].std() # # Keep only those below median + 3*stddev # cutoff = asterr_median + (2.0 * asterr_stddev) # tmp = np.where(asterr[lo:hi] < cutoff)[0] # tmp += lo # keep = np.append(keep, tmp) # print 'Stars from %.2f - %.2f have median(asterr) = %.4f std(asterr) = %.4f' % (mag[lo:hi].min(), mag[lo:hi].max(), asterr_median, asterr_stddev) # print 'Throwing out %d of %d stars with outlying astrometric errors' % \ # (len(x) - len(keep), len(x)) # mag = mag[keep] # x = x[keep] # y = y[keep] starCount = len(mag) magMatrix = np.tile(mag, (starCount, 1)) xMatrix = np.tile(x, (starCount, 1)) yMatrix = np.tile(y, (starCount, 1)) # Do the matrix calculation, then take the upper triangule dm = util.triu2flat(magMatrix.transpose() - magMatrix) dx = util.triu2flat(xMatrix.transpose() - xMatrix) dy = util.triu2flat(yMatrix.transpose() - yMatrix) dr = np.hypot(dx, dy) # Also pull out the x and y positions (and magnitudes) of the # primary star in each pair. x = util.triu2flat(xMatrix.transpose()) y = util.triu2flat(yMatrix.transpose()) m = util.triu2flat(magMatrix.transpose()) xmid = (x.max() - x.min()) / 2.0 ymid = (y.max() - y.min()) / 2.0 r = np.hypot(x - xmid, y - ymid) # Calculate the edges of the detectors edge_xlo = x.min() edge_xhi = x.max() edge_ylo = y.min() edge_yhi = y.max() # Azimuthally average the PSF psf_r, psf_f, psf_std, psf_n = radialProfile.azimuthalAverage(psf2D) psf = -2.5 * np.log10(psf_f[0] / psf_f) # convert to magnitudes # Trim down to a manageable size idx = np.where((dr > 0) & (dr < 500) & (m < magCut) & (r < radCut))[0] dm = dm[idx] dx = dx[idx] dy = dy[idx] dr = dr[idx] x = x[idx] y = y[idx] r = r[idx] m = m[idx] py.close(2) py.figure(2, figsize=(8, 6)) # ########## # Plot 2D scatter of positions # ########## py.clf() py.scatter(dx, dy, s=2, c=dm, marker='o', edgecolor='none') py.xlabel('X (pixels)') py.ylabel('Y (pixels)') py.title('MagCut < %g, RadCut < %d' % (magCut, radCut)) cbar = py.colorbar() cbar.set_label('Delta Magnitude') print 'Saving plots/pairs_xy_%s.png' % outSuffix py.savefig('plots/pairs_xy_%s.png' % outSuffix) # ########## # Plot 2D histogram of positions # ########## (xy, x_edges, y_edges) = py.histogram2d(dx, dy, bins=[25, 25]) dx_bin_size = (x_edges[1] - x_edges[0]) * 0.00995 dy_bin_size = (y_edges[1] - y_edges[0]) * 0.00995 xy /= dx_bin_size * dy_bin_size py.clf() py.imshow(xy.transpose(), extent=[x_edges[0], x_edges[-1], y_edges[0], y_edges[-1]], cmap=py.cm.gray_r) py.axis('equal') py.xlabel('X (pixel)') py.ylabel('Y (pixel)') py.title('MagCut < %g, RadCut < %d' % (magCut, radCut)) cbar = py.colorbar() cbar.set_label('stars / arcsec^2') print 'Saving plots/pairs_xy_hist_%s.png' % outSuffix py.savefig('plots/pairs_xy_hist_%s.png' % outSuffix) # ########## # Grid up into magnitude and distance 2D bins # ########## dr_bins = np.arange(0, 501, drBinSize) dm_bins = np.arange(-11, 0.1, dmBinSize) (h, r_edges, m_edges) = py.histogram2d(dr, dm, bins=[dr_bins,dm_bins]) # Calculate the area covered for each star, taking into account # edge limits. Use a dummy grid to calculate this for each star. grid_pix_size = 1.0 grid_side = np.arange(-500, 501, grid_pix_size) grid_y, grid_x = np.meshgrid(grid_side, grid_side) grid_r = np.hypot(grid_x, grid_y) areaFile = 'area_%s_dr%d.dat' % (outSuffix, drBinSize) if os.path.isfile(areaFile) and not calcArea: print 'Loading area file: %s' % areaFile _area = open(areaFile, 'r') area_at_r = pickle.load(_area) _area.close() if len(area_at_r) != len(dr_bins)-1: print 'Problem with area_at_r in %s' % areaFile print ' len(area_at_r) = %d' % len(area_at_r) print ' len(dr_bins)-1 = %d' % (len(dr_bins) - 1) else: print 'Creating area file: %s' % areaFile area_at_r = np.zeros(len(dr_bins)-1, dtype=float) for rr in range(len(dr_bins)-1): idx = np.where((grid_r > r_edges[rr]) & (grid_r <= r_edges[rr+1])) rgrid_x = grid_x[idx[0], idx[1]] rgrid_y = grid_y[idx[0], idx[1]] for ss in range(len(dr)): sgrid_x = rgrid_x + x[ss] sgrid_y = rgrid_y + y[ss] sdx = np.where((sgrid_x > edge_xlo) & (sgrid_x < edge_xhi) & (sgrid_y > edge_ylo) & (sgrid_y < edge_yhi))[0] area_at_r[rr] += len(sdx) area_at_r[rr] *= 0.00995**2 * grid_pix_size**2 / len(dr) area_formula = (r_edges[rr+1]**2 - r_edges[rr]**2) area_formula *= math.pi * 0.00995**2 print '%3d < r <= %3d %.5f vs. %.5f' % \ (r_edges[rr], r_edges[rr+1], area_at_r[rr], area_formula) _area = open(areaFile, 'w') pickle.dump(area_at_r, _area) _area.close() for ii in range(h.shape[0]): h[ii] /= area_at_r[ii] * dmBinSize # Calculate a 2nd histogram for a sliding window in magnitude space. This # means we have to code our own 2D histogram. dr_bins2 = dr_bins dm_bins2 = np.arange(-11, 0.1, dmBinSize/5.0) h2 = np.zeros((len(dr_bins2)-1, len(dm_bins2)), dtype=float) for rr in range(len(dr_bins2)-1): for mm in range(len(dm_bins2)): dm_lo = dm_bins2[mm] - (dmBinSize / 2.0) dm_hi = dm_bins2[mm] + (dmBinSize / 2.0) idx = np.where((dr >= dr_bins2[rr]) & (dr < dr_bins2[rr+1]) & (dm >= dm_lo) & (dm < dm_hi))[0] h2[rr, mm] = len(idx) / (area_at_r[rr] * dmBinSize) #m_edges = dm_bins2 #h = h2 #r_edges = dr_bins2 # Now calculate the envelope by taking the average from # outside 2" critDist = np.zeros(h.shape[1], dtype=float) idx = np.where(r_edges[:-1] > 2.0/0.00995)[0] h_avg_hi_r = np.median(h[idx[0]:, :], axis=0) h_std_hi_r = h[idx[0]:, :].std(axis=0) r_center = r_edges[0:-1] + (drBinSize / 2.0) m_center = m_edges[0:-1] + (dmBinSize / 2.0) #m_center = m_edges for mm in range(len(m_edges)-1): # Walk from the inside out until we get to a pixel # that has a density of at least avgDensity / 3.0 idx = np.where(h[:, mm] > (h_avg_hi_r[mm] / 3.0))[0] if len(idx) > 0: critDist[mm] = r_edges[idx[0]] print mm, m_edges[mm], critDist[mm], h_avg_hi_r[mm] # ########## # Make a 2D version of the envelope (smoothed) # - from 0 > dm > -8, use the PSF # - from dm < -8, use a smoothed version of the envelope. # ########## # Trim the envelope down to dm < -8 idx = np.where((m_center < -8) & (critDist > 0))[0] int_dist = critDist[idx] int_mag = m_center[idx] foo = int_dist.argsort() int_dist = int_dist[foo] int_mag = int_mag[foo] tck = interpolate.splrep(int_dist, int_mag, s=0, k=1) env_r = np.arange(400) env_m = interpolate.splev(env_r, tck) # Graft just the tail onto the existing PSF. (past dm < -8) npsf_side = np.arange(-200, 201, 1) npsf_y, npsf_x = np.meshgrid(npsf_side, npsf_side) npsf_r = np.hypot(npsf_x, npsf_y) npsf2D = np.zeros(npsf_r.shape, dtype=float) npsf1D = np.zeros(npsf_r.shape, dtype=float) # Set to the 1D azimuthally averaged PSF. tck_psf = interpolate.splrep(psf_r, psf_f) idx = np.where(npsf_r < 100) npsf1D[idx[0], idx[1]] = interpolate.splev(npsf_r[idx[0], idx[1]], tck_psf) npsf2D[100:300, 100:300] = psf2D # Add in the halo. idx = np.where(env_m < -8.25)[0] startingDistance = env_r[idx].min() idx = np.where(npsf_r >= startingDistance) halo = interpolate.splev(npsf_r[idx[0], idx[1]], tck) halo = psf_f[0] / 10**(-0.4 * halo) npsf1D[idx[0], idx[1]] = np.hypot(npsf1D[idx[0], idx[1]], halo) npsf2D[idx[0], idx[1]] = np.hypot(npsf2D[idx[0], idx[1]], halo) # Possible choices of the envelope include: # azimuthally averaged version env_file = imageRoot + '_env1D.fits' if os.access(env_file, os.F_OK): os.remove(env_file) pyfits.writeto(env_file, npsf1D) # full 2D structure inside ~1" env_file = imageRoot + '_env2D.fits' if os.access(env_file, os.F_OK): os.remove(env_file) pyfits.writeto(env_file, npsf2D) # the original PSF env_file = imageRoot + '_psf2D.fits' if os.access(env_file, os.F_OK): os.remove(env_file) pyfits.writeto(env_file, psf2D) # For plotting purposes get the 1D evelope back out again. env_r, env_f, env_std, env_n = radialProfile.azimuthalAverage(npsf2D) env_m = -2.5 * np.log10(env_f[0] / env_f) # convert to magnitudes # ########## # Plot points of dr vs. dm (unbinned) # ########## py.clf() py.plot(dr, dm, 'k.', ms=2) py.plot(psf_r, psf, 'b-') py.axis([0, 500, -11, 0]) py.xlabel('X (pixel)') py.ylabel('Y (pixel)') py.title('MagCut < %g, RadCut < %d' % (magCut, radCut)) print 'Saving plots/pairs_rm_%s.png' % outSuffix py.savefig('plots/pairs_rm_%s.png' % outSuffix) # ########## # Plot dr vs. dm in a 2D histogram # ########## hmask = np.ma.masked_where(h.transpose() == 0, h.transpose()) r_edges = r_edges * 0.00995 py.clf() py.imshow(hmask, extent=[r_edges[0], r_edges[-1], m_edges[0], m_edges[-1]], cmap=py.cm.spectral_r) py.plot(psf_r * 0.00995, psf, 'b-') py.plot(critDist * 0.00995, m_center, 'r.-') py.plot(env_r * 0.00995, env_m, 'g.-') py.axis('tight') py.axis([0, 5.0, -11, 0]) py.xlabel('Radius (arcsec)') py.ylabel('Delta Magnitude') py.title('MagCut < %g, RadCut < %d' % (magCut, radCut)) cbar = py.colorbar() cbar.set_label('stars / (mag * arcsec^2)') print 'Saving plots/pairs_rm_hist_%s.png' % outSuffix py.savefig('plots/pairs_rm_hist_%s.png' % outSuffix)