Beispiel #1
0
def create_aperture_from_ds9_region(region_file):
    '''
    Loads a ds9 region ('reg') file saved in physical format and returns an astropy aperture instance.
    '''
    
    # 
    f = open(region_file,'rb')
    for i in range(3):
        f.readline()
    region_text = f.read()

    pdb.set_trace()
    regions = region_text.split('\n')

    src_apertures,bkg_apertures = [],[] 

    for region in regions[:-1]:
        # This is a poor example of string handling, but it works.
        value_text = region.split('(')[1].split(')')[0]
        pos_x,pos_y,r_in,r_out = np.array(value_text.split(','),dtype = float)
        
        src_apertures.append(photutils.CircularAperture((pos_x,pos_y), r=r_in))
        bkg_aperture.append(photutils.CircularAnnulus((pos_x,pos_y), r_in=r_in, r_out=r_out))

    return src_apertures,bkg_apertures
Beispiel #2
0
    def _aperture_phot(self, x, y, data, radsize=1,
                       sky_inner=5, skywidth=5, method="subpixel", subpixels=4):
        """Perform sky subtracted aperture photometry, uses photutils functions, photutil must be installed

        Parameters
        ----------
        radsize: int
            Size of the radius

        sky_inner: int
            Inner radius of the sky annulus

        skywidth: int
            Width of the sky annulus

        method: string
            Pixel sampling method to use

        subpixels: int
            How many subpixels to use

        Notes
        -----
           background is taken from sky annulus pixels, check into masking bad pixels

        """
        if not photutils_installed:
            print("Install photutils to enable")
        else:

            apertures = photutils.CircularAperture((x, y), radsize)
            rawflux_table = photutils.aperture_photometry(
                data,
                apertures,
                subpixels=1,
                method="center")

            outer = sky_inner + skywidth
            annulus_apertures = photutils.CircularAnnulus(
                (x, y), r_in=sky_inner, r_out=outer)
            bkgflux_table = photutils.aperture_photometry(
                data,
                annulus_apertures)

            # to calculate the mean local background, divide the circular annulus aperture sums
            # by the area fo the circular annuls. The bkg sum with the circular aperture is then
            # then mean local background tims the circular apreture area.
            aperture_area = apertures.area()
            annulus_area = annulus_apertures.area()

            bkg_sum = (
                bkgflux_table['aperture_sum'] *
                aperture_area /
                annulus_area)[0]
            skysub_flux = rawflux_table['aperture_sum'][0] - bkg_sum

            return (
                float(rawflux_table['aperture_sum'][0]), bkg_sum, skysub_flux)
Beispiel #3
0
def get_encircled_energy_and_rad_at_EE(data,
                                       x,
                                       y,
                                       radii,
                                       get_rad_at_EE=0.9,
                                       plot=False,
                                       ax=None):
    """
    A function to calculate the encircled energy at a given position, summing up the flux in apertures of size *radii*,
    normalizing the EE to the last flux value.
    
    INPUT:
    data - a two dimensional np.array
    x - x centroid
    y - y centroid
    radii - an array of radii to calculate the EE
    get_rad_at_EE - the EE of which to calculate the radius value
    plot - plot a EE vs radii plot
    
    OUTPUT:
    df
        a dataframe with two columns:
        - radii
        - EE
    rad_at_EE
        - the radius when EE is a given input value

    NOTE:
    Assumes that the data is background subtracted

    EXAMPLE:
    radii = np.arange(1,450)
    df_ee, r_at_EE90 = phothelp.get_encircled_energy(fimg.data,fimg.xcenter,fimg.ycenter,radii,plot=True)
    """
    apertures = [photutils.CircularAperture((x, y), r=r) for r in radii]
    phot_table = photutils.aperture_photometry(data, apertures)
    df = phot_table[phot_table.colnames[3:]].to_pandas()
    EE = df.loc[0] / df.loc[0][-1]

    df = pd.DataFrame(list(zip(radii, EE)), columns=["radii", "EE"])

    #r_at_EE = df[df["EE"] > get_rad_at_EE]["radii"].values[0]
    r_at_EE = np.interp(get_rad_at_EE, df.EE.values, df.radii.values)

    if plot:
        if ax == None:
            fig, ax = plt.subplots()
        ax.plot(radii, EE.values)
        ax.set_xlabel("Radii")
        ax.set_ylabel("Encircled Energy")
        ax.set_title("EE" + gk.num2str(get_rad_at_EE * 100, 1) + "% at r=" +
                     str(r_at_EE))

        ax.vlines(r_at_EE, 0, get_rad_at_EE, color="green", linestyle="--")
        ax.hlines(get_rad_at_EE, 0, r_at_EE, color="green", linestyle="--")
        ax.minorticks_on()

    return df, r_at_EE
Beispiel #4
0
    def subtract_background(self,
                            subtract_min_value=True,
                            plot_background=False,
                            ax=None):
        """
        A function to subtract the background for the FRD tests

        INPUT:
        subtract_min_value - subtracts the .min value (no negative numbers)
        plot_background    - if True, plots the estimated background with the meshes it used.
        """
        self.aper = photutils.CircularAperture(positions=(self.x, self.y),
                                               r=self.r)

        # get the mask from the aperture
        # hack
        mask = self.aper.to_mask()[0].to_image(self.data.shape)

        # use sigma clipping
        sigma_clip = SigmaClip(sigma=3., iters=10)

        bkg_estimator = photutils.MedianBackground()
        self.bkg = photutils.Background2D(self.data,
                                          self.box_size,
                                          filter_size=(3, 3),
                                          sigma_clip=sigma_clip,
                                          bkg_estimator=bkg_estimator,
                                          mask=mask,
                                          edge_method="crop")

        self.data_background = self.data - self.bkg.background

        if subtract_min_value:
            self.subtracted_value = self.data_background.min()
            print("Subtracted min value:", self.subtracted_value)
            self.data_background -= self.subtracted_value

        if plot_background:
            if ax == None:
                self.fig, self.ax = plt.subplots()
            else:
                self.ax = ax
            im = self.ax.imshow(self.bkg.background,
                                origin='lower',
                                cmap='Greys_r')
            self.ax.set_xlim(0, self.bkg.background.shape[1])
            self.ax.set_ylim(0, self.bkg.background.shape[0])
            self.ax.set_title("Estimated Background", y=1.02)
            self.ax.set_xlabel("X pixels")
            self.ax.set_ylabel("Y pixels")
            if ax == None:
                # Only do this if ax is not supplied
                # Don't know how to deal with this without passing the figure explicitly
                self.fig.colorbar(im)
            self.bkg.plot_meshes(outlines=True, color='#1f77b4', ax=self.ax)

        return self.data_background
Beispiel #5
0
    def finish(self, survey, brickname, version_header,
               apradec=None, apertures=None):
        # apradec = (ra,dec): aperture photometry locations
        # apertures: RADII in PIXELS
        if apradec is not None:
            assert(apertures is not None)
            (ra,dec) = apradec
            ok,xx,yy = self.wcs.radec2pixelxy(ra, dec)
            assert(np.all(ok))
            del ok
            apxy = np.vstack((xx - 1., yy - 1.)).T
            ap_iphots = [np.zeros((len(ra), len(apertures)), np.float32)
                         for band in self.bands]
            ap_dphots = [np.zeros((len(ra), len(apertures)), np.float32)
                         for band in self.bands]
            ap_rphots = [np.zeros((len(ra), len(apertures)), np.float32)
                         for band in self.bands]

        coimgs = []
        comods = []
        for iband,band in enumerate(self.bands):
            coimg = self.co_images[band]
            comod = self.co_models[band]
            coiv  = self.co_invvars[band]
            con   = self.co_nobs[band]
            with np.errstate(divide='ignore', invalid='ignore'):
                coimg /= coiv
                comod /= coiv
            coimg[coiv == 0] = 0.
            comod[coiv == 0] = 0.
            coimgs.append(coimg)
            comods.append(comod)

            hdr = copy_header_with_wcs(version_header, self.wcs)
            self.add_to_header(hdr, band)
            self.write_coadds(survey, brickname, hdr, band, coimg, comod, coiv, con)

            if apradec is not None:
                import photutils
                mask = (coiv == 0)
                with np.errstate(divide='ignore'):
                    imsigma = 1.0/np.sqrt(coiv)
                imsigma[mask] = 0.
                for irad,rad in enumerate(apertures):
                    aper = photutils.CircularAperture(apxy, rad)
                    p = photutils.aperture_photometry(coimg, aper, error=imsigma,
                                                      mask=mask)
                    ap_iphots[iband][:,irad] = p.field('aperture_sum')
                    ap_dphots[iband][:,irad] = p.field('aperture_sum_err')
                    p = photutils.aperture_photometry(coimg - comod, aper, mask=mask)
                    ap_rphots[iband][:,irad] = p.field('aperture_sum')

        self.write_color_image(survey, brickname, coimgs, comods)

        if apradec is not None:
            return ap_iphots, ap_dphots, ap_rphots
Beispiel #6
0
    def psf_norm_2d(array, fwhm, size, threshold, mask_core, full_output,
                    verbose):
        """ 2d case """
        if size is not None:
            if size < array.shape[0]:
                psfs = frame_crop(array, size, force=True, verbose=False)
            else:
                psfs = array.copy()
        else:
            psfs = array.copy()

        # we check if the psf is centered and fix it if needed
        cy, cx = frame_center(psfs, verbose=False)
        xcom, ycom = photutils.centroid_com(psfs)
        if not (np.allclose(cy, ycom, atol=1e-2) or
                np.allclose(cx, xcom, atol=1e-2)):
            # first we find the centroid and put it in the center of the array
            centry, centrx = fit_2d(psfs)
            shiftx, shifty = centrx - cx, centry - cy
            psfs = frame_shift(array, -shifty, -shiftx, imlib=imlib,
                               interpolation=interpolation)
            if size is not None:
                psfs = frame_crop(psfs, size, force=True, verbose=False)

            for _ in range(2):
                centry, centrx = fit_2d(psfs)
                cy, cx = frame_center(psfs, verbose=False)
                shiftx, shifty = centrx - cx, centry - cy
                psfs = frame_shift(psfs, -shifty, -shiftx, imlib=imlib,
                                   interpolation=interpolation)

        # we check whether the flux is normalized and fix it if needed
        fwhm_aper = photutils.CircularAperture((frame_center(psfs)), fwhm/2)
        fwhm_aper_phot = photutils.aperture_photometry(psfs, fwhm_aper,
                                                       method='exact')
        fwhm_flux = np.array(fwhm_aper_phot['aperture_sum'])

        if fwhm_flux > 1.1 or fwhm_flux < 0.9:
            psf_norm_array = psfs / np.array(fwhm_aper_phot['aperture_sum'])
        else:
            psf_norm_array = psfs

        if threshold is not None:
            psf_norm_array[np.where(psf_norm_array < threshold)] = 0

        if mask_core is not None:
            psf_norm_array = get_circle(psf_norm_array, radius=mask_core)

        if verbose:
            print("Flux in 1xFWHM aperture: {:.3f}".format(fwhm_flux[0]))

        if full_output:
            return psf_norm_array, fwhm_flux, fwhm
        else:
            return psf_norm_array
Beispiel #7
0
def _apphot_one((irad, band, rad, img, sigma, isimage, apxy)):
    import photutils
    result = [irad, band, isimage]
    aper = photutils.CircularAperture(apxy, rad)
    p = photutils.aperture_photometry(img, aper, error=sigma)
    result.append(p.field('aperture_sum'))
    if sigma is not None:
        result.append(p.field('aperture_sum_err'))
    else:
        result.append(None)
    return result
def perform_aperture_photometry(xcen, ycen, filename, aperture_radii = np.arange(2, 15), bkg_r_in=16., bkg_r_out=20):
    ofile = fits.open(filename)
    apertures = [pu.CircularAperture((xcen, ycen), r=r) for r in aperture_radii]
    annulus_apertures = pu.CircularAnnulus((xcen, ycen), r_in=bkg_r_in, r_out=bkg_r_out)
    apertures.append(annulus_apertures)
    phot_table = pu.aperture_photometry(ofile[1].data, apertures )
    bkg_colname = phot_table.colnames[-1]
    bkg_mean = phot_table[bkg_colname] / annulus_apertures.area()
    for aper, icol in zip(apertures, phot_table.colnames[3:]):
        bkg_sum = bkg_mean*aper.area()
        phot_table.add_column(phot_table[icol]-bkg_sum, name='{}_bkg_sub'.format(icol))
    return phot_table, apertures
Beispiel #9
0
def aperture_flux(array, yc, xc, fwhm, ap_factor=1, mean=False, verbose=False):
    """ Returns the sum of pixel values in a circular aperture centered on the
    input coordinates. The radius of the aperture is set as (ap_factor*fwhm)/2.

    Parameters
    ----------
    array : array_like
        Input frame.
    yc, xc : list or 1d arrays
        List of y and x coordinates of sources.
    fwhm : float
        FWHM in pixels.
    ap_factor : int, optional
        Diameter of aperture in terms of the FWHM.

    Returns
    -------
    flux : list of floats
        List of fluxes.

    Note
    ----
    From Photutils documentation, the aperture photometry defines the aperture
    using one of 3 methods:

    'center': A pixel is considered to be entirely in or out of the aperture
              depending on whether its center is in or out of the aperture.
    'subpixel': A pixel is divided into subpixels and the center of each
                subpixel is tested (as above).
    'exact': (default) The exact overlap between the aperture and each pixel is
             calculated.

    """
    n_obj = len(yc)
    flux = np.zeros((n_obj))
    for i, (y, x) in enumerate(zip(yc, xc)):
        if mean:
            ind = circle(y, x, (ap_factor * fwhm) / 2)
            values = array[ind]
            obj_flux = np.mean(values)
        else:
            aper = photutils.CircularAperture((x, y), (ap_factor * fwhm) / 2)
            obj_flux = photutils.aperture_photometry(array,
                                                     aper,
                                                     method='exact')
            obj_flux = np.array(obj_flux['aperture_sum'])
        flux[i] = obj_flux

        if verbose:
            print('Coordinates of object {} : ({},{})'.format(i, y, x))
            print('Object Flux = {:.2f}'.format(flux[i]))

    return flux
Beispiel #10
0
def test_aper_phot(capsys):
    """Check that apertures are as expected from photutils"""
    radius = 5
    apertures = photutils.CircularAperture((50, 50), radius)
    aperture_area = apertures.area()
    assert_equal(aperture_area, np.pi * radius**2)
    rawflux_table = photutils.aperture_photometry(test_data,
                                                  apertures,
                                                  subpixels=1,
                                                  method="center")
    total_flux = float(rawflux_table['aperture_sum'][0])
    # Verify the expected circular area sum
    assert_equal(total_flux, 207.0)
Beispiel #11
0
def doAperturePhotometry(locs, data, fitsfilename, params, bkg_method='2d'):
    aplocs = []
    for i, pair in enumerate(locs):
        aplocs.append(pair[::-1])

    apertures = pt.CircularAperture(aplocs, r=params['ap_phot_rad'])
    uncert_table = pt.aperture_photometry(data,
                                          apertures,
                                          method='subpixel',
                                          subpixels=10)
    bkg = getBackground(data,
                        fitsfilename,
                        bkg_method=bkg_method,
                        locs=locs,
                        params=params)
    if bkg_method == '2d':
        phot_table = pt.aperture_photometry(data,
                                            apertures,
                                            method='subpixel',
                                            subpixels=10)
        bkg_table = pt.aperture_photometry(bkg.background,
                                           apertures,
                                           method='subpixel',
                                           subpixels=10)
        phot_table['residual_aperture_sum'] = phot_table[
            'aperture_sum'] - bkg_table['aperture_sum']
    elif bkg_method == 'aperture':
        phot_table = pt.aperture_photometry(data,
                                            apertures,
                                            method='subpixel',
                                            subpixels=10)
        phot_table['residual_aperture_sum'] = phot_table[
            'aperture_sum'] - bkg.background * apertures.area()
    elif bkg_method == 'median':
        phot_table = pt.aperture_photometry(data,
                                            apertures,
                                            method='subpixel',
                                            subpixels=10)
        phot_table['residual_aperture_sum'] = phot_table[
            'aperture_sum'] - bkg.background * apertures.area()
    elif bkg_method == 'None':
        phot_table = pt.aperture_photometry(data,
                                            apertures,
                                            method='subpixel',
                                            subpixels=10)
        phot_table['residual_aperture_sum'] = phot_table['aperture_sum']

    uncert_final = np.sqrt(uncert_table['aperture_sum'])
    return phot_table, bkg, uncert_final
Beispiel #12
0
def gaussian_kernel(size, size_y=None):
    """ Gaussian kernel.
    """
    size = int(size)
    if not size_y:
        size_y = size
    else:
        size_y = int(size_y)
    x, y = np.mgrid[-size:size + 1, -size_y:size_y + 1]
    g = np.exp(-(x**2 / float(size) + y**2 / float(size_y)))

    fwhm = size
    fwhm_aper = photutils.CircularAperture((frame_center(g)), fwhm / 2.)
    fwhm_aper_phot = photutils.aperture_photometry(g, fwhm_aper)
    g_norm = g / np.array(fwhm_aper_phot['aperture_sum'])

    return g_norm / g_norm.max()
Beispiel #13
0
def starphot(imdata, position, radius, r_in, r_out):
    """
    sources: http://photutils.readthedocs.io/en/stable/
    photutils/aperture.html
    ARGS:
        imdata:   Numpy array containing the star.
        position: [x,y] coordinates where x corresponds to the second index of
                  imdata
        radius:   Radius of the circular aperture used to compute the flux of
                  the star.
        r_in:     Inner radius of the annulus used to compute the background
                  mean.
        r_out:    Outer radius of the annulus used to compute the background
                  mean.
    Returns [flux, background variance, background mean]
    """
    try:
        statmask = photutils.make_source_mask(imdata,
                                              snr=5,
                                              npixels=5,
                                              dilate_size=10)
    except TypeError:
        return None
    bkg_annulus = photutils.CircularAnnulus(position, r_in, r_out)
    bkg_phot_table = photutils.aperture_photometry(imdata,
                                                   bkg_annulus,
                                                   method='subpixel',
                                                   mask=statmask)
    bkg_mean_per_pixel = bkg_phot_table['aperture_sum'] / bkg_annulus.area()
    src_aperture = photutils.CircularAperture(position, radius)
    src_phot_table = photutils.aperture_photometry(imdata,
                                                   src_aperture,
                                                   method='subpixel')
    signal = src_phot_table['aperture_sum'] - bkg_mean_per_pixel*\
                                              src_aperture.area()
    #noise_squared = signal + bkg_mean_per_pixel*src_aperture.area()
    mean, median, std = sigma_clipped_stats(imdata,
                                            sigma=3.0,
                                            iters=5,
                                            mask=statmask)
    noise_squared = std**2
    return float(str(signal.data[0])), noise_squared,\
           float(str(bkg_mean_per_pixel.data[0]))
def plot(image, radius, mul):
    """Use photutils DAO starfinder to get the locations of any
    objects in the image (above) with the threshold being one of the input
    values. Then use astropy's statistics to subtract the median from the image.
    Makes an array of two arrays which are our data points locations, then transpose
    those points to get the actual locations on our .fits image. Uses photutils CircularAperture
    to put an aperture around each potential star in our positions array.
    """

    mean, median, std = astropy.stats.sigma_clipped_stats(image.data)
    DAO = photutils.detection.DAOStarFinder(threshold=mul * std, fwhm=3.0)
    sources = DAO(image.data - median)
    source_points = np.array([sources['xcentroid'], sources['ycentroid']])
    positions = np.transpose(source_points)
    apertures = photutils.CircularAperture(positions, r=radius)
    fig, ax = plt.subplots(figsize=(15, 15))
    ax.imshow(image.data, cmap='Greys', origin='lower', vmin=100, vmax=5000)
    ax.set_title('Interactive Starfinder')
    apertures.plot(color='c', lw=1, alpha=1)
def mk_sky_phot(instr, filt):

    img = fitsio.getdata(orig_names[instr][filt]["img"])

    pixscale = proj_plane_pixel_scales(
        WCS(fitsio.getheader(orig_names[instr][filt]["img"])))[0] * 3600.
    apersizes = useful.apersizes / pixscale
    aperradii = apersizes / 2.

    sky_apers = fitsio.getdata(
        '/data/highzgal/PUBLICACCESS/SPLASH/PROCESS/errors/sky_apers_%s_%s.fits'
        % (instr, filt))
    orig_wcs = WCS(
        fitsio.getheader(
            '/data/highzgal/PUBLICACCESS/SPLASH/PROCESS/data/orig/mosaic_%s_%s.img.fits'
            % (instr, filt)))
    new_wcs = WCS(fitsio.getheader(orig_names[instr][filt]["img"]))

    pos = np.array(zip(sky_apers['IMGX'], sky_apers['IMGY']))
    pos = orig_wcs.all_pix2world(pos, 1)
    pos = new_wcs.all_world2pix(pos, 1)

    # cond = (aperradii[-1] < pos[:,0]) & (pos[:,0] < img.shape[1]-aperradii[-1]) & \
    #        (aperradii[-1] < pos[:,1]) & (pos[:,1] < img.shape[0]-aperradii[-1])

    for i, radius in enumerate(aperradii):

        sys.stdout.write(
            "\rMeasuring Photometry on sky apertures for %s %s - aperture#%i (%.2f px) ..."
            % (instr, filt, i + 1, radius))
        sys.stdout.flush()

        apertures = photutils.CircularAperture(pos, r=radius)
        sky_apers['FLUX_APER'][:, i] = photutils.aperture_photometry(
            img, apertures)['aperture_sum']

    sys.stdout.write("done!\n")
    sys.stdout.flush()

    fitsio.writeto('sky_apers_orig_%s_%s.fits' % (instr, filt),
                   sky_apers,
                   overwrite=True)
Beispiel #16
0
def petrosian_radiu(data, r_step=5., petrosian_ratio=0.2):
    """ measure petrosian radiu in units of pixel from data. 
	
	Note: 
		Centroid position is determined from data

	Args: 
		data (2d np array)
		r_step=5. (float): aperture radius steps in units of pixel
		petrosian_ratio=0.2: the surface brightness at r_petrosian is petrosian_ratio times the surface brightness within r_petrosian. 
	"""
    ny, nx = data.shape
    xc, yc = pu.centroid_1dg(data)
    rs = np.arange(r_step, ny // 2, r_step)

    apts = [pu.CircularAperture(positions=(xc, yc), r=r) for r in rs]

    tab = at.Table(pu.aperture_photometry(data, apts))

    if len(rs) == 1:
        cols = ['aperture_sum']
    else:
        cols = ['aperture_sum_' + str(i) for i in range(len(rs))]

    aperture_sum = np.array(list(tab[cols][0]))
    annulus_sum = np.zeros_like(rs)
    annulus_sum[0] = aperture_sum[0]
    for i in range(1, len(rs)):
        annulus_sum[i] = aperture_sum[i] - aperture_sum[i - 1]

    aperture_areas = np.pi * rs**2
    annulus_areas = np.append(aperture_areas[0], np.diff(aperture_areas))

    annulus_avg = annulus_sum / annulus_areas
    aperture_avg = aperture_sum / aperture_areas

    diff = annulus_avg - aperture_avg * petrosian_ratio

    r_petrosian = _find_a_root(x=rs, y=diff)

    return r_petrosian
def get_sex_whts(catalog, instr, filt):

    radius = 3. / 2. / useful.pix_scale

    orig_wcs = WCS(
        fitsio.getheader(
            '/data/highzgal/PUBLICACCESS/SPLASH/PROCESS/data/orig/mosaic_%s_%s.img.fits'
            % (instr, filt)))
    new_wcs = WCS(fitsio.getheader(orig_names[instr][filt]["img"]))

    pos = zip(catalog['X_IMAGE'], catalog['Y_IMAGE'])
    pos = orig_wcs.all_pix2world(pos, 1)
    pos = new_wcs.all_world2pix(pos, 1)

    wht = fitsio.getdata(
        '/data/highzgal/PUBLICACCESS/SPLASH/PROCESS/data/orig/mosaic_%s_%s.wht.fits'
        % (instr, filt))
    aperture = photutils.CircularAperture(pos, r=radius)
    avg_wht = photutils.aperture_photometry(
        wht, aperture)['aperture_sum'] / (np.pi * radius**2)

    return avg_wht
Beispiel #18
0
def BuildEPSF(filter='Ks'):
    """Builds the effective PSF used for the photometry.
    Currently uses the SCAO PSF from SimCADO. 
    """
    src = sim.source.star(mag=19, filter_name=filter, spec_type='M0V')
    image = img.MakeImage(src,
                          exposure=1800,
                          NDIT=1,
                          view='wide',
                          chip='centre',
                          filter=filter,
                          ao_mode='scao')
    # PSF_AnisoCADO_SCAO_FVPSF_4mas_EsoMedian_20190328.fits

    peaks_tbl = phu.find_peaks(image, threshold=135000., box_size=11)
    peaks_tbl['peak_value'].info.format = '%.8g'  # for consistent table output
    # make sure the positions are correct (use the exact ones)
    peaks_tbl['x_peak'] = src.x_pix
    peaks_tbl['y_peak'] = src.y_pix
    positions = (peaks_tbl['x_peak'], peaks_tbl['y_peak'])
    apertures = phu.CircularAperture(positions, r=5.)
    # extract cutouts of the stars using the extract_stars() function
    stars_tbl = apta.Table()
    stars_tbl['x'] = peaks_tbl['x_peak']
    stars_tbl['y'] = peaks_tbl['y_peak']
    mean_val, median_val, std_val = apy.stats.sigma_clipped_stats(img_data,
                                                                  sigma=2.)
    img_data -= median_val  # subtract background
    nddata = apy.nddata.NDData(data=img_data)
    stars = phu.psf.extract_stars(nddata, stars_tbl, size=170)
    # build the epsf
    epsf_builder = phu.EPSFBuilder(oversampling=4,
                                   maxiters=5,
                                   progress_bar=False)
    epsf, fitted_stars = epsf_builder(stars)
    # save the epsf
    with open(os.path.join('objects', 'epsf-scao-fv.pkl'), 'wb') as output:
        pickle.dump(epsf, output, -1)
Beispiel #19
0
def _apphot_one(args):
    (irad, band, rad, img, sigma, mask, isimage, apxy) = args
    import photutils
    result = [irad, band, isimage]
    aper = photutils.CircularAperture(apxy, rad)
    p = photutils.aperture_photometry(img, aper, error=sigma, mask=mask)
    result.append(p.field('aperture_sum'))
    if sigma is not None:
        result.append(p.field('aperture_sum_err'))
    else:
        result.append(None)

    # If a mask is passed, also photometer it!
    if mask is not None:
        p = photutils.aperture_photometry(mask, aper)
        maskedpix = p.field('aperture_sum')
        # normalize by number of pixels (pi * rad**2)
        maskedpix /= (np.pi * rad**2)
        result.append(maskedpix)
    else:
        result.append(None)

    return result
Beispiel #20
0
def run_forced_phot(cat,
                    tim,
                    ceres=True,
                    derivs=False,
                    agn=False,
                    do_forced=True,
                    do_apphot=True,
                    get_model=False,
                    ps=None,
                    timing=False,
                    fixed_also=False,
                    ceres_threads=1):
    '''
    fixed_also: if derivs=True, also run without derivatives and report
    that flux too?
    '''
    if timing:
        tlast = Time()
    if ps is not None:
        import pylab as plt
    opti = None
    forced_kwargs = {}
    if ceres:
        from tractor.ceres_optimizer import CeresOptimizer
        B = 8

        try:
            opti = CeresOptimizer(BW=B, BH=B, threads=ceres_threads)
        except:
            if ceres_threads > 1:
                raise RuntimeError(
                    'ceres_threads requested but not supported by tractor.ceres version'
                )
            opti = CeresOptimizer(BW=B, BH=B)
        #forced_kwargs.update(verbose=True)

    # nsize = 0
    for src in cat:
        # Limit sizes of huge models
        # from tractor.galaxy import ProfileGalaxy
        # if isinstance(src, ProfileGalaxy):
        #     px,py = tim.wcs.positionToPixel(src.getPosition())
        #     h = src._getUnitFluxPatchSize(tim, px, py, tim.modelMinval)
        #     MAXHALF = 128
        #     if h > MAXHALF:
        #         #print('halfsize', h,'for',src,'-> setting to',MAXHALF)
        #         nsize += 1
        #         src.halfsize = MAXHALF

        src.freezeAllBut('brightness')
        src.getBrightness().freezeAllBut(tim.band)
    #print('Limited the size of', nsize, 'large galaxy models')

    if derivs:
        realsrcs = []
        derivsrcs = []
        Iderivs = []
        for i, src in enumerate(cat):
            from tractor import PointSource
            realsrcs.append(src)

            if not isinstance(src, PointSource):
                continue
            Iderivs.append(i)

            brightness_dra = src.getBrightness().copy()
            brightness_ddec = src.getBrightness().copy()
            brightness_dra.setParams(np.zeros(brightness_dra.numberOfParams()))
            brightness_ddec.setParams(
                np.zeros(brightness_ddec.numberOfParams()))
            brightness_dra.freezeAllBut(tim.band)
            brightness_ddec.freezeAllBut(tim.band)

            dsrc = SourceDerivatives(src, [brightness_dra, brightness_ddec],
                                     tim, ps)
            derivsrcs.append(dsrc)
        Iderivs = np.array(Iderivs)

        if fixed_also:
            pass
        else:
            # For convenience, put all the real sources at the front of
            # the list, so we can pull the IVs off the front of the list.
            cat = realsrcs + derivsrcs

    if agn:
        from tractor.galaxy import ExpGalaxy, DevGalaxy, FixedCompositeGalaxy
        from tractor import PointSource
        from legacypipe.survey import SimpleGalaxy, RexGalaxy

        realsrcs = []
        agnsrcs = []
        iagn = []
        for i, src in enumerate(cat):
            realsrcs.append(src)
            ## ??
            if isinstance(src, (SimpleGalaxy, RexGalaxy)):
                #print('Skipping SIMP or REX:', src)
                continue
            if isinstance(src, (ExpGalaxy, DevGalaxy, FixedCompositeGalaxy)):
                iagn.append(i)
                bright = src.getBrightness().copy()
                bright.setParams(np.zeros(bright.numberOfParams()))
                bright.freezeAllBut(tim.band)
                agn = PointSource(src.pos, bright)
                agn.freezeAllBut('brightness')
                #print('Adding "agn"', agn, 'to', src)
                #print('agn params:', agn.getParamNames())
                agnsrcs.append(src)
        iagn = np.array(iagn)
        cat = realsrcs + agnsrcs
        print('Added AGN to', len(iagn), 'galaxies')

    tr = Tractor([tim], cat, optimizer=opti)
    tr.freezeParam('images')
    disable_galaxy_cache()

    F = fits_table()

    if do_forced:

        if timing and (derivs or agn):
            t = Time()
            print('Setting up:', t - tlast)
            tlast = t

        if derivs:
            if fixed_also:
                print('Forced photom with fixed positions:')
                R = tr.optimize_forced_photometry(variance=True,
                                                  fitstats=False,
                                                  shared_params=False,
                                                  priors=False,
                                                  **forced_kwargs)
                F.flux_fixed = np.array([
                    src.getBrightness().getFlux(tim.band) for src in cat
                ]).astype(np.float32)
                N = len(cat)
                F.flux_fixed_ivar = R.IV[:N].astype(np.float32)

                if timing:
                    t = Time()
                    print('Forced photom with fixed positions finished:',
                          t - tlast)
                    tlast = t

                cat = realsrcs + derivsrcs
                tr.setCatalog(Catalog(*cat))
            print('Forced photom with position derivatives:')

        if ps is None and not get_model:
            forced_kwargs.update(wantims=False)

        R = tr.optimize_forced_photometry(variance=True,
                                          fitstats=True,
                                          shared_params=False,
                                          priors=False,
                                          **forced_kwargs)

        if ps is not None or get_model:
            (data, mod, ie, chi, roi) = R.ims1[0]

        if ps is not None:
            ima = dict(vmin=-2. * tim.sig1,
                       vmax=5. * tim.sig1,
                       interpolation='nearest',
                       origin='lower',
                       cmap='gray')
            imchi = dict(interpolation='nearest',
                         origin='lower',
                         vmin=-5,
                         vmax=5,
                         cmap='RdBu')
            plt.clf()
            plt.imshow(data, **ima)
            plt.title('Data: %s' % tim.name)
            ps.savefig()

            plt.clf()
            plt.imshow(mod, **ima)
            plt.title('Model: %s' % tim.name)
            ps.savefig()

            plt.clf()
            plt.imshow(chi, **imchi)
            plt.title('Chi: %s' % tim.name)
            ps.savefig()

            if derivs:
                trx = Tractor([tim], realsrcs)
                trx.freezeParam('images')

                modx = trx.getModelImage(0)
                chix = (data - modx) * tim.getInvError()

                plt.clf()
                plt.imshow(modx, **ima)
                plt.title('Model without derivatives: %s' % tim.name)
                ps.savefig()

                plt.clf()
                plt.imshow(chix, **imchi)
                plt.title('Chi without derivatives: %s' % tim.name)
                ps.savefig()

        if derivs or agn:
            cat = realsrcs
        N = len(cat)

        F.flux = np.array([
            src.getBrightness().getFlux(tim.band) for src in cat
        ]).astype(np.float32)
        F.flux_ivar = R.IV[:N].astype(np.float32)

        F.fracflux = R.fitstats.profracflux[:N].astype(np.float32)
        F.rchisq = R.fitstats.prochi2[:N].astype(np.float32)
        try:
            F.fracmasked = R.fitstats.promasked[:N].astype(np.float32)
        except:
            print(
                'No "fracmasked" available (only in recent Tractor versions)')

        if derivs:
            F.flux_dra = np.zeros(len(F), np.float32)
            F.flux_ddec = np.zeros(len(F), np.float32)
            F.flux_dra[Iderivs] = np.array(
                [src.getParams()[0] for src in derivsrcs]).astype(np.float32)
            F.flux_ddec[Iderivs] = np.array(
                [src.getParams()[1] for src in derivsrcs]).astype(np.float32)
            F.flux_dra_ivar = np.zeros(len(F), np.float32)
            F.flux_ddec_ivar = np.zeros(len(F), np.float32)
            F.flux_dra_ivar[Iderivs] = R.IV[N::2].astype(np.float32)
            F.flux_ddec_ivar[Iderivs] = R.IV[N + 1::2].astype(np.float32)

        if agn:
            F.flux_agn = np.zeros(len(F), np.float32)
            F.flux_agn_ivar = np.zeros(len(F), np.float32)
            F.flux_agn[iagn] = np.array(
                [src.getParams()[0] for src in agnsrcs])
            F.flux_agn_ivar[iagn] = R.IV[N:].astype(np.float32)

        if timing:
            t = Time()
            print('Forced photom:', t - tlast)
            tlast = t

    if do_apphot:
        import photutils

        img = tim.getImage()
        ie = tim.getInvError()
        with np.errstate(divide='ignore'):
            imsigma = 1. / ie
        imsigma[ie == 0] = 0.

        apimg = []
        apimgerr = []

        # Aperture photometry locations
        xxyy = np.vstack(
            [tim.wcs.positionToPixel(src.getPosition()) for src in cat]).T
        apxy = xxyy - 1.

        apertures = apertures_arcsec / tim.wcs.pixel_scale()
        #print('Apertures:', apertures, 'pixels')

        #print('apxy shape', apxy.shape)  # --> (2,N)

        # The aperture photometry routine doesn't like pixel positions outside the image
        H, W = img.shape
        Iap = np.flatnonzero((apxy[0, :] >= 0) * (apxy[1, :] >= 0) *
                             (apxy[0, :] <= W - 1) * (apxy[1, :] <= H - 1))
        print('Aperture photometry for', len(Iap), 'of', len(apxy[0, :]),
              'sources within image bounds')

        for rad in apertures:
            aper = photutils.CircularAperture(apxy[:, Iap], rad)
            p = photutils.aperture_photometry(img, aper, error=imsigma)
            apimg.append(p.field('aperture_sum'))
            apimgerr.append(p.field('aperture_sum_err'))
        ap = np.vstack(apimg).T
        ap[np.logical_not(np.isfinite(ap))] = 0.
        F.apflux = np.zeros((len(F), len(apertures)), np.float32)
        F.apflux[Iap, :] = ap.astype(np.float32)

        apimgerr = np.vstack(apimgerr).T
        apiv = np.zeros(apimgerr.shape, np.float32)
        apiv[apimgerr != 0] = 1. / apimgerr[apimgerr != 0]**2

        F.apflux_ivar = np.zeros((len(F), len(apertures)), np.float32)
        F.apflux_ivar[Iap, :] = apiv
        if timing:
            print('Aperture photom:', Time() - tlast)

    if get_model:
        return F, mod
    return F
Beispiel #21
0
def photometry(ax, image, pos, ap_size=10, r_in=20, r_out=30, back_photo=True):
    '''
    Create apertures around specified list of stars

    Parameters:
    -----------
    ax : axis class
        axis of a subplot.
    image : ndarray
        Image for aperture photometry to be performed on.
    pos : 2darray
        A list of positions in x,y pixel coordinates for each star.
        Needs to be as [[0,0],[1,1]...]
    ap_size : int
        The radius of a circular aperture in pixel size
    r_in : int
        The inner radius of background aperture in pixel size
        (Ignore if back_photo=False)
    r_out : int
        The outer radius of background aperture in pixel size
        (Ignore if back_photo=False)
    back_photo : bool
        Set to True if want to return an array of background values, False
        to ignore anything to do with background

    Returns
    -------
    photometry of each star : array
    average background pixel value around each star : array (If back_photo=True)
    plots image with the aperture and centroids located for each star
    '''

    nstars = np.arange(0, np.shape(pos)[0], 1)
    name_stars = []
    for i in nstars:
        name_stars.append('Star {}'.format(i))
    #print name_stars

    aperture = photutils.CircularAperture(pos, r=ap_size)

    if back_photo == True:
        back_aperture = photutils.CircularAnnulus(pos, r_in, r_out)

    pos = np.array(pos)

    #plt.imshow(image,origin='lower')

    for i in range(len(name_stars)):
        circle1 = plt.Circle((pos[i, 0], pos[i, 1]),
                             ap_size,
                             color='black',
                             fill=False,
                             zorder=100)
        ax.add_artist(circle1)
        plt.axhline(pos[i, 1],
                    xmin=pos[i, 0] / 100. - .01,
                    xmax=pos[i, 0] / 100. + .02,
                    color='black')
        plt.axvline(pos[i, 0],
                    ymin=pos[i, 1] / 100. - .01,
                    ymax=pos[i, 1] / 100. + .02,
                    color='black')
        plt.text(pos[i, 0] + ap_size + 1, pos[i, 1], name_stars[i], zorder=11)
        #print pos[i,1]
        #print pos[i,0]

        if back_photo == True:
            circle2 = plt.Circle((pos[i, 0], pos[i, 1]),
                                 r_in,
                                 color='cyan',
                                 fill=False,
                                 zorder=10)
            circle3 = plt.Circle((pos[i, 0], pos[i, 1]),
                                 r_out,
                                 color='cyan',
                                 fill=False,
                                 zorder=10)
            ax.add_artist(circle2)
            ax.add_artist(circle3)
    #aperture.plot(origin=(0,0),indices=None,ax=ax,fill=False)
    #plt.ion()

    phot_table = photutils.aperture_photometry(image, aperture)
    flux_values = phot_table[
        'aperture_sum'].data  #gets a list of the total flux in specified aperture for each star

    if back_photo == True:
        back_table = photutils.aperture_photometry(image, back_aperture)
        area = np.pi * (r_out**2 - r_in**2)
        a = np.ones((np.shape(image)[0], np.shape(image)[1]))
        area = photutils.aperture_photometry(a, back_aperture)
        back_values = back_table['aperture_sum'].data / area[
            'aperture_sum'].data
        return flux_values, back_values * np.pi * ap_size**2
    else:
        return flux_values
Beispiel #22
0
            ph, pw = psfimg.shape
            print('psf img shape', psfimg.shape)

            apertures = [1., 3., 3.5, 3.75, 4., 6., 8., 10.]

            #apxy = np.array([[pw/2., ph/2.]])

            #for ioff,apxy in enumerate([np.array([[pw/2., ph/2.]]),
            #                            np.array([[pw/2, ph/2]])]):
            for ioff, apxy in enumerate([np.array([[pw / 2, ph / 2]])]):
                print('apxy', apxy)

                ap = []
                for rad in apertures:
                    aper = photutils.CircularAperture(apxy, rad)
                    p = photutils.aperture_photometry(psfimg, aper)
                    ap.append(p.field('aperture_sum'))

                ap = np.vstack(ap).T
                ap = ap[0, :]
                print('Aperture fluxes:', ap)

                #plt.plot(apertures, ap, '.-', color='br'[ioff], label='%i,%i + %.1f,%.1f' % (x, y, apxy[0,0], apxy[0,1]))
                plt.plot(apertures, ap, '.-', label='%i,%i' % (x, y))
        plt.legend(loc='lower right')
        plt.xlabel('Aperture')
        plt.ylabel('Flux of PSF model')
        plt.ylim(0.8, 1.2)
        plt.xlim(2, 6)
        plt.axhline(1.0, color='k', alpha=0.25)
Beispiel #23
0
def aperture_photometry(calibratable,
                        ra,
                        dec,
                        apply_calibration=False,
                        assume_background_subtracted=False,
                        use_cutout=False,
                        direct_load=None):

    import photutils
    from astropy.coordinates import SkyCoord
    from astropy.io import fits
    from astropy.table import vstack
    from astropy.wcs import WCS

    ra = np.atleast_1d(ra)
    dec = np.atleast_1d(dec)
    coord = SkyCoord(ra, dec, unit='deg')

    if not use_cutout:

        wcs = calibratable.wcs

        apertures = photutils.SkyCircularAperture(coord, r=APERTURE_RADIUS)

        # something that is photometerable implements mask, background, and wcs
        if not assume_background_subtracted:
            pixels_bkgsub = calibratable.background_subtracted_image.data
        else:
            pixels_bkgsub = calibratable.data

        bkgrms = calibratable.rms_image.data
        mask = calibratable.mask_image.data

        phot_table = photutils.aperture_photometry(pixels_bkgsub,
                                                   apertures,
                                                   error=bkgrms,
                                                   wcs=wcs)

        phot_table['zp'] = calibratable.header['MAGZP'] + calibratable.header[
            'APCOR4']
        phot_table['obsjd'] = calibratable.header['OBSJD']
        phot_table['filtercode'] = 'z' + calibratable.header['FILTER'][-1]

        pixap = apertures.to_pixel(wcs)
        annulus_masks = pixap.to_mask(method='center')
        maskpix = [
            annulus_mask.cutout(mask.data) for annulus_mask in annulus_masks
        ]

    else:
        phot_table = []
        maskpix = []
        for s in coord:

            if direct_load is not None and 'sci' in direct_load:
                sci_path = direct_load['sci']
            else:
                if assume_background_subtracted:
                    sci_path = calibratable.local_path
                else:
                    sci_path = calibratable.background_subtracted_image.local_path

            if direct_load is not None and 'mask' in direct_load:
                mask_path = direct_load['mask']
            else:
                mask_path = calibratable.mask_image.local_path

            if direct_load is not None and 'rms' in direct_load:
                rms_path = direct_load['rms']
            else:
                rms_path = calibratable.rms_image.local_path

            with fits.open(sci_path, memmap=True) as f:
                wcs = WCS(f[0].header)

            pixcoord = wcs.all_world2pix([[s.ra.deg, s.dec.deg]], 0)[0]
            pixx, pixy = pixcoord

            nx = calibratable.header['NAXIS1']
            ny = calibratable.header['NAXIS2']

            xmin = max(0, pixx - 1.5 * APERTURE_RADIUS.value)
            xmax = min(nx, pixx + 1.5 * APERTURE_RADIUS.value)

            ymin = max(0, pixy - 1.5 * APERTURE_RADIUS.value)
            ymax = min(ny, pixy + 1.5 * APERTURE_RADIUS.value)

            ixmin = int(np.floor(xmin))
            ixmax = int(np.ceil(xmax))

            iymin = int(np.floor(ymin))
            iymax = int(np.ceil(ymax))

            ap = photutils.CircularAperture([pixx - ixmin, pixy - iymin],
                                            APERTURE_RADIUS.value)

            # something that is photometerable implements mask, background, and wcs
            with fits.open(sci_path, memmap=True) as f:
                pixels_bkgsub = f[0].data[iymin:iymax, ixmin:ixmax]

            with fits.open(rms_path, memmap=True) as f:
                bkgrms = f[0].data[iymin:iymax, ixmin:ixmax]

            with fits.open(mask_path, memmap=True) as f:
                mask = f[0].data[iymin:iymax, ixmin:ixmax]

            pt = photutils.aperture_photometry(pixels_bkgsub, ap, error=bkgrms)

            annulus_mask = ap.to_mask(method='center')
            mp = annulus_mask.cutout(mask.data)
            maskpix.append(mp)

            phot_table.append(pt)

        phot_table = vstack(phot_table)

    if apply_calibration:
        magzp = calibratable.header['MAGZP']
        apcor = calibratable.header[APER_KEY]

        phot_table['mag'] = -2.5 * np.log10(
            phot_table['aperture_sum']) + magzp + apcor
        phot_table['magerr'] = 1.0826 * phot_table[
            'aperture_sum_err'] / phot_table['aperture_sum']

    # check for invalid photometry on masked pixels
    phot_table['flags'] = [
        int(np.bitwise_or.reduce(m, axis=(0, 1))) for m in maskpix
    ]

    # rename some columns
    phot_table.rename_column('aperture_sum', 'flux')
    phot_table.rename_column('aperture_sum_err', 'fluxerr')

    return phot_table
Beispiel #24
0
def psf_norm(array,
             fwhm=4,
             size=None,
             threshold=None,
             mask_core=None,
             full_output=False,
             verbose=False):
    """ Scales a PSF, so the 1*FWHM aperture flux equals 1.
    
    Parameters
    ----------
    array: array_like
        The psf 2d array.
    fwhm: float, optional
        The the Full Width Half Maximum in pixels.
    size : int or None, optional
        If int it will correspond to the size of the squared subimage to be 
        cropped form the psf array.
    threshold : None of float, optional
        Sets to zero small values, trying to leave only the core of the PSF.
    mask_core : None of float, optional
        Sets the radius of a circular aperture for the core of the PSF, 
        everything else will be set to zero.
        
    Returns
    -------
    psf_norm: array_like
        The normalized psf.

    """
    if size is not None:
        psfs = frame_crop(array, min(int(size), array.shape[0]), verbose=False)
    else:
        psfs = array.copy()
        # If frame size is even we drop last row and last column
        if psfs.shape[0] % 2 == 0:
            psfs = psfs[:-1, :]
        if psfs.shape[1] % 2 == 0:
            psfs = psfs[:, :-1]

    # we check if the psf is centered and fix it if needed
    cy, cx = frame_center(psfs, verbose=False)
    if cy != np.where(psfs == psfs.max())[0] or cx != np.where(
            psfs == psfs.max())[1]:
        # first we find the centroid and put it in the center of the array
        centroidy, centroidx = fit_2dgaussian(psfs, fwhmx=fwhm, fwhmy=fwhm)
        shiftx, shifty = centroidx - cx, centroidy - cy
        psfs = frame_shift(psfs, -shifty, -shiftx)
        for _ in range(2):
            centroidy, centroidx = fit_2dgaussian(psfs, fwhmx=fwhm, fwhmy=fwhm)
            cy, cx = frame_center(psfs, verbose=False)
            shiftx, shifty = centroidx - cx, centroidy - cy
            psfs = frame_shift(psfs, -shifty, -shiftx)

    # we check whether the flux is normalized and fix it if needed
    fwhm_aper = photutils.CircularAperture((frame_center(psfs)), fwhm / 2.)
    fwhm_aper_phot = photutils.aperture_photometry(psfs,
                                                   fwhm_aper,
                                                   method='exact')
    fwhm_flux = np.array(fwhm_aper_phot['aperture_sum'])
    if verbose:
        print "Flux in 1xFWHM aperture: {}".format(fwhm_flux)

    if fwhm_flux > 1.1 or fwhm_flux < 0.9:
        psf_norm_array = psfs / np.array(fwhm_aper_phot['aperture_sum'])
    else:
        psf_norm_array = psfs

    if threshold is not None:
        psf_norm_array[np.where(psf_norm_array < threshold)] = 0

    if mask_core is not None:
        psf_norm_array = get_circle(psf_norm_array, radius=mask_core)

    if full_output:
        return psf_norm_array, fwhm_flux
    else:
        return psf_norm_array
Beispiel #25
0
def stage_4(resid=None,
            sky=None,
            ps=None,
            tim=None,
            mask=None,
            sourcepix=None,
            filters=None,
            radii_arcsec=None,
            orig_catalog=None,
            plots=False,
            lsbcat='lsb.fits',
            expnum=None,
            extname=None,
            pixscale=None,
            **kwa):

    #ok,x,y = tim.subwcs.radec2pixelxy(188.7543, 13.3847)
    #print 'X,Y', x,y

    fstack = np.dstack(filters)
    amax = np.argmax(fstack, axis=2)
    fmax = np.max(fstack, axis=2)

    if plots:
        sna = dict(interpolation='nearest',
                   origin='lower',
                   vmin=-2.,
                   vmax=32.,
                   cmap='gray')
        plt.clf()
        plt.imshow(fmax, **sna)
        plt.title('Filter max')
        ps.savefig()

        from matplotlib.ticker import FixedFormatter
        radformat = FixedFormatter(['%i' % r for r in radii_arcsec])

        plt.clf()
        plt.imshow(amax, interpolation='nearest', origin='lower', cmap='jet')
        plt.title('Filter argmax')
        plt.colorbar(ticks=np.arange(amax.max() + 1), format=radformat)
        ps.savefig()

        peak_amax = np.zeros_like(amax)

    hot = (fmax > 10.)
    blobs, nblobs = label(hot)
    print 'Nblobs', nblobs
    #print 'blobs max', blobs.max()
    peaks = []
    for blob in range(1, nblobs + 1):
        I = (blobs == blob)
        imax = np.argmax(fmax * I)
        py, px = np.unravel_index(imax, fmax.shape)
        peaks.append((px, py))
        #print 'blob imax', imax
        print 'px,py', px, py
        print 'blob max', fmax.flat[imax]
        ifilt = amax.flat[imax]
        print 'blob argmax', ifilt
        #print '  =', amax[py,px]

        if plots:
            peak_amax[I] = ifilt

    px = [x for x, y in peaks]
    py = [y for x, y in peaks]

    if plots:
        plt.clf()
        plt.imshow(amax * hot,
                   interpolation='nearest',
                   origin='lower',
                   cmap='jet')
        ax = plt.axis()
        plt.plot(px, py, '+', color='w')
        plt.axis(ax)
        plt.title('Filter argmax')
        plt.colorbar(ticks=np.arange((amax * hot).max() + 1), format=radformat)
        ps.savefig()

    # Total flux estimate
    # fmax is S/N in the amax filter.  Back out...
    fluxes = []
    for x, y in zip(px, py):
        print 'peak', x, y
        ifilt = amax[y, x]
        print 'ifilt', ifilt
        sn = fmax[y, x]
        print 'S/N', sn
        r = radii_arcsec[ifilt]
        sigma = r / pixscale
        knorm = 1. / (2. * np.sqrt(np.pi) * sigma)
        blurred = sn * (knorm * tim.sig1)
        fluxest = blurred * 2. * np.pi * (2. * sigma**2)
        fluxes.append(fluxest)

    fluxes = np.array(fluxes)
    mags = 22.5 - 2.5 * np.log10(fluxes)

    if plots:
        for bg in [1, 2]:
            plt.clf()
            if bg == 1:
                plt.imshow(peak_amax,
                           interpolation='nearest',
                           origin='lower',
                           cmap='jet')
            else:
                plt.imshow(tim.getImage(), **tim.ima)
            ax = plt.axis()
            plt.plot(px, py, '+', color='w', ms=10, mew=2)
            # Extended sources in the catalog
            if len(orig_catalog):
                E = orig_catalog[np.maximum(orig_catalog.shapeexp_r,
                                            orig_catalog.shapedev_r) >= 3.]
                plt.plot(E.x, E.y, 'x', color='k', ms=10, mew=2)

            for x, y, m in zip(px, py, mags):
                ra, dec = tim.subwcs.pixelxy2radec(x + 1, y + 1)
                plt.text(x,
                         y,
                         '%.1f (%.2f,%.2f)' % (m, ra, dec),
                         color='w',
                         ha='left',
                         fontsize=12)
            ''' evcc.fits:

            https://sites.google.com/site/extendedvcc/
            wget "https://sites.google.com/site/extendedvcc/table/Table2_2014_8_7.txt?attredirects=0&d=1" -O table2.txt
            text2fits -S 35 -H "id_evcc id_vcc ngc ra dec ra_fiber dec_fiber delta cz_sdss cz_ned mem_evcc mem_vcc morph_pri morph_sec morph_index morph_vcc u u_err g g_err r r_err i i_err z z_err r_kron r_50" -f sssddddfffssssssffffffffffff table2.txt evcc.fits  -n -

            vcc.fits:

            text2fits -S 27 -H "id_vcc ngc ra dec cz_sdss cz_ned mem morph_vcc u u_err g g_err r r_err i i_err z z_err r_kron r_50" -f ssddffssffffffffffff table3.txt vcc.fits -n -
            '''

            mydir = os.path.dirname(__file__)
            fn = os.path.join(mydir, 'evcc.fits')
            T = fits_table(fn)
            ok, x, y = tim.subwcs.radec2pixelxy(T.ra, T.dec)
            x = x[ok]
            y = y[ok]
            plt.plot(x, y, 'o', mec=(0, 1, 0), mfc='none', ms=50, mew=5)
            fn = os.path.join(mydir, 'vcc.fits')
            T = fits_table(fn)
            ok, x, y = tim.subwcs.radec2pixelxy(T.ra, T.dec)
            x = x[ok]
            y = y[ok]
            plt.plot(x, y, 'o', mec=(0, 1, 1), mfc='none', ms=50, mew=5)

            plt.axis(ax)
            plt.title('Peaks')
            #plt.title('Filter peak argmax')
            #plt.colorbar(ticks=np.arange((peak_amax*hot).max()+1), format=radformat)
            ps.savefig()

    LSB = fits_table()
    LSB.filter = np.array([tim.band] * len(px))
    LSB.expnum = np.array([expnum] * len(px)).astype(np.int32)
    LSB.extname = np.array([extname] * len(px))
    LSB.x = np.array(px).astype(np.int16)
    LSB.y = np.array(py).astype(np.int16)
    ra, dec = tim.subwcs.pixelxy2radec(LSB.x, LSB.y)
    LSB.ra = ra
    LSB.dec = dec
    LSB.flux = fluxes.astype(np.float32)
    LSB.mag = mags.astype(np.float32)
    LSB.radius = np.array(radii_arcsec)[amax[py, px]].astype(np.float32)
    LSB.sn = fmax[py, px].astype(np.float32)

    # Apertures, radii in ARCSEC.
    apertures_arcsec = np.array([0.5, 0.75, 1., 1.5, 2., 3.5, 5., 7.])
    apertures = apertures_arcsec / pixscale
    apxy = np.vstack((px, py)).T

    import photutils
    with np.errstate(divide='ignore'):
        imsigma = 1.0 / tim.getInvError()
        imsigma[tim.getInvError() == 0] = 0

    for photimg, err, name, errname in [
        (resid, imsigma, 'apflux', 'apflux_ivar'),
        (tim.getImage() - sky, None, 'apimgflux', None),
        ((tim.getImage() - sky) * mask, None, 'apmaskedimgflux', None),
        (1. - (mask * 1.), None, 'apgoodpix', None),
        (sourcepix, None, 'apsources', None),
    ]:

        apimg = []
        apimgerr = []
        for rad in apertures:
            aper = photutils.CircularAperture(apxy, rad)
            p = photutils.aperture_photometry(photimg, aper, error=err)
            apimg.append(p.field('aperture_sum'))
            if err is not None:
                apimgerr.append(p.field('aperture_sum_err'))
        ap = np.vstack(apimg).T
        ap[np.logical_not(np.isfinite(ap))] = 0.
        LSB.set(name, ap.astype(np.float32))
        if err is not None:
            apiv = 1. / (np.vstack(apimgerr).T)**2
            apiv[np.logical_not(np.isfinite(apiv))] = 0.
            LSB.set(errname, apiv.astype(np.float32))

    LSB.cut(np.argsort(-LSB.sn))
    LSB.writeto(lsbcat)

    return dict(LSB=LSB, filters=None, mod=None, sky=None)
Beispiel #26
0
    def run(self,
            plot_suffix,
            plot_folder,
            get_rad_at_EE=0.96,
            MAXRAD_FACTOR=0.54,
            fwzm_z=20,
            use_azimuthal_averaging=True,
            force_max_radii_to_390=False,
            soft_bg_est=True):
        """
        Run the analysis
        
        INPUT:
            plot_suffix = "f01"
            plot_folder = "results/"
            get_rad_at_EE = 0.96
            FACTOR = 0.54
            fwzm_z=20
            soft_bg_est = True : If False, will not use software background estimator

        OUTPUT:
            Saves files to folders  
        """
        utils.make_dir(plot_folder)
        fig, ax = plt.subplots(ncols=3, nrows=2, figsize=(20, 15))
        plt.title('FIND ME')

        ax_img = ax.flat[0]
        ax_img_bkg = ax.flat[1]
        ax_img_bkg_sub = ax.flat[2]
        ax_cut = ax.flat[3]
        ax_ee = ax.flat[4]
        ax_img_bkg_sub2 = ax.flat[5]

        # -------------
        # Plot #1: Normal image
        x, y = self.fimg.get_centroid(plot_lines=True, ax=ax_img)
        self.fimg.ax.set_title("Hist stretch")
        #cbar_ax = fig.add_axes([0.38, 0.59, 0.015, 0.3],label="Counts")
        #fig.colorbar(self.fimg.im, cax=cbar_ax)

        # -------------
        # Plot #2: Background estimation
        if soft_bg_est == True:
            #x,y = self.fimg.get_centroid()
            #print("Centroids",x,y)
            CBS = phothelp.CircularBackgroundSubractor(self.fimg.data,
                                                       x=x,
                                                       y=y,
                                                       r=400)
            data_back_sub = CBS.subtract_background(plot_background=True,
                                                    ax=ax_img_bkg)
            self.subtracted_value = CBS.subtracted_value

            # -------------
            # Plot #3: Background subtracted image
            self.fimg.data = data_back_sub
            self.fimg.plot(ax=ax_img_bkg_sub,
                           colorbar=False,
                           title="Background subtracted (linear stretch)",
                           stretch="linear")
            # add colorbar
            #cbar_ax = fig.add_axes([0.38, 0.09, 0.015, 0.3],label="Counts")
            #fig.colorbar(self.fimg.im, cax=cbar_ax)
            # Get centroid again after taking out the background
            x, y = self.fimg.get_centroid()

        else:
            print('Not subtracting backround')
            self.subtracted_value = 0

        # -------------
        # Plot #4: Cuts
        if use_azimuthal_averaging == True:
            #self.max_radii_for_EE =
            print("Using azimuthal averaging")
            _r, _mean, _r_hwzm = self.fimg.get_radial_profile(
                rmax=500,
                plot=True,
                z=fwzm_z,
                return_hwzm=True,
                ax=ax_cut,
                xcen=x,
                ycen=y,
                subtract_min=True)  # 500 ~2/1024
            self.max_radii_for_EE = (_r_hwzm * 2. * MAXRAD_FACTOR)[0]
            if force_max_radii_to_390 == True:
                print("FORCING MAX RADII TO 390")
                self.max_radii_for_EE = 390.
        else:
            print("Not using azimuthal averaging, Using mean(X+Y) cutouts")
            cut_x, self.fwhm_x = self.fimg.get_centroid_line_cut(
                line="X",
                return_FWHM=True,
                plot=True,
                ax=ax_cut,
                use_butter_filter=True,
                butter_cutoff_freq=0.03,
                fwzm_z=fwzm_z)
            cut_y, self.fwhm_y = self.fimg.get_centroid_line_cut(
                line="Y",
                return_FWHM=True,
                plot=True,
                ax=ax_cut,
                use_butter_filter=True,
                butter_cutoff_freq=0.03,
                fwzm_z=fwzm_z)
            #return cut_x, cut_y
            ax_cut.plot(butter.low_pass_butter(cut_x, cutoff_freq=0.03))
            ax_cut.plot(butter.low_pass_butter(cut_y, cutoff_freq=0.03))
            self.max_radii_for_EE = (
                (self.fwhm_x + self.fwhm_y) / 2.) * MAXRAD_FACTOR

        ax_cut.set_ylim(0, 64000.)

        # -------------
        # Plot #4: Encircled energy plot

        print('Max radii for EE = {}'.format(self.max_radii_for_EE))
        radii = np.arange(1, self.max_radii_for_EE)
        df, self.r_ee = phothelp.get_encircled_energy_and_rad_at_EE(
            self.fimg.data,
            self.fimg.xcenter,
            self.fimg.ycenter,
            radii,
            plot=True,
            ax=ax_ee,
            get_rad_at_EE=get_rad_at_EE)
        ax_ee.set_xlim(0, 500)
        ax_ee.set_xlabel("Radii (pixels)")

        # Overplot aperture in figure $ with EE
        aper = photutils.CircularAperture((x, y), r=self.r_ee)
        aper.plot(ax=ax_img_bkg_sub, color="green")
        ax_img_bkg_sub.annotate("EE" + str(100 * get_rad_at_EE) + "%",
                                xy=(x, y + self.r_ee),
                                color="white",
                                fontsize=8)
        # overplot max aperture
        aper = photutils.CircularAperture((x, y), r=self.max_radii_for_EE)
        aper.plot(ax=ax_img_bkg_sub, color="red")
        ax_img_bkg_sub.annotate("EE100% @ r = " + str(MAXRAD_FACTOR * 2) +
                                " HWHM",
                                xy=(x, y + self.max_radii_for_EE),
                                color="white",
                                fontsize=8)

        # Hist plot
        self.fimg.plot(ax=ax_img_bkg_sub2,
                       colorbar=False,
                       title="Background subtracted (Hist stretch)",
                       stretch="hist")
        aper = photutils.CircularAperture((x, y), r=self.r_ee)
        aper.plot(ax=ax_img_bkg_sub2, color="green")
        ax_img_bkg_sub2.annotate("EE" + str(100 * get_rad_at_EE) + "%",
                                 xy=(x, y + self.r_ee),
                                 color="white",
                                 fontsize=8)
        # overplot max aperture
        aper = photutils.CircularAperture((x, y), r=self.max_radii_for_EE)
        aper.plot(ax=ax_img_bkg_sub2, color="red")
        ax_img_bkg_sub2.annotate("EE100% @ r = " + str(MAXRAD_FACTOR * 2) +
                                 " HWHM",
                                 xy=(x, y + self.max_radii_for_EE),
                                 color="white",
                                 fontsize=8)

        fig.tight_layout()
        fig.subplots_adjust(top=0.9)
        fig.suptitle("FRD Overview Plot, file: " + self.basename, fontsize=20)
        fig.savefig(plot_folder + self.basename + "_" + plot_suffix + ".png")
        print("Saved file:",
              plot_folder + self.basename + "_" + plot_suffix + ".png")
        df.to_csv(plot_folder + self.basename + "_" + plot_suffix + ".csv")
        print("Saved file:",
              plot_folder + self.basename + "_" + plot_suffix + ".csv")
Beispiel #27
0
def noise_per_annulus(array,
                      separation,
                      fwhm,
                      init_rad=None,
                      wedge=(0, 360),
                      verbose=False,
                      debug=False,
                      mask=None):
    """ Measures the noise as the standard deviation of apertures defined in
    each annulus with a given separation.

    Parameters
    ----------
    array : array_like
        Input frame.
    separation : float
        Separation in pixels of the centers of the annuli measured from the
        center of the frame.
    fwhm : float
        FWHM in pixels.
    init_rad : float
        Initial radial distance to be used. If None then the init_rad = FWHM.
    wedge : tuple of floats, optional
        Initial and Final angles for using a wedge. For example (-90,90) only
        considers the right side of an image. Be careful when using small
        wedges, this leads to computing a standard deviation of very small
        samples (<10 values).
    verbose : bool, optional
        If True prints information.
    debug : bool, optional
        If True plots the positioning of the apertures.

    Returns
    -------
    noise : array_like
        Vector with the noise value per annulus.
    vector_radd : array_like
        Vector with the radial distances values.

    """

    # dprint(fwhm)
    def find_coords(rad, sep, init_angle, fin_angle):
        angular_range = fin_angle - init_angle
        npoints = (np.deg2rad(angular_range) * rad) / sep  #(2*np.pi*rad)/sep
        ang_step = angular_range / npoints  #360/npoints
        x = []
        y = []
        for i in range(int(npoints)):
            newx = rad * np.cos(np.deg2rad(ang_step * i + init_angle))
            newy = rad * np.sin(np.deg2rad(ang_step * i + init_angle))
            x.append(newx)
            y.append(newy)
        return np.array(y), np.array(x)

    ###

    if array.ndim != 2:
        raise TypeError('Input array is not a frame or 2d array')
    if not isinstance(wedge, tuple):
        raise TypeError('Wedge must be a tuple with the initial and final '
                        'angles')

    init_angle, fin_angle = wedge
    centery, centerx = frame_center(array)
    n_annuli = int(np.floor((centery) / separation)) - 1
    noise = []
    vector_radd = []
    if verbose:
        print('{} annuli'.format(n_annuli))

    if init_rad is None:
        init_rad = fwhm

    if debug:
        _, ax = plt.subplots(figsize=(6, 6))
        ax.imshow(array,
                  origin='lower',
                  interpolation='nearest',
                  alpha=0.5,
                  cmap='gray')

    for i in range(n_annuli):
        y = centery + init_rad + separation * i
        rad = dist(centery, centerx, y, centerx)
        yy, xx = find_coords(rad, fwhm, init_angle, fin_angle)
        yy += centery
        xx += centerx

        apertures = photutils.CircularAperture((xx, yy), fwhm / 2)
        mask = np.bool_(mask)
        # quick2D(mask)
        if mask:
            fluxes = photutils.aperture_photometry(array, apertures, mask=mask)
        else:
            fluxes = photutils.aperture_photometry(array, apertures)
        fluxes = np.array(fluxes['aperture_sum'])

        noise_ann = np.std(fluxes)
        noise.append(noise_ann)
        vector_radd.append(rad)
        # if debug:
        #     if i == 1:
        #         plt.plot(fluxes)

        # plt.figure()
        # plt.hist(fluxes, bins=50)

        if debug:
            for j in range(xx.shape[0]):
                # Circle takes coordinates as (X,Y)
                aper = plt.Circle((xx[j], yy[j]),
                                  radius=fwhm / 2,
                                  color='r',
                                  fill=False,
                                  alpha=0.8)
                ax.add_patch(aper)
                cent = plt.Circle((xx[j], yy[j]),
                                  radius=0.8,
                                  color='r',
                                  fill=True,
                                  alpha=0.5)
                ax.add_patch(cent)

        if verbose:
            print('Radius(px) = {}, Noise = {:.3f} '.format(rad, noise_ann))

    return np.array(noise), np.array(vector_radd)
Beispiel #28
0
    def aper_phot(self, x, y):
        """Perform aperture photometry, uses photutils functions, photutils must be available

        """
        if not photutils_installed:
            print("Install photutil to enable")
        else:

            sigma = 0.  # no centering
            amp = 0.  # no centering
            if self.aperphot_pars["center"][0]:
                center = True
                delta = 10
                popt = self.gauss_center(x, y, delta)
                if 5 > popt.count(0) > 1:  # an error occurred in centering
                    warnings.warn(
                        "Problem fitting center, using original coordinates")
                else:
                    amp, x, y, sigma, offset = popt

            radius = int(self.aperphot_pars["radius"][0])
            width = int(self.aperphot_pars["width"][0])
            inner = int(self.aperphot_pars["skyrad"][0])
            subsky = bool(self.aperphot_pars["subsky"][0])

            aper_flux = photutils.aperture_photometry(
                self._data,
                x,
                y,
                apertures=photutils.CircularAperture(radius),
                subpixels=1,
                method="center")
            aperture_area = np.pi * (radius)**2
            if subsky:
                outer = inner + width
                annulus_sky = photutils.annulus_circular(
                    self._data, x, y, inner, outer)
                annulus_area = np.pi * (outer**2 - inner**2)

                total_flux = aper_flux - annulus_sky * (aperture_area /
                                                        annulus_area)
            else:
                total_flux = aper_flux

            # compute the magnitude of the sky corrected flux
            magzero = float(self.aperphot_pars["zmag"][0])
            mag = magzero - 2.5 * (np.log10(total_flux))

            pheader = ("x\ty\tradius\tflux\tmag(zpt={0:0.2f})\tsky\t".format(
                magzero)).expandtabs(15)
            if center:
                pheader += ("fwhm")
                pstr = "\n{0:.2f}\t{1:0.2f}\t{2:d}\t{3:0.2f}\t{4:0.2f}\t{5:0.2f}\t{6:0.2f}".format(
                    x + 1, y + 1, radius,
                    total_flux, mag, annulus_sky / annulus_area,
                    math_helper.gfwhm(sigma)).expandtabs(15)
            else:
                pstr = "\n{0:0.2f}\t{1:0.2f}\t{2:d}\t{3:0.2f}\t{4:0.2f}\t{5:0.2f}".format(
                    x + 1,
                    y + 1,
                    radius,
                    total_flux,
                    mag,
                    annulus_sky / annulus_area,
                ).expandtabs(15)

            print(pheader + pstr)
            logging.info(pheader + pstr)
Beispiel #29
0
def frame_quick_report(array, fwhm, source_xy=None, verbose=True):
    """ Gets information from given frame: Integrated flux in aperture, SNR of
    central pixel (max or given coordinates), mean SNR in aperture.
    
    Parameters
    ----------
    array : array_like
        2d array or input frame.
    fwhm : float
        Size of the FWHM in pixels.
    source_xy : tuple of floats
        X and Y coordinates of the source center.
    verbose : {True, False}, bool optional    
        If True prints to stdout the frame info.
        
    Returns
    -------
    obj_flux : float
        Integrated flux in aperture.
    snr_pixels : array_like
        SNR of pixels in 1FWHM aperture.
    fy, fx : float
        Fitted coordinates.
        
    """
    if not array.ndim == 2: raise TypeError('Array is not 2d.')
    
    if source_xy is not None: 
        x, y = source_xy
        if verbose: 
            print
            print('Coordinates of chosen px X,Y = {:},{:}'.format(x,y))
    else:
        y, x = np.where(array == array.max())
        y = y[0]
        x = x[0]
        if verbose: 
            print
            print('Coordinates of Max px X,Y = {:},{:}'.format(x,y))
    
    # we get integrated flux on aperture with diameter=1FWHM
    aper = photutils.CircularAperture((x, y), fwhm/2.)
    obj_flux = photutils.aperture_photometry(array, aper, method='exact')
    obj_flux = obj_flux['aperture_sum'][0]
    
    # we get the mean and stddev of SNRs on aperture
    yy, xx = draw.circle(y, x, fwhm/2.)
    snr_pixels = [snr_ss(array, (x_,y_), fwhm, plot=False, verbose=False) for \
                  y_, x_ in zip(yy, xx)]
    meansnr = np.mean(snr_pixels)
    stdsnr = np.std(snr_pixels)
    if verbose: 
        print('Central pixel SNR: ')
        snr_ss(array, (x,y), fwhm, plot=False, verbose=True)
        print('-----------------------------------------')
        print('In 1*FWHM circular aperture:')
        print('Integrated flux = {:.3f}'.format(obj_flux))
        print('Mean SNR = {:.3f}'.format(meansnr)) 
        print('Max SNR = {:.3f}, stddev SNRs = {:.3f}'.format(np.max(snr_pixels), 
                                                              stdsnr)) 
        print('-----------------------------------------')
    
    return obj_flux, snr_pixels
Beispiel #30
0
def sky_fibers_for_brick(
        survey,
        brickname,
        bands=['g', 'r', 'z'],
        apertures_arcsec=[0.5, 0.75, 1., 1.5, 2., 3.5, 5., 7.]):
    '''
    Produces a table of possible DESI sky fiber locations for a given
    "brickname" (eg, "0001p000") read from the given LegacySurveyData object *survey*.
    '''
    import fitsio
    from astrometry.util.fits import fits_table
    from astrometry.util.util import Tan
    import photutils
    from legacypipe.utils import find_unique_pixels

    fn = survey.find_file('blobmap', brick=brickname)
    blobs = fitsio.read(fn)
    print('Blobs:', blobs.min(), blobs.max())
    header = fitsio.read_header(fn)
    wcs = Tan(header)

    goodpix = (blobs == -1)
    for band in bands:
        fn = survey.find_file('nexp', brick=brickname, band=band)
        if not os.path.exists(fn):
            # Skip
            continue
        nexp = fitsio.read(fn)
        goodpix[nexp == 0] = False

    # Cut to unique brick area... required since the blob map drops
    # blobs that are completely outside the brick's unique area, thus
    # those locations are not masked.
    brick = survey.get_brick_by_name(brickname)
    H, W = wcs.shape
    U = find_unique_pixels(wcs, W, H, None, brick.ra1, brick.ra2, brick.dec1,
                           brick.dec2)
    goodpix[U == 0] = False
    del U

    x, y, blobdist = sky_fiber_locations(goodpix)

    skyfibers = fits_table()
    skyfibers.brickid = np.zeros(len(x), np.int32) + brick.brickid
    skyfibers.brickname = np.array([brickname] * len(x))
    skyfibers.x = x.astype(np.int16)
    skyfibers.y = y.astype(np.int16)
    skyfibers.blobdist = blobdist
    skyfibers.ra, skyfibers.dec = wcs.pixelxy2radec(x + 1, y + 1)

    pixscale = wcs.pixel_scale()
    apertures = np.array(apertures_arcsec) / pixscale

    # Now, do aperture photometry at these points in the coadd images
    for band in bands:
        imfn = survey.find_file('image', brick=brickname, band=band)
        ivfn = survey.find_file('invvar', brick=brickname, band=band)
        if not (os.path.exists(imfn) and os.path.exists(ivfn)):
            continue
        coimg = fitsio.read(imfn)
        coiv = fitsio.read(ivfn)

        apflux = np.zeros((len(skyfibers), len(apertures)), np.float32)
        apiv = np.zeros((len(skyfibers), len(apertures)), np.float32)
        skyfibers.set('apflux_%s' % band, apflux)
        skyfibers.set('apflux_ivar_%s' % band, apiv)
        with np.errstate(divide='ignore', invalid='ignore'):
            imsigma = 1. / np.sqrt(coiv)
            imsigma[coiv == 0] = 0
        apxy = np.vstack((skyfibers.x, skyfibers.y)).T
        for irad, rad in enumerate(apertures):
            aper = photutils.CircularAperture(apxy, rad)
            p = photutils.aperture_photometry(coimg, aper, error=imsigma)
            apflux[:, irad] = p.field('aperture_sum')
            err = p.field('aperture_sum_err')
            apiv[:, irad] = 1. / err**2

    header = fitsio.FITSHDR()
    for i, ap in enumerate(apertures_arcsec):
        header.add_record(
            dict(name='AP%i' % i, value=ap,
                 comment='Aperture radius (arcsec)'))
    skyfibers._header = header

    return skyfibers