Example #1
0
    def autocorr(self, ell_mask_scale=2, aperture_radius=5, annulus_width=4):
        # Compute 2D autocorrelation function

        try:
            masked_image = self.masked_image.copy() 
            if ell_mask_scale > 0:
                masked_image.mask |=  ~self.elliptical_mask(ell_mask_scale)
            masked_image = masked_image.filled(0.0)

            fft_imgae = np.fft.fft2(masked_image)
            acorr_image = np.fft.ifft2(fft_imgae * np.conjugate(fft_imgae)).real
            acorr_image = np.fft.ifftshift(acorr_image)

            ny, nx = masked_image.shape
            yy, xx = np.mgrid[:ny, :nx]

            circ = CircularAperture([nx // 2, ny // 2], r=aperture_radius)
            ann = CircularAnnulus([nx // 2, ny // 2],
                                  r_in=aperture_radius,
                                  r_out=aperture_radius + annulus_width)

            ann_mean = aperture_photometry(
                acorr_image, ann)['aperture_sum'][0] / ann.area()
            circ_mean = aperture_photometry(
                acorr_image, circ)['aperture_sum'][0] / circ.area()
        except:
            acorr_image = np.nan
            circ_mean = np.nan
            ann_mean = np.nan

        return acorr_image, circ_mean, ann_mean
Example #2
0
def measure_fluxes(dataset):
    dataA = pf.getdata(dataset.filenameA)[0,0,:,:]
    dataB = pf.getdata(dataset.filenameA)[0,0,:,:]
    positions_A = [
        (dataset.pos_A_pix["A_core"][0], dataset.pos_A_pix["A_core"][1]),
        (dataset.pos_A_pix["A_jet"][0], dataset.pos_A_pix["A_jet"][1])]
    positions_B = [
    (dataset.pos_B_pix["B_core"][0], dataset.pos_B_pix["B_core"][1]),
    (dataset.pos_B_pix["B_jet"][0], dataset.pos_B_pix["B_jet"][1])]
    apertures_A = EllipticalAperture(
        positions_A, 
        dataset.beam_size_A[0] / dataset.pixel_scale_A,  
        dataset.beam_size_A[1] / dataset.pixel_scale_A, 
        dataset.beam_PA_A)
    apertures_B = EllipticalAperture(
        positions_B, 
        dataset.beam_size_B[0] / dataset.pixel_scale_B,  
        dataset.beam_size_B[1] / dataset.pixel_scale_B, 
        dataset.beam_PA_B)
    phot_table_A = aperture_photometry(dataA, apertures_A)#, error=data_error)
    phot_table_B = aperture_photometry(dataB, apertures_B)#, error=data_error)

    print "A fluxes in mJy"
    print phot_table_A['aperture_sum'] * 1e3 / (dataset.beam_size_A[0] * 3600.e3 * dataset.beam_size_A[1] * 3600.e3 * math.pi)
    print "B fluxes in mJy"
    print phot_table_B['aperture_sum'] * 1e3 / (dataset.beam_size_B[0] * 3600.e3 * dataset.beam_size_B[1] * 3600.e3 * math.pi)
Example #3
0
 def calculate_fluxes(self,stardata,apertures,aper_annulus):
     '''
         Calculates the photon flux in an aperture, and an annulus
         around the aperture to subtract the background.
         
         As far as I can tell, the output value is still just a 'photon count', not technically a 
         photon flux. Possible modifications will start here, maybe uncommenting the apertures.area()
         which calculates the aperture phot_count divided by area of aperture.
         giving photons per area.
         
         I think we would further have to supplement that by dividing by the exposure time, and some 
         other wavelength value I cant think of, to get PHOTON FLUX ( photons per sec per cm^2 per wavelength)
     '''
     flux_table = aperture_photometry(stardata, apertures)
     bkg_table  = aperture_photometry(stardata, aper_annulus)
     
     phot_table = hstack([flux_table, bkg_table], table_names=['raw','bkg'])
     bkg_mean = phot_table['aperture_sum_bkg'] / aper_annulus.area()
     
     bkg_sum = bkg_mean * apertures.area()
     final_sum = phot_table['aperture_sum_raw'] - bkg_sum
     phot_table['residual_aperture_sum'] = final_sum
     #phot_table['res_aper_div_area'] = final_sum/apertures.area()
     #print(phot_table)
     return self.cut_vals(phot_table)
Example #4
0
def frame_phot(hdu, cat_objects, phot_file, filter_name, exp_time, mag_zero=0,
                aperture_radius=5, annulus_radius=None, cut_vars={}):
    print('total objects:',len(cat_objects))
    for key, cut_var in cut_vars.items():
        cat_objects = cat_objects[(cat_objects[key]>cut_var['min']) & 
                                    (cat_objects[key]<cut_var['max'])]
    print('good objects:', len(cat_objects))
    cat_objects = Table(cat_objects)

    aperture_area = np.pi * aperture_radius**2
    if annulus_radius is None:
        annulus_radius = aperture_radius+2
    annulus_area = np.pi * (annulus_radius**2 - aperture_radius**2)

    objects = zip(cat_objects['x'],cat_objects['y'])
    apertures = photutils.CircularAperture(objects, aperture_radius)
    annulus_apertures = photutils.CircularAnnulus(objects, aperture_radius, annulus_radius)
    flux = photutils.aperture_photometry(hdu.data, apertures)
    bkg_flux = photutils.aperture_photometry(hdu.data, annulus_apertures)
    
    total_flux = flux-bkg_flux*aperture_area/annulus_area
    instrumental_mag = mag_zero - (2.5*np.log10(total_flux/exp_time))
    cat_objects[filter_name] = instrumental_mag
    cat_array=np.array(cat_objects)
    np.save(phot_file, cat_array)
    return cat_objects
Example #5
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)
Example #6
0
    def do_test(data_shape=None, apertures=None, method=None, subpixels=None, error=None):

        data = np.ones(data_shape)

        if error:
            error = np.ones(data_shape)
        else:
            error = None

        aperture_photometry(data, apertures, method=method, error=error, subpixels=subpixels)
def photometry_local(data, x, y, aperture_radius, sky_radius_inner,
                     sky_radius_outer):
    logger.debug('Sky annulus radii: %s -> %s', sky_radius_inner,
                 sky_radius_outer)
    apertures = ph.CircularAperture((x, y), r=aperture_radius)
    annulus_apertures = ph.CircularAnnulus((x, y),
                                           r_in=sky_radius_inner,
                                           r_out=sky_radius_outer)
    rawflux_table = ph.aperture_photometry(data, apertures)
    bkgflux_table = ph.aperture_photometry(data, annulus_apertures)
    bkg_mean = bkgflux_table['aperture_sum'] / annulus_apertures.area()
    bkg_sum = bkg_mean * apertures.area()
    final_sum = rawflux_table['aperture_sum'] - bkg_sum
    return np.array(final_sum)
def doPhot(image, median, Xs, Ys, hdr):
    # Maybe implement PSF photometry sometime in the future
    #print(ph.psf.create_prf(imageData, positions, 3))
    #Gauss = ph.psf.GaussianPSF(sigma = sources['fwhm'][index1]/2.355s, x_0=Xs[index1], y_0=Ys[index1])

    # Fix the masked values so they are just 0. This is not working in photutils,
    image.filled(0)

    # Figure out how big the aperture should be (when the change is < 1% we can stop)
    radii = []
    for j in range(len(Xs)): # Loop over every extracted source
        for i in range(1,20):
            apertures = ph.CircularAperture((Xs[j], Ys[j]), r=i)
            phot_table1 = ph.aperture_photometry(image, apertures)#, mask=mask)
            flux1 = phot_table1['aperture_sum']
            apertures = ph.CircularAperture((Xs[j], Ys[j]), r=i+1)
            phot_table2 = ph.aperture_photometry(image, apertures)#, mask=mask)
            flux2 = phot_table2['aperture_sum']
            if 100 - (flux1/flux2 *100) < 1:
                radii.append(float(i))
                break
            
    # Now we grab the most common aperture size
    try: radius = sp.stats.mode(radii)[0][0]
    except: radius = 10 # This is the typical optimal value
    print('Radius size:', radius)

    # Show the objects and the aperture size
    fig = plt.figure(10, figsize=(12,12))
    ax = fig.add_subplot(111)
    apertures = ph.CircularAperture((Xs,Ys), r=radius)
    fig.canvas.mpl_connect('button_press_event', onclickclose)
    ax.imshow(image, cmap='Greys', norm=LogNorm())
    apertures.plot(color='red', lw=1.5, alpha=0.5)
    plt.show()

    # Now let's do the photometry
    apertures = ph.CircularAperture((Xs, Ys), r=radius) # Create circular apertures for each source
 
    phot_table = ph.aperture_photometry(image, apertures)#, mask=mask)
    #print(phot_table)

    # Compute the instrumental magnitude and associated error
    inM = -2.5*np.log10(phot_table['aperture_sum'].data / hdr['EXPTIME'])
    #print(inM)

    sigma_mag = 1.0857 * np.sqrt( phot_table['aperture_sum'].data*Gain + 2*np.pi*radius**2 * (median*Gain + (RN*Gain)**2) ) / (phot_table['aperture_sum'].data*Gain)
    #print(sigma_mag)
    #print(ObjName2, band2, hdr2['EXPTIME'], inM, sigma_mag)
    return inM, sigma_mag
Example #9
0
def photometry():
    
    filters = ['I','B','V','R'] #filter names
   
   # create a table here for Photometry results
    photo_table=Table(names=('Residuals','Error','Time'))
    Photometry = open('photometry_'+str(sn_name)+'.txt','w')
    
    for f in filters:
        
        #create a txt file where the Photometry Results table will be saved
        
        
        #join the two paths given above
        search_str = os.path.join(date_search_path,str(sn_name)+str(f)+'.fits')
    
        #names will be the supernova fits files for different filters
        for name in glob(search_str):
        
            with fits.open(name) as analysis:
                
                N = analysis[0].header['NCOMBINE'] # number of images stacked in the fit file
                final_date = convert_time(analysis) # The Time series must be MJD
                
                #Position of Supernova as coordinate, aperture is calculated with the coordinate
                cordinate = SkyCoord('01:48:08.66 +37:33:29.22', unit = (u.hourangle, u.deg))
                #coordinates = SkyCoord('01:48:08.66 +37:33:29.22',unit = (u.hourangle, u.deg))
                
                #exp_time= analysis[0].header['EXPTIME']
                #data_error = np.sqrt(N*analysis[0].data)
                
                aperture = SkyCircularAperture(cordinate, r=5*u.arcsec)
                annulus_apertures = SkyCircularAnnulus(cordinate, r_in=6*u.arcsec, r_out=8*u.arcsec)
                
                aperture_area = np.pi * 3 ** 2
                annulus_area = np.pi * (8 ** 2 - 6 ** 2)
                
                rawflux_table = aperture_photometry(analysis[0], aperture)
                bkgflux_table = aperture_photometry(analysis[0], annulus_apertures )
                
                residual_sum = rawflux_table[0]['aperture_sum'] - bkgflux_table[0]['aperture_sum'] * aperture_area / annulus_area
                error=np.sqrt(np.abs(residual_sum)*N)
                photo_table.add_row((residual_sum,error,final_date))
                
    print "***** Photometry Results without Calibration ****"
    print photo_table
    print >> Photometry, photo_table
    Photometry.close()
    calibration(N)
 def zero_check(self, fits_file, cordinate, r):
     
     '''
     Perform photometry on a exp type .fits file and check if there are
     data pixels in an aperture. Return a number code that corresponds
     to the result: 0 = no exp file found, 1 = data pixels found inside
     the aperture, 2 = no data pixels found in the aperture
     
     Args:
         fits_file (str)     : File path of an int type .fits file
         cordinate (SkyCoord): Coordinate of a supernova in degrees
         r         (Quantity): Radius of a photometry aperture in arcmin
     
     Returns:
         result (int): A number code as outlined in the description
     '''
     
     if os.path.isfile(fits_file.replace("d-int", "d-exp")):
         with fits.open(fits_file.replace("d-int", "d-exp")) as exp_file:
             
             aperture = SkyCircularAperture(cordinate, r)
             phot_table = aperture_photometry(exp_file[0], aperture)
         
             if phot_table[0][0] != 0:
                 result = 1
         
             elif phot_table[0][0] == 0:
                 result = 2
     
     else:
         result = 0
     
     return(result)
Example #11
0
def getFluxesForRADec(radecList, image, the_wcs, bkg_level = 0, apRadius = 3.5):
    """Get the aperture flux at the (RA, Dec) position for the radecList array"""
    pix_ctr = []
    good_pix_mask = []
    h, w = image.shape
    for aPoint in radecList:
        try:
            pixPoint = the_wcs.all_world2pix([aPoint],0,tolerance=1E-3)[0]
            x,y = pixPoint.astype('int')
            xmin, xmax = max(0, x - apRadius), min(w, x + apRadius)
            ymin, ymax = max(0, y - apRadius), min(h, x + apRadius)
            if(x > w or x < 0 or y < 0 or y > h):
                good_pix_mask.append(False)
            elif(image.mask[ymin:ymax,xmin:xmax].any() == True):
                good_pix_mask.append(False)
            else:
                pix_ctr.append(pixPoint)
                good_pix_mask.append(True)
        except:
            good_pix_mask.append(False)
    
    pix_ctr = np.array(pix_ctr)
    good_pix_mask = np.array(good_pix_mask)
    
    apertures = CircularAperture(pix_ctr, apRadius)
    fluxes = np.array(aperture_photometry(image, apertures)['aperture_sum'])
    fluxes -= bkg_level * np.pi * apRadius**2
    
    return fluxes, good_pix_mask
def photometry():
    filters=['I','B','V','R'] #filter names
    for f in filters:
        All_data=Table(names=('Count','Error','Time'))
        file=open('photometry_'+str(sn_name)+str(f)+'.txt','w')
        super_lotis_path='/Users/zeynepyaseminkalender/Documents/MyFiles_Pyhton/SuperLOTIS_final'
        date_search_path=os.path.join(super_lotis_path, '13*')
        search_str=os.path.join(date_search_path,str(sn_name)+str(f)+'.fits')
        for name in glob(search_str):
            date=extract_date_from_fullpath(name)
            final_date=convert_time(date)
            with fits.open(name) as analysis:
                z = .086
                r = 1 * u.kpc / cosmo.kpc_comoving_per_arcmin(z)
                cordinate = SkyCoord('01:48:08.66 +37:33:29.22', unit = (u.hourangle, u.deg))
                aperture = SkyCircularAperture(cordinate, r)
                exp_time= analysis[0].header['EXPTIME'] # error calculation
                
                data_error = np.sqrt(analysis[0].data*exp_time) / exp_time
                tbl=Table(aperture_photometry(analysis[0],aperture,error=data_error),names=('Count','Count_Error','x_center','y_center','center_input'))
                tbl.keep_columns(['Count','Count_Error'])
                count=tbl[0]['Count']
                error=tbl[0]['Count_Error']
                All_data.add_row((count,error,final_date))
    
        print >> file , All_data
        file.close()
    plot(filters)
Example #13
0
def circ_flux(image, maskmap, ap_center, ap_radii, max_rad=None):
    """
    Calculate flux in a circular aperture at the given set of aperture radii.
    """
    
    mean, median, std = sigma_clipped_stats(image, mask=(maskmap==0),
                                            sigma=3.0, iters=3)
    # Calculate the background level
    bkgd_flux = median

    ap_fluxes = np.zeros(len(ap_radii))*np.nan
    bkgd_fluxes = np.zeros(len(ap_radii))*np.nan

    if max_rad is None:
        max_rad = max(np.shape(maskmap)) / 2.0
    
    # Compute fluxes and background levels for every given radius
    for i, rad in enumerate(ap_radii):
        # If the radius is bigger than half the image, the photometry
        # will fail (because the aperture will fall off the image)
        if rad > max_rad:
            continue

        # Just take bkgd as median of whole image
        # Otherwise no background left with big apertures
        bkgd_fluxes[i] = bkgd_flux
        bkgd_subtracted = image - bkgd_fluxes[i]
        
        # Now do the aperture photometry itself
        aperture = photutils.CircularAperture(ap_center, r=rad)
        phot_table = photutils.aperture_photometry(bkgd_subtracted, aperture)
        ap_fluxes[i] = phot_table["aperture_sum"][0]
        
    return ap_fluxes, bkgd_fluxes
Example #14
0
def ellip_flux(image, maskmap, ap_center, ap_radii, a, b, theta, background,
    max_rad=None):
    """
    Calculate flux in an elliptical aperture at the given set of aperture radii.
    """
    
    ap_fluxes = np.zeros(len(ap_radii))*np.nan

    if max_rad is None:
        mshape = np.shape(maskmap)
        max_rad = np.sqrt(mshape[0]**2 + mshape[1]**2)
    
    # Compute fluxes and background levels for every given radius
    for i, rad in enumerate(ap_radii):
        # If the radius is bigger than half the image, the photometry
        # will fail (because the aperture will fall off the image)
        if a*rad > max_rad:
            continue

        bkgd_subtracted = image - background
        
        # Now do the aperture photometry itself
        aperture = photutils.EllipticalAperture(ap_center, rad*a, rad*b, 
                                                theta=theta)
        phot_table = photutils.aperture_photometry(bkgd_subtracted, aperture)
        ap_fluxes[i] = phot_table["aperture_sum"][0]
        
    return ap_fluxes
Example #15
0
def photometry(image2d, cen_x, cen_y, mask, index = 0, shape = 'Circ', rad = None, r_in = None, r_out = None, ht = None, wid = None, w_in = None, w_out = None, h_out = None, ang = 0.0):
    """
    Takes:
    image2d = 2 dimensional image array. Type = ndarray
    cen_x, cen_y = x & y center position. Type = ndarray/list
    mask = mask that blocks out NaNs. Type = ndarray
    index = if cen_x and cen_Y is a list of more than 1 element, specify the desired index. Type = Integer
    shape = 'Circ':CircularAperture, 'Rect':RectangularAperture, 'CircAnn':CircularAnnulus, 'RectAnn':RectangularAnnulus
    rad, r_in, r_out, ht, wid, w_in, w_out, h_out, ang = Astropy's aperture parameters 
    
    Returns:
    flux = flux of the image extracted by the aperture described in the "shape" parameter. Type = Float
    aperture = aperture object created by astropy
    """
    if shape == 'Circ':
        aperture = CircularAperture((cen_x[index], cen_y[index]), r = rad)
    elif shape == 'Rect':
        aperture = RectangularAperture((cen_x[index], cen_y[index]), w = wid, h = ht, theta = ang)
    elif shape == 'CircAnn':
        aperture = CircularAnnulus((cen_x[index], cen_y[index]), r_in = r_in, r_out = r_out)
    elif shape == 'RectAnn':
        aperture = RectangularAnnulus((cen_x[index], cen_y[index]), w_in = w_in, w_out = w_out, h_out = h_out, theta = ang)
            
    phot_table = aperture_photometry(image2d, aperture, mask = mask)
    flux = phot_table[0][0]
    return flux, aperture
Example #16
0
def psf_norm(array, size, fwhm):
    """ Scales a PSF, so the 1*FWHM aperture flux equals 1.
    
    Parameters
    ----------
    array: array_like
        The relative path to the psf fits image.
    size : int
        Size of the squared subimage.
    fwhm: float
        The size of the Full Width Half Maximum in pixel.
        
    Returns
    -------
    psf_norm: array_like
        The scaled psf.

    """
    psfs = frame_crop(array, size) 
    fwhm_aper = photutils.CircularAperture((frame_center(psfs)), fwhm/2.)
    fwhm_aper_phot = photutils.aperture_photometry(psfs, fwhm_aper)
    
    fwhm_flux = np.array(fwhm_aper_phot['aperture_sum'])
    if fwhm_flux>1.1 or fwhm_flux<0.9:
        psf_norm = psfs/np.array(fwhm_aper_phot['aperture_sum'])
    else:
        psf_norm = psfs
    
    return psf_norm
Example #17
0
def do_photometry(hdu, extensions=None, threshold=5, fwhm=2.5):

    if extensions is None:
        extensions = np.arange(1, len(hdu))
    if not isiterable(extensions):
        extensions = (extensions, )

    output = {}
    for ext in extensions:
        header = hdu[ext].header
        data = hdu[ext].data
        image_wcs = WCS(header)

        background = mad_std(data)

        sources = daofind(data, threshold=threshold * background, fwhm=fwhm)
        positions = (sources['xcentroid'], sources['ycentroid'])
        sky_positions = pixel_to_skycoord(*positions, wcs=image_wcs)

        apertures = CircularAperture(positions, r=2.)
        photometry_table = aperture_photometry(data, apertures)
        photometry_table['sky_center'] = sky_positions

        output[str(ext)] = photometry_table

    return output
    def get_concentration_ell(self, image):

        '''
        To calculate the conctration we need to find the radius 
            -- which encloses 20% of the total light
            -- which encloses 80% of the total light
        So we need a running sum of the total pixel counts in increasing radii
        We also need to know the total flux -- 
           define as the total pixel counts within 
           an aperture of  one petrosian radius
        Divide the running sum by the fixed total flux value and 
           see where this ratio crosses .2 and .8
        #'''
        print "calculating Concentration..."

        a = 10*np.logspace(-1.0, np.log10(np.min([self.xc,self.yc])/10.),num=20)
        b = a/self.e
        position = [self.Ax, self.Ay]

        annuli = np.hstack([EllipticalAnnulus(position, a[idx], a[idx+1],
                                              b[idx+1], self.theta) \
                                for idx, radius in enumerate(a[:-1])])
        counts = np.hstack([aperture_photometry(image, an, method='exact') \
                            for an in annuli])['aperture_sum']
        cum_sum = np.cumsum(counts)[:-1]

        tot_aper = EllipticalAperture(position, 1.5*self.Rp, 
                                      1.5*self.Rp/self.e, self.theta)
        tot_flux = float(aperture_photometry(image, tot_aper, 
                                             method='center')['aperture_sum'])
        
        # ratio of the cumulative counts over the total counts in the galaxy
        ratio = cum_sum/tot_flux
        
        # now we need to find the intersection of ratio with 0.2 and 0.8
        interp_radii, interp_ratio = morph.get_interp(a[1:-1], ratio)
        
        if not np.any(np.isnan(interp_ratio)):
            r20 = morph.get_intersect(interp_ratio, 0.2, interp_radii)
            r50 = morph.get_intersect(interp_ratio, 0.5, interp_radii)
            r80 = morph.get_intersect(interp_ratio, 0.8, interp_radii)
        else:
            r20 = r50 = r80 = np.nan
            
        conc = 5*np.log10(np.divide(r80, r20))

        return r20, r50, r80, conc
Example #19
0
def aperphot(image_data,ape_radius,cx,cy):
	ape_sum=np.zeros(64)
	for i in range(64):
		position=[cx[i],cy[i]]
		aperture=CircularAperture(position,r=ape_radius)
		phot_table=aperture_photometry(image_data[i,:,:],aperture)
		temp=phot_table['aperture_sum']
		ape_sum[i]=phot_table['aperture_sum']
	return ape_sum
def check_rmse_subtracted_image(subtracted_image, ref_sources, aperRad = 4.0):
    ref_positions = (ref_sources['xcentroid'], ref_sources['ycentroid'])
    ref_apertures = CircularAperture(ref_positions, r=aperRad)
    
    subtracted_aperture_phot    = aperture_photometry(subtracted_image, ref_apertures)
    # print(subtracted_aperture_phot['aperture_sum_err'])
    # median_aperture_background  = nanmedian(subtracted_image) + np.zeros(subtracted_image.shape)
    # median_aperture_background  = aperture_photometry(median_aperture_background, ref_apertures)['aperture_sum'].data
    
    return nansum((subtracted_aperture_phot['aperture_sum'].data)**2) / len(ref_apertures)
Example #21
0
 def phot(self, image, objpos, aper):
     """
     Aperture photometry using Astropy's photutils.
     
     Parameters
     ----------
     image : numpy array
         2D image array
         
     objpos : list of tuple
         Object poistions as list of tuples
         
     aper : float
         Aperture radius in pixels
      
     Returns 
     -------
     phot_table : astropy table
          Output table with stellar photometry   
     """
     try:
         from astropy.table import hstack
         from photutils import aperture_photometry, CircularAnnulus, CircularAperture
     except ImportError:
         pass
 
     apertures = CircularAperture(objpos, r = aper) 
     annulus_apertures = CircularAnnulus(objpos, r_in = self.inner_radius, r_out = self.outer_radius)
     
     rawflux_table = aperture_photometry(image, apertures = apertures, method = self.method)
     bkgflux_table = aperture_photometry(image, apertures = annulus_apertures, method = self.method)
     phot_table = hstack([rawflux_table, bkgflux_table], table_names = ["raw", "bkg"])
     
     bkg = phot_table["aperture_sum_bkg"] / annulus_apertures.area()
     phot_table["msky"] = bkg
     phot_table["area"] = apertures.area()
     phot_table["nsky"] = annulus_apertures.area()
             
     bkg_sum = bkg * apertures.area()
     final_sum = phot_table["aperture_sum_raw"] - bkg_sum
     phot_table["flux"] = final_sum
     
     return phot_table
Example #22
0
    def aper_phot(self,x,y):
        """Perform aperture photometry, uses photutils functions
        
            Rapert,  sum,  area  and  flux  are  the  radius  of the aperture in
            pixels, the total number of counts including sky  in  the  aperture,
            the  area  of the aperture in square pixels, and the total number of
            counts in  the  aperture  excluding  sky.   Mag  and  merr  are  the
            magnitude and error in the magnitude in the aperture (see below).

                    flux = sum - area * msky
                     mag = zmag - 2.5 * log10 (flux) + 2.5 * log10 (itime)
                    merr = 1.0857 * error / flux
                   error = sqrt (flux / epadu + area * stdev**2 +
                           area**2 * stdev**2 / nsky)      
          """
        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".format(magzero))
        if center:
            pheader+=("\tfwhm")
            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,y,radius,total_flux,mag,annulus_sky/annulus_area,math_helper.gfwhm(sigma))
        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,y,radius,total_flux,mag,annulus_sky/annulus_area,)

        print(pheader+pstr)
        logging.info(pheader + pstr)
Example #23
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
Example #24
0
def aperphot(image_data,ape_radius,cx,cy,op):
	if(op==1):
		ape_sum=np.zeros(len(image_data))
		print "Radius:",ape_radius
		for i in range(len(image_data)):
			position=[cx[i],cy[i]]
			aperture=CircularAperture(position,r=ape_radius)
			phot_table=aperture_photometry(image_data[i,:,:],aperture)
			temp=phot_table['aperture_sum']
			ape_sum[i]=phot_table['aperture_sum']
	else:
		ape_sum=np.zeros(len(image_data))
		print "Radius:",ape_radius
		for i in range(len(image_data)):
			position=[cx[i],cy[i]]
			aperture=CircularAperture(position,r=ape_radius)
			phot_table=aperture_photometry(image_data[i,:,:],aperture,method='subpixel', subpixels=5)
			temp=phot_table['aperture_sum']
			ape_sum[i]=phot_table['aperture_sum']
	return ape_sum
Example #25
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
Example #26
0
def dophot(data,x,y,rad):

    positions=[]
    for i in range(len(x)):
        positions.append((x[i],y[i]))
    apertures=phot.CircularAperture(positions,r=rad)

    phot_table=phot.aperture_photometry(data,apertures)
    sum=phot_table['aperture_sum']

    return sum
Example #27
0
def test_aper_phot(capsys):
    """Check that apertures are as expected from photutils"""
    apertures = photutils.CircularAperture((50, 50), 5)
    aperture_area = apertures.area()
    assert_equal(aperture_area, 78.53981633974483)
    rawflux_table = photutils.aperture_photometry(
        test_data,
        apertures,
        subpixels=1,
        method="center")
    total_flux = float(rawflux_table['aperture_sum'][0])
    assert_equal(total_flux, 207.)
Example #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)
Example #29
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
def doPhot(image, median, Xs, Ys, hdr):
    # Maybe implement PSF photometry sometime in the future
    #print(ph.psf.create_prf(imageData, positions, 3))
    #Gauss = ph.psf.GaussianPSF(sigma = sources['fwhm'][index1]/2.355s, x_0=Xs[index1], y_0=Ys[index1])

    # Fix the masked values so they are just 0. This is not working in photutils,
    image.filled(0)

    # Figure out how big the aperture should be (when the change is < 1% we can stop)
    # WE CAN CLEAN THIS UP BY DOING MULTIPLE APERTURES AT ONCE AND COMPARING AT THE END, AS AN ENSEMBLE
    radius = None
    for i in range(1,20):
        apertures = ph.CircularAperture((Xs, Ys), r=i)
        phot_table1 = ph.aperture_photometry(image, apertures)#, mask=mask)
        flux1 = phot_table1['aperture_sum']
        apertures = ph.CircularAperture((Xs, Ys), r=i+1)
        phot_table2 = ph.aperture_photometry(image, apertures)#, mask=mask)
        flux2 = phot_table2['aperture_sum']
        if 100 - (flux1/flux2 *100) < 1:
            radius = float(i)
            break
    if radius == None: radius=10 # This is the optimal aperture size historically. This is just a fix for contaminted areas.

    fig = plt.figure(10, figsize=(12,12))
    ax = fig.add_subplot(111)
    apertures = ph.CircularAperture((Xs,Ys), r=radius)
    fig.canvas.mpl_connect('button_press_event', onclickclose)
    ax.imshow(image, cmap='Greys', norm=LogNorm())
    apertures.plot(color='red', lw=1.5, alpha=0.5)
    plt.show()

    apertures = ph.CircularAperture((Xs, Ys), r=radius)
    phot_table = ph.aperture_photometry(image, apertures)#, mask=mask)
    #print(phot_table)

    # Compute the instrumental magnitude and associated error
    inM = -2.5*np.log10(phot_table['aperture_sum'].data / hdr['EXPTIME'])
    sigma_mag = 1.0857 * np.sqrt( phot_table['aperture_sum'].data*Gain + 2*np.pi*radius**2 * (median1*Gain + (RN*Gain)**2) ) / (phot_table['aperture_sum'].data*Gain)
    return inM, sigma_mag
Example #31
0
    # create a "postage stamp" image centered on the science target
    stamp160 = data160[round(ycen - dy):round(ycen + dy),
                       round(xcen - dx):round(xcen + dx)]

    # plot the "postage stamp"
    ax = fig.add_subplot(2, 3, 3)
    plot_image(stamp160)
    plt.title('F160W')

    # plot F160W photometric curve of growth
    positions = [(xcen, ycen)]
    radii = np.arange(dx) + 1
    flux = []
    for radius in radii:
        aperture = CircularAperture(positions, radius)
        phot_table = aperture_photometry(data160, aperture)
        flux.append(phot_table['aperture_sum'][0])
    ax = fig.add_subplot(2, 3, 6)
    ax.plot(radii, flux, 'ro')
    plt.ylim([0, 3e6])
    plt.xlabel('Aperture Radius (pixels)')
    plt.ylabel('Flux (data values)')
    plt.tick_params(axis='both', which='major', labelsize=8)
    fluxtot1 = flux[40]
    plt.tight_layout()

    # plot F814W photometric curve of growth
    positions = [(xcen, ycen)]
    radii = np.arange(dx) + 1
    flux = []
    for radius in radii:
Example #32
0
def contrast_limit(
        path_images: str, path_psf: str, noise: np.ndarray, mask: np.ndarray,
        parang: np.ndarray, psf_scaling: float, extra_rot: float,
        pca_number: int, threshold: Tuple[str, float], aperture: float,
        residuals: str, snr_inject: float,
        position: Tuple[float, float]) -> Tuple[float, float, float, float]:
    """
    Function for calculating the contrast limit at a specified position for a given sigma level or
    false positive fraction, both corrected for small sample statistics.

    Parameters
    ----------
    path_images : str
        System location of the stack of images (3D).
    path_psf : str
        System location of the PSF template for the fake planet (3D). Either a single image or a
        stack of images equal in size to science data.
    noise : numpy.ndarray
        Residuals of the PSF subtraction (3D) without injection of fake planets. Used to measure
        the noise level with a correction for small sample statistics.
    mask : numpy.ndarray
        Mask (2D).
    parang : numpy.ndarray
        Derotation angles (deg).
    psf_scaling : float
        Additional scaling factor of the planet flux (e.g., to correct for a neutral density
        filter). Should have a positive value.
    extra_rot : float
        Additional rotation angle of the images in clockwise direction (deg).
    pca_number : int
        Number of principal components used for the PSF subtraction.
    threshold : tuple(str, float)
        Detection threshold for the contrast curve, either in terms of 'sigma' or the false
        positive fraction (FPF). The value is a tuple, for example provided as ('sigma', 5.) or
        ('fpf', 1e-6). Note that when sigma is fixed, the false positive fraction will change with
        separation. Also, sigma only corresponds to the standard deviation of a normal distribution
        at large separations (i.e., large number of samples).
    aperture : float
        Aperture radius (pix) for the calculation of the false positive fraction.
    residuals : str
        Method used for combining the residuals ('mean', 'median', 'weighted', or 'clipped').
    snr_inject : float
        Signal-to-noise ratio of the injected planet signal that is used to measure the amount
        of self-subtraction.
    position : tuple(float, float)
        The separation (pix) and position angle (deg) of the fake planet.

    Returns
    -------
    float
        Separation (pix).
    float
        Position angle (deg).
    float
        Contrast (mag).
    float
        False positive fraction.
    """

    images = np.load(path_images)
    psf = np.load(path_psf)

    # Cartesian coordinates of the fake planet
    yx_fake = polar_to_cartesian(images, position[0], position[1] - extra_rot)

    # Determine the noise level
    noise_apertures = compute_aperture_flux_elements(image=noise[0, ],
                                                     x_pos=yx_fake[1],
                                                     y_pos=yx_fake[0],
                                                     size=aperture,
                                                     ignore=False)

    t_noise = np.std(noise_apertures, ddof=1) * \
              math.sqrt(1 + 1 / (noise_apertures.shape[0]))

    # get sigma from fpf or fpf from sigma
    # Note that the number of degrees of freedom is given by nu = n-1 with n the number of samples.
    # See Section 3 of Mawet et al. (2014) for more details on the Student's t distribution.

    if threshold[0] == 'sigma':
        sigma = threshold[1]

        # Calculate the FPF for a given sigma level

        fpf = t.sf(sigma, noise_apertures.shape[0] - 1, loc=0., scale=1.)

    elif threshold[0] == 'fpf':
        fpf = threshold[1]

        # Calculate the sigma level for a given FPF
        sigma = t.isf(fpf, noise_apertures.shape[0] - 1, loc=0., scale=1.)

    else:
        raise ValueError('Threshold type not recognized.')

    # Aperture properties
    im_center = center_subpixel(images)

    # Measure the flux of the star
    ap_phot = CircularAperture((im_center[1], im_center[0]), aperture)
    phot_table = aperture_photometry(psf_scaling * psf[0, ],
                                     ap_phot,
                                     method='exact')
    star = phot_table['aperture_sum'][0]

    # Magnitude of the injected planet
    flux_in = snr_inject * t_noise
    mag = -2.5 * math.log10(flux_in / star)

    # Inject the fake planet
    fake = fake_planet(images=images,
                       psf=psf,
                       parang=parang,
                       position=(position[0], position[1]),
                       magnitude=mag,
                       psf_scaling=psf_scaling)

    # Run the PSF subtraction
    _, im_res = pca_psf_subtraction(images=fake * mask,
                                    angles=-1. * parang + extra_rot,
                                    pca_number=pca_number)

    # Stack the residuals
    im_res = combine_residuals(method=residuals, res_rot=im_res)
    flux_out_frame = im_res[0, ] - noise[0, ]

    # Measure the flux of the fake planet after PCA
    # the first element is the planet
    flux_out = compute_aperture_flux_elements(image=flux_out_frame,
                                              x_pos=yx_fake[1],
                                              y_pos=yx_fake[0],
                                              size=aperture,
                                              ignore=False)[0]

    # Calculate the amount of self-subtraction
    attenuation = flux_out / flux_in
    # the throughput can not be negative. However, this can happen due to numerical inaccuracies
    if attenuation < 0:
        attenuation = 0

    # Calculate the detection limit
    contrast = (sigma * t_noise + np.mean(noise_apertures)) / (attenuation *
                                                               star)

    # The flux_out can be negative, for example if the aperture includes self-subtraction regions
    if contrast > 0.:
        contrast = -2.5 * math.log10(contrast)
    else:
        contrast = np.nan

    # Separation [pix], position angle [deg], contrast [mag], FPF
    return position[0], position[1], contrast, fpf
Example #33
0
def stack(cutout, radiusStack, gain, zeroPoint, wavelenght):
    """
    Print out pdf with stamp stacking and plot graph magnitude 
    in function of wavelenght
    
    Parameters
    ---------_
    cutout: list
        array of images N filt x N sources
    radiusStack: float
        radius in pixel
    zeroPoint: float
        Zero point of your image
    gain: float
        The gain of your image
    wavelenght: float
        wavelenght of each filters    
    """

    # define the resulting stacked image as a cutout with the same dimension of the input cutouts
    o = 0

    # Create pdf where are storing stack stamp and graph
    pdfOut = PdfPages(dirpath + 'stacking.pdf')

    fig, axs = plt.subplots(1, len(filters), figsize=(5, 5))

    # Saving magnitude and error
    mag = [[0.0 for i in range(len(filters))] for j in range(2)]

    for i in cutout:  # i is a list of galaxies

        print('Photometry ' + filters[o])

        # Assuming that the shape is the same for all galaxies
        #this is now a tuple, e.g. (25,25), so the code will work also for rectangular stamps
        sizeStack = i[0].shape

        #this is now a tuple, e.g. (25,25), so the code will work also for rectangular stamps
        print(sizeStack)  #just for testing
        stackImg = np.zeros(sizeStack)

        #LOOP over pixels: (I changed a lot here)
        # fait tous les pixel x
        for x in range(sizeStack[0]):
            # fait tous les pixel y
            for y in range(sizeStack[1]):

                # for the given pixels, collect the flux from all stamps into a list
                pxl = []  #use an empty list, but it can be also np.zeros()
                for stamp in i:
                    pxl.append(stamp.data[x, y])
                # caluclate the median:
                stackImg[x, y] = np.median(pxl)

        axs[o].set_title(filters[o], fontsize=5, pad=2.5)
        axs[o].get_xaxis().set_visible(False)
        axs[o].get_yaxis().set_visible(False)
        mappa = axs[o].imshow(stackImg,
                              cmap='afmhot',
                              origin='lower',
                              interpolation='nearest')
        zrange = zscale.zscale(stackImg)
        mappa.set_clim(zrange)

        # Mask sources
        mask = make_source_mask(stackImg, snr=1, npixels=3, dilate_size=3)

        # Derive the background and the rms image
        bkg = Background2D(
            stackImg,
            int(sizeStack[0] / 10),
            filter_size=1,
            sigma_clip=None,
            bkg_estimator=SExtractorBackground(SigmaClip(sigma=2.5)),
            bkgrms_estimator=StdBackgroundRMS(SigmaClip(sigma=2.5)),
            exclude_percentile=90,
            mask=mask)

        if gain[o] == 0.:

            gain[o] = 1000000000000000000000000000.

        # Calculate the total error
        error = calc_total_error(stackImg, bkg.background_rms, gain[o])

        # Define a cicularAperture in the wcs position of your objects
        apertures = CircularAperture(
            (int(sizeStack[0] / 2), int(sizeStack[1] / 2)), r=radiusStack[o])

        # Derive the flux and error flux
        photometry = aperture_photometry(stackImg - bkg.background,
                                         apertures,
                                         error=error)

        # Saving magnitude and error
        mag[0][o] = -2.5 * np.log10(
            photometry['aperture_sum'][0]) + zeroPoint[o]
        mag[1][o] = 1.0857 * (photometry['aperture_sum_err'][0] /
                              photometry['aperture_sum'][0])

        o = o + 1

    plt.savefig(pdfOut, format='pdf')

    # Plot
    plt.clf()

    y = mag[0]
    x = wavelenght
    plt.plot(x, y, 'ro')

    xlimL = wavelenght[0] - 1000
    xlimR = wavelenght[len(wavelenght) - 1] + 1000

    plt.xlim(xlimL, xlimR)
    plt.ylim(32, 22)
    plt.errorbar(wavelenght,
                 mag[0],
                 yerr=mag[1],
                 fmt='none',
                 capsize=10,
                 ecolor='blue',
                 zorder=1)

    plt.xlabel('wavelenght(Ã…)')
    plt.ylabel('magnitude')
    plt.title('')

    plt.savefig(pdfOut, format='pdf')
    pdfOut.close()
    np.savetxt(dirpath + 'fluxStack.txt',
               mag,
               header='Ligne1: mag, Ligne2: mag_err')

    return
Example #34
0
            print('Failed:')
            traceback.print_exc()
            continue

        h,w = im.get_image_shape()

        for x,y in [(0,0), (0,h), (w,0), (w,h), (w/2, h/2)]:
            psfimg = psf.getImage(x, y)
            print('PSF image at', (x,y))#, ':', psfimg)
            print('sum', psfimg.sum())

            ph,pw = psfimg.shape
            print('psf img shape', psfimg.shape)

            apertures = [1., 3., 3.75, 5., 6., 7., 7.5, 8., 9., 10., 12.5, 15.]

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

            for apxy in [np.array([[pw/2., ph/2.]]),
                         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
                print('Aperture fluxes:', ap)
Example #35
0
def radial_profile(data, lim):

    ############################################################
    # Fetching information
    imfile = open("../Image_alma.out").readlines()
    for line in imfile:
        if line.split('=')[0] == 'MCobs:fov':
            fov = float(line.split('=')[1].split('!')[0])
        elif line.split('=')[0] == 'MCobs:npix':
            npix = float(line.split('=')[1].split('!')[0])
        elif line.split('=')[0] == 'MCobs:phi':
            phi_image = float(line.split('=')[1].split('!')[0])
        elif line.split('=')[0] == 'MCobs:theta':
            theta = float(line.split('=')[1].split('!')[0])
        else:
            continue

    infile = open("../input.dat").readlines()
    for line in infile:
        if line.split('=')[0] == 'Distance':
            d = float(line.split('=')[1])

    ############################################################
    # Derived quantities
    pxsize = fov / npix  # pixel scale (arcsec/px)
    theta = (theta * units.deg).to(units.rad).value  # Inclination (rad)
    d = (d * units.pc).to(units.au).value  # Distance (au)
    e = np.sin(theta)  # eccentricity of the annulus

    ############################################################
    # Input params
    angle_annulus = 0.0

    # Determining limit for radial profile
    #lim=120.0
    linear_lim = 2 * (lim)  # AU
    angular_lim = linear_lim / d  # rad
    angular_lim = (angular_lim * units.rad).to(units.arcsec).value  # arcsec
    pixel_lim = int(round(angular_lim / pxsize))
    xc = 0.5 * data.shape[0]  # Image center in data coordinates
    yc = 0.5 * data.shape[1]  # Image center in data coordinates
    dr = 1.0  # Width of the annulus
    a_in_array = []
    for i in np.arange(yc + dr, yc + 0.5 * pixel_lim, dr):
        a_in_array.append(i - xc)
    a_out_array = [i + dr for i in a_in_array]
    b_out_array = [i * (1 - e**2)**0.5 for i in a_out_array]

    apertures = [
        EllipticalAnnulus((yc, xc),
                          a_in=ain,
                          a_out=aout,
                          b_out=bout,
                          theta=angle_annulus)
        for (ain, aout, bout) in zip(a_in_array, a_out_array, b_out_array)
    ]
    """
    ############################################################
    # Do a check
    a=0.01
    vmin_jband=np.percentile(data,a)
    vmax_jband=np.percentile(data,100-a)
    aperture=apertures[-1]
    plt.imshow(data,clim=(vmin_jband,vmax_jband))
    plt.title("Image model")
    aperture.plot(color='red',lw=1)
    plt.show()
    print(data.max())
    sys.exit()
    """

    # Radial distance of each annulus
    r_arcsec = [(j + 0.5 * (i - j)) * pxsize
                for (i, j) in zip(a_out_array, a_in_array)]  # arcsec
    r_rad = [(i * units.arcsec).to(units.rad).value for i in r_arcsec]  # rad
    r_au = [(i * d) for i in r_rad]  # AU

    # Creating numpy arrays
    r_au = np.array(r_au)
    r_arcsec = np.array(r_arcsec)

    phot_table = aperture_photometry(data, apertures)
    col_values = []
    for col in phot_table.colnames:
        col_values.append(phot_table[col][0])
    brightness = [col_values[i] for i in range(3, len(col_values))]
    brightness = np.array(brightness)

    for i in range(0, len(brightness)):
        brightness[i] = brightness[i] / apertures[i].area

    rcmin = 30.0
    rcmax = 100.0
    bmaxc = []
    for i in range(0, len(r_au)):
        if rcmin <= r_au[i] <= rcmax:
            bmaxc.append(brightness[i])
    bmaxc = np.array(bmaxc)

    fac = 1 / max(bmaxc)
    brightness = brightness * fac
    """
    ############################################################
    # Creating brightness profile
    fig=plt.figure()
    ax=plt.axes()
    ax.plot(r_au,brightness/max(brightness),'*')
    ax.set_xlabel(r"Projected radial distance (AU)")
    ax.set_ylabel("Density flux (mJy/beam)")
    ax.set_title("Radial profile model")
    plt.show()
    sys.exit()
    """

    ############################################################
    # Creating file
    file = open('../alma_radial_profile_modeled.dat', "w")
    for i in range(0, len(r_au)):
        file.write('%.15e %.15e \n' % (r_au[i], brightness[i]))

    return None
Example #36
0
from tqdm import tqdm, trange
from itertools import repeat
import os

rng = np.random.seed(11256)

data = np.random.randn(512, 512) + 10

rows = []
for r in trange(1, 201, 5):
    ap = CircularAperture((255.5, 255.5), r)

    ts = []
    for i in range(5):
        t0 = datetime.now()
        t = aperture_photometry(data, ap, method="exact")
        t1 = datetime.now()
        time = (t1 - t0).total_seconds()
        ts.append(time)

    time = sum(ts) / 5
    rows.append((r, time))

df = pd.DataFrame(rows, columns=["r", "time"])

path = os.path.dirname(__file__)
df.to_csv(os.path.join(path, "python_aperture_size.csv"), index=False)

## Ellipse

rows = []
Example #37
0
plt.show()

# Calculate the flux and uncertainties
data_cut.shape
rms_12CO10 = 0.0016
chan_width = 10
beam_area = 2.186 * 1.896 * 1.1331
beam_area_pix = beam_area / 0.09
error_value = rms_12CO10 * 10 * sqrt(50 / beam_area_pix)
error_12CO10 = np.full((180, 140), error_value)
data_cut = data_cut / beam_area_pix

for region in regions:
    stat12[region]['flux'] = aperture_photometry(
        data_cut,
        apertures=apertures[region]['pix'],
        error=error_12CO10,
        mask=mask)['aperture_sum'][0]
    stat12[region]['uncertainty'] = aperture_photometry(
        data_cut,
        apertures=apertures[region]['pix'],
        error=error_12CO10,
        mask=mask)['aperture_sum_err'][0]

##############################
# Calculate the flux and uncertainty of 13CO1-0
fitsimage = image_13CO10 + '.fits'

# input the 13CO1-0 data
hdr = fits.open(fitsimage)[0].header
wcs = WCS(hdr).celestial
Example #38
0
def extract_ifu(input_model, source_type, extract_params):
    """This function does the extraction.

    Parameters
    ----------
    input_model : IFUCubeModel
        The input model.

    source_type : string
        "POINT" or "EXTENDED"

    extract_params : dict
        The extraction parameters for aperture photometry.

    Returns
    -------
    ra, dec : float
        ra and dec are the right ascension and declination respectively
        at the nominal center of the image.

    wavelength : ndarray, 1-D
        The wavelength in micrometers at each plane of the IFU cube.

    temp_flux : ndarray, 1-D
        The sum of the data values in the extraction aperture minus the
        sum of the data values in the background region (scaled by the
        ratio of areas), for each plane.
        The data values are in units of surface brightness, so this value
        isn't really the flux, it's an intermediate value.  Dividing by
        `npixels` (to compute the average) will give the value for the
        `surf_bright` (surface brightness) column, and multiplying by
        the solid angle of a pixel will give the flux for a point source.

    background : ndarray, 1-D
        The background count rate that was subtracted from the total
        source data values to get `temp_flux`.

    npixels : ndarray, 1-D, float64
        For each slice, this is the number of pixels that were added
        together to get `temp_flux`.

    dq : ndarray, 1-D, uint32
        The data quality array.

    npixels_annulus : ndarray, 1-D, float64
        For each slice, this is the number of pixels that were added
        together to get `temp_flux` for an annulus region.

    radius_match: ndarray,1-D, float64
        The size of the extract radius in pixels used at each wavelength of the IFU cube

    x_center, y_center : float
        The x and y center of the extraction region
    """

    data = input_model.data
    weightmap = input_model.weightmap

    shape = data.shape
    if len(shape) != 3:
        log.error("Expected a 3-D IFU cube; dimension is %d.", len(shape))
        raise RuntimeError("The IFU cube should be 3-D.")

    # We need to allocate temp_flux, background, npixels, and dq arrays
    # no matter what.  We may need to divide by npixels, so the default
    # is 1 rather than 0.
    temp_flux = np.zeros(shape[0], dtype=np.float64)
    background = np.zeros(shape[0], dtype=np.float64)
    npixels = np.ones(shape[0], dtype=np.float64)
    npixels_annulus = np.ones(shape[0], dtype=np.float64)

    dq = np.zeros(shape[0], dtype=np.uint32)

    # For an extended target, the entire aperture will be extracted, so
    # it makes no sense to shift the extraction location.
    if source_type != "EXTENDED":
        ra_targ = input_model.meta.target.ra
        dec_targ = input_model.meta.target.dec
        locn = locn_from_wcs(input_model, ra_targ, dec_targ)

        if locn is None or np.isnan(locn[0]):
            log.warning("Couldn't determine pixel location from WCS, so "
                        "source offset correction will not be applied.")

            x_center = float(shape[-1]) / 2.
            y_center = float(shape[-2]) / 2.

        else:
            (x_center, y_center) = locn
            log.info("Using x_center = %g, y_center = %g, based on "
                     "TARG_RA and TARG_DEC.", x_center, y_center)

    method = extract_params['method']
    subpixels = extract_params['subpixels']
    subtract_background = extract_params['subtract_background']

    radius = None
    inner_bkg = None
    outer_bkg = None
    width = None
    height = None
    theta = None
    # pull wavelength plane out of input data.
    # using extract 1d wavelength, interpolate the radius, inner_bkg, outer_bkg to match input wavelength

    # find the wavelength array of the IFU cube
    x0 = float(shape[2]) / 2.
    y0 = float(shape[1]) / 2.
    (ra, dec, wavelength) = get_coordinates(input_model, x0, y0)

    # interpolate the extraction parameters to the wavelength of the IFU cube
    radius_match = None
    if source_type == 'POINT':
        wave_extract = extract_params['wavelength'].flatten()
        inner_bkg = extract_params['inner_bkg'].flatten()
        outer_bkg = extract_params['outer_bkg'].flatten()
        radius = extract_params['radius'].flatten()

        frad = interp1d(wave_extract, radius, bounds_error=False, fill_value="extrapolate")
        radius_match = frad(wavelength)
        # radius_match is in arc seconds - need to convert to pixels
        # the spatial scale is the same for all wavelengths do we only need to call compute_scale once.

        if locn is None:
            locn_use = (input_model.meta.wcsinfo.crval1, input_model.meta.wcsinfo.crval2, wavelength[0])
        else:
            locn_use = (ra_targ, dec_targ, wavelength[0])

        scale_degrees =  compute_scale(
            input_model.meta.wcs,
            locn_use,
            disp_axis=input_model.meta.wcsinfo.dispersion_direction)

        scale_arcsec = scale_degrees*3600.00
        radius_match /= scale_arcsec

        finner = interp1d(wave_extract, inner_bkg, bounds_error=False, fill_value="extrapolate")
        inner_bkg_match = finner(wavelength)/scale_arcsec

        fouter = interp1d(wave_extract, outer_bkg, bounds_error=False, fill_value="extrapolate")
        outer_bkg_match = fouter(wavelength)/scale_arcsec

    elif  source_type == 'EXTENDED':
        # Ignore any input parameters, and extract the whole image.
        width = float(shape[-1])
        height = float(shape[-2])
        x_center = width / 2. - 0.5
        y_center = height / 2. - 0.5
        theta = 0.
        subtract_background = False

    log.debug("IFU 1-D extraction parameters:")
    log.debug("  x_center = %s", str(x_center))
    log.debug("  y_center = %s", str(y_center))
    if source_type == 'POINT':
        log.debug("  method = %s", method)
        if method == "subpixel":
            log.debug("  subpixels = %s", str(subpixels))
    else:
        log.debug("  width = %s", str(width))
        log.debug("  height = %s", str(height))
        log.debug("  theta = %s degrees", str(theta))
        log.debug("  subtract_background = %s", str(subtract_background))
        log.debug("  method = %s", method)
        if method == "subpixel":
            log.debug("  subpixels = %s", str(subpixels))

    position = (x_center, y_center)

    # get aperture for extended it will not change with wavelength
    if source_type == 'EXTENDED':
        aperture = RectangularAperture(position, width, height, theta)
        annulus = None

    for k in range(shape[0]):
        inner_bkg = None
        outer_bkg = None

        if source_type == 'POINT':
            radius = radius_match[k] # this radius has been converted to pixels
            aperture = CircularAperture(position, r=radius)
            inner_bkg = inner_bkg_match[k]
            outer_bkg = outer_bkg_match[k]
            if inner_bkg <= 0. or outer_bkg <= 0. or inner_bkg >= outer_bkg:
                log.debug("Turning background subtraction off, due to "
                          "the values of inner_bkg and outer_bkg.")
                subtract_background = False

        if subtract_background and inner_bkg is not None and outer_bkg is not None:
            annulus = CircularAnnulus(position, r_in=inner_bkg, r_out=outer_bkg)
        else:
            annulus = None

        subtract_background_plane = subtract_background
        # Compute the area of the aperture and possibly also of the annulus.
        # for each wavelength bin (taking into account empty spaxels)
        normalization = 1.
        temp = weightmap[k,:,:]
        temp[temp>1] = 1
        aperture_area = 0
        annulus_area = 0

        # aperture_photometry - using weight map
        phot_table = aperture_photometry(temp, aperture,
                                         method=method, subpixels=subpixels)

        aperture_area = float(phot_table['aperture_sum'][0])

        if LooseVersion(photutils.__version__) >= '0.7':
            log.debug("aperture.area = %g; aperture_area = %g",
                      aperture.area, aperture_area)
        else:
            log.debug("aperture.area() = %g; aperture_area = %g",
                      aperture.area(), aperture_area)

        if(aperture_area ==0 and aperture.area > 0):
            aperture_area = aperture.area

        if subtract_background and annulus is not None:
            # Compute the area of the annulus.
            phot_table = aperture_photometry(temp, annulus,
                                             method=method, subpixels=subpixels)
            annulus_area = float(phot_table['aperture_sum'][0])

            if LooseVersion(photutils.__version__) >= '0.7':
                log.debug("annulus.area = %g; annulus_area = %g",
                          annulus.area, annulus_area)
            else:
                log.debug("annulus.area() = %g; annulus_area = %g",
                          annulus.area(), annulus_area)

            if(annulus_area ==0 and annulus.area > 0):
                annulus_area = annulus.area

            if annulus_area > 0.:
                normalization = aperture_area / annulus_area
            else:
                log.warning("Background annulus has no area, so background "
                            "subtraction will be turned off. %g" ,k)
                subtract_background_plane = False
        del temp

        npixels[k] = aperture_area
        npixels_annulus[k] = 0.0
        if annulus is not None:
            npixels_annulus[k] = annulus_area
        # aperture_photometry - using data

        phot_table = aperture_photometry(data[k, :, :], aperture,
                                         method=method, subpixels=subpixels)
        temp_flux[k] = float(phot_table['aperture_sum'][0])
        if subtract_background_plane:
            bkg_table = aperture_photometry(data[k, :, :], annulus,
                                            method=method, subpixels=subpixels)
            background[k] = float(bkg_table['aperture_sum'][0])
            temp_flux[k] = temp_flux[k] - background[k] * normalization

    # Check for NaNs in the wavelength array, flag them in the dq array,
    # and truncate the arrays if NaNs are found at endpoints (unless the
    # entire array is NaN).
    (wavelength, temp_flux, background, npixels, dq, npixels_annulus) = \
        nans_in_wavelength(wavelength, temp_flux, background, npixels, dq, npixels_annulus)

    return (ra, dec, wavelength, temp_flux, background, npixels, dq,
            npixels_annulus, radius_match, x_center, y_center)
Example #39
0
    def process(self):
        self.info('Processing has been started')
        for image in self.images_list:
            self.info('Processing image: {}'.format(image.name))
            apertures, sigma_values_table = self._create_apertures(
                image, self.stars_coordinates[image.savart],
                image.shape)

            out_table = []
            counts_tab = []
            counts_error_tab = []

            for aperture, sigma_value in zip(apertures, sigma_values_table):
                rawflux_table = aperture_photometry(image.data, aperture[0])
                bkgflux_table = aperture_photometry(image.data, aperture[1])
                phot_table = hstack([rawflux_table, bkgflux_table],
                                    table_names=['raw', 'bkg'])

                if self.config_section.get('bkg_annulus'):
                    self.info(
                        'Mean background value from annulus has been used.')
                    bkg_mean = phot_table['aperture_sum_bkg'] / \
                        aperture[1].area()
                    bkg_sum = bkg_mean * aperture[0].area()
                    self.info('Mean background value\n {}'.format(bkg_mean))
                else:
                    self.info('Mean background value from mask \
                        sigma clipped stats has been used.')
                    bkg_mean = sigma_value.median
                    bkg_sum = bkg_mean * aperture[0].area()
                    self.info('Mean background value\n {}'.format(bkg_mean))

                final_sum = phot_table['aperture_sum_raw'] - bkg_sum
                phot_table['residual_aperture_sum'] = final_sum

                final_sum_error = self._calc_phot_error(image.hdr, aperture,
                                                        phot_table, bkgflux_table, sigma_value.std)

                phot_table.add_column(
                    Column(name='residual_aperture_err_sum',
                           data=[final_sum_error]))

                phot_table['xcenter_raw'].shape = 1
                phot_table['ycenter_raw'].shape = 1
                phot_table['xcenter_bkg'].shape = 1
                phot_table['ycenter_bkg'].shape = 1

                out_table.append(phot_table)
                counts_tab.append(final_sum)
                counts_error_tab.append(final_sum_error)

            out_table = vstack(out_table)

            self.measurements.append(
                SavartCounts(image.savart, image.jd,
                             counts_tab, counts_error_tab))

            if self.config_section.get('plot_images'):
                self._make_image_plot(image.data, apertures, image.name)

            self._save_image_output(out_table, image.name + '.csv')

        self._save_polarizaton_results()
Example #40
0
def master_photometry(hdul, dtype=np.float32, method=None, sigma=3, fwhm=4,
                      kappa=5, r=3, r_in=5, r_out=9, save_format="fits",
                      saveto=None, overwrite=False):
    r"""
    Generate statistics, positions and more fore a given hdul object.
    This uses photutils package, see it for more information,
    also astropy tables could be relevant to look at.

    Parameters
    ----------
    hdul : astropy.io.fits.HDUList
        Image to process.
    dtype : data-type, optional
        Type to use for computing, defaults to np.float32.
    method : str, optional
        Method to use for normalization if value is not None.
        Valid values/metods are 'mean' or 'median'.
        Pay attention if you already used this with master_science,
        it's the same thing!
    sigma : float, optional
        Sigma level for mean, median and standard deviation, defaults to 3.
    fwhm : float, optional
        Expected FWHM in pixels, defaults to 4.
    kappa : float, optional
        Sigma level for source detection above background, defaults to 5.
    r : float, optional
        Aperture radius, defaults to 3.
    r_in : float, optional
        Inner sky annulus radius, defaults to 5.
    r_out : float, optional
        Outer sky annulus radius, defaults to 9.
    save_format : str, optional
        Format to save the table with, defaults to 'fits',
        has no effect if saveto is None.
    saveto : str, optional
        If this is not set (None, default) files won't be saved.
        If this is set to a string, save the file with the string as name.
    overwrite : bool, optional
        While saving, overwrite existing files? Defaults to False.

    Returns
    -------
    table : photutils.aperture_photometry
    """
    data = normalize(hdul[0].data.astype(dtype), method)
    mean, median, std = sigma_clipped_stats(data, sigma=sigma)
    DAOfind = DAOStarFinder(fwhm=fwhm, threshold=kappa*std)
    positions = DAOfind(data-median)
    centroid = (positions["xcentroid"], positions["ycentroid"])
    aperture = CircularAperture(centroid, r)
    annulus = CircularAnnulus(centroid, r_in, r_out)
    apertures = [aperture, annulus]
    table = aperture_photometry(data, apertures)
    bg_mean = table["aperture_sum_1"] / annulus.area()
    bg_sum = bg_mean * aperture.area()
    table["residual_aperture_sum"] = table["aperture_sum_0"] - bg_sum
    table["mag"] = - 2.5 * np.log10(table["residual_aperture_sum"])
    if saveto is not None:
        # TODO: dtype?
        table.write(saveto, overwrite=overwrite, format=save_format)
    return table
    #    r_inner=20.
    #    r_outer=25.
    #    r_inner_as=r_inner*u.arcsec
    #    r_outer_as=r_outer*u.arcsec
    #    print(r_inner_as,r_outer_as)

    #   sys.exit(0)

    #    time.sleep(1)
    #    print(WCS.world_axis_physical_types)
    aperture_pix = aperture.to_pixel(wcs)
    #    print(aperture_pix)
    r_pix = aperture_pix.r
    print('r_pix =', r_pix)
    #    phot_table = aperture_photometry(imdata, aperture,wcs=wcs)
    phot_table = aperture_photometry(imdata, aperture_pix)
    #    print(phot_table)
    #    print(phot_table.colnames)
    #   print(phot_table['sky_center'])
    #    print(phot_table['xcenter'])
    #    print(phot_table['ycenter'])
    aper_sum = phot_table['aperture_sum']
    phot_table[
        'aperture_sum'].info.format = '%.8g'  # for consistent table output

    aper_annu = SkyCircularAnnulus(positions, r_inner_as, r_outer_as)
    #    print(aper_annu)
    #    print(aper_annu.r_in)
    #    print(aper_annu.r_out)
    aper_annu_pix = aper_annu.to_pixel(wcs)
    #    print(aper_annu_pix)
Example #42
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)
Example #43
0
flux_r = np.zeros(len(a), 'f')
flux_ha = np.zeros(len(a), 'f')
if args.mask:
    maskdat = fits.getdata(args.mask)
    maskdat = np.array(maskdat, 'bool')

for i in range(len(a)):
    if args.verbose:
        print('defining elliptical aperture ' + str(i) + ' ap size = ',
              str(a[i]))
    ap = EllipticalAperture(position, a[i], b[i],
                            theta)  #,ai,bi,theta) for ai,bi in zip(a,b)]

    if args.mask:
        phot_table_r = aperture_photometry(imdat_r, ap, mask=maskdat)
        phot_table_ha = aperture_photometry(imdat_ha, ap, mask=maskdat)
    else:
        phot_table_r = aperture_photometry(imdat_r, ap)
        phot_table_ha = aperture_photometry(imdat_ha, ap)
    if args.verbose:
        print('measuring flux in aperture ' + str(i) + ' ap size = ',
              str(a[i]))
    flux_r[i] = phot_table_r['aperture_sum'][0]
    flux_ha[i] = phot_table_ha['aperture_sum'][0]

# plot image with outer ellipse

if args.plot:
    if args.verbose:
        print('plotting results \n')
        #        aper_annu_pix[j1]=CircularAnnulus(ra_pix[j1],dec_pix[j1],r_inner_as,r_outer_as)
        aperture_pix[j1] = aperture[j1].to_pixel(wcs)
        #        phot_table = aperture_photometry(imdata, aperture_pix[i],error=err_imdata)
        aper_annu_pix[j1] = aper_annu[j1].to_pixel(wcs)
        #        print(aper_annu_pix[j1])
        r_pix = aperture_pix[j1].r
        r_in_pix = aper_annu_pix[j1].r_in
        r_out_pix = aper_annu_pix[j1].r_out
        #        print(r_in_pix,r_out_pix)
        #        position_pix=(ra_pix[j1],dec_pix[j1])
        #        position_pix=np.transpose(positions_pix)
        #        r_pix=aperture_pix[i].r
        #       print('r_pix =',r_pix)
        apper = [aperture_pix[j1], aper_annu_pix[j1]]
        #        phot_annu_table = aperture_photometry(imdata, apper)
        phot_annu_table = aperture_photometry(imdata, apper, error=err_imdata)
        #        phot_annu_table = aperture_photometry(imdata, aperture_pix[i],error=err_imdata)
        aper_annu_sum0 = phot_annu_table['aperture_sum_0']
        print('... aper_annu_sum0 =', '%.2f' % aper_annu_sum0)
        aper_annu_sum1 = phot_annu_table['aperture_sum_1']
        print('... aper_annu_sum1 =', '%.2f' % aper_annu_sum1)
        aper_sum0[k][j1] = aper_annu_sum0
        aper_sum1[k][j1] = aper_annu_sum1

        aper_annu_sum_err0 = phot_annu_table['aperture_sum_err_0']
        print('... aper_annu_sum_err0 =', '%.2f' % aper_annu_sum_err0)
        aper_annu_sum_err1 = phot_annu_table['aperture_sum_err_1']
        print('... aper_annu_sum_err1 =', '%.2f' % aper_annu_sum_err1)
        aper_sum_err0[k][j1] = aper_annu_sum_err0
        aper_sum_err1[k][j1] = aper_annu_sum_err1
def brightnessProfile(imageName):
    image = fits.open(imageName)
    newData, header = image[0].data, image[0].header
    #print (header)
    height = header['NAXIS2']
    width = header['NAXIS1']
    image.close()

    #Begin placing aperture and annulus
    xAxis = (width) / 2  #Center point X-axis
    yAxis = height / 2  #Center point Y-axis

    positions = [(xAxis, yAxis)]  #Center point plotted
    aperture = CircularAperture(positions, r=1)
    phot_table_ap = aperture_photometry(newData, aperture)
    r_in = np.linspace(1, 11, 110)  #Inner radii per pixel
    r_out = np.linspace(2, 12, 120)  #Outer radii per pixel

    fluxArray = [phot_table_ap['aperture_sum'] / aperture.area()]
    radArray = [1]
    for i in range(0, len(r_in)):
        rIn = r_in[i]
        rOut = r_out[i]
        annulus_apertures = CircularAnnulus(positions, rIn, rOut)
        phot_table = aperture_photometry(newData, annulus_apertures)
        fluxArray.append(phot_table['aperture_sum'] / annulus_apertures.area())
        rMean = (rOut + rIn) / 2
        radArray.append(rMean)
    sumFlux = sum(fluxArray)

    #Plot flux as radius increases
    plt.clf()
    plt.plot(radArray, fluxArray, label=imageName)
    plt.legend()
    plt.savefig(imageName + "_Radial_Profile.png")
    plt.show()

    fluxFrac = []
    percentSum = 0
    for f in fluxArray:
        percentSum += f
        fluxFrac.append(percentSum / sumFlux)

    #Find the radius at 50% enclosed
    radius50 = 1.0
    for i in range(0, len(fluxFrac)):
        if (fluxFrac[i] < .50):
            radius50 += 1 / 10  #Radius 50% enclosed
    print("50 percent enclosed:", radius50)

    #Find the radius at 90% encolsed
    radius90 = 1.0
    for i in range(0, len(fluxFrac)):
        if (fluxFrac[i] < .90):
            radius90 += 1 / 10  #Radius 90% enclosed
    print("90 percent enclosed:", radius90)
    """
    #Gaussian Blur
    imgBlur = ndimage.gaussian_filter(newData, sigma=(2,2), order=0)
    plt.imshow(imgBlur)
    plt.savefig('Annuli_' + imageName + '.png', dpi=100)
    plt.subplots_adjust(right=2.0)
    plt.subplots_adjust(top=1.0)
    plt.show()
    """

    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    circle50 = plt.Circle((xAxis, yAxis),
                          radius=radius50,
                          color='m',
                          fill=False,
                          lw=2)
    circle90 = plt.Circle((xAxis, yAxis),
                          radius=radius90,
                          color='r',
                          fill=False,
                          lw=2)
    plt.imshow(newData, cmap='gray')
    ax.add_patch(circle50)  #50% enclosed
    ax.add_patch(circle90)  #90% enclosed
    #ax.text(left, top, galRedshift, horizontalalignment='left', verticalalignment='top', fontsize=12, color='red')
    #ax.text(left, bottom, hFlux, horizontalalignment='left', verticalalignment='bottom', fontsize=14, color='green')
    plt.savefig('Annuli_' + imageName + '.png', dpi=100)
    plt.show()
def do_aperture_photometry(filename):

    fwhm,filename=iraf_fwhm()

    xpix,ypix=source_list(filename)

    #ast=AstrometryNet()
    #ast.api_key= 'iqmqwvazpvolmjmn'


    data,header=fits.getdata(filename,header=True)
    exposure_time=header['EXPOSURE']

    sigma_clip = SigmaClip(sigma=3., maxiters=10) 
    bkg_estimator = MedianBackground() 
    bkg = Background2D(data, (10,10), filter_size=(3, 3),sigma_clip=sigma_clip, bkg_estimator=bkg_estimator)
    back=bkg.background # this is the background we need for the background subtraction.
    back2=np.median(bkg.background)


    mask = data == 0
    unit = u.electron / u.s


    xdf_image = CCDData(data, unit=unit, meta=header, mask=mask)
    norm_image = ImageNormalize(vmin=1e-4, vmax=5e-2, stretch=LogStretch(), clip=False)
    xdf_image_clipped = np.clip(xdf_image, 1e-4, None)

    mean, median, std = sigma_clipped_stats(xdf_image.data, sigma=3.0, maxiters=20, mask=xdf_image.mask)

    print('Finding the sources')

    #daofind = DAOStarFinder(fwhm=fwhm, threshold=5*std) # 3 sigma above the background.
    #sources = daofind(data - median)

    #sources_findpeaks = find_peaks(xdf_image.data, mask=xdf_image.mask, threshold=30.*std, box_size=30, centroid_func=centroid_2dg)

    #print('We have found:',len(sources),' sources')
    #print(sources)

    #print(sources['xcentroid'], sources['ycentroid'],sources['fwhm'])
    #positions=sources['xcentroid'], sources['ycentroid']
    positions=np.genfromtxt('co_ordinates_list_1.txt',unpack=True,usecols=(0,1))
    #print(positions)
    radii=[ fwhm,2*fwhm, 4*fwhm, 6*fwhm]

    #positions=(sources['xcentroid'], sources['ycentroid'])
    apertures = [CircularAperture(positions, r=r) for r in radii] 

    an_ap = CircularAnnulus(positions, r_in=8*fwhm, r_out=10*fwhm)
    #apers = [apertures, annulus_apertures]


    #bkg_sigma=mad_std(data)
    effective_gain=exposure_time
    error=calc_total_error(data,back,effective_gain)


    #error=0.1*data
    phot_table = aperture_photometry(data, apertures,error=error)
    phot_table2=aperture_photometry(data,an_ap)


    bkg_mean = phot_table2['aperture_sum'] / an_ap.area()
    bkg_sum = bkg_mean * an_ap.area()


    final_sum0=phot_table['aperture_sum_0']-bkg_sum
    final_sum1=phot_table['aperture_sum_1']-bkg_sum
    final_sum2=phot_table['aperture_sum_2']-bkg_sum
    final_sum3=phot_table['aperture_sum_3']-bkg_sum



    mag_0=-2.5*np.log10(final_sum0/exposure_time)+25
    mag_1=-2.5*np.log10(final_sum1/exposure_time)+25
    mag_2=-2.5*np.log10(final_sum2/exposure_time)+25
    mag_3=-2.5*np.log10(final_sum3/exposure_time)+25

    fig=plt.figure()
    plt.imshow(data,cmap='gray',origin='lower',vmin=50,vmax=400)
    colors=['red','green','yellow','blue']
    for i in range(len(apertures)):
        apertures[i].plot(color=colors[i], alpha=0.7) 
    
    an_ap.plot(color='green', alpha=0.7) 
    plt.show()

    for i in range (len(phot_table)):
        print(mag_0[i],mag_1[i],mag_2[i],mag_3[i])



    '''



    mag=-2.5*np.log10(final_sum/30)+25

    flux=final_sum
    flux_err=phot_table['aperture_sum_err_0']
    mag_err=1.09*flux_err/flux

    x=[phot.value for phot in phot_table['xcenter']]
    y=[phot.value for phot in phot_table['ycenter']]

    #with open('result.dat', 'w') as f:
    #with open('out.txt', 'w') as f:
    for i in range(len(x)):
        print(x[i],y[i],'\t',mag[i],mag_err[i])


    outfile=' '
    for i in range (len(phot_table)):
        outfile+=x[i]+ " "+ y[i]+" "+ mag[i]+" " +mag_err[i]
        outfile+='\n'

    out=open('result.txt','w')
    out.write(outfile,overwrite=True)
    out.close()

    '''

    '''
### Convert FWHM into a sigma ###
sigmaold = np.array([FWHM2sigma(fwhm, const) for fwhm in oldavgFWHM])
sigmabroad = sigmaold[aimind]

phot = {}
flux = np.zeros(8)
oldphot = {}
oldflux = np.zeros(8)

pixelr = (1.5 / 3600) / const
aperture = CircularAperture(centre, pixelr)

for n, sem in enumerate(semesters):
    ### Determine flux within 3 arcsec apertures ###
    phot[sem] = aperture_photometry(psf[sem], aperture)
    flux[n] = phot[sem]['aperture_sum'][0]
    oldphot[sem] = aperture_photometry(oldpsf[sem], aperture)
    oldflux[n] = oldphot[sem]['aperture_sum'][0]

plt.figure()
plt.plot(oldflux, 'bs')
plt.plot(flux, 'ro')
plt.ylabel('Flux within 3 arcsec aperture')
plt.figure()
ax = plt.subplot(111)
plt.plot(oldavgFWHM, 'bs')
plt.plot(avgFWHM, 'ro')
plt.ylabel('FWHM')
ax.invert_yaxis()
### testing the extra factor method ###
Example #48
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:
        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
            realmod = src.getUnitFluxModelPatch(tim)
            if realmod is None:
                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
        from tractor import PointSource
        from tractor.sersic import SersicGalaxy
        from legacypipe.survey import RexGalaxy

        realsrcs = []
        agnsrcs = []
        iagn = []
        for i, src in enumerate(cat):
            realsrcs.append(src)
            if isinstance(src, RexGalaxy):
                continue
            if isinstance(src, (ExpGalaxy, DevGalaxy, SersicGalaxy)):
                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, _) = 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.fracin = R.fitstats.fracin[:N].astype(np.float32)
        F.rchisq = R.fitstats.prochi2[:N].astype(np.float32)
        F.fracmasked = R.fitstats.promasked[:N].astype(np.float32)

        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)
            if len(iagn):
                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 -- this is using the Tractor wcs infrastructure,
        # so pixel positions are 0-indexed.
        apxy = np.vstack(
            [tim.wcs.positionToPixel(src.getPosition()) for src in cat])

        apertures = apertures_arcsec / tim.wcs.pixel_scale()

        # 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
Example #49
0
def flux(nddata, tbl, zeroPoint, gain, radius):
    """
    Derive the flux and the magnitude within circular aperture
    
    Parameters
    ----------
    nddata: numpy array
        Numpy array where is saved the data and the sky coordinates wcs.
    tbl: table
        Table where the first column is the id, the second the ra coordinate, the third
        is dec coordinate and the four the skycoordinate. 
    zeroPoint: float
        Zero point of your image
    gain: float
        The gain of your image
    radius: float 
        The radius of your circle in arcsec to derive the flux
    Return
    ------
    Table with id, skycoord, flux, flux error, magnitude, magnitude error       
    """

    # By convention, sextractor
    if gain == 0.:

        gain = 1000000000000000000000000000.

    result = tbl['id', 'skycoord']
    result['flux'] = float(np.size(tbl))
    result['flux_err'] = float(np.size(tbl))

    for i in range(np.size(tbl)):

        # Recover the position for each object
        position = tbl['skycoord'][i]

        if hdr['NAXIS1'] >= 50 and hdr['NAXIS2'] >= 50:

            # size of the background map
            sizeBkg = 50
            # cut the mosaic in stamp to the wcs coordinate of your objects
            cutout = Cutout2D(nddata.data,
                              position, (sizeBkg, sizeBkg),
                              wcs=nddata.wcs)

            # Recover new data and wcs of the stamp
            data = cutout.data
            wcs = cutout.wcs

        else:

            # size of the background map
            sizeBkg = min(hdr['NAXIS1'], hdr['NAXIS2'])

            # Keep data and wcs of the initial image
            data = nddata.data
            wcs = nddata.wcs

        #########################
        ####### Background ######
        #########################

        # Mask sources
        mask = make_source_mask(data, snr=1, npixels=3, dilate_size=3)

        # Derive the background and the rms image
        bkg = Background2D(
            data,
            int(sizeBkg / 10),
            filter_size=1,
            sigma_clip=None,
            bkg_estimator=SExtractorBackground(SigmaClip(sigma=2.5)),
            bkgrms_estimator=StdBackgroundRMS(SigmaClip(sigma=2.5)),
            exclude_percentile=60,
            mask=mask)

        ###########################
        ###### Aperture Flux ######
        ###########################

        nddataStamp = NDData(data=data - bkg.background, wcs=wcs)

        # Calculate the total error
        error = calc_total_error(cutout.data, bkg.background_rms, gain)

        # Define a cicularAperture in the wcs position of your objects
        apertures = SkyCircularAperture(position, r=radius * u.arcsec)

        # Derive the flux and error flux
        phot_table = aperture_photometry(nddataStamp, apertures, error=error)
        phot_table['aperture_sum'].info.format = '%.8g'
        phot_table['aperture_sum_err'].info.format = '%.8g'

        # Recover data
        result['flux'][i] = phot_table['aperture_sum'][0]
        result['flux_err'][i] = phot_table['aperture_sum_err'][0]

        ###########################
        ######## Magnitude ########
        ###########################

    # convert flux into magnitude
    result['mag'] = -2.5 * np.log10(result['flux']) + zeroPoint

    # convert flux error into magnitude error
    result['mag_err'] = 1.0857 * (result['flux_err'] / result['flux'])

    return result
Example #50
0
    # --- measure PSF profile

    if make_profile:

        Ndim = img_sub.shape[0]

        centre = (Ndim // 2, Ndim // 2)

        radii_pix = np.arange(1, 500., 1)
        radii_arcsec = radii_pix * (
            flare.observatories.filter_info[f]['pixel_scale'] / sampling)

        apertures = [CircularAperture(centre, r=r)
                     for r in radii_pix]  #r in pixels

        phot_table = aperture_photometry(img_sub, apertures)

        frac = np.array([
            phot_table['aperture_sum_{0}'.format(i)][0]
            for i, r in enumerate(radii_pix)
        ])

        for efrac in [0.5, 0.8]:
            print('EE(f={0}): {1:0.2f}"'.format(
                efrac, np.interp(efrac, frac, radii_arcsec)))

        for r in [0.35 / 2.]:
            print('EE(r<{0}): {1:0.2f}'.format(
                r, np.interp(r, radii_arcsec, frac)))

        ax_profile.plot(radii_arcsec, frac, label=f)
        # read in the images
        file = glob.glob(dir + 'J0905_final_' + collection[i] + '*sci.fits')
        hdu = fits.open(file[0])
        data[i], header[i] = hdu[0].data, hdu[0].header
        fnu[i] = header[i]['PHOTFNU']
        exp[i] = header[i]['EXPTIME']

        #define positions for photometry
        positions = [(xcen, ycen)]

        #do photometry on images
        #convert to proper units
        for j in range(0, len(radii)):
            aperture = CircularAperture(positions, radii[j])
            phot_table = aperture_photometry(data[i], aperture)
            flux[i, j] = phot_table['aperture_sum'][0] * (fnu[i] / exp[i])
            if j == 0:
                subflux[i, j] = flux[i, j]
            else:
                subflux[i, j] = flux[i, j] - flux[i, j - 1]

        #set up the plot
        ax = fig.add_subplot(1, 1, 1)
        cax = ax.scatter(
            -2.5 * np.log10(subflux[1] / subflux[2]),
            -2.5 * np.log10(subflux[0] / subflux[1]),
            c=radii,
            vmin=radii[0],
            vmax=radii[-1],
            cmap=cm.coolwarm,
Example #52
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
# Random aperture positions
positions = [
    np.random.randint(0 + int(np.ceil(r)), cutoutwidth - int(np.ceil(r)), N),
    np.random.randint(0 + int(np.ceil(r)), cutoutwidth - int(np.ceil(r)), N)
]

# Creating apertures
aperture = CircularAperture(positions, r=r)

aperture.plot(color='red', lw=1., alpha=0.5)

plt.show()

# Measuring photometry in the random apertures
phot_table = aperture_photometry(img.bkg / img.nJy_to_es,
                                 aperture,
                                 method='subpixel')
phot_table['aperture_sum'].info.format = '%.8g'

print('')
print('Printout of random aperture values (nJy)')

#print(phot_table)

aperture_sums = np.asarray(phot_table['aperture_sum'])

print(
    f'mean aperture flux = {np.mean(aperture_sums):.2f}, std = {np.std(aperture_sums):.2f}'
)

# plotting a normalised histogram of the aperture fluxes
Example #54
0
    y_2 = 4090

for image_name in files[0:1]:
    image = fits.getdata(star + "/" + image_name, ext=0)
    data = image[x_1:x_2, y_1:y_2]
    tbl = find_peaks(data, 300, box_size=50)
    pe = np.array(tbl['peak_value'])
    pe_x = np.array(tbl['x_peak'])
    pe_y = np.array(tbl['y_peak'])
    peaks = np.array((pe_x, pe_y, pe)).T
    peaks = peaks.tolist()
    peaks = sorted(peaks, key=lambda t: t[2], reverse=True)
    positions = (peaks[0][0], peaks[0][1]
                 )  #[peaks[0][0], peaks[0][1]], [peaks[1][0], peaks[1][1]]
    apertures = lambda r: CircularAperture(positions, r=r)
    phot_table = lambda r: aperture_photometry(data, apertures(r))
    rad = [0.0]
    numcounts = [0.0]
    noise = 10000
    i = 0
    while (noise >= 5000):
        rad.append(rad[i] + 1.0)
        numcounts.append(phot_table(rad[i + 1])['aperture_sum'])
        noise = numcounts[i + 1] - numcounts[i]
        i += 1
    rad = np.array(rad)
    numcounts = np.array(numcounts)
    radius = np.array([
        1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0,
        14.0, 15.0, 16.0
    ])
Example #55
0
        yloc = int(input("Yloc?"))
    AP2 = input(
        "Do you want to enter the annulus aperture values? (Y) or (N) ")
    if AP2 == 'Y':
        r_in = float(input("Inner radius factor? "))
        r_out = float(input("Outter radius factor? "))
    else:
        r_in = r * 3
        r_out = r * 4.5

    positions = (xloc, yloc)
    apertures = CircularAperture(positions, r)
    annulus_apertures = CircularAnnulus(positions, r_in, r_out)
    apers = [apertures, annulus_apertures]

    phot_table = aperture_photometry(image, apers)
    print("BB Phot table 2018 ")
    print(phot_table)

    print()
    print("Apertures Area is / Annulus Area is", apertures.area(),
          annulus_apertures.area())
    bkg_mean = phot_table['aperture_sum_1'] / annulus_apertures.area()
    bkg_sum = bkg_mean * apertures.area()

    final_sum = phot_table['aperture_sum_0'] - bkg_sum
    phot_table['Aperture_final'] = final_sum
    print("Final sum is ", final_sum, phot_table[0][5])

    print(phot_table)
Example #56
0
def compare_rate_images(subarray_file,
                        fullframe_file,
                        out_dir='./',
                        subarray_threshold=100,
                        fullframe_threshold=100,
                        max_separation=3.,
                        aperture_radius=5,
                        bkgd_in_radius=6,
                        bkgd_out_radius=8,
                        subarray_rate_file=None,
                        fullframe_rate_file=None):
    """MAIN FUNCTiON FOR COMPARING SOURCE RATES IN RATE FILES

    Parameters
    ----------
    subarray_file : str
        Fits file containing the subarray data to be compared

    fullframe_file : sr
        Fits file containing the full frame data to be compared

    out_dir : str
        Output directory into which products are saved

    subarray_threshold : float
        Number of sigma above the background needed to identify a source

    fullframe_threshold : float
        Number of sigma above the background needed to identify a source

    max_separation : float
        Maximum allowed separation between sources, in pixels, between the subarray
        and full frame data in order for a source to be considered a match.

    aperture_radius : int
        Aperture radius (in pixels) to use for photometry

    bkgd_in_radius : int
        Inner radius (in pixels) to use for photometry background subtraction

    bkgd_out_radius : int
        Outer radius (in pixels) to use for photometry background subtraction

    Returns
    -------
    sub_sources : astropy.table.Table
        Table of source positions, equivalent full frame positions, and photometry
        results from the data
    """
    # Read in data
    subarray = datamodels.open(subarray_file)
    fullframe = datamodels.open(fullframe_file)

    # Quick test to see if using the rate files rather than the cal files
    # makes any difference in the LW discrepancy between fullframe and subarray data
    #if subarray_rate_file is not None:
    #    subarray_rate = datamodels.open(subarray_rate_file)
    #else:
    #    subarray_rate = subarray

    #if fullframe_rate_file is not None:
    #    fullframe_rate = datamodels.open(fullframe_rate_file)
    #else:
    #    fullframe_rate = fullframe

    # Define coord transform functions
    sub_xy_to_radec = subarray.meta.wcs.get_transform('detector', 'world')
    ff_radec_to_xy = fullframe.meta.wcs.get_transform('world', 'detector')
    ff_xy_to_radec = fullframe.meta.wcs.get_transform('detector', 'world')

    # Check to be sure the two images overlap
    ff_min_x = 0
    ff_min_y = 0
    ff_max_x = fullframe.meta.subarray.xsize - 1
    ff_max_y = fullframe.meta.subarray.ysize - 1
    cornerx = [
        0, 0, subarray.meta.subarray.xsize, subarray.meta.subarray.xsize
    ]
    cornery = [
        0, subarray.meta.subarray.ysize, subarray.meta.subarray.ysize, 0
    ]
    cornerra, cornerdec = sub_xy_to_radec(cornerx, cornery)
    ffcornerx, ffcornery = ff_radec_to_xy(cornerra, cornerdec)
    overlap = False
    for fcx, fcy in zip(ffcornerx, ffcornery):
        if ((fcx > ff_min_x) & (fcx < ff_max_x) & (fcy > ff_min_y)
                and (fcy < ff_max_y)):
            overlap = True
    if not overlap:
        print(
            "Suabrray file and full frame file do not overlap. Quitting.\n\n")
        return 0

    # Locate sources
    sub_fwhm = get_fwhm(subarray.meta.instrument.filter)
    sub_source_image = os.path.join(
        out_dir, '{}_subarray_source_map_countrate_compare.png'.format(
            os.path.basename(subarray_file)))
    #sub_sources = find_sources(subarray.data, threshold=subarray_threshold, fwhm=sub_fwhm, show_sources=True, save_sources=True, plot_name=sub_source_image)
    sub_sources = find_sources(subarray_rate.data,
                               threshold=subarray_threshold,
                               fwhm=sub_fwhm,
                               show_sources=True,
                               save_sources=True,
                               plot_name=sub_source_image)

    ff_fwhm = get_fwhm(fullframe.meta.instrument.filter)
    full_source_image = os.path.join(
        out_dir, '{}_fullframe_map_datamodels.png'.format(
            os.path.basename(fullframe_file)))
    #ff_sources = find_sources(fullframe.data, threshold=fullframe_threshold, fwhm=ff_fwhm, show_sources=True, save_sources=True, plot_name=full_source_image)
    ff_sources = find_sources(fullframe_rate.data,
                              threshold=fullframe_threshold,
                              fwhm=ff_fwhm,
                              show_sources=True,
                              save_sources=True,
                              plot_name=full_source_image)

    if sub_sources is None:
        print("No subarray sources to compare.")
        return 0

    if ff_sources is None:
        print("No full frame sources to compare")
        return 0

    # Put subarray sources in full frame detector coordinates
    # 1. Transform to RA, Dec
    # 2. Use WCS of full frame file to put coordinates in full frame coords

    # Transform subarray x,y -> RA, Dec -> full frame x, y
    ra, dec = sub_xy_to_radec(sub_sources['xcentroid'],
                              sub_sources['ycentroid'])
    ffx, ffy = ff_radec_to_xy(ra, dec)

    # Add RA, Dec and fullframe equivalent x,y to the subarray source catalog
    sub_sources['RA'] = ra
    sub_sources['Dec'] = dec
    sub_sources['fullframe_x'] = ffx
    sub_sources['fullframe_y'] = ffy

    # Find RA, Dec of sources in full frame catalog
    ffra, ffdec = ff_xy_to_radec(ff_sources['xcentroid'],
                                 ff_sources['ycentroid'])
    ff_sources['RA'] = ffra
    ff_sources['Dec'] = ffdec

    # Match catalogs
    ff_cat = SkyCoord(ra=ffra * u.degree, dec=ffdec * u.degree)
    sub_cat = SkyCoord(ra=ra * u.degree, dec=dec * u.degree)
    idx, d2d, d3d = sub_cat.match_to_catalog_3d(ff_cat)

    # Remove bad matches
    pscale = subarray.meta.wcsinfo.cdelt1
    if pscale is None:
        pscale = np.abs(subarray.meta.wcsinfo.cd1_1)
    pix_scale = pscale * 3600.
    max_sep = max_separation * pix_scale * u.arcsec  # Matches must be within a pixel
    sep_constraint = d2d < max_sep
    sub_catalog_matches = sub_sources[sep_constraint]
    ff_catalog_matches = ff_sources[idx[sep_constraint]]
    num_matched = len(ff_catalog_matches)
    print('Found {} matching sources in the two input files.'.format(
        num_matched))
    if num_matched == 0:
        print("No matching sources found. Quitting.\n\n\n")
        return 0, 0

    # What if we just do photometry on the sources in the subarray and their
    # calculated positions in the full frame?
    sub_pos = []
    ff_pos = []
    good_indexes = []
    non_zero_sub_dq = []
    non_zero_full_dq = []
    for i, line in enumerate(sub_catalog_matches):
        if ((line['fullframe_x'] > 5) & (line['fullframe_x'] < 2039) & \
            (line['fullframe_y'] > 5) & (line['fullframe_y'] < 2039)):
            sub_pos.append((line['xcentroid'], line['ycentroid']))
            #ff_pos.append((line['fullframe_x'], line['fullframe_y']))
            ff_pos.append((ff_catalog_matches[i]['xcentroid'],
                           ff_catalog_matches[i]['ycentroid']))
            good_indexes.append(i)

            # Make a note if there are any non-zero DQ flags within the apertures
            # During development, found some cases with NO_LIN_CORR and NO_FLAT_FIELD
            # that were screwing up photometry
            yc_sub = int(np.round(line['ycentroid']))
            xc_sub = int(np.round(line['xcentroid']))
            sub_dq = subarray.dq[yc_sub - 3:yc_sub + 4, xc_sub - 3:xc_sub + 4]
            if np.sum(sub_dq) > 0:
                non_zero_sub_dq.append(True)
            else:
                non_zero_sub_dq.append(False)

            yc = int(np.round(line['fullframe_x']))
            xc = int(np.round(line['fullframe_y']))
            sub_dq = fullframe.dq[yc - 1:yc + 2, xc - 1:xc + 2]
            if np.sum(sub_dq) > 0:
                non_zero_full_dq.append(True)
            else:
                non_zero_full_dq.append(False)

    print('Performing photometry on a total of {} sources.'.format(
        len(sub_pos)))

    # Now perform aperture photometry on the sources in the subarray
    # and full frame data. Keep the aperture small since the difference
    # in exposure time and SNR will be large
    #sub_pos = [(m['xcentroid'], m['ycentroid']) for m in sub_catalog_matches]
    #ff_pos = [(m['xcentroid'], m['ycentroid']) for m in ff_catalog_matches]

    sub_aperture = CircularAperture(sub_pos, r=aperture_radius)
    ff_aperture = CircularAperture(ff_pos, r=aperture_radius)
    sub_annulus = CircularAnnulus(sub_pos,
                                  r_in=bkgd_in_radius,
                                  r_out=bkgd_out_radius)
    full_annulus = CircularAnnulus(ff_pos,
                                   r_in=bkgd_in_radius,
                                   r_out=bkgd_out_radius)

    # Photometry
    #sub_phot_table = aperture_photometry(subarray.data, sub_aperture)
    #ff_phot_table = aperture_photometry(fullframe.data, ff_aperture)
    sub_phot_table = aperture_photometry(subarray_rate.data, sub_aperture)
    ff_phot_table = aperture_photometry(fullframe_rate.data, ff_aperture)

    sub_annulus_masks = sub_annulus.to_mask(method='center')
    full_annulus_masks = full_annulus.to_mask(method='center')

    #sub_bkg_median = median_background(sub_annulus_masks, subarray.data)
    sub_bkg_median = median_background(sub_annulus_masks, subarray_rate.data)

    sub_phot_table['annulus_median'] = sub_bkg_median
    sub_phot_table['aper_bkg'] = sub_bkg_median * sub_aperture.area
    sub_phot_table['aper_sum_bkgsub'] = sub_phot_table[
        'aperture_sum'] - sub_phot_table['aper_bkg']

    #full_bkg_median = median_background(full_annulus_masks, fullframe.data)
    full_bkg_median = median_background(full_annulus_masks,
                                        fullframe_rate.data)
    ff_phot_table['annulus_median'] = full_bkg_median
    ff_phot_table['aper_bkg'] = full_bkg_median * ff_aperture.area
    ff_phot_table['aper_sum_bkgsub'] = ff_phot_table[
        'aperture_sum'] - ff_phot_table['aper_bkg']

    # Compare photometry results
    delta_phot = ff_phot_table['aper_sum_bkgsub'].data - sub_phot_table[
        'aper_sum_bkgsub'].data
    delta_phot_perc = delta_phot / ff_phot_table['aper_sum_bkgsub'].data * 100.
    sub_phot_table['delta_from_fullframe'] = delta_phot
    sub_phot_table['delta_from_fullframe_percent'] = delta_phot_perc

    # Keep track of whether there are bad pixels in the apertures
    #sub_dq = np.zeros(len(sub_sources), dtype=bool)
    #sub_dq[good_indexes] = non_zero_sub_dq
    #sub_sources['sub_dq'] = sub_dq
    #full_dq = np.zeros(len(sub_sources), dtype=bool)
    #full_dq[good_indexes] = non_zero_full_dq
    #sub_sources['full_dq'] = full_dq

    sub_dq = np.zeros(len(sub_catalog_matches), dtype=bool)
    sub_dq[good_indexes] = non_zero_sub_dq
    sub_catalog_matches['sub_dq'] = sub_dq
    full_dq = np.zeros(len(sub_catalog_matches), dtype=bool)
    full_dq[good_indexes] = non_zero_full_dq
    sub_catalog_matches['full_dq'] = full_dq

    # Add photometry to the table
    #sub_phot_data = np.zeros(len(sub_sources))
    #sub_phot_data[good_indexes] = sub_phot_table['aper_sum_bkgsub'].data
    #ff_phot_data = np.zeros(len(sub_sources))
    #ff_phot_data[good_indexes] = ff_phot_table['aper_sum_bkgsub'].data
    #delta_phot_col = np.zeros(len(sub_sources))
    #delta_phot_col[good_indexes] = delta_phot
    #delta_phot_perc_col = np.zeros(len(sub_sources))
    #delta_phot_perc_col[good_indexes] = delta_phot_perc

    sub_phot_data = np.zeros(len(sub_catalog_matches))
    sub_phot_data[good_indexes] = sub_phot_table['aper_sum_bkgsub'].data
    ff_phot_data = np.zeros(len(sub_catalog_matches))
    ff_phot_data[good_indexes] = ff_phot_table['aper_sum_bkgsub'].data
    delta_phot_col = np.zeros(len(sub_catalog_matches))
    delta_phot_col[good_indexes] = delta_phot
    delta_phot_perc_col = np.zeros(len(sub_catalog_matches))
    delta_phot_perc_col[good_indexes] = delta_phot_perc

    #sub_sources['sub_phot'] = sub_phot_data
    #sub_sources['ff_phot'] = ff_phot_data
    #sub_sources['d_phot'] = delta_phot_col
    #sub_sources['d_phot_p'] = delta_phot_perc_col

    #sub_sources['xcentroid'].info.format = '7.3f'
    #sub_sources['ycentroid'].info.format = '7.3f'
    #sub_sources['fullframe_x'].info.format = '7.3f'
    #sub_sources['fullframe_y'].info.format = '7.3f'
    #sub_sources['sub_phot'].info.format = '7.3f'
    #sub_sources['ff_phot'].info.format = '7.3f'
    #sub_sources['d_phot'].info.format = '7.3f'
    #sub_sources['d_phot_p'].info.format = '7.3f'
    #print(sub_sources['xcentroid', 'ycentroid', 'fullframe_x', 'fullframe_y', 'sub_phot', 'ff_phot', 'd_phot_p', 'sub_dq', 'full_dq'])

    sub_catalog_matches['sub_phot'] = sub_phot_data
    sub_catalog_matches['ff_phot'] = ff_phot_data
    sub_catalog_matches['d_phot'] = delta_phot_col
    sub_catalog_matches['d_phot_p'] = delta_phot_perc_col

    sub_catalog_matches['xcentroid'].info.format = '7.3f'
    sub_catalog_matches['ycentroid'].info.format = '7.3f'
    sub_catalog_matches['fullframe_x'].info.format = '7.3f'
    sub_catalog_matches['fullframe_y'].info.format = '7.3f'
    sub_catalog_matches['sub_phot'].info.format = '7.3f'
    sub_catalog_matches['ff_phot'].info.format = '7.3f'
    sub_catalog_matches['d_phot'].info.format = '7.3f'
    sub_catalog_matches['d_phot_p'].info.format = '7.3f'

    final_sub_cat = sub_catalog_matches[good_indexes]

    print(final_sub_cat['xcentroid', 'ycentroid', 'fullframe_x', 'fullframe_y',
                        'sub_phot', 'ff_phot', 'd_phot_p', 'sub_dq',
                        'full_dq'])
    print('')

    # Save the complete table
    sub_base = os.path.basename(subarray_file).replace('.fits', '')
    full_base = os.path.basename(fullframe_file).replace('.fits', '')
    table_name = os.path.join(
        out_dir, 'photometry_comparison_{}_{}.txt'.format(sub_base, full_base))
    ascii.write(final_sub_cat, table_name, overwrite=True)
    print('Photometry results saved to: {}'.format(table_name))

    # Try filtering out sources where there is a pixel flagged in the full
    # frame or subarray DQ mask at the source location
    clean = []
    for row in final_sub_cat:
        clean.append(row['sub_dq'] == False and row['full_dq'] == False)
    if np.sum(clean) > 0:
        clean_table = final_sub_cat[clean]
        print('Excluding sources with a pixel flagged in the DQ array:')
        med_clean_diff = np.around(np.median(clean_table['d_phot_p']), 1)
        print(
            'Median photometry difference between subarray and full frame sources is: {}%\n\n\n'
            .format(med_clean_diff))
    else:
        clean_table = None
        print('No sources without a flagged pixel in the DQ arrays.')
    return final_sub_cat, clean_table
Example #57
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
Example #58
0
def fit_ellipse_for_source(
    friendid=None,
    detectid=None,
    coords=None,
    shotid=None,
    subcont=True,
    convolve_image=False,
    pixscale=pixscale,
    imsize=imsize,
    wave_range=None,
):

    if detectid is not None:

        global deth5

        detectid_obj = detectid

        if detectid_obj <= 2190000000:
            det_info = deth5.root.Detections.read_where("detectid == detectid_obj")[0]
            linewidth = det_info["linewidth"]
            wave_obj = det_info["wave"]
            redshift = wave_obj / (1216) - 1
        else:
            det_info = conth5.root.Detections.read_where("detectid == detectid_obj")[0]
            redshift = 0
            wave_obj = 4500

        coords_obj = SkyCoord(det_info["ra"], det_info["dec"], unit="deg")

        shotid_obj = det_info["shotid"]
        fwhm = surveyh5.root.Survey.read_where("shotid == shotid_obj")["fwhm_virus"][0]
        amp = det_info["multiframe"]

        if wave_range is not None:
            wave_range_obj = wave_range
        else:
            if detectid_obj <= 2190000000:
                wave_range_obj = [wave_obj - 2 * linewidth, wave_obj + 2 * linewidth]
            else:
                wave_range_obj = [4100, 4200]

        if coords is not None:
            coords_obj = coords

        if shotid is not None:
            shotid_obj = shotid
            fwhm = surveyh5.root.Survey.read_where("shotid == shotid_obj")[
                "fwhm_virus"
            ][0]

        try:
            hdu = make_narrowband_image(
                coords=coords_obj,
                shotid=shotid_obj,
                wave_range=wave_range_obj,
                imsize=imsize * u.arcsec,
                pixscale=pixscale * u.arcsec,
                subcont=subcont,
                convolve_image=convolve_image,
                include_error=True,
            )

        except:
            print("Could not make narrowband image for {}".format(detectid))
            return np.nan, np.nan

    elif friendid is not None:

        global friend_cat

        sel = friend_cat["friendid"] == friendid
        group = friend_cat[sel]
        coords_obj = SkyCoord(ra=group["icx"][0] * u.deg, dec=group["icy"][0] * u.deg)
        wave_obj = group["icz"][0]
        redshift = wave_obj / (1216) - 1
        linewidth = group["linewidth"][0]
        shotid_obj = group["shotid"][0]
        fwhm = group["fwhm"][0]
        amp = group["multiframe"][0]

        if wave_range is not None:
            wave_range_obj = wave_range
        else:
            wave_range_obj = [wave_obj - 2 * linewidth, wave_obj + 2 * linewidth]

        if shotid is not None:
            shotid_obj = shotid
            fwhm = surveyh5.root.Survey.read_where("shotid == shotid_obj")[
                "fwhm_virus"
            ][0]

        try:
            hdu = make_narrowband_image(
                coords=coords_obj,
                shotid=shotid_obj,
                wave_range=wave_range_obj,
                imsize=imsize * u.arcsec,
                pixscale=pixscale * u.arcsec,
                subcont=subcont,
                convolve_image=convolve_image,
                include_error=True,
            )
        except:
            print("Could not make narrowband image for {}".format(friendid))
            return None

    elif coords is not None:
        coords_obj = coords

        if wave_range is not None:
            wave_range_obj = wave_range
        else:
            print(
                "You need to supply wave_range=[wave_start, wave_end] for collapsed image"
            )

        if shotid is not None:
            shotid_obj = shotid
            fwhm = surveyh5.root.Survey.read_where("shotid == shotid_obj")[
                "fwhm_virus"
            ][0]
        else:
            print("Enter the shotid to use (eg. 20200123003)")

        hdu = make_narrowband_image(
            coords=coords_obj,
            shotid=shotid_obj,
            wave_range=wave_range_obj,
            imsize=imsize * u.arcsec,
            pixscale=pixscale * u.arcsec,
            subcont=subcont,
            convolve_image=convolve_image,
            include_error=True,
        )
    else:
        print("You must provide a detectid, friendid or coords/wave_range/shotid")
        return np.nan, np.nan

    w = wcs.WCS(hdu[0].header)

    if friendid is not None:

        sel_friend_group = friend_cat["friendid"] == friendid
        group = friend_cat[sel_friend_group]
        eps = 1 - group["a2"][0] / group["b2"][0]
        pa = group["pa"][0] * np.pi / 180.0 - 90
        sma = group["a"][0] * 3600 / pixscale

        coords = SkyCoord(ra=group["icx"][0] * u.deg, dec=group["icy"][0] * u.deg)
        wave_obj = group["icz"][0]
        redshift = wave_obj / (1216) - 1
        linewidth = np.nanmedian(group["linewidth"])
        shotid_obj = group["shotid"][0]
        fwhm = group["fwhm"][0]

        geometry = EllipseGeometry(
            x0=w.wcs.crpix[0], y0=w.wcs.crpix[0], sma=sma, eps=eps, pa=pa
        )
    else:
        geometry = EllipseGeometry(
            x0=w.wcs.crpix[0], y0=w.wcs.crpix[0], sma=20, eps=0.2, pa=20.0
        )

    geometry = EllipseGeometry(
        x0=w.wcs.crpix[0], y0=w.wcs.crpix[0], sma=20, eps=0.2, pa=20.0
    )
    # geometry.find_center(hdu.data)
    # aper = EllipticalAperture((geometry.x0, geometry.y0), geometry.sma,
    #                          geometry.sma*(1 - geometry.eps), geometry.pa)

    # plt.imshow(hdu.data, origin='lower')
    # aper.plot(color='white')

    ellipse = Ellipse(hdu[0].data)
    isolist = ellipse.fit_image()
    iso_tab = isolist.to_table()

    if len(iso_tab) == 0:
        geometry.find_center(hdu[0].data, verbose=False, threshold=0.5)
        ellipse = Ellipse(hdu[0].data, geometry)
        isolist = ellipse.fit_image()
        iso_tab = isolist.to_table()

    if len(iso_tab) == 0:
        return np.nan, np.nan, np.nan

        try:
            # compute iso's manually in steps of 3 pixels
            ellipse = Ellipse(hdu[0].data)  # reset ellipse
            iso_list = []
            for sma in np.arange(1, 60, 2):
                iso = ellipse.fit_isophote(sma)
                if np.isnan(iso.intens):
                    # print('break at {}'.format(sma))
                    break
                else:
                    iso_list.append(iso)
            isolist = IsophoteList(iso_list)
            iso_tab = isolist.to_table()
        except:
            return np.nan, np.nan, np.nan

    try:
        model_image = build_ellipse_model(hdu[0].data.shape, isolist)
        residual = hdu[0].data - model_image
    except:
        return np.nan, np.nan, np.nan

    sma = iso_tab["sma"] * pixscale
    const_arcsec_to_kpc = cosmo.kpc_proper_per_arcmin(redshift).value / 60.0

    def arcsec_to_kpc(sma):
        dist = const_arcsec_to_kpc * sma
        return dist

    def kpc_to_arcsec(dist):
        sma = dist / const_arcsec_to_kpc
        return sma

    dist_kpc = (
        sma * u.arcsec.to(u.arcmin) * u.arcmin * cosmo.kpc_proper_per_arcmin(redshift)
    )
    dist_arcsec = kpc_to_arcsec(dist_kpc)

    # print(shotid_obj, fwhm)
    # s_exp1d = models.Exponential1D(amplitude=0.2, tau=-50)

    alpha = 3.5
    s_moffat = models.Moffat1D(
        amplitude=1,
        gamma=(0.5 * fwhm) / np.sqrt(2 ** (1.0 / alpha) - 1.0),
        x_0=0.0,
        alpha=alpha,
        fixed={"amplitude": False, "x_0": True, "gamma": True, "alpha": True},
    )

    s_init = models.Exponential1D(amplitude=0.2, tau=-50)

    fit = fitting.LevMarLSQFitter()
    s_r = fit(s_init, dist_kpc, iso_tab["intens"])

    # Fitting can be done using the uncertainties as weights.
    # To get the standard weighting of 1/unc^2 for the case of
    # Gaussian errors, the weights to pass to the fitting are 1/unc.
    # fitted_line = fit(line_init, x, y, weights=1.0/yunc)

    # s_r = fit(s_init, dist_kpc, iso_tab['intens'])#, weights=iso_tab['intens']/iso_tab['intens_err'] )

    print(s_r)
    try:
        r_n = -1.0 * s_r.tau  # _0 #* const_arcsec_to_kpc
    except:
        r_n = np.nan  # r_n = -1. * s_r.tau_0
    try:
        sel_iso = np.where(dist_kpc >= 2 * r_n)[0][0]
    except:
        sel_iso = -1

    aper = EllipticalAperture(
        (isolist.x0[sel_iso], isolist.y0[sel_iso]),
        isolist.sma[sel_iso],
        isolist.sma[sel_iso] * (1 - isolist.eps[sel_iso]),
        isolist.pa[sel_iso],
    )

    phottable = aperture_photometry(hdu[0].data, aper, error=hdu[1].data)
    flux = phottable["aperture_sum"][0] * 10 ** -17 * u.erg / (u.cm ** 2 * u.s)
    flux_err = phottable["aperture_sum_err"][0] * 10 ** -17 * u.erg / (u.cm ** 2 * u.s)

    lum_dist = cosmo.luminosity_distance(redshift).to(u.cm)
    lum = flux * 4.0 * np.pi * lum_dist ** 2
    lum_err = flux_err * 4.0 * np.pi * lum_dist ** 2

    if detectid:
        name = detectid
    elif friendid:
        name = friendid

    # Get Image data from Elixer
    catlib = catalogs.CatalogLibrary()
    try:
        cutout = catlib.get_cutouts(
            position=coords_obj,
            side=imsize,
            aperture=None,
            dynamic=False,
            filter=["r", "g", "f606W"],
            first=True,
            allow_bad_image=False,
            allow_web=True,
        )[0]
    except:
        print("Could not get imaging for " + str(name))

    zscale = ZScaleInterval(contrast=0.5, krej=1.5)
    vmin, vmax = zscale.get_limits(values=hdu[0].data)

    fig = plt.figure(figsize=(20, 12))
    fig.suptitle(
        "{}  ra={:3.2f}, dec={:3.2f}, wave={:5.2f}, z={:3.2f}, mf={}".format(
            name, coords_obj.ra.value, coords_obj.dec.value, wave_obj, redshift, amp
        ),
        fontsize=22,
    )

    ax1 = fig.add_subplot(231, projection=w)
    plt.imshow(hdu[0].data, vmin=vmin, vmax=vmax)
    plt.xlabel("RA")
    plt.ylabel("Dec")
    plt.colorbar()
    plt.title("Image summed across 4*linewidth")

    ax2 = fig.add_subplot(232, projection=w)
    plt.imshow(model_image, vmin=vmin, vmax=vmax)
    plt.xlabel("RA")
    plt.ylabel("Dec")
    plt.colorbar()
    plt.title("model")

    ax3 = fig.add_subplot(233, projection=w)
    plt.imshow(residual, vmin=vmin, vmax=vmax)
    plt.xlabel("RA")
    plt.ylabel("Dec")
    plt.colorbar()
    plt.title("residuals (image-model)")
    # fig = plt.figure(figsize=(10,5))

    im_zscale = ZScaleInterval(contrast=0.5, krej=2.5)
    im_vmin, im_vmax = im_zscale.get_limits(values=cutout["cutout"].data)

    ax4 = fig.add_subplot(234, projection=cutout["cutout"].wcs)

    plt.imshow(
        cutout["cutout"].data,
        vmin=im_vmin,
        vmax=im_vmax,
        origin="lower",
        cmap=plt.get_cmap("gray"),
        interpolation="none",
    )

    plt.text(
        0.8,
        0.9,
        cutout["instrument"] + cutout["filter"],
        transform=ax4.transAxes,
        fontsize=20,
        color="w",
    )
    plt.contour(hdu[0].data, transform=ax4.get_transform(w))
    plt.xlabel("RA")
    plt.ylabel("Dec")
    aper.plot(
        color="white", linestyle="dashed", linewidth=2, transform=ax4.get_transform(w)
    )

    ax5 = fig.add_subplot(235)
    plt.errorbar(
        dist_kpc.value,
        iso_tab["intens"],
        yerr=iso_tab["intens_err"] * iso_tab["intens"],
        linestyle="none",
        marker="o",
        label="Lya SB profile",
    )

    plt.plot(dist_kpc, s_r(dist_kpc), color="r", label="Lya exp SB model", linewidth=2)

    plt.xlabel("Semi-major axis (kpc)")
    # plt.xlabel('Semi-major axis (arcsec)')
    plt.ylabel("Flux ({})".format(10 ** -17 * (u.erg / (u.s * u.cm ** 2))))
    plt.text(0.4, 0.7, "r_n={:3.2f}".format(r_n), transform=ax5.transAxes, fontsize=16)
    plt.text(
        0.4, 0.6, "L_lya={:3.2e}".format(lum), transform=ax5.transAxes, fontsize=16
    )
    secax = ax5.secondary_xaxis("top", functions=(kpc_to_arcsec, kpc_to_arcsec))
    secax.set_xlabel("Semi-major axis (arcsec)")
    # secax.set_xlabel('Semi-major axis (kpc)')
    plt.xlim(0, 100)

    # plt.plot(sma, s_r(sma), label='moffat psf')

    # plt.plot(dist_kpc.value, s1(kpc_to_arcsec(dist_kpc.value)),
    #        linestyle='dashed', linewidth=2,
    #         color='green', label='PSF seeing:{:3.2f}'.format(fwhm))

    # These two are the exact same
    # s1 = models.Moffat1D()
    # s1.amplitude = iso_tab['intens'][0]
    # alpha=3.5
    # s1.gamma = 0.5*(fwhm*const_arcsec_to_kpc)/ np.sqrt(2 ** (1.0 / alpha) - 1.0)
    # s1.alpha = alpha
    # plt.plot(r_1d, moffat_1d, color='orange')

    #    plt.plot(dist_kpc.value, (s1(dist_kpc.value)),
    #            linestyle='dashed', linewidth=2,
    #             color='blue', label='PSF seeing:{:3.2f}'.format(fwhm))

    E = Extract()
    E.load_shot(shotid_obj)
    moffat_psf = E.moffat_psf(seeing=fwhm, boxsize=imsize, scale=pixscale)
    moffat_shape = np.shape(moffat_psf)
    xcen = int(moffat_shape[1] / 2)
    ycen = int(moffat_shape[2] / 2)
    moffat_1d = (
        moffat_psf[0, xcen:-1, ycen] / moffat_psf[0, xcen, ycen] * iso_tab["intens"][0]
    )
    r_1d = moffat_psf[1, xcen:-1, ycen]
    E.close()

    plt.plot(
        arcsec_to_kpc(pixscale * np.arange(80)),
        iso_tab["intens"][0] * (moffat_psf[0, 80:-1, 80] / moffat_psf[0, 80, 80]),
        linestyle="dashed",
        color="green",
        label="PSF seeing:{:3.2f}".format(fwhm),
    )
    plt.legend()

    if friendid is not None:
        ax6 = fig.add_subplot(236, projection=cutout["cutout"].wcs)
        plot_friends(friendid, friend_cat, cutout, ax=ax6, label=False)
    plt.savefig("fit2d_{}.png".format(name))

    # filename = 'param_{}.txt'.format(name)
    # np.savetxt(filename, (r_n.value, lum.value))

    return r_n, lum, lum_err
Example #59
0
            world = np.array([[308.15274048, 46.58061218]])
            refpix = w.wcs_world2pix(world, 1)

            positions = [(targetpix[0, 0], targetpix[0, 1]),
                         (refpix[0, 0], refpix[0, 1])]

            aperture = CircularAperture(positions, r=r_source)
            annulus = CircularAnnulus(positions, r_in, r_out)

            # define the apertures

            apertures = CircularAperture(positions, r=7)
            annulus_apertures = CircularAnnulus(positions, r_in=10, r_out=13)

            # call aperture functions for aperture and annulus
            rawflux_table = aperture_photometry(data, apertures)
            bkgflux_table = aperture_photometry(data, annulus_apertures)

            # hstack just combines two arrays
            phot_table = hstack([rawflux_table, bkgflux_table],
                                table_names=['raw', 'bkg'])

            print(
                "================================================================================"
            )
            print(phot_table)
            print(
                "================================================================================"
            )

            #store the flux values from the phot_table
Example #60
0
def FitCircularAperture(
    hdu=None,
    coords=None,
    radius=1.5 * u.arcsec,
    annulus=[5, 7] * u.arcsec,
    plot=False,
    plottitle=None,
):
    """
    Fit a circular aperture with either an HDU object or and
    """

    im = hdu[0].data
    error = hdu[1].data
    w = wcs.WCS(hdu[0].header)

    # create mask (set True for where you want to mask)
    im_mask = im == 0

    # define circular aperture and annulus aperture for background subtraction
    aper = SkyCircularAperture(coords, r=radius)
    aper_annulus = SkyCircularAnnulus(coords, annulus[0], annulus[1])

    mask = aper_annulus.to_pixel(w).to_mask(method="center").data
    annulus_data = aper_annulus.to_pixel(w).to_mask(method="center").multiply(im)
    annulus_data_1d = annulus_data[mask > 0]
    annulus_mask = aper_annulus.to_pixel(w).to_mask(method="center").multiply(im_mask)
    annulus_mask_1d = annulus_mask[mask > 0]

    # determine fractional fiber coverage
    apcor_im = aper.to_pixel(w).to_mask(method="center").multiply(
        im_mask
    ) / aper.to_pixel(w).to_mask(method="center").multiply(np.ones_like(im))
    apcor = np.sum(apcor_im == 0) / np.sum(np.isfinite(apcor_im))

    # get median and standard deviation in background
    mean_sigclip, median_sigclip, stddev_sigclip = sigma_clipped_stats(
        annulus_data_1d, mask=annulus_mask_1d
    )
    bkg_median = median_sigclip * aper.to_pixel(w).area * apcor
    bkg_stddev = stddev_sigclip * aper.to_pixel(w).area * apcor

    phottable = aperture_photometry(
        hdu[0].data,
        [aper, aper_annulus],
        error=hdu[1].data,
        mask=im_mask,
        wcs=wcs.WCS(hdu[0].header),
    )
    if np.abs(bkg_median) > 2 * bkg_stddev:
        flux = (phottable["aperture_sum_0"][0] - bkg_median) * u.Unit(
            "10^-17 erg cm-2 s-1"
        )
    else:
        flux = (phottable["aperture_sum_0"][0]) * u.Unit("10^-17 erg cm-2 s-1")

    flux_err = phottable["aperture_sum_err_0"][0] * u.Unit("10^-17 erg cm-2 s-1")

    if plot:
        plt.subplot(111, projection=w)
        plt.imshow(im, vmin= -1 * stddev_sigclip, vmax=4 * stddev_sigclip)
        aper.to_pixel(w).plot(color="white")  # for SkyCircularAperture
        aper_annulus.to_pixel(w).plot(color="red", linestyle="dashed")
        plt.xlabel("RA")
        plt.ylabel("Dec")
        plt.colorbar()
        if plottitle is not None:
            plt.title(plottitle)

    return flux, flux_err, bkg_stddev * u.Unit("10^-17 erg cm-2 s-1"), apcor