Ejemplo n.º 1
1
def do_phot(image,position,radius = 5, r_in=15., r_out=20.):
    
    aperture = CircularAperture(position,r=radius)

    bkg_aperture = CircularAnnulus(position,r_in=r_in,r_out=r_out)

    # perform the photometry; the default method is 'exact'
    phot = aperture_photometry(image, aperture)
    bkg = aperture_photometry(image, bkg_aperture)

    # calculate the mean background level (per pixel) in the annuli
    bkg_mean = bkg['aperture_sum'] / bkg_aperture.area()
    bkg_sum = bkg_mean * aperture.area()
   
    #look at ipython notebook; his may need editing; 'phot' in second line below may need brackets with 'flux_sum' inside
    #phot['bkg_sum'] = bkg_sum
    #phot['flux_sum'] = phot['flux'] - bkg_sum
    
    #these two lines from ipython notebook
    flux_bkgsub = phot['aperture_sum'] - bkg_sum
    phot['aperture_sum_bkgsub'] = flux_bkgsub
    
    return phot
Ejemplo n.º 2
0
    def _make_apertures(self, colpos, rowpos):
        """Create an apertures, bg annular, and annular mask object for 
           aperture photometry.
           
        See https://photutils.readthedocs.io/en/stable/aperture.html#sigma-clipped-median-within-a-circular-annulus
        """

        positions = np.transpose((colpos, rowpos))
        
        # Radius of circular source region radius
        ap_radius = math.ceil(self._ap_fwhm_mult * self._search_fwhm)
        
        # BG outer annulus radius. By making this 1.5 times ap_radius
        # the BG annulus has an area 1.25 times the inner circle, so
        # we should get decent sampling.
        outer_radius = math.ceil(1.5 * ap_radius) 
        
        self._logger.debug(f'Radius of circular aperture photometry is {ap_radius} pixels.')
        self._logger.debug(f'Local BG estimation in annulus outer radius {outer_radius} pixels, inner radius {ap_radius} pixels.')
        
        apertures         = CircularAperture(positions, r=ap_radius)
        bg_apertures      = CircularAnnulus(positions, r_in=ap_radius, 
            r_out=outer_radius)
        bg_aperture_masks = bg_apertures.to_mask(method='center')
        
        return apertures, bg_apertures, bg_aperture_masks
Ejemplo n.º 3
0
def _fiber_fracflux(psf, x_centroid=None, y_centroid=None, fib_rad_pix=None):

    # not really sure if this edge case will ever happen ??
    if (np.sum(psf) <= 0):
        return np.nan, np.nan, np.nan

    if fib_rad_pix is None:
        fib_rad_pix = 3.567 * (1.52 / 1.462)  # pixels

    position = (x_centroid, y_centroid)

    aperture = CircularAperture(position, r=fib_rad_pix)
    annulus_aperture = CircularAnnulus(position, r_in=25.0, r_out=40.0)
    annulus_mask = annulus_aperture.to_mask(method='center')

    annulus_data = annulus_mask.multiply(psf)
    annulus_data_1d = annulus_data[annulus_mask.data > 0]

    _, bkg_median, std_bg = sigma_clipped_stats(annulus_data_1d)

    phot = aperture_photometry(psf, aperture)

    aper_bkg_tot = bkg_median * _get_area_from_ap(aperture)

    numerator = phot['aperture_sum'][0] - aper_bkg_tot  # aper flux
    denominator = np.sum(psf)

    frac = numerator / denominator

    return frac, numerator, denominator
Ejemplo n.º 4
0
def find_backgrounds(image,sources,inner_radius=10.,outer_radius=15.):
    '''
    Return the backgrounds of multiple sources
    determine by centering an annulus on each source
    and taking a mean.
    
    Parameters:
        image : nd array
            2D stellar image
        sources : nd array
            Array of (x,y) coordinates
        inner_radius : float
            Radial distance (pixels) of inner annulus
        outer_radius : 
            Radial distance (pixels) of outer annulus
            
    Returns:
        backgrounds : nd array
            Measured background for each star in sources.
    '''
    annulus_apertures = CircularAnnulus(sources, r_in=inner_radius, r_out=outer_radius)
    annulus_phot = aperture_photometry(image, annulus_apertures)
    
    bkg_mean = annulus_phot['aperture_sum'] / annulus_apertures.area()
    backgrounds = bkg_mean.data
    
    return backgrounds
Ejemplo n.º 5
0
    def set_apertures(self, stars_coords, fwhm=1):

        self.annulus_final_rin = self.annulus_inner_radius * fwhm
        self.annulus_final_rout = self.annulus_outer_radius * fwhm
        self.aperture_final_r = fwhm * self.apertures

        self.annulus_apertures = CircularAnnulus(
            stars_coords,
            r_in=self.annulus_final_rin,
            r_out=self.annulus_final_rout,
        )
        if callable(self.annulus_apertures.area):
            self.annulus_area = self.annulus_apertures.area()
        else:
            self.annulus_area = self.annulus_apertures.area

        self.circular_apertures = [
            CircularAperture(stars_coords, r=r) for r in self.aperture_final_r
        ]

        # Unresolved buf; sometimes circular_apertures.area is a method, sometimes a float
        if callable(self.circular_apertures[0].area):
            self.circular_apertures_area = [
                ca.area() for ca in self.circular_apertures
            ]
        else:
            self.circular_apertures_area = [
                ca.area for ca in self.circular_apertures
            ]

        self.annulus_masks = self.annulus_apertures.to_mask(method="center")
        self.n_stars = len(stars_coords)
Ejemplo n.º 6
0
 def plot_sky_masks(self,
                    r1,
                    r2,
                    minp=0.0,
                    maxp=99.9,
                    cols=5,
                    figsize=(11, 2.5)):
     aps = CircularAnnulus([self._stars.xcentroid, self._stars.ycentroid],
                           r1, r2)
     fig, axs = subplots(int(ceil(self.nstars / cols)),
                         cols,
                         figsize=figsize,
                         sharex=True,
                         sharey=True)
     for m, ax in zip(aps.to_mask(), axs.flat):
         d = where(m.data.astype('bool'), m.cutout(self.reduced),
                   nan)  #m.multiply(self.reduced)
         ax.imshow(d,
                   cmap=cm.gray_r,
                   origin='image',
                   norm=sn(d,
                           stretch='linear',
                           min_percent=minp,
                           max_percent=maxp))
     fig.tight_layout()
Ejemplo n.º 7
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
Ejemplo n.º 8
0
def aper_phot(data, header, positions, aper, data_out, gain=1, rdnoise=0):
    exptime = header['EXPTIME']
    apertures = CircularAperture(positions, r=aper[0])
    annulus_apertures = CircularAnnulus(positions, r_in=aper[1], r_out=aper[2])
    annulus_masks = annulus_apertures.to_mask(method='center')

    bkg_median = []
    for mask in annulus_masks:
        annulus_data = mask.multiply(data)
        annulus_data_1d = annulus_data[mask.data > 0]
        _, median_sigclip, _ = sigma_clipped_stats(annulus_data_1d)
        bkg_median.append(median_sigclip)
    bkg_intensity = np.array(bkg_median) * apertures.area() * gain
    phot = aperture_photometry(data, apertures)
    phot['signal_intensity'] = phot['aperture_sum'] * gain - bkg_intensity
    phot['SNR'] = phot['signal_intensity'] / (phot['signal_intensity'] +
                                              bkg_intensity + rdnoise**2)**0.5
    phot['magnitude'] = -2.5 * np.log10(
        phot['signal_intensity'] / exptime) + 24
    phot['delta_magnitude'] = 2.5 * np.log10(1 + 1 / phot['SNR'])

    for col in phot.colnames:
        phot[col].info.format = '%.4f'  # for consistent table output

    imageshow(data, positions, aper=aper)
    return phot
Ejemplo n.º 9
0
    def _aper_local_background(self):
        """
        Estimate the local background and error using a circular annulus
        aperture.

        The local backround is the sigma-clipped median value in the
        annulus.  The background error is the standard error of the
        median, sqrt(pi / 2N) * std.
        """
        bkg_aper = CircularAnnulus(
            self.xypos, self.aperture_params['bkg_aperture_inner_radius'],
            self.aperture_params['bkg_aperture_outer_radius'])
        bkg_aper_masks = bkg_aper.to_mask(method='center')
        sigclip = SigmaClip(sigma=3)

        nvalues = []
        bkg_median = []
        bkg_std = []
        for mask in bkg_aper_masks:
            bkg_data = mask.multiply(self.model.data.value)
            bkg_data_1d = bkg_data[mask.data > 0]
            values = sigclip(bkg_data_1d, masked=False)
            nvalues.append(values.size)
            bkg_median.append(np.median(values))
            bkg_std.append(np.std(values))

        nvalues = np.array(nvalues)
        bkg_median = np.array(bkg_median)
        # standard error of the median
        bkg_median_err = np.sqrt(np.pi / (2. * nvalues)) * np.array(bkg_std)

        bkg_median <<= self.model.data.unit
        bkg_median_err <<= self.model.data.unit

        return bkg_median, bkg_median_err
Ejemplo n.º 10
0
def snr_astropy(image,sx,sy,r,r_in,r_out):
    """
    Returns signal to noise ratio, signal value, noise value using Astropy's Photutils module
    Args:
        image (2d float array): Image array extracted from fits file
        sx,sy (float): x and y pixel locations for the center of the source
        r (float): radius for aperture
        r_in,r_out (float): inner and outer radii for annulus
    Return:
        snr (float): signal-to-noise ratio
        signal (float): sum of all pixel values within the specified aperture minus sky background
        noise (float): noise in the signal calculated as std deviation of pixels in the sky annulus times sqrt of the area of the
        signal aperture
        poisson_noise (float): snr determined from the poisson noise in the source signal.  Poisson noise = sqrt(counts) [because variance
        of a poisson distribution is the parameter itself].  Poisson snr = Signal/sqrt(signal) = sqrt(signal)
    Written by: Logan Pearce, 2018
    """
    import warnings
    warnings.filterwarnings('ignore')
    from photutils import CircularAperture, CircularAnnulus
    positions = (cx-1,cy-1)
    ap = CircularAperture(positions,r=r)
    skyan = CircularAnnulus(positions,r_in=11,r_out=14)
    apsum = ap.do_photometry(image)[0]
    skysum = skyan.do_photometry(image)[0]
    averagesky = skysum/skyan.area()
    signal = (apsum - ap.area()*averagesky)[0]
    n = ap.area()
    ap_an = aperture_annulus(sx,sy,r,r_in,r_out)
    skyan = ap_an[1]
    poisson_noise = np.sqrt(signal)
    noise = noise = np.std(image[skyan[1],skyan[0]])
    noise = noise*np.sqrt(n)
    snr = signal/noise
    return snr,signal,noise,poisson_noise
Ejemplo n.º 11
0
def ap_phot(sources, data, source_r=6., sky_in=15, sky_out=20, plot=False):
    global fig
    centroids = (sources['xcentroid'], sources['ycentroid'])
    source_aperture = CircularAperture(centroids, r=source_r)
    source_area = source_aperture.area()
    source_table = aperture_photometry(data, source_aperture)

    sky_aperture = CircularAnnulus(centroids, r_in=sky_in, r_out=sky_out)
    sky_area = sky_aperture.area()
    sky_table = aperture_photometry(data, sky_aperture)

    sky_subtracted_source = deepcopy(source_table)

    for i in range(np.shape(centroids)[1]):
        sky_value = sky_table[i][3]
        sky_per_pix = sky_value / sky_area
        sky_behind_source = sky_per_pix * source_area
        sky_subtracted_source[i][3] -= sky_behind_source

    if plot:
        fig = plt.figure(figsize=(17, 17))
        plt.imshow(data, cmap='gray', origin='lower', vmin=0, vmax=1500)
        for i in range(np.shape(centroids)[1]):
            plt.annotate(str(source_table[i][0]),
                         xy=(np.float64(source_table[i][1]) + 15.,
                             np.float64(source_table[i][2]) + 15.),
                         color="white")
        source_aperture.plot(color='blue', lw=1.5, alpha=0.5)
        sky_aperture.plot(color="orange", lw=0.5, alpha=0.5)
        plt.tight_layout()
        plt.show()

    return sky_subtracted_source
Ejemplo n.º 12
0
def get_background(frames, centroids, bckg_method):
    print 'Calculating background levels'
    frames = np.asarray(frames)
    backgrounds = []

    pbar = progressbar.ProgressBar()
    for i in pbar(range(len(frames))):
        if bckg_method == 'annulus':
            annulus_apertures = CircularAnnulus(centroids[i],
                                                r_in=10.,
                                                r_out=15.)
            bkgflux = aperture_photometry(frames[i], annulus_apertures)
            bkg_mean = bkgflux['aperture_sum'] / annulus_apertures.area()
            backgrounds.append(bkg_mean[0])

        if bckg_method == 'corners':
            #calculate background by summing flux in corners of image, fit gaussian, get mean
            background = []
            N = 10
            background += list(np.reshape(frames[i, :N, :N], (N**2)))
            background += list(np.reshape(frames[i, -N:, :N], (N**2)))
            background += list(np.reshape(frames[i, :N, -N:], (N**2)))
            background += list(np.reshape(frames[i, -N:, -N:], (N**2)))

            mu, sigma = norm.fit(background)
            backgrounds.append(mu)

    print 'Backgrounds done calculating'
    print ' '
    return backgrounds
Ejemplo n.º 13
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
Ejemplo n.º 14
0
    def plot_apertures(self, ax, offset=9, wcs=None):
        if wcs:
            cpix = self._ref_centroids_sky.to_pixel(wcs)
        xlim = ax.get_xlim()
        ylim = ax.get_ylim()

        if self._apertures_obj is not None:
            if wcs:
                apertures_obj = [
                    CircularAperture(cpix, r) for r in self.aperture_radii
                ]
            else:
                apertures_obj = self._apertures_obj
            [apt.plot(ax=ax, alpha=0.25) for apt in apertures_obj]
            for istar, (x, y) in enumerate(apertures_obj[0].positions):
                if (xlim[0] <= x <= xlim[1]) and (ylim[0] <= y <= ylim[1]):
                    yoffset = offset if y < ylim[1] - 10 else -offset
                    ax.text(x + offset, y + yoffset, istar)
        if self._apertures_sky is not None:
            if wcs:
                apertures_sky = CircularAnnulus(cpix, self.aperture_radii[-1],
                                                self.aperture_radii[-1] + 15)
            else:
                apertures_sky = self._apertures_sky
            apertures_sky.plot(ax=ax, alpha=0.25)
Ejemplo n.º 15
0
def GetAP(cut, theta, reso=0.5):
    """
	Performs aperture photometry.

	Calculates the average value of the cutout within a circle of radius theta minus the average in the outer ring [theta, sqrt(2)*theta]

	Params
	------
	- cut:  the cutout (numpy array)
	- theta: radius (float, in arcmin)
	- reso: pixel resolution (float, in arcmin/pix)
	"""
    theta_R_pix = theta / reso
    positions = [(cut.shape[1] / 2., cut.shape[0] / 2.)]
    apertures = CircularAperture(positions, r=theta_R_pix)
    annulus_apertures = CircularAnnulus(positions,
                                        r_in=theta_R_pix,
                                        r_out=theta_R_pix * np.sqrt(2))
    apers = [apertures, annulus_apertures]

    phot_table = aperture_photometry(cut, apers)
    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['residual_aperture_sum'] = final_sum

    return phot_table['residual_aperture_sum'][0] / apertures.area()
Ejemplo n.º 16
0
def photometry_custom(image_data, radpix, wcs):
    #aperture = CircularAperture((image_data.shape[0]/2,image_data.shape[0]/2), radpix[19])
    position = [image_data.shape[0] / 2, image_data.shape[0] / 2]
    apertures = [CircularAperture(position, r=r) for r in radpix]
    annulus_aperture = CircularAnnulus(position,
                                       r_in=radpix[19],
                                       r_out=radpix[19] + radpix[16])
    phot_table = aperture_photometry(image_data, apertures, wcs=wcs)

    annulus_masks = annulus_aperture.to_mask(method='center')
    annulus_data = annulus_masks.multiply(image_data)
    mask = annulus_masks.data
    annulus_data_1d = annulus_data[mask > 0]
    _, median_sigclip, _ = sigma_clipped_stats(annulus_data_1d)
    bkg_mean = median_sigclip

    #sky_aperture = to_sky(apertures,wcs)
    phot_array = np.zeros(20)
    bkg_sum_array = np.zeros(20)
    for i in range(0, 20):
        phot_array[i] = phot_table['aperture_sum_' + str(i)][0]
        bkg_sum_array[i] = bkg_mean * apertures[i].area

    final_sum = phot_array - bkg_sum_array

    scale = np.mean(proj_plane_pixel_scales(wcs))
    phot_Jy_custom = final_sum

    print('Backgorud outer radius =', radpix[19] + radpix[16], 'pixels')
    print(phot_table)
    return (phot_Jy_custom)
Ejemplo n.º 17
0
def nb_cogphot(nbima, nbvar, xc, yc, maxrad=15, growthlim=1.025, plots=False):

    from photutils import CircularAperture, CircularAnnulus
    from photutils import aperture_photometry
    from astropy.stats import sigma_clipped_stats as scl
    from astropy.convolution import convolve, Box2DKernel

    rad = np.arange(1, maxrad + 1)
    phot = np.zeros_like(rad, dtype=float)
    photerr = np.zeros_like(rad, dtype=float)
    growth = np.zeros_like(rad, dtype=float)

    skyaper = CircularAnnulus((xc - 1, yc - 1),
                              r_in=maxrad,
                              r_out=np.max([1.5 * maxrad, 20]))
    skymask = skyaper.to_mask(method='center')
    skydata = skymask.multiply(nbima)[skymask.data > 0]

    bkg_avg, bkg_med, _ = scl(skydata)

    for ii, r in enumerate(rad):

        aper = CircularAperture((xc - 1, yc - 1), r=r)
        phot[ii] = (aperture_photometry(
            nbima, aper))['aperture_sum'][0] - bkg_med * aper.area
        photerr[ii] = np.sqrt((aperture_photometry(nbvar,
                                                   aper))['aperture_sum'][0])
        if ii < 3:
            growth[ii] = 100
        else:
            growth[ii] = phot[ii] / phot[ii - 1]

    rlim = np.argmin(growth > growthlim) - 1

    fluxarr = phot[rlim]
    errarr = photerr[rlim]
    radarr = rad[rlim]

    if plots:
        fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(5, 5))
        ax.imshow(convolve(nbima, Box2DKernel(5)),
                  vmin=-2,
                  vmax=30,
                  origin='lower')
        #ax.imshow(tmpnbima, vmin=-2, vmax=30, origin='lower')
        circ = plt.Circle((xc - 1, yc - 1),
                          rad[rlim],
                          color='r',
                          fill=False,
                          lw=3)
        ax.add_artist(circ)
        ax.set_xlim(xc - 50, xc + 50)
        ax.set_ylim(yc - 50, yc + 50)
        plt.show()

        plt.plot(rad, phot)
        plt.show()

    return fluxarr, errarr, radarr
Ejemplo n.º 18
0
Archivo: fji.py Proyecto: felipeji/fji
    def __init__(self, data, coord, r_in, r_out, method, subpixels=None):
        from photutils import CircularAnnulus

        self.ap = CircularAnnulus(coord, r_in=r_in, r_out=r_out)

        self.sec_data = SecImData(self.ap,
                                  data,
                                  method=method,
                                  subpixels=subpixels)
Ejemplo n.º 19
0
def do_photometry(image,
                  source_table,
                  aperture_radius=3,
                  subtract_background=False,
                  annulus_radii=(6, 8)):
    """Perform aperture photometry on the input data using the source
    locations specified in the source_table

    Parameters
    ----------
    image : numpy.ndarray
        2D image

    source_table : astropy.table.Table
        Table of source locations (i.e. output from photutils's
        DAOStarFinder)

    subtract_background : bool
        If True, use photutils to estimate and subtract background

    Returns
    -------
    source_table : astropy.table.Table
        Updated source_table including photometry results
    """
    # Create list of tuples giving source locations
    positions = [(tab['xcentroid'], tab['ycentroid']) for tab in source_table]

    apertures = CircularAperture(positions, r=aperture_radius)

    # If background is to be subtracted, calculate the sigma-clipped median
    # value of the pixels in the annuli around the sources
    if subtract_background:
        annulus_apertures = CircularAnnulus(positions,
                                            r_in=annulus_radii[0],
                                            r_out=annulus_radii[1])
        annulus_masks = annulus_apertures.to_mask(method='center')

        bkg_median = []
        for mask in annulus_masks:
            annulus_data = mask.multiply(image)
            annulus_data_1d = annulus_data[mask.data > 0]
            _, median_sigclip, _ = sigma_clipped_stats(annulus_data_1d)
            bkg_median.append(median_sigclip)
        bkg_median = np.array(bkg_median)

    # Do the photometry and add to the input table
    phot_table = aperture_photometry(image, apertures)
    source_table['aperture_sum'] = phot_table['aperture_sum']

    if subtract_background:
        # Add columns with that background subtraction info
        source_table['annulus_median'] = bkg_median
        source_table['aper_bkg'] = bkg_median * apertures.area
        source_table['aper_sum_bkgsub'] = source_table[
            'aperture_sum'] - source_table['aper_bkg']
    return source_table
Ejemplo n.º 20
0
def do_Circ_phot(pos, FWHM, ap_min=3., ap_factor=1.5, rin=None, rout=None, \
                   sky_nsigma=3., sky_iter=10):
    '''
    In rigorous manner, we should use
    error = sqrt (flux / epadu + area * stdev**2 + area**2 * stdev**2 / nsky)
    as in http://stsdas.stsci.edu/cgi-bin/gethelp.cgi?phot .
    Here flux == aperture_sum - sky, i.e., flux from image_reduc.
        stdev should include sky error AND ronoise.
    '''
    if rin == None:
        rin  = 4 * FWHM
    if rout == None:
        rout = 6 * FWHM
    N = len(pos)
    if pos.ndim == 1:
        N = 1
    an       = CircAn(pos, r_in=rin, r_out=rout)
    ap_size  = np.max([ap_min, ap_factor*FWHM])
    aperture = CircAp(pos, r=ap_size)
    flux     = aperture.do_photometry(image_reduc, method='exact')[0]
    # do phot and get sum from aperture. [0] is sum and [1] is error.
#For test:
#N=len(pos_star_fit)
#an       = CircAn(pos_star_fit, r_in=4*FWHM_moffat, r_out=6*FWHM_moffat)
#ap_size  = 1.5*FWHM_moffat
#aperture = CircAp(pos_star_fit, r=ap_size)
#flux     = aperture.do_photometry(image_reduc, method='exact')[0]
    flux_ss  = np.zeros(N)
    error    = np.zeros(N)
    for i in range(0, N):
        mask_an    = (an.to_mask(method='center'))[i]
        #   cf: test = mask_an.cutout(image_reduc) <-- will make cutout image.
        sky_an     = mask_an.apply(image_reduc)
        all_sky    = sky_an[np.nonzero(sky_an)]
        # only annulus region will be saved as np.ndarray
        msky, stdev, nsky, nrej = sky_fit(all_sky, method='Mode', mode_option='sex')
        area       = aperture.area()
        flux_ss[i] = flux[i] - msky*area  # sky subtracted flux
        error[i]   = np.sqrt( flux_ss[i]/gain \
                           + area * stdev**2 \
                           + area**2 * stdev**2 / nsky )
# To know rejected number, uncomment the following.
#        plt.imshow(sky_an, cmap='gray_r', vmin=-20)
#        plt.colorbar()
#        plt.show()
#        mask_ap  = (aperture.to_mask(method='exact'))[i]
#        star_ap  = mask_ap.apply(image_reduc)
#        plt.imshow(star_ap)
#        plt.colorbar()
#        plt.show()
#        plt.cla()
        if pos.ndim > 1:
            print('\t[{x:7.2f}, {y:7.2f}], {nsky:3d} {nrej:3d} {msky:7.2f} {stdev:7.2f} {flux:7.1f} {ferr:3.1f}'.format(\
                          x=pos[i][0], y=pos[i][1], \
                          nsky=nsky, nrej=nrej, msky=msky, stdev=stdev,\
                          flux=flux_ss[i], ferr=error[i]))
    return flux_ss, error
Ejemplo n.º 21
0
def pmgstars_forced_phot(xcentroid, ycentroid, image, elg=False,
                         bgs=False):

    assert(len(xcentroid) > 0)
    assert(len(ycentroid) > 0)

    # create the apertures
    # get the fluxes

    print('Attempting to do forced aperture photometry')

    # shouldn't happen...
    assert(not (elg and bgs))

    if elg or bgs:
        par = common.gfa_misc_params()

        param = 'exp_kernel_filename' if elg else 'devauc_kernel_filename'

        fname = os.path.join(os.environ[par['meta_env_var']],
                             par[param])

        kern = fits.getdata(fname) # non-optimal to repeatedly read this...

        image = ndimage.convolve(image, kern, mode='constant')

    positions = list(zip(xcentroid, ycentroid))

    # the 1.52/1.462 factor comes from David Schlegel's request
    # to have gfa_reduce fiber flux fraction related quantities
    # be referenced to a 1.52 asec diameter aperture, even though
    # the angular diameter corresponding to a 107 um fiber at the
    # GFA focal plane position is smaller (1.462 asec using GFA
    # platescale geometric mean); see SurveySpeed wiki page for 1.52 value
    radius = 3.567*(1.52/1.462) # pixels

    apertures = CircularAperture(positions, r=radius)
    annulus_apertures = CircularAnnulus(positions, r_in=60.0, r_out=65.0)
    annulus_masks = annulus_apertures.to_mask(method='center')

    bkg_median = []
    for mask in annulus_masks:
        annulus_data = mask.multiply(image)
        annulus_data_1d = annulus_data[mask.data > 0]
        # this sigma_clipped_stats call is actually the slow part !!
        _, median_sigclip, std_bg = sigma_clipped_stats(annulus_data_1d)
        bkg_median.append(median_sigclip)

    bkg_median = np.array(bkg_median)
    phot = aperture_photometry(image, apertures)

    aper_bkg_tot = bkg_median*_get_area_from_ap(apertures[0])

    aper_fluxes = np.array(phot['aperture_sum']) - aper_bkg_tot

    return aper_fluxes
Ejemplo n.º 22
0
 def annulus_background(self, positions, radius=3.):
     #Obtain the sky local background
     annulus_apertures = CircularAnnulus(positions,
                                         r_in=radius + 2.,
                                         r_out=radius + 4.)
     bkg_table = aperture_photometry(self.data, annulus_apertures)
     bkg_counts = float(bkg_table['aperture_sum'])
     bkg_mean = bkg_counts / annulus_apertures.area()
     bkg = np.random.poisson(bkg_mean, self.data.shape)
     return bkg, bkg_counts, bkg_mean
Ejemplo n.º 23
0
 def load_bkg_cutout(self, manual_mask=False, col_mask_start=0, col_mask_end=0,
                     row_mask_start=0, row_mask_end=0):
     '''       
     Only need to manually mask the background if the number of bad 
     pixels in the background annulus is more than half of the total;
     Otherwise *median absolute deviation*(or percentiles) should give a 
     robust estimate of the background noise.
     
     imgpath = pobj.imgpath
     pixX = pobj.pixX
     pixY = pobj.pixY  
     # bad_threshold = pobj.bad_threshold
     r_bkg_in = pobj.r_bkg_in
     r_bkg_out = pobj.r_bkg_out
     '''
     imgpath = self.imgpath              
     pixX = self.pixX
     pixY = self.pixY
     # bad_threshold = self.bad_threshold
     r_bkg_in = self.r_bkg_in
     r_bkg_out = self.r_bkg_out
     
     dt = fits.open(imgpath)[1].data        
     positions = [(pixX, pixY)]
     annulus_aperture = CircularAnnulus(positions, 
                                        r_in = r_bkg_in, r_out = r_bkg_out)
     annulus_masks = annulus_aperture.to_mask(method='center')
     annulus_data = annulus_masks[0].multiply(dt)
     
     bkg_fn = deepcopy(annulus_data)
     bad_bkg_mask = np.isnan(annulus_data)
     if manual_mask == True:    
         bad_bkg_mask[r_bkg_out+row_mask_start:r_bkg_out+row_mask_end, 
                      r_bkg_out+col_mask_start:r_bkg_out+col_mask_end] = True
     nbad_bkg = np.sum(bad_bkg_mask)
         
     self.nbad_bkg = nbad_bkg
     
     setnan = annulus_masks[0].data==0
     bkg_fn[setnan] = np.nan
     # bkgstd = np.nanstd(bkg_fn) 
     
     temp = bkg_fn.ravel()
     temp = temp[~np.isnan(temp)]
     bkgstd = 0.5 * (np.percentile(temp, 84.13)-np.percentile(temp, 15.86))
     # bkgstd = np.median(abs(temp - np.median(temp)))
     bkgmed = np.median(temp)
     
     self.bkgstd = bkgstd 
     self.bkg_fn = bkg_fn
     self.bkgmed = bkgmed
     
     if self.verbose == True:
         print ('\t bkgstd pixel RMS in original diff-image cutout = %.2f DN'%(self.bkgstd))
         print ('\t bkgmed pixel in original diff-image cutout = %.2f DN'%(self.bkgmed))
Ejemplo n.º 24
0
def ref2image(data,positions,aper,fig_name):
    apertures = CircularAperture(positions, r=aper[0])
    annulus_apertures = CircularAnnulus(positions, r_in=aper[1], r_out=aper[2])          
    fig = plt.figure(figsize=(20,20));fig.add_subplot(111)
    apertures.plot(color='blue',lw=2,alpha=1)
    annulus_apertures.plot(color='red',lw=2,alpha=0.5)
    norm = ImageNormalize(stretch=HistEqStretch(data))
    plt.imshow(data, cmap='Greys', origin='lower', norm=norm)
    for i in range(len(positions)):
        plt.text(positions[i][0]+10,positions[i][1]+10,str(i+1),fontdict={'size':'50','color':'blue'})
    plt.savefig(fig_name,dpi=150)
    plt.show()
Ejemplo n.º 25
0
def imageshow(data,positions,aper=[8,12,20],rim_size=50):
    min_x=int(np.min(positions.T[0]))-rim_size;max_x=int(np.max(positions.T[0]))+rim_size
    min_y=int(np.min(positions.T[1]))-rim_size;max_y=int(np.max(positions.T[1]))+rim_size
    data=data[min_y:max_y,min_x:max_x]
    positions=positions-np.array([min_x,min_y])
    apertures = CircularAperture(positions, r=aper[0])
    annulus_apertures = CircularAnnulus(positions, r_in=aper[1], r_out=aper[2])          
    fig = plt.figure(figsize=(20,20));fig.add_subplot(111)
    apertures.plot(color='blue',lw=2,alpha=1)
    annulus_apertures.plot(color='red',lw=2,alpha=0.5)
    norm = ImageNormalize(stretch=HistEqStretch(data))
    plt.imshow(data, cmap='Greys', origin='lower', norm=norm)
    plt.show()
Ejemplo n.º 26
0
def ap_phot(im, cen, r1, r2, r3):
    """
    Simple aperture photometry, using a circular source aperture and sky annulus.
    """

    apertures = CircularAperture(cen, r1)
    annulus_apertures = CircularAnnulus(cen, r2, r3)
    apers = [apertures, annulus_apertures]
    phot_table = aperture_photometry(im, apers)
    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
    return float(final_sum)
Ejemplo n.º 27
0
def remove_concentric(data, x_mean=512, y_mean=512, x_stddev=3, y_stddev=3, Nsig=10, dp=0.1):
    """
    This function first fits a gaussian PSF to the data to find the centroid.
    Then, it subtracts concentric apertures from the data rather than just 
    subtracting the gaussian model.
    """
    data = data.copy() # Don't overwrite the data
    nx, ny = data.shape
    
    gauss, psf, centroid = fit_gaussian_psf(data, x_mean=x_mean, y_mean=y_mean, 
                                          x_stddev=x_stddev, y_stddev=y_stddev)
    std = (gauss.x_stddev_0.value + gauss.y_stddev_0.value)/2.0
    x0, y0 = centroid
    
    radii = np.arange(dp, Nsig*std, dp)[::-1]
    
    # Get extents using the photutils function
    pos = np.atleast_2d(centroid)
    extents = np.zeros((len(pos), 4), dtype=int)

    extents[:, 0] = pos[:, 0] - max(radii) + 0.5
    extents[:, 1] = pos[:, 0] + max(radii) + 1.5
    extents[:, 2] = pos[:, 1] - max(radii) + 0.5
    extents[:, 3] = pos[:, 1] + max(radii) + 1.5

    _, extent, phot_extent = get_phot_extents(data, pos, extents)
    x_min, x_max, y_min, y_max = extent
    x_pmin, x_pmax, y_pmin, y_pmax = phot_extent
    args = [x_pmin[0], x_pmax[0], y_pmin[0], y_pmax[0], x_max[0]-x_min[0], y_max[0]-y_min[0]]

    # Fit apertures
    psf = np.zeros(data.shape)
    for radius in radii:
        Rin = radius - dp
        Rout = radius
        if Rin > dp/10.0:
            ap = CircularAnnulus(centroid, r_in=Rin, r_out=Rout)
        else:
            ap = CircularAperture(centroid, r=Rout)
        phot = aperture_photometry(data, ap)
        avg_flux = phot['aperture_sum'].item()/ap.area()
        
        outer = circular_overlap_grid(*args, r=Rout, use_exact=1, subpixels=5)
        if Rout-dp > dp/10.0:
            inner = circular_overlap_grid(*args, r=Rin, use_exact=1, subpixels=5)
        else:
            inner = 0.0
        annulus_overlap = outer - inner
        psf[y_min[0]:y_max[0], x_min[0]:x_max[0]] += annulus_overlap * avg_flux
    return data - psf, psf, np.array(centroid)
Ejemplo n.º 28
0
    def aperture_photometry(self, image, positions, r, r_int, r_ext):
        # Define apertures and anulluses at all found sources:
        object_aperture = CircularAperture(positions, r)
        background_annulus = CircularAnnulus(positions, r_int, r_ext)

        # Calculate the flux in each aperture (star, and background, and subtract)
        backgound_solution = aperture_photometry(image, background_annulus)
        object_solution = aperture_photometry(image, object_aperture)
        background_per_pixel = backgound_solution[
            "aperture_sum"] / background_annulus.area()
        object_solution[
            "aperture_sum"] -= background_per_pixel * object_aperture.area()

        return np.array(object_solution["aperture_sum"]), background_per_pixel
Ejemplo n.º 29
0
def do_phot(fname, datadir, phot_dir_name, apsize, annsize):
    hdul = fits.open(fname)
    if '.fz' in fname:
        data = hdul[1].data
        header = hdul[1].header
        hdul.close()
    else:
        data = hdul[0].data
        header = hdul[0].header
        hdul.close()
    gain = header.get('GAIN')
    if gain == None:
        a = 1
    else:
        data = data.clip(min=0)
        rdnoise = header['RDNOISE']
        error = np.sqrt(data * gain) + rdnoise
        mean, median, std = sigma_clipped_stats(data, sigma=3.0, iters=5)
        daofind = DAOStarFinder(fwhm=5.0, threshold=5. * std)
        sources = daofind(data - median)
        positions = (sources['xcentroid'], sources['ycentroid'])
        apertures_pix = CircularAperture(positions, r=apsize)
        annulus_pix = CircularAnnulus(positions,
                                      r_in=annsize[0],
                                      r_out=annsize[1])
        apertures_sky = apertures_pix.to_sky(wcs.WCS(header))
        annulus_sky = annulus_pix.to_sky(wcs.WCS(header))
        apers = [apertures_sky, annulus_sky]
        # plt.imshow(data)#, cmap='Greys', origin='lower', norm=norm)
        # apertures_pix.plot(color='white', lw=1.5, alpha=0.5)
        # annulus_pix.plot(color='white', lw=1.5, alpha=0.5)
        # plt.show()
        # pdb.set_trace()
        phot_table = aperture_photometry(data,
                                         apers,
                                         wcs=wcs.WCS(header),
                                         error=error)
        bkg_mean = phot_table['aperture_sum_1'] / annulus_pix.area()
        bkg_sum = bkg_mean * apertures_pix.area()
        apertures_pix.area()
        final_sum = phot_table['aperture_sum_0'] - bkg_sum
        final_error = np.sqrt(phot_table['aperture_sum_err_0']**2 +
                              phot_table['aperture_sum_err_1']**2)
        phot_table['residual_aperture_sum'] = final_sum
        phot_table['residual_err'] = final_error
        fname = datadir + phot_dir_name + "phot_table_{0:.7f}_{1}s.txt".format(
            header['MJD-OBS'], header['EXPTIME'])
        phot_table.write(fname, format='ascii')
        replace_comma(fname)
Ejemplo n.º 30
0
    def Photometrie(self):
        q = []
        for elem in self.data:
            phot = []
            for x, y in zip(self.Tx[self.index], self.Ty[self.index]):
                radii = range(3, 25)
                positions = [(x, y)]
                apertures = [CircularAperture(positions, r=r) for r in radii]
                annulus_apertures = CircularAnnulus(positions,
                                                    r_in=70.,
                                                    r_out=80.)
                phot_table = aperture_photometry(self.data[self.index],
                                                 apertures)
                phot_background = aperture_photometry(self.data[self.index],
                                                      annulus_apertures)
                bkg_mean = (phot_background['aperture_sum'] /
                            annulus_apertures.area())
                Int = []
                Area = []
                Int_bkg1 = []

                for num in range(3, 25):
                    Int.append(phot_table[0][num])
                    Area.append(apertures[num - 3].area())
                    Int_bkg1.append(phot_table[0][num] -
                                    apertures[num - 3].area() * bkg_mean)

                phot.append(Int_bkg1)

            filename = self.files[self.index]
            print('Processing file: ' + str(filename))
            phot = numpy.array(phot)
            qq = (phot[0] - phot[1]) / (phot[0] + phot[1])
            with open(filename + '.txt', 'w') as f:
                for elem3 in qq:
                    for elem2 in elem3:
                        f.write(
                            str(self.JD[self.index]) + '\t' +
                            str(self.retarder[self.index]) + '\t' +
                            str(elem2) + '\n')
            q.append(qq.flatten())
            self.nextframe(1)

        q = numpy.array(q)
        with open('q', 'w') as f:
            for elem in q:
                for elem2 in elem:
                    f.write(str(elem2) + '\n')
Ejemplo n.º 31
0
 def add_star(self, y, x, mag=None, name=None):
     print("Adding star ({},{})".format(x, y))
     self.make_current()
     if mag is not None:
         isVar = False
     else:
         isVar = True
     st = Star(self, x, y, isVar, mag=mag, name=name)
     self.stars.append(st)
     r = np.mean([s.r for s in self.stars])
     d_d = np.mean([s.d_d for s in self.stars])
     d_a = np.mean([s.d_a for s in self.stars])
     print("Added star", st)
     for s in self.stars:
         s.apertures[self] = CircularAperture((s.x[self], s.y[self]), r)
         s.annuli[self] = CircularAnnulus(
                 (s.x[self], s.y[self]), r + d_d, r + d_d + d_a
                 )
         s.r = r
         s.d_d = d_d
         s.d_a = d_a
         print("\tUpdated aperture radii of star"
               "({},{}) to ({}, {}~{})".format(
                       np.around(s.x[self], decimals=2),
                       np.around(s.y[self], decimals=2),
                       np.around(r, decimals=2),
                       np.around(r + d_d, decimals=2),
                       np.around(r + d_d + d_a, decimals=2)
                       )
               )
Ejemplo n.º 32
0
def measure_source_fwhm(detection, data, rmax=10):
    """
    TO USE CAREFULLY
    Function used to estimate the FWHM of a source.
    It performs aperture photometry with inscreasing radius from the source position, and then, tries to find where half of the maximum of flux is reached.

    Parameters
    ----------
    detection : :class:`~pandas:pandas.Series`
        Row of a DataFrame containing detected sources. Should have columns ``xcentroid`` and ``ycentroid``, in classic convention (not astropy)
    data : 2D :class:`~numpy:numpy.ndarray`
        Flux map used for the photometry
    """
    x, y = np.array(detection[['xcentroid', 'ycentroid']])
    photo_flux = np.zeros(rmax)
    for r in range(rmax):
        if r == 0:
            aper = CircularAperture((x, y), 1.)
        else:
            aper = CircularAnnulus((x, y), r, r + 1)
        photo_flux[r] = aper.do_photometry(data)[0] / aper.area()

    def get_fwhm(flux):
        #We assume max is on 0. If not, source is probably contaminated
        flux = flux - flux.min()
        spline = UnivariateSpline(np.arange(rmax), flux - flux[0] / 2., s=0)
        if spline.roots().shape != (1, ):
            return np.nan
        return spline.roots()[0]

    return (get_fwhm(photo_flux))
        def skyvalue(data, y0, x0, r_in, r_out, masking):
            masking = masking.astype(bool)
            ann = CircularAnnulus([x0, y0], r_in=r_in, r_out=r_out)
            phot = aperture_photometry(data, ann, mask=masking)

            phot1 = aperture_photometry(masking * 1, ann)
            pixel_count = phot1['aperture_sum'][0]
            sky = phot['aperture_sum'][0] / (ann.area - pixel_count)

            masked_image = np.ma.masked_array(data, masking)

            # Determine sky std
            y_in = int(y0 - r_out)
            y_out = int(y0 + r_out)
            x_in = int(x0 - r_out)
            x_out = int(x0 + r_out)
            if y_in < 0:
                y_in = 0
            if y_out < 0:
                y_out = 0
            if x_in < 0:
                x_in = 0
            if x_out < 0:
                x_out = 0
            masked_image = masked_image[y_in:y_out, x_in:x_out]
            new_mask = np.zeros(np.shape(masked_image)) + 1
            for yi in range(len(masked_image)):
                for xi in range(len(masked_image[0])):
                    position = (xi - r_out)**2 + (yi - r_out)**2
                    if position < (r_out)**2 and position > r_in**2:
                        new_mask[yi, xi] = 0
            new_mask = new_mask.astype(bool)
            Sky_region = np.ma.masked_array(masked_image, new_mask)
            std = np.ma.std(Sky_region)
            return (sky, std, ann.area - pixel_count)
Ejemplo n.º 34
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
Ejemplo n.º 35
0
# print mean_i, median_i, std_i

r2 = pyregion.open('regions_phys.reg')
full_mask = r2.get_mask(hdu=hdu_g[0])
# full_mask_i = full_mask_g #r2.get_mask(hdu=hdu_i[0])

# plt.imshow(full_mask_g)
# plt.show()

median_g = 191.9227
median_i = 623.8584

positions = [(5819.6140, 5535.8705)]
radii = [91., 136., 182., 227., 273., 318., 364., 409., 455., 500., 545., 591., 636., 682., 727., 772., 818.]
apertures = [CircularAperture(positions, r=r) for r in radii]
annulus = CircularAnnulus(positions, r_in=900., r_out=1000.)
ann_mask = annulus.to_mask(method='exact')
ann_g = ann_mask[0].apply(hdu_g[0].data) * ann_mask[0].apply(np.abs(full_mask-1))
ann_i = ann_mask[0].apply(hdu_i[0].data) * ann_mask[0].apply(np.abs(full_mask-1))
ann_keep = np.where(ann_g != 0)
bkg_mean_g = np.median(ann_g[ann_keep])
bkg_mean_i = np.median(ann_i[ann_keep])

print bkg_mean_g, bkg_mean_i

aper_mask = apertures[0].to_mask(method='exact')
dbl_mask_aper = aper_mask[0].apply(hdu_g[0].data-bkg_mean_g, fill_value=-999.) * aper_mask[0].apply(np.abs(full_mask-1), fill_value=-999.)
plt.imshow(dbl_mask_aper)
plt.show()

mean, median, std = sigma_clipped_stats(dbl_mask_aper, mask_value=-999.)
Ejemplo n.º 36
0
def align_norm(fnlist, tolerance=5, thresh=3.5):
    """Aligns a set of images to each other, as well as normalizing the images
    to the same average brightness.

    Both the alignment and normalization are accomplished through stellar
    photometry using the IRAF routine 'daophot'. The centroids of a handful
    of stars are found and used to run the IRAF routine 'imalign'. The
    instrumental magnitudes of the stars are used to determine by how much
    each image must be scaled for the photometry to match across images.

    The images are simply updated with their rescaled, shifted selves. This
    overwrites the previous images and adds the header keyword 'fpphot' to
    the images.

    A handful of temporary files are created during this process, which should
    all be deleted by the routine at the end. But if it is interrupted, they
    might not be.

    If the uncertainty images exist, this routine also shifts them by the same
    amounts as the intensity images, as well as updating the uncertainty values
    for both the new normalization and the uncertainties in normalizing the
    images.

    Inputs:
    fnlist -> List of strings, each the path to a fits image.
    tolerance -> How close two objects can be and still be considered the same
                 object. Default is 3 pixels.
    thresh -> Optional. Level above sky background variation to look for objs.
              Default is 3.5 (times SkySigma). Decrease if center positions
              aren't being found accurately. Increase for crowded fields to
              decrease computation time.

    """

    # Get image FWHMs
    fwhm = np.empty(len(fnlist))
    firstimage = FPImage(fnlist[0])
    toggle = firstimage.fwhm
    axcen = firstimage.axcen
    aycen = firstimage.aycen
    arad = firstimage.arad
    firstimage.close()
    if axcen is None:
        print "Error! Images have not yet been aperture-masked! Do this first!"
        crash()
    if toggle is None:
        print "Warning! FWHMs have not been measured!"
        print "Assuming 5 pixel FWHM for all images."
        for i in range(len(fnlist)):
            fwhm[i] = 5
    else:
        for i in range(len(fnlist)):
            image = FPImage(fnlist[i])
            fwhm[i] = image.fwhm
            image.close()

    # Get sky background levels
    skyavg = np.empty(len(fnlist))
    skysig = np.empty(len(fnlist))
    for i in range(len(fnlist)):
        image = FPImage(fnlist[i])
        skyavg[i], skysig[i], _skyvar = image.skybackground()
        image.close()

    # Identify the stars in each image
    xlists = []
    ylists = []
    print "Identifying stars in each image..."
    for i in range(len(fnlist)):
        xlists.append([])
        ylists.append([])
        image = FPImage(fnlist[i])
        axcen = image.axcen
        aycen = image.aycen
        arad = image.arad
        sources = daofind(image.inty-skyavg[i],
                          fwhm=fwhm[i],
                          threshold=thresh*skysig[i]).as_array()
        for j in range(len(sources)):
            # If the source is not near the center or edge
            centermask = ((sources[j][1]-axcen)**2 +
                          (sources[j][2]-aycen)**2 > (0.05*arad)**2)
            edgemask = ((sources[j][1]-axcen)**2 +
                        (sources[j][2]-aycen)**2 < (0.95*arad)**2)
            if np.logical_and(centermask, edgemask):
                xlists[i].append(sources[j][1])
                ylists[i].append(sources[j][2])
        image.close()

    # Match objects between fields
    print "Matching objects between images..."
    xcoo = []
    ycoo = []
    for i in range(len(xlists[0])):
        # For each object in the first image
        accept = True
        for j in range(1, len(fnlist)):
            # For each other image
            dist2 = ((np.array(xlists[j])-xlists[0][i])**2 +
                     (np.array(ylists[j])-ylists[0][i])**2)
            if (min(dist2) > tolerance**2):
                accept = False
                break
        if accept:
            # We found an object at that position in every image
            xcoo.append(xlists[0][i])
            ycoo.append(ylists[0][i])

    # Create coordinate arrays for the photometry and shifting
    x = np.zeros((len(fnlist), len(xcoo)))
    y = np.zeros_like(x)
    for i in range(len(xcoo)):
        # For every object found in the first image
        for j in range(len(fnlist)):
            # Find that object in every image
            dist2 = ((np.array(xlists[j])-xcoo[i])**2 +
                     (np.array(ylists[j])-ycoo[i])**2)
            index = np.argmin(dist2)
            x[j, i] = xlists[j][index]
            y[j, i] = ylists[j][index]

    # Do aperture photometry on the matched objects
    print "Performing photometry on matched stars..."
    counts = np.zeros_like(x)
    dcounts = np.zeros_like(x)
    for i in range(len(fnlist)):
        image = FPImage(fnlist[i])
        apertures = CircularAperture((x[i], y[i]), r=2*fwhm[i])
        annuli = CircularAnnulus((x[i], y[i]), r_in=3*fwhm[i], r_out=4*fwhm[i])
        phot_table = aperture_photometry(image.inty,
                                         apertures, error=np.sqrt(image.vari))
        sky_phot_table = aperture_photometry(image.inty, annuli,
                                             error=np.sqrt(image.vari))
        counts[i] = phot_table["aperture_sum"] / apertures.area()
        counts[i] -= sky_phot_table["aperture_sum"] / annuli.area()
        counts[i] *= apertures.area()
        dcounts[i] = phot_table["aperture_sum_err"] / apertures.area()
        image.close()

    # Calculate the shifts and normalizations
    norm, dnorm = calc_norm(counts, dcounts)
    for i in range(x.shape[1]):
        x[:, i] = -(x[:, i] - x[0, i])
        y[:, i] = -(y[:, i] - y[0, i])
    xshifts = np.average(x, axis=1)
    yshifts = np.average(y, axis=1)

    # Normalize the images and put shifts in the image headers
    for i in range(len(fnlist)):
        image = FPImage(fnlist[i], update=True)
        image.phottog = "True"
        image.dnorm = dnorm[i]
        image.inty /= norm[i]
        image.vari = image.vari/norm[i]**2
        image.xshift = xshifts[i]
        image.yshift = yshifts[i]
        image.close()

    return
Ejemplo n.º 37
0
def tso_aperture_photometry(datamodel, xcenter, ycenter, radius, radius_inner,
                            radius_outer):
    """
    Create a photometric catalog for NIRCam TSO imaging observations.

    Parameters
    ----------
    datamodel : `CubeModel`
        The input `CubeModel` of a NIRCam TSO imaging observation.

    xcenter, ycenter : float
        The ``x`` and ``y`` center of the aperture.

    radius : float
        The radius (in pixels) of the circular aperture.

    radius_inner, radius_outer : float
        The inner and outer radii (in pixels) of the circular-annulus
        aperture, used for local background estimation.

    Returns
    -------
    catalog : `~astropy.table.QTable`
        An astropy QTable (Quantity Table) containing the source
        photometry.
    """

    if not isinstance(datamodel, CubeModel):
        raise ValueError('The input data model must be a CubeModel.')

    # For the SUB64P subarray with the WLP8 pupil, the circular aperture
    # extends beyond the image and the circular annulus does not have any
    # overlap with the image.  In that case, we simply sum all values
    # in the array and skip the background subtraction.
    sub64p_wlp8 = False
    if (datamodel.meta.instrument.pupil == 'WLP8' and
            datamodel.meta.subarray.name == 'SUB64P'):
        sub64p_wlp8 = True

    if not sub64p_wlp8:
        phot_aper = CircularAperture((xcenter, ycenter), r=radius)
        bkg_aper = CircularAnnulus((xcenter, ycenter), r_in=radius_inner,
                                   r_out=radius_outer)

    aperture_sum = []
    aperture_sum_err = []
    annulus_sum = []
    annulus_sum_err = []

    nimg = datamodel.data.shape[0]

    if sub64p_wlp8:
        info = ('Photometry measured as the sum of all values in the '
               'subarray.  No background subtraction was performed.')

        for i in np.arange(nimg):
            aperture_sum.append(np.sum(datamodel.data[i, :, :]))
            aperture_sum_err.append(
                np.sqrt(np.sum(datamodel.err[i, :, :]**2)))
    else:
        info = ('Photometry measured in a circular aperture of r={0} '
                'pixels.  Background calculated as the mean in a '
                'circular annulus with r_inner={1} pixels and '
                'r_outer={2} pixels.'.format(radius, radius_inner,
                                                radius_outer))
        for i in np.arange(nimg):
            aper_sum, aper_sum_err = phot_aper.do_photometry(
                datamodel.data[i, :, :], error=datamodel.err[i, :, :])
            ann_sum, ann_sum_err = bkg_aper.do_photometry(
                datamodel.data[i, :, :], error=datamodel.err[i, :, :])

            aperture_sum.append(aper_sum[0])
            aperture_sum_err.append(aper_sum_err[0])
            annulus_sum.append(ann_sum[0])
            annulus_sum_err.append(ann_sum_err[0])

    aperture_sum = np.array(aperture_sum)
    aperture_sum_err = np.array(aperture_sum_err)
    annulus_sum = np.array(annulus_sum)
    annulus_sum_err = np.array(annulus_sum_err)

    # construct metadata for output table
    meta = OrderedDict()
    meta['instrument'] = datamodel.meta.instrument.name
    meta['detector'] = datamodel.meta.instrument.detector
    meta['channel'] = datamodel.meta.instrument.channel
    meta['subarray'] = datamodel.meta.subarray.name
    meta['filter'] = datamodel.meta.instrument.filter
    meta['pupil'] = datamodel.meta.instrument.pupil
    meta['target_name'] = datamodel.meta.target.catalog_name
    meta['xcenter'] = xcenter
    meta['ycenter'] = ycenter
    ra_icrs, dec_icrs = datamodel.meta.wcs(xcenter, ycenter)
    meta['ra_icrs'] = ra_icrs
    meta['dec_icrs'] = dec_icrs
    meta['apertures'] = info

    # initialize the output table
    tbl = QTable(meta=meta)

    if hasattr(datamodel, 'int_times') and datamodel.int_times is not None:
        nrows = len(datamodel.int_times)
    else:
        nrows = 0
    if nrows == 0:
        log.warning("There is no INT_TIMES table in the input file.")

    if nrows > 0:
        shape = datamodel.data.shape
        if len(shape) == 2:
            num_integ = 1
        else:                                   # len(shape) == 3
            num_integ = shape[0]
        int_start = datamodel.meta.exposure.integration_start
        if int_start is None:
            int_start = 1
            log.warning("INTSTART not found; assuming a value of %d",
                        int_start)

        # Columns of integration numbers & times of integration from the
        # INT_TIMES table.
        int_num = datamodel.int_times['integration_number']
        mid_utc = datamodel.int_times['int_mid_MJD_UTC']
        offset = int_start - int_num[0]                 # both are one-indexed
        if offset < 0:
            log.warning("Range of integration numbers in science data extends "
                        "outside the range in INT_TIMES table.")
            log.warning("Can't use INT_TIMES table.")
            del int_num, mid_utc
            nrows = 0                   # flag as bad
        else:
            log.debug("Times are from the INT_TIMES table.")
            time_arr = mid_utc[offset: offset + num_integ]
            int_times = Time(time_arr, format='mjd', scale='utc')
    else:
        log.debug("Times were computed from EXPSTART and TGROUP.")

        dt = (datamodel.meta.exposure.group_time *
              (datamodel.meta.exposure.ngroups + 1))
        dt_arr = (np.arange(1, 1 + datamodel.meta.exposure.nints) *
                  dt - (dt / 2.))
        int_dt = TimeDelta(dt_arr, format='sec')
        int_times = (Time(datamodel.meta.exposure.start_time, format='mjd') +
                     int_dt)

    tbl['MJD'] = int_times.mjd

    tbl['aperture_sum'] = aperture_sum
    tbl['aperture_sum_err'] = aperture_sum_err

    if not sub64p_wlp8:
        tbl['annulus_sum'] = annulus_sum
        tbl['annulus_sum_err'] = annulus_sum_err

        annulus_mean = annulus_sum / bkg_aper.area()
        annulus_mean_err = annulus_sum_err / bkg_aper.area()
        tbl['annulus_mean'] = annulus_mean
        tbl['annulus_mean_err'] = annulus_mean_err

        aperture_bkg = annulus_mean * phot_aper.area()
        aperture_bkg_err = annulus_mean_err * phot_aper.area()
        tbl['aperture_bkg'] = aperture_bkg
        tbl['aperture_bkg_err'] = aperture_bkg_err

        net_aperture_sum = aperture_sum - aperture_bkg
        net_aperture_sum_err = np.sqrt(aperture_sum_err ** 2 +
                                       aperture_bkg_err ** 2)
        tbl['net_aperture_sum'] = net_aperture_sum
        tbl['net_aperture_sum_err'] = net_aperture_sum_err
    else:
        colnames = ['annulus_sum', 'annulus_sum_err', 'annulus_mean',
                    'annulus_mean_err', 'aperture_bkg', 'aperture_bkg_err']
        for col in colnames:
            tbl[col] = np.full(nimg, np.nan)

        tbl['net_aperture_sum'] = aperture_sum
        tbl['net_aperture_sum_err'] = aperture_sum_err

    return tbl
			xcenterOffset = center[0] - margins
			#xcenterOffset = xcenterInt - margins
			
			ycenterInt = int(center[1])
			ycenterOffset = center[1] - margins
			#ycenterOffset = ycenterInt - margins
			
			if (ycenterOffset<0) or (xcenterOffset<0): continue
			zoomImageData = window.data[ycenterInt-margins:ycenterInt+margins, xcenterInt-margins:xcenterInt+margins]
			(xcen, ycen) = photutils.morphology.centroid_2dg(zoomImageData, error=None, mask=None)
			
			xcen+= xcenterOffset
			ycen+= ycenterOffset
			s.setLatestPosition(trueFrameNumber, (xcen, ycen))
			apertures = CircularAperture((xcen, ycen), r=apertureRadius)
			annulus_apertures = CircularAnnulus((xcen, ycen), r_in=innerSkyRadius, r_out=outerSkyRadius)
			
			# Draw the re-positioned apertures
			xll = window.xll/window.xbin - xmin
			yll = window.yll/window.ybin - ymin
			if arg.preview:
				ppgplot.pgslct(bitmapView)
				plotx= xcen + xll
				ploty= ycen + yll
				#print xll, yll, center, xcen, ycen
				ppgplot.pgcirc(plotx, ploty, apertureRadius)
				ppgplot.pgcirc(plotx, ploty, innerSkyRadius)
				ppgplot.pgcirc(plotx, ploty, outerSkyRadius)
				ppgplot.pgptxt(plotx-10, ploty-10, 0, 0, str(index)) 
				
			
Ejemplo n.º 39
0
def photom_av(ima, pos, radius, r_in=False, r_out=False, mode='median'):
    '''
    Aperture photometry in an aperture located at pixel coordinates 
    pos = ( (x0, y0), (x1, y1), ... ) with a radius=radius.
    When r_in and r_out are given, background is estimated in CircularAnnulus and subtracted.
    
    mode refers to how the background is estimated within the circlar annulus.
    Can be 'median' or 'mean'
    
    Photometry is calculating by median averaging the pixels within the aperture and 
    multiplying by the number of pixels in the aperture (including fractions of pixels).

    '''
    # Setting up the mask 
    if hasattr(ima, 'mask'):
      if ima.mask.size == 1:
	mask = np.zeros(ima.shape, dtype=np.bool) | ima.mask
      else:
        mask = ima.mask.copy()
    else:
        mask = np.zeros(ima.shape, dtype=np.bool)
        
        
    ### Performing the actual photometry - identical for each method
    # Median averaging of flux in aperture
    # Setting up the aperture 
    apertures = CircularAperture(pos, r = radius) 
    ap_mask = apertures.to_mask(method='center')
    # Setting up arrays to store data
    nflx = len(ap_mask)
    flx = np.zeros(nflx, dtype=np.float)
    flux_max = np.zeros(nflx, dtype=np.float)
    flux_min = np.zeros(nflx, dtype=np.float)
    # Median averaging of flux
    for i, am in enumerate(ap_mask):
      fluxmask = ~mask & am.to_image(shape=mask.shape).astype(np.bool)
      flx[i] = np.median(ima[fluxmask])
      flux_max[i] = np.max(ima[fluxmask])
      flux_min[i] = np.min(ima[fluxmask])
      
      
      
      
    # Aperture photometry on mask to see how many masked pixels are in the 
    # aperture
    apm       = aperture_photometry(mask.astype(int), apertures)
    # Number of unmasked pixels in aperture
    ap_area   = Column(name = 'area_aper',
		       data=apertures.area() - apm['aperture_sum'].data)
    
    # Flux in aperture using median av flux and fractional no. pixels in aperture
    flux_init = flx*ap_area
    

    ### Two different modes for analysing the background
    if ( r_in and r_out and mode in ('mean', 'median') ):
      
      ### This stuff is the same regardless of method
      # Setting up the annulus
      anulus_apertures = CircularAnnulus(pos, r_in=r_in, r_out=r_out)
      # Performing annulus photometry on the mask
      bkgm = aperture_photometry(mask.astype(int), anulus_apertures)
      # Number of masked pixels in bkg
      mbkg_area = Column(name = 'bpix_bkg',
			 data=bkgm['aperture_sum'])  
      # Number of non-masked pixels in aperture and bkg        
      bkg_area  = Column(name = 'area_bkg',
			 data=anulus_apertures.area() - bkgm['aperture_sum'])
      
      
      ### This stuff is specific to the mean
      if mode == 'mean':
	# Perform the annulus photometry on the image
	bkg  = aperture_photometry(ima, anulus_apertures, mask=mask)
        # Average bkg where this divides by only number of NONMASKED pixels
        # as the aperture photometry ignores the masked pixels
        bkga = Column(name='background',
		      data=bkg['aperture_sum']/bkg_area)
        # Bkg subtracted flux
        flux = flux_init - bkga*ap_area
        # Adding that data
        ap.add_column(bkga)
        
        
      elif mode == 'median':
	# Number of pixels in the annulus, a different method
	aperture_mask = anulus_apertures.to_mask(method='center')
	nbkg = len(aperture_mask)
	
	# Background mask
	bkgm = np.zeros(nbkg, dtype=np.float)
	
	# Median averaging
	for i, am in enumerate(aperture_mask):
	  bmask = ~mask & am.to_image(shape=mask.shape).astype(np.bool)
	  bkgm[i] = np.median(ima[bmask])
		
	flux = flux_init - bkgm*ap_area
	bkgm = Column(name = 'background', data = bkgm)

        
    return flux, apm, flx, ap_area, flux_max, flux_min #flux, no.masked pixels in ap, median av flux
Ejemplo n.º 40
0
def photom(ima, pos, radius, r_in=None, r_out=None, method='median'):
    '''
    Aperture photometry in an aperture located at pixel coordinates 
    pos = ( (x0, y0), (x1, y1), ... ) with a radius=radius.
    When r_in and r_out are given, background is estimated in CircularAnnulus and subtracted.
    
    method refers to how the background is estimated within the circlar annulus.
    Can be 'median' or 'mean' or 'mode'

    '''
    
    ima_local = np.ma.asanyarray(ima.copy())
    ima_local.fill_value = np.nan
    mask_ = ima_local.mask
    ima_  = ima_local.filled()
    
    ### Do photometry - identical for each method
    apertures = CircularAperture(pos, r = radius)
    ap        = aperture_photometry(ima_, apertures, 
                                    mask=mask_, method='exact')
    # Aperture photometry on mask to estimate # of masked pixels in aperture
    apm       = aperture_photometry(mask_.astype(int), apertures,
                                    method='exact')
    ap.add_columns( [apertures.area()-apm['aperture_sum'], apm['aperture_sum']],
                   names=['aperture_area', 'aperture_badpix'])
    ap.add_column(ap['aperture_sum'], index=3, name='Flux')

    if ( r_in == None or r_out == None or not method in ('mean', 'median', 'mode') ): 
      # Quit here if background correction is not requested
      return ap

    annulus_apertures = CircularAnnulus(pos, r_in=r_in, r_out=r_out)
    annulus_masks = annulus_apertures.to_mask(method='center')
    bg_values = []
    for annulus_mask in annulus_masks:
      bg_ima = annulus_mask.cutout(ima_)
      bg_mask = annulus_mask.cutout(mask_.astype(np.int))
      bg_ima = np.ma.array(bg_ima, mask= bg_mask.astype(np.bool) | ~annulus_mask.data.astype(np.bool))
      
      if method == 'mean': bg_val = bg_ima.mean()
      elif method == 'median': bg_val = np.ma.median(bg_ima)
      elif method == 'mode': 
        kernel = gaussian_kde(bg_ima.data[~bg_ima.mask], bw_method='silverman')
        mode = bg_ima.mean()
        std  = bg_ima.std()
        
        mode = minimize_scalar(lambda x: -kernel(x), bounds=(mode-3*std, mode+3*std),
                               method='bounded')
        bg_val=mode.x[0]
        
        if False:
          median = np.ma.median(bg_ima)
          h, b = np.histogram(bg_ima.data[~bg_ima.mask], bins=15, normed=True)
          bc = 0.5*(b[1:]+ b[:-1])
          plt.figure(33); plt.clf(); plt.ioff()
          fig, (ax0,ax1) = plt.subplots(ncols=2, nrows=1, num=33)
          ax0.plot(bc, h, 'x')
          x = np.linspace(bc.min(), bc.max(), 100)
          ax0.plot(x, kernel(x))
          ax0.vlines(mode.x, ax0.get_ylim()[0], ax0.get_ylim()[1])
          ax0.vlines(median, ax0.get_ylim()[0], ax0.get_ylim()[1])
          ax1.imshow(bg_ima)
          plt.show()
        
        
      bg_values.append(bg_val)
    ap.add_column(Column(data=bg_values, name = 'background'))  
    ap['Flux'] = ap['Flux'] - ap['aperture_area']*ap['background']
    return ap, bg_ima
        lf, rt = xStar - 10, xStar + 10
        bt, tp = yStar - 10, yStar + 10
        patch = stokesI.arr[lf:rt, bt:tp]
        saturatedStars.append(np.sum(np.logical_or(patch > 9e3, patch < -100)) > 1)
    
    # Check for stars near the edge of the image
    ny, nx    = stokesI.arr.shape
    edgeStars = np.logical_or(
                np.logical_or(xStars < 40, xStars > (nx - 40)),
                np.logical_or(yStars < 40, yStars > (ny - 40)))
    
    # Now let's do aperture photometry on the remaining sources in the image
    # 1. Setup the apertures
    sourcePos = [xStars, yStars]
    apertures = CircularAperture(sourcePos, r = 6.0)
    annulus_apertures = CircularAnnulus(sourcePos, r_in=12., r_out=14.)
    # 2. Perform the basic photometry
    rawflux_table = aperture_photometry(stokesI.arr, apertures)
    bkgflux_table = aperture_photometry(stokesI.arr, annulus_apertures)
    phot_table = hstack([rawflux_table, bkgflux_table], table_names=['raw', 'bkg'])
    
    # 3. Compute background contribution and subtract from raw photometry
    bkg_mean = phot_table['aperture_sum_bkg'] / annulus_apertures.area()
    bkg_sum = bkg_mean * apertures.area()
    final_sum = phot_table['aperture_sum_raw'] - bkg_sum
    phot_table['residual_aperture_sum'] = final_sum

    # Compute the signal-to-noise ratio and find the stars with SNR < 3.0
    SNR          = final_sum/bkg_sum
    bkgDominated = SNR < 1.0
    
Ejemplo n.º 42
0
Archivo: ifu.py Proyecto: mcara/jwst
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 pixel.

    net : ndarray, 1-D
        The count rate (or flux) minus the background at each pixel.

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

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

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

    data = input_model.data
    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 net, background, npixels, and dq arrays
    # no matter what.  We may need to divide by npixels, so the default
    # is 1 rather than 0.
    net = np.zeros(shape[0], dtype=np.float64)
    background = np.zeros(shape[0], dtype=np.float64)
    npixels = np.ones(shape[0], dtype=np.float64)

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

    x_center = extract_params['x_center']
    y_center = extract_params['y_center']
    if x_center is None:
        x_center = float(shape[2]) / 2.
    else:
        x_center = float(x_center)
    if y_center is None:
        y_center = float(shape[1]) / 2.
    else:
        y_center = float(y_center)

    method = extract_params['method']
    # subpixels is only needed if method = 'subpixel'.
    subpixels = extract_params['subpixels']

    subtract_background = extract_params['subtract_background']
    smaller_axis = float(min(shape[1], shape[2]))       # for defaults
    radius = None
    inner_bkg = None
    outer_bkg = None

    if source_type == 'point':
        radius = extract_params['radius']
        if radius is None:
            radius = smaller_axis / 4.
        if subtract_background:
            inner_bkg = extract_params['inner_bkg']
            if inner_bkg is None:
                inner_bkg = radius
            outer_bkg = extract_params['outer_bkg']
            if outer_bkg is None:
                outer_bkg = min(inner_bkg * math.sqrt(2.),
                                smaller_axis / 2. - 1.)
            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
        width = None
        height = None
        theta = None
    else:
        width = extract_params['width']
        if width is None:
            width = smaller_axis / 2.
        height = extract_params['height']
        if height is None:
            height = smaller_axis / 2.
        theta = extract_params['theta'] * math.pi / 180.
        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("  radius = %s", str(radius))
        log.debug("  subtract_background = %s", str(subtract_background))
        log.debug("  inner_bkg = %s", str(inner_bkg))
        log.debug("  outer_bkg = %s", str(outer_bkg))
        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(extract_params['theta']))
        log.debug("  subtract_background = %s", str(subtract_background))
        log.debug("  method = %s", method)
        if method == "subpixel":
            log.debug("  subpixels = %s", str(subpixels))

    # Check for out of bounds.
    # The problem with having the background aperture extend beyond the
    # image is that the normalization would not account for the resulting
    # decrease in the area of the annulus, so the background subtraction
    # would be systematically low.
    outside = False
    f_nx = float(shape[2])
    f_ny = float(shape[1])
    if x_center < 0. or x_center >= f_nx - 1. or \
       y_center < 0. or y_center >= f_ny - 1.:
        outside = True
        log.error("Target location is outside the image.")
    if subtract_background and \
       (x_center - outer_bkg < -0.5 or x_center + outer_bkg > f_nx - 0.5 or
        y_center - outer_bkg < -0.5 or y_center + outer_bkg > f_ny - 0.5):
            outside = True
            log.error("Background region extends outside the image.")

    if outside:
        (ra, dec) = (0., 0.)
        wavelength = np.zeros(shape[0], dtype=np.float64)
        dq[:] = dqflags.pixel['DO_NOT_USE']
        return (ra, dec, wavelength, net, background, npixels, dq)  # all bad

    x0 = float(shape[2]) / 2.
    y0 = float(shape[1]) / 2.
    (ra, dec, wavelength) = get_coordinates(input_model, x0, y0)

    position = (x_center, y_center)
    if source_type == 'point':
        aperture = CircularAperture(position, r=radius)
        if subtract_background:
            annulus = CircularAnnulus(position,
                                      r_in=inner_bkg, r_out=outer_bkg)
            normalization = aperture.area() / annulus.area()
    else:
        aperture = RectangularAperture(position, width, height, theta)
        # No background is computed for an extended source.

    npixels[:] = aperture.area()
    for k in range(shape[0]):
        phot_table = aperture_photometry(data[k, :, :], aperture,
                                         method=method, subpixels=subpixels)
        net[k] = float(phot_table['aperture_sum'][0])
        if subtract_background:
            bkg_table = aperture_photometry(data[k, :, :], annulus,
                                            method=method, subpixels=subpixels)
            background[k] = float(bkg_table['aperture_sum'][0])
            net[k] = net[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, net, background, npixels, dq) = \
                nans_in_wavelength(wavelength, net, background, npixels, dq)

    return (ra, dec, wavelength, net, background, npixels, dq)
Ejemplo n.º 43
0
    follow the algorithm outlined in 
    http://photutils.readthedocs.org/en/latest/photutils/aperture.html#global-background-subtraction
    error in photometry is assumed as Poissonian -- sqrt(N)
    but smooth background error not included for now
    """
for eachFile in imFiles:
    print('Prcoessing %s ...' %(eachFile))
    
    try: 
        hdu = pyfits.open(eachFile)
        im = hdu[0].data
    except: print('File could not be opened: %s' %(eachFile))

    # create aperture and annulus objects
    apertures = CircularAperture(coords, r=aper_size)
    annulus_apertures = CircularAnnulus(coords, r_in=annulus, r_out=dannulus)
    
    npix_src, npix_bkg = apertures.area(),  annulus_apertures.area()
    
    # calculate the object and annulus flux
    data_error = np.sqrt(im)
    rawflux_table = aperture_photometry(im, apertures, error=data_error)
    bkgflux_table = aperture_photometry(im, annulus_apertures, error=data_error)
    # stack the two tables into one
    phot_table = hstack([rawflux_table, bkgflux_table], table_names=['raw', 'bkg'])

    # calculate bkg mean & normalize by area
    bkg_mean = phot_table['aperture_sum_bkg'] / npix_bkg

    # final photometric counts -- in ADUs
    Nsrc = phot_table['aperture_sum_raw'] - bkg_mean * npix_src
Ejemplo n.º 44
0
    def do_detection(self):
        """Flag outlier pixels in DQ of input images."""
        self.build_suffix(**self.outlierpars)
        self._convert_inputs()

        pars = self.outlierpars
        save_intermediate_results = pars['save_intermediate_results']

        # Start by performing initial TSO Photometry on stack of DataModels
        # TODO:  need information about the actual source position in
        # TSO imaging mode (for all subarrays).
        # Meanwhile, this is a placeholder representing the geometric
        # center of the image.
        nints, ny, nx = self.inputs.data.shape
        xcenter = (ny - 1) / 2.
        ycenter = (ny - 1) / 2.

        # all radii are in pixel units
        if self.inputs.meta.instrument.pupil == 'WLP8':
            radius = 50
            radius_inner = 60
            radius_outer = 70
        else:
            radius = 3
            radius_inner = 4
            radius_outer = 5

        apertures = CircularAperture((xcenter, ycenter), r=radius)
        aperture_mask = apertures.to_mask(method='center')[0]
        # This mask has 1 for mask region, 0 for outside of mask
        median_mask = aperture_mask.to_image((ny, nx))
        inv_median_mask = np.abs(median_mask - 1)
        # Perform photometry
        catalog = tso_aperture_photometry(self.inputs, xcenter, ycenter,
                                          radius, radius_inner,
                                          radius_outer)

        # Extract net photometry for the source
        # This will be the value used for scaling the median image within
        # the aperture region
        phot_values = catalog['net_aperture_sum']

        # Convert CubeModel into ModelContainer of 2-D DataModels
        for image in self.input_models:
            image.wht = resample_utils.build_driz_weight(
                image,
                weight_type='exptime',
                good_bits=pars['good_bits']
            )

        # Initialize intermediate products used in the outlier detection
        input_shape = self.input_models[0].data.shape
        median_model = datamodels.ImageModel(init=input_shape)
        median_model.meta = deepcopy(self.input_models[0].meta)
        base_filename = self.inputs.meta.filename
        median_model.meta.filename = self.make_output_path(
            basepath=base_filename, suffix='median'
        )

        # Perform median combination on set of drizzled mosaics
        median_model.data = self.create_median(self.input_models)
        aper2 = CircularAnnulus((xcenter, ycenter), r_in=radius_inner,
                                r_out=radius_outer)

        tbl1 = aperture_photometry(median_model.data, apertures,
                                   error=median_model.data * 0.0 + 1.0)
        tbl2 = aperture_photometry(median_model.data, aper2,
                                   error=median_model.data * 0.0 + 1.0)

        aperture_sum = u.Quantity(tbl1['aperture_sum'][0])
        annulus_sum = u.Quantity(tbl2['aperture_sum'][0])
        annulus_mean = annulus_sum / aper2.area()
        aperture_bkg = annulus_mean * apertures.area()
        median_phot_value = aperture_sum - aperture_bkg

        if save_intermediate_results:
            log.info("Writing out MEDIAN image to: {}".format(
                     median_model.meta.filename))
            median_model.save(median_model.meta.filename)

        # Scale the median image by the initial photometry (only in aperture)
        # to create equivalent of 'blot' images
        # Area outside of aperture in median will remain unchanged
        blot_models = datamodels.ModelContainer()
        for i in range(nints):
            scale_factor = float(phot_values[i] / median_phot_value)
            scaled_image = datamodels.ImageModel(init=median_model.data.shape)
            scaled_image.meta = deepcopy(median_model.meta)
            scaled_data = (median_model.data * (scale_factor * median_mask) + (
                           median_model.data * inv_median_mask))
            scaled_image.data = scaled_data
            blot_models.append(scaled_image)

        if save_intermediate_results:
            log.info("Writing out Scaled Median images...")

            def make_output_path(ignored, idx=None):
                output_path = self.make_output_path(
                    basepath=base_filename, suffix='blot', idx=idx,
                    component_format='_{asn_id}_{idx}'
                )
                return output_path

            blot_models.save(make_output_path)

        # Perform outlier detection using statistical comparisons between
        # each original input image and its blotted version of the median image
        self.detect_outliers(blot_models)

        # clean-up (just to be explicit about being finished
        # with these results)
        del median_model, blot_models
Ejemplo n.º 45
0
def time_series(xcenter, ycenter, filenames, r = None, r_in = None, r_out = None, rs_in = None, rs_out = None, flat_name = False, w = None, h = None, w_in = None, w_out = None, h_out = None, ws_in = None, ws_out = None, hs_out = None, red = False, red2 = False, bg_xcen = None, bg_ycen = None, mode = "astropy", src_shape = "Circ", bkg_shape = "Circ", average = "med"):

    flux_table = Table(names = ('raw_flux', 'bkg_flux', 'res_flux', 'time'))
    
    for i, hdu in enumerate(filenames):
        test_im = test_image(filename = hdu, r = red, r2 = red2, f_name = flat_name)
        image2d, time, header, mask = test_im[0], test_im[1], test_im[2], test_im[3]
        ap_phot = photometry(image2d, xcenter, ycenter, mask, index = i, shape = src_shape, rad = r, r_in = rs_in, r_out = rs_out, ht = h, wid = w, w_in = ws_in, w_out = ws_out, h_out = hs_out)
        raw_flux = ap_phot[0]
        source_ap = ap_phot[1]
       
        
        if mode == "astropy":
            if bkg_shape == "Circ":
                bkg_ap = CircularAnnulus((xcenter[i], ycenter[i]), r_in = r_in, r_out = r_out)
                bkg = aperture_photometry(image2d, bkg_ap, mask = mask)
                bkg_mean = bkg['aperture_sum']/bkg_ap.area()
            
            elif bkg_shape == "Rect":
                bkg_ap = photometry(image2d, bg_xcen, bg_ycen, mask, index = i, shape = bkg_shape, ht = h, wid = w)[1]
                bkg = aperture_photometry(image2d, bkg_ap, mask = mask)
                bkg_mean = bkg['aperture_sum']/bkg_ap.area()
            
            elif bkg_shape == "RectAnn":
                bkg_ap = RectangularAnnulus((xcenter[i], ycenter[i]), w_in = w_in, w_out = w_out, h_out = h_out, 
                                                   theta = 0.0)
                bkg = aperture_photometry(image2d, bkg_ap, mask = mask)
                bkg_mean = bkg['aperture_sum']/bkg_ap.area()
                
            else:
                warnings.warn("Not a recognized astropy shape")
            
            bkg_flux = bkg_mean*source_ap.area()
            res_flux = raw_flux - bkg_flux
                

        elif mode == "shapes":
            y, x = np.mgrid[:image2d.shape[0], :image2d.shape[1]]
            if bkg_shape == "Circ":
                bkg_pts = ((((x - xcenter[i])**2 + (y - ycenter[i])**2) > (r_in)**2) & 
                               (((x - xcenter[i])**2 + (y -ycenter[i])**2) < (r_out)**2))
            elif bkg_shape == "CIS":
                bkg_pts = ((((x - xcenter[i])**2 + (y - ycenter[i])**2) > (r_in)**2) & 
                               ((np.abs(x - xcenter[i]) < r_out) & (np.abs(y -ycenter[i]) < r_out)))
            else:
                warnings.warn("Not a recognized shape")

            if average == "med":
                bkg_med = np.nanmedian(image2d[bkg_pts])
            elif average == "avg":
                bkg_med = np.nanmean(image2d[bkg_pts])
            elif average =="mad":
                ad = np.abs(image2d[bkg_pts]-np.nanmedian(image2d[bkg_pts]))
                mad = np.nanmedian(ad)
                keep_pts = (np.abs(image2d-np.nanmedian(image2d[bkg_pts]))<(5*mad)) & bkg_pts
                bkg_med = np.nanmean(image2d[keep_pts])
            else:
                warnings.warn("Not a recognized average")

            bkg_flux = bkg_med*(np.pi*(r**2))
            res_flux = raw_flux - bkg_flux
            
        elif mode == "col_col":
            new_im = col_col(image2d, mask, xcenter[i], ycenter[i], r, box = 150)
            bkg_flux = 0
            res_flux = photometry(new_im, xcenter, ycenter, mask, index = i, shape = 'Circ', rad = r)[0]
            
        elif mode == "row_row":
            new_im = row_row(image2d, mask, xcenter[i], ycenter[i], r, box = 150)
            bkg_flux = 0
            res_flux = photometry(new_im, xcenter, ycenter, mask, index = i, shape = 'Circ', rad = r)[0]
            
        else:
            raise Warning("Not a recognized mode")
        
        flux_table.add_row([raw_flux, bkg_flux, res_flux, time])

    return flux_table
Ejemplo n.º 46
0
txdump_out = open('phot_test_g.txdump','w+')
iraf.ptools.txdump(textfiles='mag_test_g.dat', fields="id,mag,merr,sum,msky,stdev,rapert,xcen,ycen,ifilter,xairmass,image", expr='yes', headers='no', Stdout=txdump_out)
txdump_out.close()

g_iraf, ge_iraf, gf_iraf, gsky_iraf = np.loadtxt('phot_test_g.txdump', usecols=(1,2,3,4), unpack=True)
i_iraf, ie_iraf, if_iraf, isky_iraf = np.loadtxt('phot_test_i.txdump', usecols=(1,2,3,4), unpack=True)

# now try python
x, y = np.loadtxt(coords_file, usecols=(0,1), unpack=True)
positions = np.array(zip(x,y))

hdu_g = fits.open(fits_g)
hdu_i = fits.open(fits_i)

apertures = CircularAperture(positions, r=8.)
annulus_apertures = CircularAnnulus(positions, r_in=10., r_out=14.)
print apertures.area()
ap_mask = apertures.to_mask(method='subpixel', subpixels=7)
dummy = np.ones_like(hdu_g[0].data)
ann_mask = annulus_apertures.to_mask(method='center')
ap_g = [m.apply(hdu_g[0].data) for i,m in enumerate(ap_mask)]
ap_i = [m.apply(hdu_i[0].data) for i,m in enumerate(ap_mask)]
area_g = [np.sum(m.apply(dummy)) for i,m in enumerate(ap_mask)]
area_i = [np.sum(m.apply(dummy)) for i,m in enumerate(ap_mask)]

print area_g, area_i
# plt.imshow(ap_g[0], interpolation='nearest')
# plt.show()
ann_g = [m.apply(hdu_g[0].data, fill_value=-999.) for i,m in enumerate(ann_mask)]
ann_i = [m.apply(hdu_i[0].data, fill_value=-999.) for i,m in enumerate(ann_mask)]
Ejemplo n.º 47
0
Archivo: ifu.py Proyecto: sosey/jwst
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
    -------
        (wavelength, net, background, dq)
    """

    data = input_model.data
    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 net, background, and dq arrays no matter what.
    net = np.zeros(shape[0], dtype=np.float64)
    background = np.zeros(shape[0], dtype=np.float64)
    dq = np.zeros(shape[0], dtype=np.int32)

    x_center = extract_params['x_center']
    y_center = extract_params['y_center']
    if x_center is None:
        x_center = float(shape[2]) / 2.
    else:
        x_center = float(x_center)
    if y_center is None:
        y_center = float(shape[1]) / 2.
    else:
        y_center = float(y_center)

    method = extract_params['method']
    # subpixels is only needed if method = 'subpixel'.
    subpixels = extract_params['subpixels']

    subtract_background = extract_params['subtract_background']
    smaller_axis = float(min(shape[1], shape[2]))       # for defaults
    if source_type == 'point':
        radius = extract_params['radius']
        if radius is None:
            radius = smaller_axis / 4.
        if subtract_background:
            inner_bkg = extract_params['inner_bkg']
            if inner_bkg is None:
                inner_bkg = radius
            outer_bkg = extract_params['outer_bkg']
            if outer_bkg is None:
                outer_bkg = min(inner_bkg * math.sqrt(2.),
                                smaller_axis / 2. - 1.)
        width = None
        height = None
        theta = None
    else:
        width = extract_params['width']
        if width is None:
            width = smaller_axis / 2.
        height = extract_params['height']
        if height is None:
            height = smaller_axis / 2.
        theta = extract_params['theta'] * math.pi / 180.
        radius = None
        inner_bkg = None
        outer_bkg = None

    if inner_bkg <= 0. or outer_bkg <= 0. or inner_bkg >= outer_bkg:
        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("  radius = %s", str(radius))
        log.debug("  subtract_background = %s", str(subtract_background))
        log.debug("  inner_bkg = %s", str(inner_bkg))
        log.debug("  outer_bkg = %s", str(outer_bkg))
        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(extract_params['theta']))
        log.debug("  subtract_background = %s", str(subtract_background))
        log.debug("  method = %s", method)
        if method == "subpixel":
            log.debug("  subpixels = %s", str(subpixels))

    # Check for out of bounds.
    # The problem with having the background aperture extend beyond the
    # image is that the normalization would not account for the resulting
    # decrease in the area of the annulus, so the background subtraction
    # would be systematically low.
    outside = False
    f_nx = float(shape[2])
    f_ny = float(shape[1])
    if x_center < 0. or x_center >= f_nx - 1. or \
       y_center < 0. or y_center >= f_ny - 1.:
        outside = True
        log.error("Target location is outside the image.")
    if subtract_background and \
       (x_center - outer_bkg < -0.5 or x_center + outer_bkg > f_nx - 0.5 or
        y_center - outer_bkg < -0.5 or y_center + outer_bkg > f_ny - 0.5):
            outside = True
            log.error("Background region extends outside the image.")

    if outside:
        wavelength = np.zeros(shape[0], dtype=np.float64)
        dq[:] = dqflags.pixel['DO_NOT_USE']
        return (wavelength, net, background, dq)        # all bad

    wcs = input_model.meta.wcs
    x_array = np.empty(shape[0], dtype=np.float64)
    x_array.fill(float(shape[2]) / 2.)
    y_array = np.empty(shape[0], dtype=np.float64)
    y_array.fill(float(shape[1]) / 2.)
    z_array = np.arange(shape[0], dtype=np.float64) # for wavelengths
    _, _, wavelength = wcs(x_array, y_array, z_array)

    position = (x_center, y_center)
    if source_type == 'point':
        aperture = CircularAperture(position, r=radius)
        if subtract_background:
            annulus = CircularAnnulus(position,
                                      r_in=inner_bkg, r_out=outer_bkg)
            normalization = aperture.area() / annulus.area()
    else:
        aperture = RectangularAperture(position, width, height, theta)
        # No background is computed for an extended source.

    for k in range(shape[0]):
        phot_table = aperture_photometry(data[k, :, :], aperture,
                                         method=method, subpixels=subpixels)
        net[k] = float(phot_table['aperture_sum'][0])
        if subtract_background:
            bkg_table = aperture_photometry(data[k, :, :], annulus,
                                            method=method, subpixels=subpixels)
            background[k] = float(bkg_table['aperture_sum'][0])
            net[k] = net[k] - background[k] * normalization

    return (wavelength, net, background, dq)
Ejemplo n.º 48
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 pixel.

    net : ndarray, 1-D
        The count rate (counts / s) minus the background at each pixel.

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

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

    data = input_model.data
    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 net, background, and dq arrays no matter what.
    net = np.zeros(shape[0], dtype=np.float64)
    background = np.zeros(shape[0], dtype=np.float64)

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

    x_center = extract_params['x_center']
    y_center = extract_params['y_center']
    if x_center is None:
        x_center = float(shape[2]) / 2.
    else:
        x_center = float(x_center)
    if y_center is None:
        y_center = float(shape[1]) / 2.
    else:
        y_center = float(y_center)

    method = extract_params['method']
    # subpixels is only needed if method = 'subpixel'.
    subpixels = extract_params['subpixels']

    subtract_background = extract_params['subtract_background']
    smaller_axis = float(min(shape[1], shape[2]))       # for defaults
    if source_type == 'point':
        radius = extract_params['radius']
        if radius is None:
            radius = smaller_axis / 4.
        if subtract_background:
            inner_bkg = extract_params['inner_bkg']
            if inner_bkg is None:
                inner_bkg = radius
            outer_bkg = extract_params['outer_bkg']
            if outer_bkg is None:
                outer_bkg = min(inner_bkg * math.sqrt(2.),
                                smaller_axis / 2. - 1.)
            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
        width = None
        height = None
        theta = None
    else:
        width = extract_params['width']
        if width is None:
            width = smaller_axis / 2.
        height = extract_params['height']
        if height is None:
            height = smaller_axis / 2.
        theta = extract_params['theta'] * math.pi / 180.
        radius = None
        subtract_background = False
        inner_bkg = None
        outer_bkg = None

    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("  radius = %s", str(radius))
        log.debug("  subtract_background = %s", str(subtract_background))
        log.debug("  inner_bkg = %s", str(inner_bkg))
        log.debug("  outer_bkg = %s", str(outer_bkg))
        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(extract_params['theta']))
        log.debug("  subtract_background = %s", str(subtract_background))
        log.debug("  method = %s", method)
        if method == "subpixel":
            log.debug("  subpixels = %s", str(subpixels))

    # Check for out of bounds.
    # The problem with having the background aperture extend beyond the
    # image is that the normalization would not account for the resulting
    # decrease in the area of the annulus, so the background subtraction
    # would be systematically low.
    outside = False
    f_nx = float(shape[2])
    f_ny = float(shape[1])
    if x_center < 0. or x_center >= f_nx - 1. or \
       y_center < 0. or y_center >= f_ny - 1.:
        outside = True
        log.error("Target location is outside the image.")
    if subtract_background and \
       (x_center - outer_bkg < -0.5 or x_center + outer_bkg > f_nx - 0.5 or
        y_center - outer_bkg < -0.5 or y_center + outer_bkg > f_ny - 0.5):
            outside = True
            log.error("Background region extends outside the image.")

    if outside:
        (ra, dec) = (0., 0.)
        wavelength = np.zeros(shape[0], dtype=np.float64)
        dq[:] = dqflags.pixel['DO_NOT_USE']
        return (ra, dec, wavelength, net, background, dq)       # all bad

    if hasattr(input_model.meta, 'wcs'):
        wcs = input_model.meta.wcs
    else:
        log.warning("WCS function not found in input.")
        wcs = None

    if wcs is not None:
        x_array = np.empty(shape[0], dtype=np.float64)
        x_array.fill(float(shape[2]) / 2.)
        y_array = np.empty(shape[0], dtype=np.float64)
        y_array.fill(float(shape[1]) / 2.)
        z_array = np.arange(shape[0], dtype=np.float64) # for wavelengths
        ra, dec, wavelength = wcs(x_array, y_array, z_array)
        nelem = len(wavelength)
        ra = ra[nelem // 2]
        dec = dec[nelem // 2]
    else:
        (ra, dec) = (0., 0.)
        wavelength = np.arange(1, shape[0] + 1, dtype=np.float64)

    position = (x_center, y_center)
    if source_type == 'point':
        aperture = CircularAperture(position, r=radius)
        if subtract_background:
            annulus = CircularAnnulus(position,
                                      r_in=inner_bkg, r_out=outer_bkg)
            normalization = aperture.area() / annulus.area()
    else:
        aperture = RectangularAperture(position, width, height, theta)
        # No background is computed for an extended source.

    for k in range(shape[0]):
        phot_table = aperture_photometry(data[k, :, :], aperture,
                                         method=method, subpixels=subpixels)
        net[k] = float(phot_table['aperture_sum'][0])
        if subtract_background:
            bkg_table = aperture_photometry(data[k, :, :], annulus,
                                            method=method, subpixels=subpixels)
            background[k] = float(bkg_table['aperture_sum'][0])
            net[k] = net[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).
    nan_mask = np.isnan(wavelength)
    n_nan = nan_mask.sum(dtype=np.intp)
    if n_nan > 0:
        log.warning("%d NaNs in wavelength array.", n_nan)
        dq[nan_mask] = np.bitwise_or(dq[nan_mask], dqflags.pixel['DO_NOT_USE'])
        not_nan = np.logical_not(nan_mask)
        flag = np.where(not_nan)
        if len(flag[0]) > 0:
            n_trimmed = flag[0][0] + nelem - (flag[0][-1] + 1)
            if n_trimmed > 0:
                log.info("Output arrays have been trimmed by %d elements",
                         n_trimmed)
                slc = slice(flag[0][0], flag[0][-1] + 1)
                wavelength = wavelength[slc]
                net = net[slc]
                background = background[slc]
                dq = dq[slc]
        else:
            dq |= dqflags.pixel['DO_NOT_USE']

    return (ra, dec, wavelength, net, background, dq)
Ejemplo n.º 49
0
def tso_aperture_photometry(datamodel, xcenter, ycenter, radius, radius_inner,
                            radius_outer):
    """
    Create a photometric catalog for NIRCam TSO imaging observations.

    Parameters
    ----------
    datamodel : `CubeModel`
        The input `CubeModel` of a NIRCam TSO imaging observation.

    xcenter, ycenter : float
        The ``x`` and ``y`` center of the aperture.

    radius : float
        The radius (in pixels) of the circular aperture.

    radius_inner, radius_outer : float
        The inner and outer radii (in pixels) of the circular-annulus
        aperture, used for local background estimation.

    Returns
    -------
    catalog : `~astropy.table.QTable`
        An astropy QTable (Quantity Table) containing the source
        photometry.
    """

    if not isinstance(datamodel, CubeModel):
        raise ValueError('The input data model must be a CubeModel.')

    aper1 = CircularAperture((xcenter, ycenter), r=radius)
    aper2 = CircularAnnulus((xcenter, ycenter), r_in=radius_inner,
                            r_out=radius_outer)

    nimg = datamodel.data.shape[0]
    aperture_sum = []
    aperture_sum_err = []
    annulus_sum = []
    annulus_sum_err = []

    for i in np.arange(nimg):
        tbl1 = aperture_photometry(datamodel.data[i, :, :], aper1,
                                   error=datamodel.err[i, :, :])
        tbl2 = aperture_photometry(datamodel.data[i, :, :], aper2,
                                   error=datamodel.err[i, :, :])

        aperture_sum.append(tbl1['aperture_sum'][0])
        aperture_sum_err.append(tbl1['aperture_sum_err'][0])
        annulus_sum.append(tbl2['aperture_sum'][0])
        annulus_sum_err.append(tbl2['aperture_sum_err'][0])

    # convert array of Quantities to Quantity arrays
    aperture_sum = u.Quantity(aperture_sum)
    aperture_sum_err = u.Quantity(aperture_sum_err)
    annulus_sum = u.Quantity(annulus_sum)
    annulus_sum_err = u.Quantity(annulus_sum_err)

    # construct metadata for output table
    meta = OrderedDict()
    meta['instrument'] = datamodel.meta.instrument.name
    meta['detector'] = datamodel.meta.instrument.detector
    meta['channel'] = datamodel.meta.instrument.channel
    meta['subarray'] = datamodel.meta.subarray.name
    meta['filter'] = datamodel.meta.instrument.filter
    meta['pupil'] = datamodel.meta.instrument.pupil

    meta['target_name'] = datamodel.meta.target.catalog_name
    meta['xcenter'] = xcenter
    meta['ycenter'] = ycenter
    ra_icrs, dec_icrs = datamodel.meta.wcs(xcenter, ycenter)
    meta['ra_icrs'] = ra_icrs
    meta['dec_icrs'] = dec_icrs

    info = ('Photometry measured in a circular aperture of r={0} pixels. '
            'Background calculated as the mean in a circular annulus with '
            'r_inner={1} pixels and r_outer={2} pixels.'
            .format(radius, radius_inner, radius_outer))
    meta['apertures'] = info

    tbl = QTable(meta=meta)

    dt = (datamodel.meta.exposure.group_time *
          (datamodel.meta.exposure.ngroups + 1))
    dt_arr = (np.arange(1, 1 + datamodel.meta.exposure.nints) *
              dt - (dt / 2.))
    int_dt = TimeDelta(dt_arr, format='sec')
    int_times = (Time(datamodel.meta.exposure.start_time, format='mjd') +
                 int_dt)
    tbl['MJD'] = int_times.mjd

    tbl['aperture_sum'] = aperture_sum
    tbl['aperture_sum_err'] = aperture_sum_err
    tbl['annulus_sum'] = annulus_sum
    tbl['annulus_sum_err'] = annulus_sum_err

    annulus_mean = annulus_sum / aper2.area()
    annulus_mean_err = annulus_sum_err / aper2.area()
    tbl['annulus_mean'] = annulus_mean
    tbl['annulus_mean_err'] = annulus_mean_err

    aperture_bkg = annulus_mean * aper1.area()
    aperture_bkg_err = annulus_mean_err * aper1.area()
    tbl['aperture_bkg'] = aperture_bkg
    tbl['aperture_bkg_err'] = aperture_bkg_err

    net_aperture_sum = aperture_sum - aperture_bkg
    net_aperture_sum_err = np.sqrt(aperture_sum_err ** 2 +
                                   aperture_bkg_err ** 2)
    tbl['net_aperture_sum'] = net_aperture_sum
    tbl['net_aperture_sum_err'] = net_aperture_sum_err

    return tbl
Ejemplo n.º 50
0
plt.figure(56)
plt.plot(info['jd']-np.median(info['jd']),info['flux'][:,0],'o-')

sys.exit()



tp.lightcurve(info)

position = (xnew,ynew)



aperture = CircularAperture(position, r=radius)

bkg_aperture = CircularAnnulus(position, r_in=15., r_out=20.)

# perform the photometry; the default method is 'exact'
phot = aperture_photometry(image, aperture)
bkg = aperture_photometry(image, bkg_aperture)

# calculate the mean background level (per pixel) in the annuli
bkg_mean = bkg['aperture_sum'] / bkg_aperture.area()
bkg_mean
bkg_sum = bkg_mean * aperture.area()

# plot the apertures
plt.imshow(scale_image(image, scale='sqrt', percent=98.), 
           origin='lower',cmap='gray')
aperture.plot(color='blue')
bkg_aperture.plot(color='cyan', hatch='//', alpha=0.8)
Ejemplo n.º 51
0
def azimuthal_avg_radial_intensity(wave, rtout, plotname, dstar,
                                   annulus_width=10, rrange=[10,200], group=8, obs=None,
                                   other_obs=None):

    """
    The 'obs' option only works for Herschel PACS/SPIRE image.
    The 'obs' option now accept
    """

    import numpy as np
    import matplotlib as mpl
    # to avoid X server error
    mpl.use('Agg')
    from astropy.io import ascii, fits
    import matplotlib.pyplot as plt
    from photutils import aperture_photometry as ap
    from photutils import CircularAperture, CircularAnnulus
    from astropy import units as u
    from astropy.coordinates import SkyCoord
    from astropy import wcs
    from hyperion.model import ModelOutput
    import astropy.constants as const
    import os

    pc = const.pc.cgs.value
    AU = const.au.cgs.value

    # radial grid in arcsec
    # make the annulus center on
    r = np.arange(rrange[0], rrange[1], annulus_width, dtype=float) - annulus_width*0.5
    # r = np.arange(rrange[0], rrange[1], annulus_width, dtype=float) - annulus_width*0.55

    # source_center = '12 01 36.3 -65 08 53.0'

    def ExtractIntensityObs(rrange, annulus_width, obs):
        import numpy as np
        from astropy.io import fits
        from astropy.coordinates import SkyCoord
        from astropy import wcs
        from photutils import aperture_photometry as ap
        from photutils import CircularAperture, CircularAnnulus

        r = np.arange(rrange[0], rrange[1], annulus_width, dtype=float) - annulus_width*0.5
        # r = np.arange(rrange[0], rrange[1], annulus_width, dtype=float) - annulus_width*0.55

        imgpath = obs['imgpath']
        source_center = obs['source_center']
        # Read in data and set up coversions
        im_hdu = fits.open(imgpath)
        im = im_hdu[1].data
        wave = im_hdu[0].header['WAVELNTH']
        # error
        if (wave < 200.0) & (wave > 70.0):
            im_err = im_hdu[5].data
        elif (wave > 200.0) & (wave < 670.0):
            im_err = im_hdu[2].data
        else:
            im_err_exten = raw_input('The extension that includes the image error: ')
            im_err = im_hdu[int(im_err_exten)].data

        w = wcs.WCS(im_hdu[1].header)

        coord = SkyCoord(source_center, unit=(u.hourangle, u.deg))
        pixcoord = w.wcs_world2pix(coord.ra.degree, coord.dec.degree, 1)
        pix2arcsec = abs(im_hdu[1].header['CDELT1'])*3600.

        # determine whether need to convert the unit
        factor = 1
        print 'Image unit is ', im_hdu[1].header['BUNIT']
        if im_hdu[1].header['BUNIT'] != 'Jy/pixel':
            print 'Image unit is ', im_hdu[1].header['BUNIT']

            if im_hdu[1].header['BUNIT'] == 'MJy/sr':
                # convert intensity unit from MJy/sr to Jy/pixel
                factor = 1e6/4.25e10*abs(im_hdu[1].header['CDELT1']*im_hdu[1].header['CDELT2'])*3600**2
            else:
                factor = raw_input('What is the conversion factor to Jy/pixel?')

        I = np.empty_like(r[:-1])
        I_low = np.empty_like(r[:-1])
        I_hi = np.empty_like(r[:-1])
        I_err = np.empty_like(r[:-1])

        # for calculating the uncertainty from the variation within each annulus
        # construct the x- and y-matrix
        grid_x, grid_y = np.meshgrid(np.linspace(0,len(im[0,:])-1,len(im[0,:])),
                                     np.linspace(0,len(im[:,0])-1,len(im[:,0])))

        grid_dist = ((grid_x-pixcoord[0])**2+(grid_y-pixcoord[1])**2)**0.5

        # iteration
        for ir in range(len(r)-1):
            aperture = CircularAnnulus((pixcoord[0],pixcoord[1]), r_in=r[ir]/pix2arcsec, r_out=r[ir+1]/pix2arcsec)
            phot = ap(im, aperture, error=im_err)
            I[ir] = phot['aperture_sum'].data * factor / aperture.area()

            # uncertainty
            im_dum = np.where((grid_dist < r[ir+1]/pix2arcsec) & (grid_dist >= r[ir]/pix2arcsec), im, np.nan)

            # estimate the uncertainty by offsetting the annulus by +/- 1 pixel
            offset = -1
            if r[ir]/pix2arcsec + offset < 0:
                offset = -r[ir]/pix2arcsec
            aperture = CircularAnnulus((pixcoord[0],pixcoord[1]),
                                r_in=r[ir]/pix2arcsec + offset, r_out=r[ir+1]/pix2arcsec + offset)
            phot = ap(im, aperture, error=im_err)
            I_low[ir] = phot['aperture_sum'].data * factor / aperture.area()

            offset = 1
            aperture = CircularAnnulus((pixcoord[0],pixcoord[1]),
                                r_in=r[ir]/pix2arcsec + offset, r_out=r[ir+1]/pix2arcsec + offset)
            phot = ap(im, aperture, error=im_err)
            I_hi[ir] = phot['aperture_sum'].data * factor / aperture.area()

        I_err = (abs(I_low - I) + abs(I_hi - I))/2.

        return r, I, I_err

    if obs != None:
        I_obs = []
        for o in obs:
            if 'label' not in o.keys():
                label_dum = r'$\rm{observation}$'
                color_dum = 'g'
                linestyle_dum = '-'
                rrange_dum = rrange
                annulus_width_dum = annulus_width
            else:
                label_dum = o['label']
                color_dum = o['plot_color']
                linestyle_dum = o['plot_linestyle']
                rrange_dum = o['rrange']
                annulus_width_dum = o['annulus_width']

            r_dum, I_dum, I_err_dum = ExtractIntensityObs(rrange_dum, annulus_width_dum, o)
            # determine the label
            I_obs.append({'imgpath':o['imgpath'], 'r':r_dum, 'I':I_dum, 'I_err':I_err_dum, 'label': label_dum,
                          'plot_color':color_dum, 'plot_linestyle':linestyle_dum})

        # The first image should be the one to be compared primarily, and written out
        I = I_obs[0]['I']
        I_err = I_obs[0]['I_err']
        imgpath = I_obs[0]['imgpath']
        #

    # read in from RTout
    rtout = ModelOutput(rtout)

    im = rtout.get_image(group=group, inclination=0, distance=dstar*pc, units='Jy', uncertainties=True)
    factor = 1

    # Find the closest wavelength
    iwav = np.argmin(np.abs(wave - im.wav))
    # avoid zero when log, and flip the image
    val = im.val[::-1, :, iwav]
    unc = im.unc[::-1, :, iwav]

    w = np.degrees(max(rtout.get_quantities().r_wall) / im.distance) * 3600
    npix = len(val[:,0])
    pix2arcsec = 2*w/npix

    I_sim = np.empty_like(r[:-1])
    I_sim_hi = np.empty_like(r[:-1])
    I_sim_low = np.empty_like(r[:-1])
    I_sim_err = np.empty_like(r[:-1])

    # for calculating the uncertainty from the variation within each annulus
    # construct the x- and y-matrix
    grid_x, grid_y = np.meshgrid(np.linspace(0,npix-1,npix),
                                 np.linspace(0,npix-1,npix))

    dist_x = abs(grid_x - ((npix-1)/2.))
    dist_y = abs(grid_y - ((npix-1)/2.))

    grid_dist = (dist_x**2+dist_y**2)**0.5

    # iteration
    for ir in range(len(r)-1):
        aperture = CircularAnnulus((npix/2.+0.5, npix/2.+0.5),
                            r_in=r[ir]/pix2arcsec, r_out=r[ir+1]/pix2arcsec)
        phot = ap(val, aperture, error=unc)
        I_sim[ir] = phot['aperture_sum'].data / aperture.area()

        # uncertainty
        im_dum = np.where((grid_dist < r[ir+1]/pix2arcsec) & (grid_dist >= r[ir]/pix2arcsec), val, np.nan)
        # I_sim_err[ir] = phot['aperture_sum_err'].data / aperture.area()
        # I_sim_err[ir] = (np.nanstd(im_dum)**2+phot['aperture_sum_err'].data**2)**0.5 * factor / aperture.area()

        offset = -1
        aperture = CircularAnnulus((npix/2.+0.5, npix/2.+0.5),
                            r_in=r[ir]/pix2arcsec + offset, r_out=r[ir+1]/pix2arcsec + offset)
        phot = ap(val, aperture, error=unc)
        I_sim_low[ir] = phot['aperture_sum'].data * factor / aperture.area()

        offset = 1
        aperture = CircularAnnulus((npix/2.+0.5, npix/2.+0.5),
                            r_in=r[ir]/pix2arcsec + offset, r_out=r[ir+1]/pix2arcsec + offset)
        phot = ap(val, aperture, error=unc)
        I_sim_hi[ir] = phot['aperture_sum'].data * factor / aperture.area()

    I_sim_err = (abs(I_sim_low - I_sim)+ abs(I_sim_hi - I_sim))/2.


    if obs != None:
        # write the numbers into file
        foo = open(plotname+'_radial_profile_'+str(wave)+'um.txt', 'w')
        # print some header info
        foo.write('# wavelength '+str(wave)+' um \n')
        foo.write('# image file '+os.path.basename(imgpath)+' \n')
        foo.write('# annulus width '+str(annulus_width)+' arcsec \n')
        # write profiles
        foo.write('r_in \t I \t I_err \t I_sim \t I_sim_err \n')
        foo.write('# [arcsec] \t [Jy/pixel] \t [Jy/pixel] \t [Jy/pixel] \t [Jy/pixel] \n')
        for i in range(len(I)):
            foo.write('%f \t %e \t %e \t %e \t %e \n' % (r[i]+annulus_width/2., I[i], I_err[i], I_sim[i], I_sim_err[i]))
        foo.close()
    else:
        # write the numbers into file
        foo = open(plotname+'_radial_profile_'+str(wave)+'um.txt', 'w')
        # print some header info
        foo.write('# wavelength '+str(wave)+' um \n')
        foo.write('# annulus width '+str(annulus_width)+' arcsec \n')
        # write profiles
        foo.write('r_in \t I_sim \t I_sim_err \n')
        foo.write('# [arcsec] \t [Jy/pixel] \t [Jy/pixel] \n')
        for i in range(len(I_sim)):
            foo.write('%f \t %e \t %e \n' % (r[i]+annulus_width/2., I_sim[i], I_sim_err[i]))
        foo.close()

    # plot
    fig = plt.figure(figsize=(8,6))
    ax = fig.add_subplot(111)

    I_sim_hi = np.log10((I_sim+I_sim_err)/I_sim.max())-np.log10(I_sim/I_sim.max())
    I_sim_low = np.log10(I_sim/I_sim.max())-np.log10((I_sim-I_sim_err)/I_sim.max())
    i_sim = ax.errorbar(np.log10(r[:-1]*dstar), np.log10(I_sim/I_sim.max()), color='b',
                    yerr=(I_sim_low, I_sim_hi), marker='o', linestyle='-', mec='None', markersize=5,
                    ecolor='b', elinewidth=1.5, capthick=1.5, barsabove=True)

    if obs != None:
        plot_profile = []
        plot_label = []
        for o in I_obs:
            I_hi = np.log10((o['I']+o['I_err'])/o['I'].max())-np.log10(o['I']/o['I'].max())
            I_low = np.log10(o['I']/o['I'].max())-np.log10((o['I']-o['I_err'])/o['I'].max())
            i = ax.errorbar(np.log10(o['r'][:-1]*dstar), np.log10(o['I']/o['I'].max()), color=o['plot_color'],
                            yerr=(I_low, I_hi), marker='o', linestyle=o['plot_linestyle'], mec='None', markersize=5,
                            ecolor=o['plot_color'], elinewidth=1.5, capthick=1.5, barsabove=True)
            plot_profile.append(i)
            plot_label.append(o['label'])

        plot_profile.append(i_sim)
        plot_label.append(r'$\rm{simulation}$')
        ax.legend(plot_profile, plot_label,
                  fontsize=16, numpoints=1, loc='best')
    else:
        ax.legend([i_sim], [r'$\rm{simulation}$'], fontsize=16, numpoints=1, loc='best')

    # limit radius
    ax.axvline([np.log10(100*dstar)], color='k', linestyle='--', linewidth=1)
    #
    [ax.spines[axis].set_linewidth(1.5) for axis in ['top','bottom','left','right']]
    ax.minorticks_on()
    ax.tick_params('both',labelsize=18,width=1.5,which='major',pad=10,length=5)
    ax.tick_params('both',labelsize=18,width=1.5,which='minor',pad=10,length=2.5)
    ax.set_xlabel(r'$\rm{log(\it{b})\,[\rm{AU}]}$', fontsize=18)
    ax.set_ylabel(r'$\rm{log(I\,/\,I_{max})}$', fontsize=18)

    # fix the tick label font
    ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral',size=18)
    for label in ax.get_xticklabels():
        label.set_fontproperties(ticks_font)
    for label in ax.get_yticklabels():
        label.set_fontproperties(ticks_font)

    fig.savefig(plotname+'_radial_profile_'+str(wave)+'um.pdf', format='pdf', dpi=300, bbox_inches='tight')
    fig.clf()
Ejemplo n.º 52
0
    def ExtractIntensityObs(rrange, annulus_width, obs):
        import numpy as np
        from astropy.io import fits
        from astropy.coordinates import SkyCoord
        from astropy import wcs
        from photutils import aperture_photometry as ap
        from photutils import CircularAperture, CircularAnnulus

        r = np.arange(rrange[0], rrange[1], annulus_width, dtype=float) - annulus_width*0.5
        # r = np.arange(rrange[0], rrange[1], annulus_width, dtype=float) - annulus_width*0.55

        imgpath = obs['imgpath']
        source_center = obs['source_center']
        # Read in data and set up coversions
        im_hdu = fits.open(imgpath)
        im = im_hdu[1].data
        wave = im_hdu[0].header['WAVELNTH']
        # error
        if (wave < 200.0) & (wave > 70.0):
            im_err = im_hdu[5].data
        elif (wave > 200.0) & (wave < 670.0):
            im_err = im_hdu[2].data
        else:
            im_err_exten = raw_input('The extension that includes the image error: ')
            im_err = im_hdu[int(im_err_exten)].data

        w = wcs.WCS(im_hdu[1].header)

        coord = SkyCoord(source_center, unit=(u.hourangle, u.deg))
        pixcoord = w.wcs_world2pix(coord.ra.degree, coord.dec.degree, 1)
        pix2arcsec = abs(im_hdu[1].header['CDELT1'])*3600.

        # determine whether need to convert the unit
        factor = 1
        print 'Image unit is ', im_hdu[1].header['BUNIT']
        if im_hdu[1].header['BUNIT'] != 'Jy/pixel':
            print 'Image unit is ', im_hdu[1].header['BUNIT']

            if im_hdu[1].header['BUNIT'] == 'MJy/sr':
                # convert intensity unit from MJy/sr to Jy/pixel
                factor = 1e6/4.25e10*abs(im_hdu[1].header['CDELT1']*im_hdu[1].header['CDELT2'])*3600**2
            else:
                factor = raw_input('What is the conversion factor to Jy/pixel?')

        I = np.empty_like(r[:-1])
        I_low = np.empty_like(r[:-1])
        I_hi = np.empty_like(r[:-1])
        I_err = np.empty_like(r[:-1])

        # for calculating the uncertainty from the variation within each annulus
        # construct the x- and y-matrix
        grid_x, grid_y = np.meshgrid(np.linspace(0,len(im[0,:])-1,len(im[0,:])),
                                     np.linspace(0,len(im[:,0])-1,len(im[:,0])))

        grid_dist = ((grid_x-pixcoord[0])**2+(grid_y-pixcoord[1])**2)**0.5

        # iteration
        for ir in range(len(r)-1):
            aperture = CircularAnnulus((pixcoord[0],pixcoord[1]), r_in=r[ir]/pix2arcsec, r_out=r[ir+1]/pix2arcsec)
            phot = ap(im, aperture, error=im_err)
            I[ir] = phot['aperture_sum'].data * factor / aperture.area()

            # uncertainty
            im_dum = np.where((grid_dist < r[ir+1]/pix2arcsec) & (grid_dist >= r[ir]/pix2arcsec), im, np.nan)

            # estimate the uncertainty by offsetting the annulus by +/- 1 pixel
            offset = -1
            if r[ir]/pix2arcsec + offset < 0:
                offset = -r[ir]/pix2arcsec
            aperture = CircularAnnulus((pixcoord[0],pixcoord[1]),
                                r_in=r[ir]/pix2arcsec + offset, r_out=r[ir+1]/pix2arcsec + offset)
            phot = ap(im, aperture, error=im_err)
            I_low[ir] = phot['aperture_sum'].data * factor / aperture.area()

            offset = 1
            aperture = CircularAnnulus((pixcoord[0],pixcoord[1]),
                                r_in=r[ir]/pix2arcsec + offset, r_out=r[ir+1]/pix2arcsec + offset)
            phot = ap(im, aperture, error=im_err)
            I_hi[ir] = phot['aperture_sum'].data * factor / aperture.area()

        I_err = (abs(I_low - I) + abs(I_hi - I))/2.

        return r, I, I_err
Ejemplo n.º 53
0
def photometry(star_positions, aperture_radii, centroid_stamp_half_width,
               psf_stddev_init, aperture_annulus_radius, output_path):
    """
    Parameters
    ----------
    master_dark_path : str
        Path to master dark frame
    master_flat_path :str
        Path to master flat field
    target_centroid : `~numpy.ndarray`
        position of centroid, with shape (2, 1)
    comparison_flux_threshold : float
        Minimum fraction of the target star flux required to accept for a
        comparison star to be included
    aperture_radii : `~numpy.ndarray`
        Range of aperture radii to use
    centroid_stamp_half_width : int
        Centroiding is done within image stamps centered on the stars. This
        parameter sets the half-width of the image stamps.
    psf_stddev_init : float
        Initial guess for the width of the PSF stddev parameter, used for
        fitting 2D Gaussian kernels to the target star's PSF.
    aperture_annulus_radius : int
        For each aperture in ``aperture_radii``, measure the background in an
        annulus ``aperture_annulus_radius`` pixels bigger than the aperture
        radius
    output_path : str
        Path to where outputs will be saved.
    """
    master_dark = fits.getdata(master_dark_path)
    master_flat = fits.getdata(master_flat_path)

    master_flat[master_flat < 0.1] = 1.0 # tmp

    #star_positions = init_centroids(image_paths[0:3], master_flat, master_dark,
    #                                target_centroid, plots=True,
    #                                min_flux=comparison_flux_threshold).T

    # Initialize some empty arrays to fill with data:
    times = np.zeros(len(image_paths))
    fluxes = np.zeros((len(image_paths), len(star_positions),
                       len(aperture_radii)))
    errors = np.zeros((len(image_paths), len(star_positions),
                       len(aperture_radii)))
    xcentroids = np.zeros((len(image_paths), len(star_positions)))
    ycentroids = np.zeros((len(image_paths), len(star_positions)))
    airmass = np.zeros(len(image_paths))
    airpress = np.zeros(len(image_paths))
    humidity = np.zeros(len(image_paths))
    telfocus = np.zeros(len(image_paths))
    psf_stddev = np.zeros(len(image_paths))

    medians = np.zeros(len(image_paths))

    with ProgressBar(len(image_paths)) as bar:
        for i in range(len(image_paths)):
            bar.update()

            # Subtract image by the dark frame, normalize by flat field
            imagedata = (fits.getdata(image_paths[i]) - master_dark) / master_flat

            # Collect information from the header
            imageheader = fits.getheader(image_paths[i])
            exposure_duration = imageheader['EXPTIME']
            times[i] = Time(imageheader['DATE-OBS'], format='isot', scale=imageheader['TIMESYS'].lower()).jd
            medians[i] = np.median(imagedata)
            airmass[i] = imageheader['AIRMASS']
            airpress[i] = imageheader['AIRPRESS']
            humidity[i] = imageheader['HUMIDITY']
            telfocus[i] = imageheader['TELFOCUS']

            # Initial guess for each stellar centroid informed by previous centroid
            for j in range(len(star_positions)):
                if i == 0:
                    init_x = star_positions[j][0]
                    init_y = star_positions[j][1]
                else:
                    init_x = ycentroids[i-1][j]
                    init_y = xcentroids[i-1][j]

                # Cut out a stamp of the full image centered on the star
                image_stamp = imagedata[int(init_y) - centroid_stamp_half_width:
                                        int(init_y) + centroid_stamp_half_width,
                                        int(init_x) - centroid_stamp_half_width:
                                        int(init_x) + centroid_stamp_half_width]

                # Measure stellar centroid with 2D gaussian fit
                x_stamp_centroid, y_stamp_centroid = centroid_com(image_stamp)
                y_centroid = x_stamp_centroid + init_x - centroid_stamp_half_width
                x_centroid = y_stamp_centroid + init_y - centroid_stamp_half_width

                xcentroids[i, j] = x_centroid
                ycentroids[i, j] = y_centroid

                # For the target star, measure PSF:
                if j == 0:
                    psf_model_init = models.Gaussian2D(amplitude=np.max(image_stamp),
                                                       x_mean=centroid_stamp_half_width,
                                                       y_mean=centroid_stamp_half_width,
                                                       x_stddev=psf_stddev_init,
                                                       y_stddev=psf_stddev_init)

                    fit_p = fitting.LevMarLSQFitter()
                    y, x = np.mgrid[:image_stamp.shape[0], :image_stamp.shape[1]]
                    best_psf_model = fit_p(psf_model_init, x, y, image_stamp -
                                           np.median(image_stamp))
                    psf_stddev[i] = 0.5*(best_psf_model.x_stddev.value +
                                          best_psf_model.y_stddev.value)

            positions = np.vstack([ycentroids[i, :], xcentroids[i, :]])

            for k, aperture_radius in enumerate(aperture_radii):
                target_apertures = CircularAperture(positions, aperture_radius)
                background_annuli = CircularAnnulus(positions,
                                                    r_in=aperture_radius +
                                                         aperture_annulus_radius,
                                                    r_out=aperture_radius +
                                                          2 * aperture_annulus_radius)
                flux_in_annuli = aperture_photometry(imagedata,
                                                     background_annuli)['aperture_sum'].data
                background = flux_in_annuli/background_annuli.area()
                flux = aperture_photometry(imagedata,
                                           target_apertures)['aperture_sum'].data
                background_subtracted_flux = (flux - background *
                                              target_apertures.area())

                fluxes[i, :, k] = background_subtracted_flux/exposure_duration
                errors[i, :, k] = np.sqrt(flux)

    ## Save some values
    results = PhotometryResults(times, fluxes, errors, xcentroids, ycentroids,
                                airmass, airpress, humidity, medians,
                                psf_stddev, aperture_radii)
    results.save(output_path)
    return results
Ejemplo n.º 54
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 pixel.

    net : ndarray, 1-D
        The count rate (or flux) minus the background at each pixel.

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

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

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

    data = input_model.data
    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 net, background, npixels, and dq arrays
    # no matter what.  We may need to divide by npixels, so the default
    # is 1 rather than 0.
    net = np.zeros(shape[0], dtype=np.float64)
    background = np.zeros(shape[0], dtype=np.float64)
    npixels = 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.lower() != "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 "
                        "nod/dither correction will not be applied.")
            x_center = extract_params['x_center']
            y_center = extract_params['y_center']
            if x_center is None:
                x_center = float(shape[-1]) / 2.
            else:
                x_center = float(x_center)
            if y_center is None:
                y_center = float(shape[-2]) / 2.
            else:
                y_center = float(y_center)
        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 is only needed if method = 'subpixel'.
    subpixels = extract_params['subpixels']

    subtract_background = extract_params['subtract_background']
    smaller_axis = float(min(shape[-2], shape[-1]))     # for defaults
    radius = None
    inner_bkg = None
    outer_bkg = None

    if 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
    else:
        radius = extract_params['radius']
        if radius is None:
            radius = smaller_axis / 4.
        if subtract_background:
            inner_bkg = extract_params['inner_bkg']
            if inner_bkg is None:
                inner_bkg = radius
            outer_bkg = extract_params['outer_bkg']
            if outer_bkg is None:
                outer_bkg = min(inner_bkg * math.sqrt(2.),
                                smaller_axis / 2. - 1.)
            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
        width = None
        height = None
        theta = None

    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("  radius = %s", str(radius))
        log.debug("  subtract_background = %s", str(subtract_background))
        log.debug("  inner_bkg = %s", str(inner_bkg))
        log.debug("  outer_bkg = %s", str(outer_bkg))
        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))

    x0 = float(shape[2]) / 2.
    y0 = float(shape[1]) / 2.
    (ra, dec, wavelength) = get_coordinates(input_model, x0, y0)

    position = (x_center, y_center)
    if source_type == 'point':
        aperture = CircularAperture(position, r=radius)
    else:
        aperture = RectangularAperture(position, width, height, theta)

    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

    # Compute the area of the aperture and possibly also of the annulus.
    normalization = 1.
    temp = np.ones(shape[-2:], dtype=np.float64)
    phot_table = aperture_photometry(temp, aperture,
                                     method=method, subpixels=subpixels)
    aperture_area = float(phot_table['aperture_sum'][0])
    log.debug("aperture.area() = %g; aperture_area = %g",
              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])
        log.debug("annulus.area() = %g; annulus_area = %g",
                  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.")
            subtract_background = False
    del temp

    npixels[:] = aperture_area
    for k in range(shape[0]):
        phot_table = aperture_photometry(data[k, :, :], aperture,
                                         method=method, subpixels=subpixels)
        net[k] = float(phot_table['aperture_sum'][0])
        if subtract_background:
            bkg_table = aperture_photometry(data[k, :, :], annulus,
                                            method=method, subpixels=subpixels)
            background[k] = float(bkg_table['aperture_sum'][0])
            net[k] = net[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, net, background, npixels, dq) = \
                nans_in_wavelength(wavelength, net, background, npixels, dq)

    return (ra, dec, wavelength, net, background, npixels, dq)
Ejemplo n.º 55
0
def addzb(fitsname, redo=False, fau_dir=None):
    telescopes = ['1','2','3','4']
#    night = (fitsname.split('/'))[3]
    night = (fitsname.split('/'))[-2]

    print 'beginning ' + fitsname


    # 2D spectrum
    h = pyfits.open(fitsname,mode='update')

    if 'BARYSRC4' in h[0].header.keys() and not redo:
        print fitsname + " already done"
        h.flush()
        h.close()
        return

    specstart = datetime.datetime.strptime(h[0].header['DATE-OBS'],"%Y-%m-%dT%H:%M:%S.%f")
    specmid = specstart + datetime.timedelta(seconds = h[0].header['EXPTIME']/2.0)
    specend = specstart + datetime.timedelta(seconds = h[0].header['EXPTIME'])

    t0 = datetime.datetime(2000,1,1)
    t0jd = 2451544.5

    aperture_radius = 3.398 # fiber radius in pixels
    annulus_inner = 2.0*aperture_radius
    annulus_outer = 3.0*aperture_radius

    for telescope in telescopes:
        print 'beginning telescope ' + telescope + ' on ' + fitsname

        # get the barycentric redshift for each time
        ra = h[0].header['TARGRA' + telescope]
        dec = h[0].header['TARGDEC' + telescope]
        try: pmra = h[0].header['PMRA' + telescope]
        except: pmra = 0.0
        try: pmdec = h[0].header['PMDEC' + telescope]
        except: pmdec = 0.0
        try: parallax = h[0].header['PARLAX' + telescope]
        except: parallax = 0.0
        try: rv = h[0].header['RV' + telescope]
        except: rv = 0.0

        objname = h[0].header['OBJECT' + telescope]
        if fau_dir is None:
            faupath = '/Data/t' + telescope + '/' + night + '/' + night + '.T' + telescope + '.FAU.' + objname + '.????.fits'
        else:
            faupath = fau_dir + '/t' + telescope + '/' + night + '/' + night + '.T' + telescope + '.FAU.' + objname + '.????.fits'
        guideimages = glob.glob(faupath)

#        if telescope == '2' and "HD62613" in fitsname: ipdb.set_trace()

        times = []
        fluxes = np.array([])

        for guideimage in guideimages:
            try:
                fauimage = pyfits.open(guideimage)
            except:
                print "corrupt file for " + guideimage
                continue

            # midtime of the guide image (UTC)
            midtime = datetime.datetime.strptime(fauimage[0].header['DATE-OBS'],"%Y-%m-%dT%H:%M:%S") +\
                datetime.timedelta(seconds=fauimage[0].header['EXPTIME']/2.0)
            
            # convert to Julian date
            midjd = t0jd + (midtime-t0).total_seconds()/86400.0

            # only look at images during the spectrum
            if midtime < specstart or midtime > specend: continue

            # find the fiber position
            try:
                fiber_x = fauimage[0].header['XFIBER' + telescope]
                fiber_y = fauimage[0].header['YFIBER' + telescope]
            except:
                print "keywords missing for " + guideimage
                continue

            # do aperture photometry
            positions = [(fiber_x,fiber_y)]
            apertures = CircularAperture(positions,r=aperture_radius)
            annulus_apertures = CircularAnnulus(positions, r_in=annulus_inner, r_out=annulus_outer)

            # calculate the background-subtracted flux at the fiber position
            rawflux_table = aperture_photometry(fauimage[0].data, apertures)
            bkgflux_table = aperture_photometry(fauimage[0].data, annulus_apertures)
            bkg_mean = bkgflux_table['aperture_sum'].sum() / annulus_apertures.area()
            bkg_sum = bkg_mean * apertures.area()
            flux = rawflux_table['aperture_sum'].sum() - bkg_sum
            
            # append to the time and flux arrays
            times.append(midjd)
            fluxes = np.append(fluxes,flux)

        if len(times) == 0:
            print "No guider images for " + fitsname + " on Telescope " + telescope + "; assuming mid time"
            if 'daytimeSky' in fitsname: 
                h[0].header['BARYCOR' + telescope] = ('UNKNOWN','Barycentric redshift')
                h[0].header['BARYSRC' + telescope] = ('UNKNOWN','Source for the barycentric redshift')
                h[0].header['FLUXMID' + telescope] = (midjd,'Flux-weighted mid exposure time (JD_UTC)')
                continue
            
            # convert specmid to Julian date
            midjd = t0jd + (specmid-t0).total_seconds()/86400.0

            print midjd
            zb = barycorr(midjd, ra, dec, pmra=pmra, pmdec=pmdec, parallax=parallax, rv=rv)/2.99792458e8
            h[0].header['BARYCOR' + telescope] = (zb,'Barycentric redshift')
            h[0].header['BARYSRC' + telescope] = ('MIDTIME','Source for the barycentric redshift')
            h[0].header['FLUXMID' + telescope] = (midjd,'Flux-weighted mid exposure time (JD_UTC)')
            continue
            

        zb = np.asarray(barycorr(times, ra, dec, pmra=pmra, pmdec=pmdec, parallax=parallax, rv=rv))/2.99792458e8

        # weight the barycentric correction by the flux
        #*******************!*!*!*!*!*!*
        #this assumes guider images were taken ~uniformly throughout the spectroscopic exposure!
        #****************!*!*!*!*!**!*!*!*!**!*!*!*!*
        wzb = np.sum(zb*fluxes)/np.sum(fluxes)
        wmidjd = np.sum(times*fluxes)/np.sum(fluxes)
        
        # update the header to include aperture photometry and barycentric redshift
        h[0].header['BARYCOR' + telescope] = (wzb,'Barycentric redshift')
        h[0].header['BARYSRC' + telescope] = ('FAU Flux Weighted','Source for the barycentric redshift')
        h[0].header['FLUXMID' + telescope] = (wmidjd,'Flux-weighted mid exposure time (JD_UTC)')
        hdu = pyfits.PrimaryHDU(zip(times,fluxes))
        hdu.header['TELESCOP'] = ('T' + telescope,'Telescope')
        h.append(hdu)

    # write updates to the disk
    h.flush()
    h.close()