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()
Esempio n. 2
0
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()
Esempio n. 3
0
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 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)
Esempio n. 5
0
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)
Esempio n. 6
0
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()
Esempio n. 7
0
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()
Esempio n. 8
0
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)
Esempio n. 9
0
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)