Beispiel #1
0
def radial_elliptical_annulus(position, r, dr, e=1., theta=0.):
    """
    Helper function given a radius, elongation and theta,
    will make an elliptical aperture.

    Parameters
    ----------
    position : tuple
        (x, y) coords for center of aperture
    r : int or float
        Semi-major radius of the inner ring
    dr : int or float
        Thickness of annulus (outer ring = r + dr).
    e : float
        Elongation
    theta : float
        Orientation in rad

    Returns
    -------
    EllipticalAnnulus
    """

    a_in, b_in = r, r / e
    a_out, b_out = r + dr, (r + dr) / e

    return EllipticalAnnulus(position, a_in, a_out, b_out, theta=theta)
Beispiel #2
0
    def measure_photo(self):
        """
        sample.extract(), from EllipseSample documentation:
        Extract sample data by scanning an elliptical path over the
        image array.

        Returns
        -------
        result : 2D `~numpy.ndarray`
            The rows of the array contain the angles, radii, and
            extracted intensity values, respectively.
        """
        if self.photomorph == 'ellipse':
            sample = EllipseSample(self.im,
                                   sma=self.params['sma'],
                                   astep=0,
                                   sclip=0.3,
                                   nclip=0,
                                   linear_growth=False,
                                   geometry=self.geom,
                                   integrmode='bilinear')
            self.ellip_data = sample.extract()
            self.mean_intens = np.mean(self.ellip_data[2])
        elif self.photomorph == 'annulus':
            aper = EllipticalAnnulus((self.params['x0'], self.params['y0']),
                                     self.params['sma']-self.beam_size_pix/2.,
                                     self.params['sma']+self.beam_size_pix/2.,
                                     (self.params['sma']+self.beam_size_pix/2.) \
                                     *(1. - self.params['eps']),
                                     self.params['pa'])
            annulus_mask = aper.to_mask()
            self.ellip_data = annulus_mask.multiply(self.im)
            self.sum_intens = np.sum(
                self.ellip_data) / self.beam_size_pix**2  #in Jy
            self.mean_intens = np.mean(self.ellip_data)


#            also: aperture_photometry(self.image_cube[self.chan] / self.beam_size_pix**2, aper)
        elif self.photomorph == 'circle':
            aper = CircularAperture((self.params['x0'], self.params['y0']),
                                    self.params['sma'])
            circle_mask = aper.to_mask()
            self.ellip_data = circle_mask.multiply(self.im)
            self.sum_intens = np.sum(self.ellip_data) / self.beam_size_pix**2
            self.mean_intens = np.mean(self.ellip_data)
        elif self.photomorph == 'ellipse_area':
            aper = EllipticalAperture(
                (self.params['x0'], self.params['y0']), self.params['sma'],
                self.params['sma'] * (1. - self.params['eps']),
                self.params['pa'])
            ellipse_mask = aper.to_mask()
            self.ellip_data = ellipse_mask.multiply(self.im)
            self.sum_intens = np.sum(self.ellip_data) / self.beam_size_pix**2
            self.mean_intens = np.mean(self.ellip_data)
Beispiel #3
0
    def maximize_intens(self, par):
        if self.photomorph == 'ellipse':
            geom = EllipseGeometry(
                par[0],
                par[1],
                par[2],
                par[3],
                par[4],
            )
            sample = EllipseSample(self.im,
                                   sma=geom.sma,
                                   astep=0,
                                   sclip=0.3,
                                   nclip=0,
                                   linear_growth=False,
                                   geometry=geom,
                                   integrmode='bilinear')
            data2min = np.mean(sample.extract()[2])
        elif self.photomorph == 'annulus':
            aper = EllipticalAnnulus(
                (par[0], par[1]), par[2] - self.beam_size_pix / 2.,
                par[2] + self.beam_size_pix / 2.,
                (par[2] + self.beam_size_pix / 2.) * (1. - par[3]), par[4])
            annulus_mask = aper.to_mask()
            data2min = annulus_mask.multiply(self.im)
        elif self.photomorph == 'circle':
            aper = CircularAperture((par[0], par[1]), par[2])
            circular_mask = aper.to_mask()
            data2min = circular_mask.multiply(self.im)
        elif self.photomorph == 'ellipse_area':
            aper = EllipticalAperture((par[0], par[1]), par[2],
                                      par[2] * (1. - par[3]), par[4])
            ellipse_mask = aper.to_mask()
            data2min = ellipse_mask.multiply(self.im)

        if self.q2min == 'sum':
            tominimize = np.sum(data2min)
        elif self.q2min == 'mean':
            tominimize = np.mean(data2min)

        return -tominimize
Beispiel #4
0
    def plot_ellipse(self, first_time):
        self.ax_text.clear()
        if not first_time:
            self.ax.patches[1].remove()
        else:
            pass
        if self.photomorph == 'ellipse':
            aper = EllipticalAperture(
                (self.params['x0'], self.params['y0']), self.params['sma'],
                self.params['sma'] * (1. - self.params['eps']),
                self.params['pa'])
            self.ax_text.text(
                0.,
                0.5,
                r"Mean intens path: {:.3} Jy/beam".format(self.mean_intens),
                fontsize=10,
                color='k',
                verticalalignment='top',
                transform=self.ax_text.transAxes,
            )
        elif self.photomorph == 'annulus':
            aper = EllipticalAnnulus((self.params['x0'], self.params['y0']),
                                     self.params['sma']-self.beam_size_pix/2.,
                                     self.params['sma']+self.beam_size_pix/2.,
                                     (self.params['sma']+self.beam_size_pix/2.) \
                                     *(1. - self.params['eps']),
                                     self.params['pa'])
            self.ax_text.text(
                0.,
                0.5,
                r"Flux density annulus: {:.3} Jy".format(self.sum_intens),
                fontsize=10,
                color='k',
                verticalalignment='top',
                transform=self.ax_text.transAxes,
            )
            self.ax_text.text(
                0.,
                1,
                r"Mean intens path: {:.3} Jy/beam".format(self.mean_intens),
                fontsize=10,
                color='k',
                verticalalignment='top',
                transform=self.ax_text.transAxes,
            )
        elif self.photomorph == 'circle':
            aper = CircularAperture((self.params['x0'], self.params['y0']),
                                    self.params['sma'])
            self.ax_text.text(
                0.,
                0.5,
                r"Flux density circle: {:.3} Jy".format(self.sum_intens),
                fontsize=10,
                color='k',
                verticalalignment='top',
                transform=self.ax_text.transAxes,
            )
            self.ax_text.text(
                0.,
                1,
                r"Mean intens: {:.3} Jy/beam".format(self.mean_intens),
                fontsize=10,
                color='k',
                verticalalignment='top',
                transform=self.ax_text.transAxes,
            )
        elif self.photomorph == 'ellipse_area':
            aper = EllipticalAperture(
                (self.params['x0'], self.params['y0']), self.params['sma'],
                self.params['sma'] * (1. - self.params['eps']),
                self.params['pa'])
            self.ax_text.text(
                0.,
                0.5,
                r"Flux density circle: {:.3} Jy".format(self.sum_intens),
                fontsize=10,
                color='k',
                verticalalignment='top',
                transform=self.ax_text.transAxes,
            )
            self.ax_text.text(
                0.,
                1,
                r"Mean intens: {:.3} Jy/beam".format(self.mean_intens),
                fontsize=10,
                color='k',
                verticalalignment='top',
                transform=self.ax_text.transAxes,
            )

        aper.plot(self.ax, color=self.color_ref_ellip)

        self.ax_text.set_axis_off()
        self.color_ref_ellip = 'r'
Beispiel #5
0
def azimuthal_profile(image,pxsize,amean,width,inc,PA,d,Nbins):

    ############################################################
    #
    # Inputs.
    # image: fits file of the image.
    # pxsize: pixel scale of the image in arcsex/px.
    # amean: mean semi-major axis of the elliptical aperture (AU).
    # width: total width of the aperture (AU).
    # inc: inclination of the disk (deg).
    # PA: east-north measured position angle of the disk (deg).
    # d: distance to the source in pc
    # Nbins: number of azimuthal bins 
    #
    # Returns 
    # The azimuthal brightness profile 
    # 
    #
    ############################################################

    """
    ############################################################
    # Loading data
    # Observation
    hdu=fits.open(image)
    data=hdu[0].data[0][0]*1000/1.702471971511841
    """
    
    # Model
    hdu=fits.open(image)
    data=hdu[0].data#/Bmax_value
    
    
    ############################################################
    # Derived quantities
    x0=data.shape[0]*0.5
    y0=data.shape[1]*0.5
    inc=(inc*units.deg).to(units.rad).value
    e=np.sin(inc)


    ############################################################
    # Creating elliptical aperture
    amin=amean-width*0.5 # AU
    amax=amean+width*0.5 # AU
    bmax=amax*(1-e**2)**0.5 # AU

    amin=topx(amin,pxsize,d) # px
    amax=topx(amax,pxsize,d) # px
    bmax=topx(bmax,pxsize,d) # px

    angle=((PA+90)*units.deg).to(units.rad).value

    aperture=EllipticalAnnulus((x0,y0),a_in=amin,a_out=amax,b_out=bmax,theta=angle)
    
    """
    # Do a check?
    plt.imshow(data)
    aperture.plot(color='red',lw=1)
    plt.show()
    """
    
    ############################################################
    # Creating aperture mask
    mask=aperture.to_mask(method="center")
    """
    # Do a check?
    plt.imshow(mask)
    plt.colorbar()
    plt.show()
    """
    
    ############################################################
    # Extracting pixels located inside the aperture
    aperture_data=mask.multiply(data)
    """
    # Do a check?
    plt.imshow(aperture_data)
    plt.colorbar()
    plt.show()
    """


    ############################################################
    # Define class "Bin"
    class Bin:
        def __init__(self,ID,theta_min,theta_max,plist):
            self.ID=ID
            self.theta_min=theta_min
            self.theta_max=theta_max
            self.plist=plist
        
        def getFlux(self):
            flux=0.0
            for pixel in self.plist:
                flux+=aperture_data[pixel[0],pixel[1]]
            return flux

        def getTheta(self):
            value=(self.theta_max-self.theta_min)*0.5+self.theta_min
            return value
    
        
    ############################################################
    # Creating array of bins
    bin_list=[]
    thetas=np.linspace(0,2*np.pi,Nbins+1)
    for i in range(0,Nbins):
        sbin=Bin(i+1,thetas[i],thetas[i+1],[])
        bin_list.append(sbin)

    
    ############################################################
    # Creating array of pixel's index within the aperture 
    # relative to the star
    pixel_list=[]
    yc=int(aperture_data.shape[0]*0.5)
    xc=int(aperture_data.shape[1]*0.5)
    for i in range(0,aperture_data.shape[1]): # Over columns 
        for j in range(0,aperture_data.shape[0]): # Over rows
            if aperture_data[j,i]!=0.0:
                pixel_list.append((j-yc,i-xc))
    

    ############################################################
    # Filling in bin_list
    for point in pixel_list:
        phi=np.arctan2(point[0],point[1])
        if phi<0.0:
            phi=2*np.pi+phi
        for sbin in bin_list:
            if sbin.theta_min<=phi<sbin.theta_max:
                pixel=(point[0]+yc,point[1]+xc)
                sbin.plist.append(pixel)
                

    ############################################################
    # Writing azimuthal profile 
    x=[]
    y=[]
    for value in bin_list:
        PA_bin=(value.getTheta()*units.rad).to(units.deg).value-90.0
        if PA_bin<0.0:
            PA_bin=360.0+PA_bin
        x.append(PA_bin)
        y.append(value.getFlux()/len(value.plist))

    f=open("azprofile_alma_mod.dat","w")
    for i in range(0,len(x)):
        f.write("%.5f %.15f\n"%(x[i],y[i]))
    f.close()
    """
    plt.plot(x,y,".")
    plt.show()
    """
    
    return 0
pixel_lim = int(round(angular_lim / pxsize))  # pixel

############################################################
# Set up aperture photometry
xc = 0.5 * data_obs.shape[0]  # Image center in data coordinates
yc = 0.5 * data_obs.shape[1]  # Image center in data coordinates
dr = 1  # Width of the annulus
a_in_array = []
for i in np.arange(yc + 0.001, yc + 0.5 * pixel_lim + 0.001, dr):
    a_in_array.append(i - xc)
a_out_array = [i + dr for i in a_in_array]
b_out_array = [i * (1 - e**2)**0.5 for i in a_out_array]
apertures = [
    EllipticalAnnulus((yc, xc),
                      a_in=ain,
                      a_out=aout,
                      b_out=bout,
                      theta=angle_annulus)
    for (ain, aout, bout) in zip(a_in_array, a_out_array, b_out_array)
]
"""
# Do a check
aperture=apertures[-1]
plt.imshow(data_obs)
aperture.plot(color='red',lw=1)
plt.show()
"""

# Radial distance of each annulus
r_arcsec = [(j + 0.5 * (i - j)) * pxsize
            for (i, j) in zip(a_out_array, a_in_array)]  # arcsec
def radial_profile(data, lim):

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

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

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

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

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

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

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

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

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

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

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

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

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

    return None
Beispiel #8
0
    def _create_apertures(self, image, image_stars_coordinates, data_shape):
        self.info('Creating apertures started')
        apertures = []
        sigma_values_table = []
        sigma_value = namedtuple('sigma_value', ['mean', 'median', 'std'])

        masks = [self._create_mask(
            star_coo, data_shape) for star_coo in image_stars_coordinates]

        for i, mask in enumerate(masks):
            mean, median, std = sigma_clipped_stats(
                image.data, mask=mask,
                sigma=self.config_section.get('sigma_clipped_sigma'),
                iters=self.config_section.get('sigma_clipped_iters'))

            self.info('Sigma clipped stats: mean={}, median={}, std={}'.format(
                mean, median, std))

            if (self.config_section.get('calculate_center') or
                    self.config_section.get('calculate_aperture')):

                star_properties = self._find_star_properties(np.copy(image.data), median,
                                                             mask, image_stars_coordinates[i])

            if self.config_section.get('calculate_center'):
                position = (star_properties['xcentroid'].value,
                            star_properties['ycentroid'].value)
            else:
                position = image_stars_coordinates[i]
                self.info(
                    'Calculate center is off, original coordinates have been used')
                self.info('Coordinates={}'.format(position))

            if self.config_section.get('calculate_aperture'):
                self.info('Calculating apertures has been started')
                a = star_properties['semimajor_axis_sigma'] * self.config_section.get(
                    'r_aperture_multi')
                b = star_properties['semiminor_axis_sigma'] * self.config_section.get(
                    'r_aperture_multi')
                theta = star_properties['orientation']
                self.info('Found aperture parameters: a={}, b={}, theta={}'.format(
                    a, b, theta))
                aperture = EllipticalAperture(
                    position, a=a.value, b=b.value, theta=theta.value)
                annulus = EllipticalAnnulus(position,
                                            a_in=a.value + self.config_section.get(
                                                'r_annulus_in'),
                                            a_out=a.value + self.config_section.get(
                                                'r_annulus_out'),
                                            b_out=b.value + self.config_section.get(
                                                'r_annulus_out'),
                                            theta=theta.value)
            else:
                self.info('Aperture calculate is off')
                self.info(
                    'Aperture paratmeters from configuration file have been used')

                aperture = CircularAperture(
                    position, r=self.config_section.get('r_aperture'))
                annulus = CircularAnnulus(position,
                                          r_in=self.config_section.get(
                                              'r_aperture') + self.config_section.get(
                                              'r_annulus_in'),
                                          r_out=self.config_section.get(
                                              'r_aperture') + self.config_section.get(
                                              'r_annulus_out'))

            apertures.append([aperture, annulus, std])
            sigma_values_table.append(sigma_value(mean, median, std))

        return apertures, sigma_values_table
Beispiel #9
0
if show_images:
    apertures.plot(color='blue', lw=2)
    norm = ImageNormalize(quadRU_data, interval=ZScaleInterval())
    plt.imshow(quadRU_data,
               origin='lower',
               norm=norm,
               cmap='BrBG',
               clim=(0, 1000))
    plt.show()
    plt.clf()

##Use EllipticalAnnulus
annuli = EllipticalAnnulus(star_coords,
                           a_in=5.5,
                           a_out=7,
                           b_out=6,
                           theta=np.pi / 4)
print("Elliptical Annuli", annuli)
phot_table_ellip = aperture_photometry(quadRU_data, annuli, method='exact')
print("phot_table_ellip", phot_table_ellip)

if show_images:
    annuli.plot(color='blue', lw=2)
    plt.imshow(quadRU_data,
               origin='lower',
               norm=norm,
               cmap='BrBG',
               clim=(0, 1000))
    plt.show()
    plt.clf()
Beispiel #10
0
def alma_data(rundir, fits_image, mode, lim):

    ############################################################
    # Absolute paths to files
    path_fits_file = rundir + 'output/' + fits_image
    path_image_file = rundir + 'Image.out'
    path_input_file = rundir + 'input.dat'

    ############################################################
    # Fetching information
    imfile = open(path_image_file).readlines()
    for line in imfile:
        if line.split('=')[0] == 'MCobs:fov':
            fov = float(line.split('=')[1].split('!')[0])
        elif line.split('=')[0] == 'MCobs:npix':
            npix = float(line.split('=')[1].split('!')[0])
        elif line.split('=')[0] == 'MCobs:phi':
            phi_image = float(line.split('=')[1].split('!')[0])
        elif line.split('=')[0] == 'MCobs:theta':
            theta = float(line.split('=')[1].split('!')[0])
        else:
            continue
    infile = open(path_input_file).readlines()
    for line in infile:
        if line.split('=')[0] == 'Distance':
            d = float(line.split('=')[1])

    ############################################################
    # Derived quantities
    pxsize = fov / npix  # pixel scale (arcsec/px)
    phi = (phi_image * units.deg).to(
        units.rad).value  # PA from north to east (rad)
    theta = (theta * units.deg).to(units.rad).value  # Inclination (rad)
    d = (d * units.pc).to(units.au).value  # Distance (au)

    ############################################################
    # For photometry
    e = np.sin(theta)  # eccentricity of the annulus

    ############################################################
    # Load data
    hdulist = fits.open(path_fits_file)
    assert (mode in ['alma', 'jband']), "%s This mode is not recognized" % mode
    if mode == 'alma':
        data = hdulist[0].data[0]
        data = convolve_image(data)
    elif mode == 'jband':
        data_Q = hdulist[0].data[1]
        data_U = hdulist[0].data[2]
        data = data_Q * np.cos(2 * phi) + data_U * np.sin(2 * phi)

    ############################################################
    # Brightness profile
    linear_lim = 2 * (lim)  # AU
    angular_lim = ((linear_lim / d) * units.rad).to(
        units.arcsec).value  # arcsec
    pixel_lim = int(round(angular_lim / pxsize))

    # Creating elliptical aperture object in pixel coordinates
    xc = 0.5 * data.shape[0]
    yc = 0.5 * data.shape[1]
    dr = 1.0
    ain_array = []
    for i in np.arange(xc + dr, xc + 0.5 * pixel_lim, dr):
        ain_array.append(i - xc)
    aout_array = [i + dr for i in ain_array]
    bout_array = [i * (1 - e**2)**0.5 for i in aout_array]

    # Creating apertures
    apertures = [
        EllipticalAnnulus((xc, yc),
                          a_in=ain,
                          a_out=aout,
                          b_out=bout,
                          theta=0.0)
        for (ain, aout, bout) in zip(ain_array, aout_array, bout_array)
    ]

    ############################################################
    # Do a check?
    a = 0.01
    vmin = np.percentile(data, a)
    vmax = np.percentile(data, 100 - a)
    aperture = apertures[-1]
    fig = plt.figure()
    ax = plt.axes()
    ax.imshow(data, clim=(vmin, vmax))
    aperture.plot(color='red', lw=1)
    if mode == "alma":
        fig.savefig("alma_image.png")
    elif mode == "jband":
        fig.savefig("jband_image.png")
    #plt.show()

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

    #if mode=='jband':

    # Create arrays for output file
    r_arcsec = [(j + 0.5 * (i - j)) * pxsize
                for (i, j) in zip(aout_array, ain_array)]  # arcsec
    r_rad = [(i * units.arcsec).to(units.rad).value for i in r_arcsec]  # rad
    r_au = [((i * d) * units.au).value for i in r_rad]  # AU

    ############################################################
    # Quick check?
    fig = plt.figure()
    ax = plt.axes()
    #ax.plot(r_au,brightness/max(brightness),'*',markersize=0.9,label="model")
    #if mode=='jband':
    #    ax.plot(r_au,brightness,'*',markersize=0.9,label="model")
    ax.set_xlabel(r"$r$ (AU)")
    if mode == 'alma':
        ax.plot(r_au,
                brightness / max(brightness),
                '*',
                markersize=0.9,
                label="model")
        odata = np.loadtxt("alma_profile_observed_normed.dat")
        r_obs = odata[:, 0:1]
        b_obs = odata[:, 1:2]
        ax.plot(r_obs, b_obs, label="observation")
        ax.set_title("No convolved")
        ax.axvline(74)
        ax.legend()
    elif mode == 'jband':
        factor = 1 / 50.8849
        brightness = brightness * factor
        ax.plot(r_au, brightness, '*', markersize=0.9, label="model")
        odata = np.loadtxt("jband_profile_observed_normed.dat")
        r_obs = odata[:, 0:1]
        b_obs = odata[:, 1:2]
        ax.axvline(54)
        ax.plot(r_obs, b_obs, label='observation')
        ax.set_ylim(-0.1, 1.8)
        ax.legend()
    plt.show()

    return None
Beispiel #11
0
def fitSersic(image: np.ndarray,
              centroid: List[float],
              fwhms: List[float],
              theta: float,
              starMask=None):
    '''Function that fits a 2D sersic function to an image of a Galaxy.

    Parameters
    ----------

    image : np.ndarray
        image to which a 2D Sersic function will be fit
    centroid : List[float]
        Centre of object of interest
    fwhms : List[float]
        Full width half maximums of object
    theta : float
        rotation of object anticlockwise from positive x axis
    starMask : np.ndarray
        Mask contains star locations.

    Returns
    -------

    Parameters : astropy.modeling.Model object

        Collection of best fit parameters for the 2D sersic function

    '''

    if starMask is None:
        imageCopy = image
    else:
        imageCopy = image * starMask

    fit_p = fitting.LevMarLSQFitter()

    # amplitude => Surface brightness at r_eff
    # r_eff => Effective (half-light) radius
    # n => sersic index, guess 1.?

    b = 2. * min(fwhms)
    a = 2. * max(fwhms)
    ellip = 1. - (b / a)

    apertureTotal = EllipticalAperture(centroid, a, b, theta)
    totalSum = apertureTotal.do_photometry(imageCopy, method="exact")[0][0]

    # get bracketing values for root finder to find r_eff
    deltaA = (a / 100.) * 2.
    aCurrent = a - deltaA
    aMin = 0
    aMax = 0
    while True:
        apertureCurrent = EllipticalAperture(centroid, aCurrent, b, theta)
        currentSum = apertureCurrent.do_photometry(imageCopy,
                                                   method="exact")[0][0]
        currentFraction = currentSum / totalSum
        if currentFraction <= .5:
            aMin = aCurrent
            aMax = aCurrent + deltaA
            break
        aCurrent -= deltaA

    # get root
    r_eff = brentq(_fractionTotalFLuxEllipse,
                   aMin,
                   aMax,
                   args=(imageCopy, b, theta, centroid, totalSum))

    # calculate amplitude at r_eff
    a_in = r_eff - 0.5
    a_out = r_eff + 0.5
    b_out = a_out - (1. * ellip)
    ellip_annulus = EllipticalAnnulus(centroid, a_in, a_out, b_out, theta)
    totalR_effFlux = ellip_annulus.do_photometry(imageCopy,
                                                 method="exact")[0][0]
    meanR_effFlux = totalR_effFlux / ellip_annulus.area

    sersic_init = models.Sersic2D(amplitude=meanR_effFlux,
                                  r_eff=r_eff,
                                  n=2.0,
                                  x_0=centroid[0],
                                  y_0=centroid[1],
                                  ellip=ellip,
                                  theta=theta)

    ny, nx = imageCopy.shape
    y, x = np.mgrid[0:ny, 0:nx]

    Parameters = fit_p(sersic_init, x, y, imageCopy, maxiter=1000, acc=1e-8)

    return Parameters
Beispiel #12
0
#creating the figure with the galaxy and its apertures
fig = plt.figure(figsize=(figsize_x,figsize_y))
ax  = plt.subplot() #nothing inside because it is the only plot
plt.imshow(image, cmap = 'cubehelix', norm = colors.LogNorm(), interpolation = 'nearest')

#calculating the flux and the area in each elliptical annulus
apers = []
area  = []
for ii in range(len(aa)):
    """ THIS WORKED WELL AS WELL
    ellip_aper = EllipticalAperture(centroid, aa[ii], bb[ii], position_angle)
    area = ellip_aper.area()
    flux.append(aperture_photometry(image, ellip_aper, error = rms_image))
    """
    if ii == 0:
        ellip_annulus = EllipticalAnnulus(centroid,       0,aa[ii],bb[ii],position_angle)
    else:
        ellip_annulus = EllipticalAnnulus(centroid,aa[ii-1],aa[ii],bb[ii],position_angle)
    apers.append(aperture_photometry(image, ellip_annulus, error = rms_image))
    area_annulus = ellip_annulus.area()
    area.append(area_annulus)
    #I plot the apertures
    ellip_annulus.plot(ax=ax)

#area's rows are scalars, but flux rows are aperture_photometry tables, and I need to join all of them. I get this by doing
table_apers = hstack(apers)

#printing the image with the apertures
plt.savefig("pyapertures.pdf")
plt.close()
plt.clf()
Beispiel #13
0
def get_profile(file, pxsize, PA_disk, inc, d, size, Nbins, dr, **kwargs):

    ############################################################
    #
    # Extract a radial cut of the brightness along diffent
    # position angles.
    #
    # file: the fits file of the observation
    # pxsize: pixel scale (arcsec/px)
    # PA_aperture: position angle of the aperture measured east-north (deg)
    # inc: disk's inclination (deg)
    # d: distance to the source (pc)
    # size: semi-major axis of the disk (AU)
    # dr: width of the annulus (AU)
    #
    # The ouput is a matrix whose the rows and columns represent
    # the position angle and the radial distance of the flux
    # measurement.
    #
    ############################################################

    ############################################################
    # Load ALMA data
    if kwargs['type'] == 'obs':
        hdulist = fits.open(file)
        data_obs = hdulist[0].data[0][0]
        """
        xc=data_obs.shape[0]*0.5
        yc=data_obs.shape[1]*0.5
        """
        xc = hdulist[0].header['CRPIX1']
        yc = hdulist[0].header['CRPIX2']

    elif kwargs['type'] == 'mod':
        hdulist = fits.open(file)
        data_obs = hdulist[0].data
        xc = data_obs.shape[0] * 0.5
        yc = data_obs.shape[1] * 0.5

    ############################################################
    # Derived properties
    angle_annulus = ((PA_disk - 90.0) * units.deg).to(units.rad).value
    e = np.sin((inc * units.deg).to(units.rad).value)
    d_au = (d * units.pc).to(units.au).value
    xc_array = []
    yc_array = []

    ############################################################
    # Creating elliptical aperture
    linear_lim = 2 * (size)  # AU
    angular_lim = linear_lim / d_au  # rad
    angular_lim = (angular_lim * units.rad).to(units.arcsec).value  # arcsec
    pixel_lim = int(round(angular_lim / pxsize))
    dr = topx(dr, pxsize, d)  # width of each annular aperture
    a_in_array = []
    for i in np.arange(yc + dr, yc + 0.5 * pixel_lim, dr):
        a_in_array.append(i - xc)
    a_out_array = [i + dr for i in a_in_array]
    b_out_array = [i * (1 - e**2)**0.5 for i in a_out_array]
    a_in_array = np.array(a_in_array)
    a_out_array = np.array(a_out_array)
    apertures = [
        EllipticalAnnulus((yc, xc),
                          a_in=ain,
                          a_out=aout,
                          b_out=bout,
                          theta=angle_annulus)
        for (ain, aout, bout) in zip(a_in_array, a_out_array, b_out_array)
    ]

    print("Number of annular apertures: %d" % len(apertures))
    """
    # Do a check?
    plt.imshow(data_obs)
    apertures[-1].plot(color='red',lw=1)
    plt.show()
    """

    ############################################################
    # Define class "Bin"
    class Bin:
        def __init__(self, ID, theta_min, theta_max, plist):
            self.ID = ID
            self.theta_min = theta_min
            self.theta_max = theta_max
            self.plist = plist

        def showFlux(self):
            i = 0
            for pixel in self.plist:
                print(i, aperture_data[pixel[0], pixel[1]])
                i += 1

        def getArea(self, aperture):
            value = aperture.area / Nbins
            return value

        def getFlux(self):
            flux = 0.0
            for pixel in self.plist:
                flux += aperture_data[pixel[0], pixel[1]]
            return flux

        def getTheta(self):
            value = self.theta_min  #(self.theta_max-self.theta_min)*0.5+self.theta_min

            return value

        def getError_beam(self, aperture):
            beam_x = 0.074  # arcsec
            beam_y = 0.057  # arcsec
            flux_array = []
            for pixel in self.plist:
                flux_array.append(aperture_data[pixel[0], pixel[1]])
            area = aperture.area / Nbins
            flux_array = np.array(flux_array) / area
            sigma = np.std(flux_array)
            beam_area = np.pi * (beam_x) * (beam_y) / (4 * np.log(2))
            Nbeam = ((aperture.area * pxsize**2) / Nbins) / beam_area
            print("I have %.1f pixels" % len(self.plist))
            return sigma / (Nbeam)**0.5

        def getError_pixel(self, aperture):
            flux_array = []
            for pixel in self.plist:
                flux_array.append(aperture_data[pixel[0], pixel[1]])
            area = aperture.area / Nbins
            flux_array = np.array(flux_array) / area
            sigma = np.std(flux_array)
            Npixel = len(self.plist)
            return sigma / (Npixel)**0.5

    #thetas=np.linspace(0,2*np.pi,Nbins+1)
    thetas = np.linspace(0, 2 * np.pi, Nbins + 1)
    M = np.zeros((Nbins, len(apertures)))
    E_beam = np.zeros((Nbins, len(apertures)))
    E_pixel = np.zeros((Nbins, len(apertures)))

    a_in_array = [i * pxsize * d for i in a_in_array]
    a_out_array = [i * pxsize * d for i in a_out_array]
    a_mid = np.array([(j - i) * 0.5 + i
                      for (j, i) in zip(a_out_array, a_in_array)])

    for ii in range(0, len(apertures)):

        ############################################################
        # Creating array of bins
        bin_list = []

        for i in range(0, Nbins):
            sbin = Bin(i + 1, thetas[i], thetas[i + 1], [])
            bin_list.append(sbin)

        if ii == 0:
            midtheta = []
            midr = []
            for value in bin_list:
                angle = value.getTheta() - 0.5 * np.pi
                if angle < 0.0:
                    angle = 2 * np.pi + angle
                midtheta.append(angle)
            midtheta = np.array(midtheta)

        ############################################################
        # Creating aperture mask
        mask = apertures[ii].to_mask(method="center")
        """
        # Do a check?
        plt.imshow(mask)
        plt.colorbar()
        plt.show()
        """

        ############################################################
        # Extracting pixels located inside the aperture
        aperture_data = mask.multiply(data_obs)
        """
        # Do a check?
        plt.imshow(aperture_data)
        plt.colorbar()
        plt.show()
        """

        ############################################################
        # Creating array of pixel's index within the aperture
        # relative to the star
        pixel_list = []
        ycc = int(aperture_data.shape[0] * 0.5)
        xcc = int(aperture_data.shape[1] * 0.5)
        for i in range(0, aperture_data.shape[1]):  # Over columns
            for j in range(0, aperture_data.shape[0]):  # Over rows
                if aperture_data[j, i] != 0.0:
                    pixel_list.append((j - ycc, i - xcc))

        ############################################################
        # Filling in bin_list
        for point in pixel_list:
            phi = np.arctan2(point[0], point[1])  #-0.5*np.pi
            if phi < 0.0:
                phi = 2 * np.pi + phi
            for sbin in bin_list:
                if sbin.theta_min <= phi < sbin.theta_max:
                    pixel = (int(point[0] + ycc), int(point[1] + xcc))
                    sbin.plist.append(pixel)

        ############################################################
        # Writing result
        j = 0  # Count over position angles
        print("radius=%.2f" % a_mid[ii])
        for value in bin_list:
            #value.getError_beam(apertures[ii])
            M[j][ii] = value.getFlux() / value.getArea(apertures[ii])
            E_beam[j][ii] = value.getError_beam(apertures[ii])
            E_pixel[j][ii] = value.getError_pixel(apertures[ii])
            j += 1

    Mmax = M.max()
    print()
    print("Max value (Jy/beam/bin_area): %.1e" % (Mmax))
    print("Max error (per beam): %.1e" % (np.nanmax(E_beam)))
    print("Max error (per pixel): %.1e" % (np.nanmax(E_pixel)))

    for i in range(0, M.shape[0]):
        M[i] = M[i] / Mmax
        E_beam[i] = E_beam[i] / Mmax
        E_pixel[i] = E_pixel[i] / Mmax

    ############################################################
    # Plotting
    index_to_swap = []
    for i in range(0, len(midtheta)):
        if 1.5 * np.pi <= midtheta[i] < 2 * np.pi:
            index_to_swap.append(i)

    M_new = np.zeros((M.shape[0], M.shape[1]))
    E_beam_new = np.zeros((E_beam.shape[0], E_beam.shape[1]))
    E_pixel_new = np.zeros((E_pixel.shape[0], E_pixel.shape[1]))

    M_new[M.shape[0] - len(index_to_swap):M.shape[0]] = M[0:len(index_to_swap)]
    M_new[0:M.shape[0] - len(index_to_swap)] = M[len(index_to_swap):M.shape[0]]
    M = M_new

    E_beam_new[E_beam.shape[0] - len(index_to_swap):E_beam.
               shape[0]] = E_beam[0:len(index_to_swap)]
    E_beam_new[0:E_beam.shape[0] -
               len(index_to_swap)] = E_beam[len(index_to_swap):E_beam.shape[0]]
    E_beam = E_beam_new

    E_pixel_new[E_pixel.shape[0] - len(index_to_swap):E_pixel.
                shape[0]] = E_pixel[0:len(index_to_swap)]
    E_pixel_new[0:E_pixel.shape[0] -
                len(index_to_swap)] = E_pixel[len(index_to_swap):E_pixel.
                                              shape[0]]
    E_pixel = E_pixel_new

    midtheta = np.sort(midtheta)

    fig = plt.figure(figsize=(5, 12))
    gs = gridspec.GridSpec(int(Nbins * 0.5), 1, hspace=0)
    for i in range(0, int(Nbins * 0.5)):
        ax = plt.subplot(gs[i, 0])
        #       ax.plot(a_mid,np.reshape(M[i:i+1,:],M.shape[1]),'.',color="red")
        #       ax.plot(-a_mid,np.reshape(M[i+int(0.5*Nbins):i+1+int(0.5*Nbins),:],M.shape[1]),'.',color="red")
        ax.errorbar(a_mid,
                    np.reshape(M[i:i + 1, :], M.shape[1]),
                    yerr=np.reshape(E_beam[i:i + 1, :], E_beam.shape[1]),
                    marker=".",
                    fmt="o",
                    color="red")
        ax.errorbar(
            -a_mid,
            np.reshape(M[i + int(0.5 * Nbins):i + 1 + int(0.5 * Nbins), :],
                       M.shape[1]),
            yerr=np.reshape(
                E_beam[i + int(0.5 * Nbins):i + 1 + int(0.5 * Nbins), :],
                E_beam.shape[1]),
            marker=".",
            fmt="o",
            color="red")
        """
        ax.errorbar(a_mid,np.reshape(M[i:i+1,:],M.shape[1]),
                    yerr=np.reshape(E_pixel[i:i+1,:],E_pixel.shape[1]),marker=".",fmt="o",color="red")
        ax.errorbar(-a_mid,np.reshape(M[i+int(0.5*Nbins):i+1+int(0.5*Nbins),:],M.shape[1]),
                    yerr=np.reshape(E_pixel[i+int(0.5*Nbins):i+1+int(0.5*Nbins),:],E_pixel.shape[1]),marker=".",fmt="o",color="red")
        """
        ax.axvline(+74, 0, 1)
        ax.axvline(-74, 0, 1)
        ax.tick_params(labelleft=False, left=False)
        ax.set_ylabel(r"%.1f" %
                      ((midtheta[i] * units.rad).to(units.deg).value))
        ax.set_xlabel(r"$r$(AU)")
    plt.show()
def ellip_ap_an(positions,
                fwhm,
                theta=0.,
                f_ap=(1.5, 1.5),
                f_in=(4., 4.),
                f_out=(6., 6.)):
    ''' A convenience function for pixel elliptical aperture/annulus
    Parameters
    ----------
    positions : array_like or `~astropy.units.Quantity`
        The pixel coordinates of the aperture center(s) in one of the
        following formats:

        * single ``(x, y)`` pair as a tuple, list, or `~numpy.ndarray`
        * tuple, list, or `~numpy.ndarray` of ``(x, y)`` pairs
        * `~astropy.units.Quantity` instance of ``(x, y)`` pairs in
            pixel units

    fwhm : float
        The FWHM in pixel unit.

    theta : float, optional
        The rotation angle in radians of the ellipse semimajor axis from
        the positive ``x`` axis.  The rotation angle increases
        counterclockwise.  The default is 0.

    f_ap, f_in, f_out: int or float, list or tuple of such, optional
        The factors multiplied to ``fwhm`` to set the aperture ``a`` and
        ``b``, inner sky ``a`` and ``b``, and outer sky ``a`` and ``b``,
        respectively. If scalar, it is assumed to be identical for both
        ``a`` and ``b`` parameters. Defaults are ``(1.5, 1.5)``, ``(4.0,
        4.0)``, and ``(6.0, 6.0)``, respectively, which are de facto
        standard values used by classical IRAF users.

    Returns
    -------
    ap, an : `~photutils.EllipticalAperture` and `~photutils.EllipticalAnnulus`
        The object aperture and sky annulus.
    '''
    if np.isscalar(fwhm):
        fwhm = np.repeat(fwhm, 2)

    if np.isscalar(f_ap):
        f_ap = np.repeat(f_ap, 2)

    if np.isscalar(f_in):
        f_in = np.repeat(f_in, 2)

    if np.isscalar(f_out):
        f_out = np.repeat(f_out, 2)

    a_ap = f_ap[0] * fwhm[0]
    b_ap = f_ap[1] * fwhm[1]
    a_in = f_in[0] * fwhm[0]
    a_out = f_out[0] * fwhm[0]
    b_out = f_out[1] * fwhm[1]

    ap = EllipticalAperture(positions=positions, a=a_ap, b=b_ap, theta=theta)
    an = EllipticalAnnulus(positions=positions,
                           a_in=a_in,
                           a_out=a_out,
                           b_out=b_out,
                           theta=theta)

    return ap, an
Beispiel #15
0
def calc_sky(hdu_counts, hdu_ex,
                 ellipse_center, major_diam, minor_diam, pos_angle,
                 sky_in, sky_out, mask_image=None, counts_off_array=None,
                 n_seg_bg_var=8, sig_clip=2, min_pix=25):
    """
    Calculate the sky count rate per pixel and the large-scale variation

    Parameters
    ----------
    hdu_counts : astropy hdu object
        An HDU with the counts image image

    hdu_counts : astropy hdu object
        An HDU with the counts image image

    ellipse_center : list of two floats
        RA and Dec (degrees) of the ellipse center

    major_diam, minor_diam : float
        major and minor axes (units irrelevant, since only the ratio is used here)

    pos_angle : float
        position angle of ellipse

    sky_in, sky_out : float
        boundaries of sky annulus (arcsec)

    mask_image : astropy hdu object (default=None)
        an image of 1s and 0s, where 0s represent masked pixels

    counts_off_array : array of floats (default=None)
        an image giving any previously applied offsets

    n_seg_bg_var : int
        number of segments to divide the sky annulus into for background
        variation estimate

    sig_clip : float (default=2)
        apply a N iterations of sigma clipping to count rate values before
        calculating sky

    min_pix : int (default=25)
        minimum number of pixels in a segment that are necessary for sky
        calculations to commence


    Returns
    -------
    sky_phot : dictionary
        sky count rate per pixel, and uncertainties

    sky_seg_phot : array of floats
        count rate per pixel in each of the 8 sky segments

    sky_seg_phot_err : array of floats
        uncertainty for each sky_seg_phot value

    """

    # WCS for the images
    wcs_counts = wcs.WCS(hdu_counts.header)
    #arcsec_per_pix = wcs_counts.wcs.cdelt[1] * 3600
    arcsec_per_pix = wcs.utils.proj_plane_pixel_scales(wcs_counts)[0] * 3600

    # -------------------------
    # sky background
    # -------------------------

       
    # define aperture object
    aperture = EllipticalAnnulus(tuple(ellipse_center),
                                     a_in=sky_in/arcsec_per_pix,
                                     a_out=sky_out/arcsec_per_pix,
                                     b_out=sky_out/arcsec_per_pix * minor_diam/major_diam,
                                     theta=(90+pos_angle)*np.pi/180)
    # make an ApertureMask object with the aperture
    annulus_mask = aperture.to_mask(method='exact')
    # turn aperture into an image
    annulus_im = annulus_mask[0].to_image(hdu_counts.data.shape)

    # make masked version using input ds9 file
    if mask_image is not None:
        annulus_im = annulus_im * mask_image

    # plot things
    #annulus_data = annulus_mask[0].multiply(hdu_counts.data)
    #plt.imshow(annulus_mask[0], origin='lower')
    #plt.imshow(np.log10(annulus_data), origin='lower')
    #plt.imshow(annulus_im, origin='lower')
    #plt.colorbar()
    #pdb.set_trace()

    # list of values within aperture
    nonzero_annulus = np.where(annulus_im > 1e-5)
    annulus_list = annulus_im[nonzero_annulus]
    counts_list = hdu_counts.data[nonzero_annulus]
    exp_list = hdu_ex.data[nonzero_annulus]
    if counts_off_array is not None:
        counts_off_list = counts_off_array[nonzero_annulus]

    # calculate background
    if counts_off_array is not None:
        sky_phot = do_phot(annulus_list, counts_list, exp_list, offset_list=counts_off_list, sig_clip=sig_clip)
    else:
        sky_phot = do_phot(annulus_list, counts_list, exp_list, sig_clip=sig_clip)

    # -------------------------
    # sky background variation
    # -------------------------

    # define theta around the sky annulus
    delta_x = nonzero_annulus[1] - ellipse_center[0]
    delta_y = nonzero_annulus[0] - ellipse_center[1]
    theta = np.arccos(delta_x/np.sqrt(delta_x**2 + delta_y**2))
    # go from 0->2pi instead of 0->pi and pi->0 (yay arccos?)
    theta[delta_y < 0] = np.pi + (np.pi - theta[delta_y < 0])
    # convert to degrees
    theta_deg = theta * 180/np.pi
    # shift starting point to match position angle of galaxy
    theta_deg = (theta_deg + (90-pos_angle)) % 360

        
    # increments of theta for N equal-area segments
    theta_k_list = np.arange(n_seg_bg_var+1) * 360/n_seg_bg_var
    phi_list = np.abs( np.arctan(minor_diam/major_diam * np.tan(theta_k_list * np.pi/180)) * 180/np.pi )
    # (adjustments for each quadrant)
    q2 = (theta_k_list > 90) & (theta_k_list <= 180)
    phi_list[q2] = (90 - phi_list[q2]) + 90
    q3 = (theta_k_list > 180) & (theta_k_list <= 270)
    phi_list[q3] = phi_list[q3] + 180
    q4 = (theta_k_list > 270) & (theta_k_list <= 360)
    phi_list[q4] = (90 - phi_list[q4]) + 270
    # list of deltas
    delta_list = np.diff(phi_list)
    
    
    # increments of theta for 8 equal-area segments
    #delta_theta = np.arctan(minor_diam/major_diam) * 180/np.pi
    #delta_list = [delta_theta, 90-delta_theta, 90-delta_theta, delta_theta,
    #                  delta_theta, 90-delta_theta, 90-delta_theta, delta_theta]
    theta_start = 0

    # array to save results
    sky_seg_phot = np.full(len(delta_list), np.nan)
    sky_seg_phot_err = np.full(len(delta_list), np.nan)
    
    
    for i in range(len(delta_list)):
        # indices of the current segment
        seg = np.where((theta_deg >= theta_start) & (theta_deg < theta_start+delta_list[i]))
        ind = (nonzero_annulus[0][seg[0]], nonzero_annulus[1][seg[0]])

        #temp = np.zeros(annulus_im.shape)
        #temp[ind] = 1
        #plt.imshow(temp, origin='lower')
        #plt.colorbar()
        #pdb.set_trace()

        if len(ind[0]) > min_pix:
            #print('** doing theta='+str(theta_start))
            # list of values within segment
            annulus_list = annulus_im[ind]
            counts_list = hdu_counts.data[ind]
            exp_list = hdu_ex.data[ind]
            if counts_off_array is not None:
                counts_off_list = counts_off_array[ind]
            # do photometry
            if counts_off_array is not None:
                temp = do_phot(annulus_list, counts_list, exp_list, offset_list=counts_off_list, sig_clip=2)
            else:
                temp = do_phot(annulus_list, counts_list, exp_list, sig_clip=2)
            # save it
            sky_seg_phot[i] = temp['count_rate_per_pix']
            sky_seg_phot_err[i] = temp['count_rate_err_per_pix']

        # next segment
        theta_start += delta_list[i]


    # return useful quantities
    return sky_phot, sky_seg_phot, sky_seg_phot_err
Beispiel #16
0
def surface_phot(label, center_ra, center_dec, major_diam, minor_diam, pos_angle,
                     ann_width, zeropoint, zeropoint_err=0.0,
                     aperture_factor=1.0, sky_aperture_factor=1.0,
                     mask_file=None, offset_file=False,
                     verbose=False):
    """
    Do surface brightness photometry within annuli

    Parameters
    ----------
    label : string
        label associated with the galaxy, both for finding image files and
        saving results (e.g., 'ngc24_offset_w2_')

    center_ra, center_dec : float
        coordinates of the center of the galaxy (degrees)

    major_diam, minor_diam : float
        major and minor axes for the galaxy ellipse (arcsec)

    pos_angle : float
        position angle of the galaxy ellipse ("position angle increases
        counterclockwise from North (PA=0)")

    ann_width : float
        width of annuli (arcsec)

    zeropoint : float
        conversion from counts/sec into magnitude units
        AB_mag = -2.5*log10(counts/sec) + zeropoint

    zeropoint_err : float (default=0)
        uncertainty for the zeropoint

    aperture_factor : float (default=1.0)
        make the aperture larger by a factor of N (useful to quickly adjust
        aperture if, e.g., you know R25 is too small for your UV galaxy)

    sky_aperture_factor : float (default=1.0)
        choose whether the sky aperture starts at the edge of the photometry
        aperture (1.0) or some factor N larger

    mask_file : string (default=None)
        path+name of ds9 region file with masks

    offset_file : boolean (default=False)
        if True, the file label+'sk_off.fits' is used to show what offsets (in
        counts) have already been added to the counts images

    verbose : boolean (default=False)
        if True, print progress

    """

    # read in the images
    counts_im = label + 'sk.fits'
    exp_im = label + 'ex.fits'
    offset_im = label + 'sk_off.fits'

    # if files don't exist, return NaN
    if (not os.path.isfile(counts_im)) or (not os.path.isfile(exp_im)):
        print('surface_phot: image(s) not found')
        return np.nan
    

    with fits.open(counts_im) as hdu_counts, fits.open(exp_im) as hdu_ex:

        # if mask region file is provided, make a mask image
        if mask_file is not None:
            mask_image = make_mask_image(hdu_counts[1], mask_file)
        # otherwise mask is all 1s
        else:
            mask_image = np.ones(hdu_counts[1].data.shape)

        # mask any areas where exposure time is 0
        mask_image[np.where(hdu_ex[1].data < 1e-5)] = 0
            
        # for some unknown reason (uvotimsum bug?), counts file could have NaNs
        # -> mask them
        mask_image[np.where(np.isfinite(hdu_counts[1].data) == 0)] = 0


        # if offset file is set, save it into an array
        if offset_file == True:
            with fits.open(label+'sk_off.fits') as hdu_off:
                counts_off_array = hdu_off[1].data

            # mask any NaNs
            mask_image[np.where(np.isfinite(counts_off_array) == 0)] = 0

        else:
            counts_off_array = None


        # WCS for the images
        wcs_counts = wcs.WCS(hdu_counts[1].header)
        arcsec_per_pix = wcs_counts.wcs.cdelt[1] * 3600
        
        # ellipse center
        #ellipse_center = SkyCoord(ra=center_ra*u.deg, dec=center_dec*u.deg)
        ellipse_center = wcs_counts.wcs_world2pix([[center_ra,center_dec]], 0)[0]
        
        # array of annuli over which to do photometry
        annulus_array = np.arange(0, major_diam*aperture_factor, ann_width)# * u.arcsec 


        # -------------------------
        # sky background and variation
        # -------------------------

        # size of sky annulus
        sky_in = annulus_array[-1] * sky_aperture_factor
        sky_ann_width = ann_width * 10
        sky_out = sky_in + sky_ann_width

        sky_phot, sky_seg_phot, sky_seg_phot_err = calc_sky(hdu_counts[1], hdu_ex[1],
                                                                ellipse_center, major_diam, minor_diam, pos_angle,
                                                                sky_in, sky_out,
                                                                mask_image=mask_image,
                                                                counts_off_array=counts_off_array)
        

        # -------------------------
        # photometry for each annulus
        # -------------------------

        # initialize a table (or, rather, the rows... turn into table later)
        cols_ann = ['radius','count_rate','count_rate_err',
                    'count_rate_err_poisson','count_rate_err_bg',
                    'mu','mu_err','n_pix']
        units_ann = ['arcsec','cts/sec','cts/sec',
                     'cts/sec','cts/sec',
                     'ABmag/arcsec2','ABmag/arcsec2','']
        dtypes = ['%9.3f','%9f','%9f',
                      '%9f','%9f',
                      '%9f','%9f','%9f']
        phot_dict_ann = {key:np.zeros(len(annulus_array)-1) for key in cols_ann}

        for i in range(len(annulus_array)-1):
        #for i in range(0,5):

            # save radius
            phot_dict_ann['radius'][i] = annulus_array[i+1]

            # define aperture object
            aperture = EllipticalAnnulus(tuple(ellipse_center),
                                             a_in=annulus_array[i]/arcsec_per_pix,
                                             a_out=annulus_array[i+1]/arcsec_per_pix,
                                             b_out=annulus_array[i+1]/arcsec_per_pix * minor_diam/major_diam,
                                             theta=(90+pos_angle)*np.pi/180)
            # make an ApertureMask object with the aperture
            annulus_mask = aperture.to_mask(method='exact')
            # turn aperture into an image
            annulus_im = annulus_mask[0].to_image(hdu_counts[1].data.shape)

            # get total number of pixels (using ellipse areas, in case some of the aperture is off the image)
            #tot_pix = np.sum(annulus_im)
            area_out = np.pi * annulus_array[i+1]/arcsec_per_pix * annulus_array[i+1]/arcsec_per_pix * minor_diam/major_diam
            area_in = np.pi * annulus_array[i]/arcsec_per_pix * annulus_array[i]/arcsec_per_pix * minor_diam/major_diam
            tot_pix = area_out - area_in
            tot_arcsec2 = tot_pix * arcsec_per_pix**2
            phot_dict_ann['n_pix'][i] = tot_pix
            
            # make masked version
            annulus_im = annulus_im * mask_image

            # plot things
            #annulus_data = annulus_mask[0].multiply(hdu_counts[1].data)
            #plt.imshow(annulus_mask[0])
            #plt.imshow(annulus_data, origin='lower')
            #plt.imshow(annulus_im, origin='lower')
            #plt.colorbar()

            # list of values within aperture
            nonzero_annulus = np.where(annulus_im > 1e-5)
            annulus_list = annulus_im[nonzero_annulus]
            counts_list = hdu_counts[1].data[nonzero_annulus]
            exp_list = hdu_ex[1].data[nonzero_annulus]
            if offset_file == True:
                counts_off_list = counts_off_array[nonzero_annulus]

            # do photometry
            if offset_file == True:
                ann_temp = do_phot(annulus_list, counts_list, exp_list, offset_list=counts_off_list)
            else:
                ann_temp = do_phot(annulus_list, counts_list, exp_list)

            # subtract background
            ann_phot_per_pix = ann_temp['count_rate_per_pix'] - sky_phot['count_rate_per_pix']
            ann_phot_per_pix_err = np.sqrt(ann_temp['count_rate_err_per_pix']**2 +
                                            sky_phot['count_rate_err_per_pix']**2 +
                                            np.nanstd(sky_seg_phot)**2 )
            ann_phot_per_pix_pois_err = ann_temp['count_rate_pois_err_per_pix']
            ann_phot_per_pix_bg_err = np.sqrt(ann_temp['count_rate_off_err_per_pix']**2 +
                                                sky_phot['count_rate_err_per_pix']**2 +
                                                np.nanstd(sky_seg_phot)**2 )

            # multiply by the number of pixels in the annulus to get the total count rate
            ann_phot = ann_phot_per_pix * tot_pix
            ann_phot_err = ann_phot_per_pix_err * tot_pix
            ann_phot_pois_err = ann_phot_per_pix_pois_err * tot_pix
            ann_phot_bg_err = ann_phot_per_pix_bg_err * tot_pix

            phot_dict_ann['count_rate'][i] = ann_phot
            phot_dict_ann['count_rate_err'][i] = ann_phot_err
            phot_dict_ann['count_rate_err_poisson'][i] = ann_phot_pois_err
            phot_dict_ann['count_rate_err_bg'][i] = ann_phot_bg_err

            # convert to surface brightness
            # - counts/sec/arcsec2
            ann_phot_arcsec2 = ann_phot / tot_arcsec2
            ann_phot_arcsec2_err = ann_phot_err / tot_arcsec2
            # - mag/arcsec2
            mag_arcsec2 = -2.5 * np.log10(ann_phot_arcsec2) + zeropoint
            mag_arcsec2_err = np.sqrt( ( 2.5/np.log(10) * ann_phot_arcsec2_err/ann_phot_arcsec2 )**2 +
                                           zeropoint_err**2 )

            phot_dict_ann['mu'][i] = mag_arcsec2
            phot_dict_ann['mu_err'][i] = mag_arcsec2_err

            
            #[print(k+': ', phot_dict_ann[k][i]) for k in cols_ann]
            #pdb.set_trace()


        # make big numpy array
        data_array = np.column_stack(tuple([phot_dict_ann[key] for key in cols_ann]))
        # save it to a file
        np.savetxt(label+'phot_annprofile.dat', data_array,
                       header=' '.join(cols_ann) + '\n' + ' '.join(units_ann),
                       delimiter='  ', fmt=dtypes)


        # -------------------------
        # total photometry within each radius
        # -------------------------

        # initialize a table (or, rather, the rows... turn into table later)
        cols_tot = ['radius','count_rate','count_rate_err',
                    'count_rate_err_poisson','count_rate_err_bg',
                    'mag','mag_err','n_pix']
        units_tot = ['arcsec','cts/sec','cts/sec',
                     'cts/sec','cts/sec',
                     'ABmag','ABmag','']
        dtypes = ['%9.3f','%9f','%9f',
                      '%9f','%9f',
                      '%9f','%9f','%9f']
        phot_dict_tot = {key:np.zeros(len(annulus_array)-1) for key in cols_tot}

        for i in range(len(annulus_array)-1):
        #for i in range(0,5):

            # save radius
            phot_dict_tot['radius'][i] = annulus_array[i+1]

            # define aperture object
            aperture = EllipticalAperture(tuple(ellipse_center),
                                             a=annulus_array[i+1]/arcsec_per_pix,
                                             b=annulus_array[i+1]/arcsec_per_pix * minor_diam/major_diam,
                                             theta=(90+pos_angle)*np.pi/180)
            # make an ApertureMask object with the aperture
            annulus_mask = aperture.to_mask(method='exact')
            # turn aperture into an image
            annulus_im = annulus_mask[0].to_image(hdu_counts[1].data.shape)
            
            # get total number of pixels (using ellipse areas, in case some of the aperture is off the image)
            #tot_pix = np.sum(annulus_im)
            tot_pix = np.pi * annulus_array[i+1]/arcsec_per_pix * annulus_array[i+1]/arcsec_per_pix * minor_diam/major_diam
            tot_arcsec2 = tot_pix * arcsec_per_pix**2
            phot_dict_tot['n_pix'][i] = tot_pix
            
            # make masked version
            annulus_im = annulus_im * mask_image

            # plot things
            #annulus_data = annulus_mask[0].multiply(hdu_counts[1].data)
            #plt.imshow(annulus_mask[0])
            #plt.imshow(annulus_data, origin='lower')
            #plt.imshow(annulus_im, origin='lower')
            #plt.colorbar()

            # list of values within aperture
            nonzero_annulus = np.where(annulus_im > 1e-5)
            annulus_list = annulus_im[nonzero_annulus]
            counts_list = hdu_counts[1].data[nonzero_annulus]
            exp_list = hdu_ex[1].data[nonzero_annulus]
            if offset_file == True:
                counts_off_list = counts_off_array[nonzero_annulus]

            # do photometry
            if offset_file == True:
                tot_temp = do_phot(annulus_list, counts_list, exp_list, offset_list=counts_off_list)
            else:
                tot_temp = do_phot(annulus_list, counts_list, exp_list)

            # subtract background
            tot_phot_per_pix = tot_temp['count_rate_per_pix'] - sky_phot['count_rate_per_pix']
            tot_phot_per_pix_err = np.sqrt(tot_temp['count_rate_err_per_pix']**2 +
                                            sky_phot['count_rate_err_per_pix']**2 +
                                            np.nanstd(sky_seg_phot)**2 )
            tot_phot_per_pix_pois_err = tot_temp['count_rate_pois_err_per_pix']
            tot_phot_per_pix_bg_err = np.sqrt(tot_temp['count_rate_off_err_per_pix']**2 +
                                                sky_phot['count_rate_err_per_pix']**2 +
                                                np.nanstd(sky_seg_phot)**2 )

            # multiply by the number of pixels in the annulus to get the total count rate
            tot_phot = tot_phot_per_pix * tot_pix
            tot_phot_err = tot_phot_per_pix_err * tot_pix
            tot_phot_pois_err = tot_phot_per_pix_pois_err * tot_pix
            tot_phot_bg_err = tot_phot_per_pix_bg_err * tot_pix

            phot_dict_tot['count_rate'][i] = tot_phot
            phot_dict_tot['count_rate_err'][i] = tot_phot_err
            phot_dict_tot['count_rate_err_poisson'][i] = tot_phot_pois_err
            phot_dict_tot['count_rate_err_bg'][i] = tot_phot_bg_err

            # convert to magnitudes
            mag = -2.5 * np.log10(tot_phot) + zeropoint
            mag_err = np.sqrt( ( 2.5/np.log(10) * tot_phot_err/tot_phot )**2 +
                                           zeropoint_err**2 )

            phot_dict_tot['mag'][i] = mag
            phot_dict_tot['mag_err'][i] = mag_err

            
            #[print(k+': ', phot_dict_tot[k][i]) for k in cols_tot]
            #pdb.set_trace()


        # make big numpy array
        data_array = np.column_stack(tuple([phot_dict_tot[key] for key in cols_tot]))
        # save it to a file
        np.savetxt(label+'phot_totprofile.dat', data_array,
                       header=' '.join(cols_tot) + '\n' + ' '.join(units_tot),
                       delimiter='  ', fmt=dtypes)



        # -------------------------
        # calculate magnitudes
        # -------------------------

        # asymptotic: plot accumulated flux vs gradient of accumulated flux, then get y-intercept
        # (see Gil de Paz et al 2007, section 4.3)
        
        # - grab points with the last part of flux accumulation
        use_ind = np.where(phot_dict_tot['count_rate'] >= 0.9 * np.max(phot_dict_tot['count_rate']))
        use_rad = phot_dict_tot['radius'][use_ind]
        use_cr = phot_dict_tot['count_rate'][use_ind]
        use_cr_err = phot_dict_tot['count_rate_err'][use_ind]
        grad = np.diff(use_cr) / np.diff(use_rad)
        
        # - bootstrap linear fit
        fit_boot = boot_lin_fit(grad, use_cr[1:], use_cr_err[1:])

        # - convert flux to mags
        asym_mag = -2.5 * np.log10(fit_boot['int']) + zeropoint
        asym_mag_err = np.sqrt( ( 2.5/np.log(10) * fit_boot['int_err']/fit_boot['int'] )**2 +
                                    zeropoint_err**2 )

        # - save it
        np.savetxt(label+'phot_asymmag.dat',
                       np.array([[fit_boot['int'], fit_boot['int_err'], asym_mag, asym_mag_err]]),
                       header='count_rate count_rate_err mag mag_err\ncts/sec cts/sec ABmag ABmag',
                       delimiter='  ', fmt=['%9f','%9f','%9f','%9f'])


        # - make plots
        if False:
            fig = plt.figure(figsize=(6,5), num='flux gradient stuff')
            plt.errorbar(grad, use_cr[1:],
                         yerr=use_cr_err[1:],
                         marker='.', color='black', ms=5, mew=0,
                         linestyle='-', ecolor='black', capsize=0)
            plt.plot(np.linspace(0,np.max(grad),50),
                     fit_boot['slope']*np.linspace(0,np.max(grad),50) + fit_boot['int'],
                     marker='.', ms=0, mew=0,
                     color='dodgerblue', linestyle='-')
            ax = plt.gca()
            ax.set_ylabel('Accumulated Flux (counts/sec)')
            ax.set_xlabel('Gradient of Accumulated Flux')
            plt.tight_layout()
            pdb.set_trace()
        
            fig = plt.figure(figsize=(6,5), num='flux stuff')
            plt.errorbar(use_rad/60, use_cr,
                         yerr=use_cr_err,
                         marker='.', color='black', ms=5, mew=0,
                         linestyle='-', ecolor='black', capsize=0)
            ax = plt.gca()
            ax.set_ylabel('Accumulated Flux (counts/sec)')
            ax.set_xlabel('Radius (arcmin)')
            plt.tight_layout()
            pdb.set_trace()



        # total: outermost annular point with S/N > 2 -> get accumulated flux within that radius
        sn = phot_dict_ann['count_rate'] / phot_dict_ann['count_rate_err']
        ind = np.nonzero(sn > 2)[0][-1]
        max_radius = phot_dict_tot['radius'][ind]
        tot_mag = phot_dict_tot['mag'][ind]
        tot_mag_err = phot_dict_tot['mag_err'][ind]
        # save it
        np.savetxt(label+'phot_totmag.dat',
                       np.array([[phot_dict_tot['count_rate'][ind], phot_dict_tot['count_rate_err'][ind], tot_mag, tot_mag_err]]),
                       header='count_rate count_rate_err mag mag_err\ncts/sec cts/sec ABmag ABmag',
                       delimiter='  ', fmt=['%9f','%9f','%9f','%9f'])
        

        # return various useful info
        return {'phot_dict_ann':phot_dict_ann, 'cols_ann':cols_ann, 'units_ann':units_ann,
                    'phot_dict_tot':phot_dict_tot, 'cols_tot':cols_tot, 'units_tot':units_tot,
                    'sky_phot':sky_phot,
                    'sky_seg_phot':sky_seg_phot, 'sky_seg_phot_err':sky_seg_phot_err,
                    'asym_mag':asym_mag, 'asym_mag_err':asym_mag_err,
                    'tot_mag':tot_mag, 'tot_mag_err':tot_mag_err}
Beispiel #17
0
def isophote_data() :
    
    from photutils.isophote import EllipseGeometry
    from photutils import EllipticalAperture
    from photutils.isophote import Ellipse
    
    test = 'a2744/cutouts/a2744_ID_5830_f160w.fits'
    (data, dim, photfnu, R_e,
     redshift, sma, smb, pa) = open_cutout(test)
    (noise, _, _, _,
     _, _, _, _) = open_cutout('a2744/cutouts/a2744_ID_5830_f160w_noise.fits')
    plt.display_image_simple(data, cmap=cm.viridis)
    
    xlen, ylen = dim[1], dim[0]
    
    geometry = EllipseGeometry(x0=xlen/2, y0=ylen/2, sma=20, eps=0.5,
                               pa=70*np.pi/180)
    aper = EllipticalAperture((geometry.x0, geometry.y0), geometry.sma,
                               geometry.sma*(1 - geometry.eps), geometry.pa)
    
    # pyp.imshow(data, origin='lower')
    # aper.plot(color='white')
    
    ellipse = Ellipse(data, geometry)
    isolist = ellipse.fit_image()
    
    # print(isolist.tflux_e)
    
    isophotes = True
    if isophotes :
        plt.display_isophotes(data, isolist, cmap=cm.viridis)
        
        # from photutils.isophote import build_ellipse_model
        # model = build_ellipse_model(data.shape, isolist)
        # residual = data - model
        # plt.display_image_simple(residual, norm=None)
    
    annuli = True
    if annuli :
        from photutils import EllipticalAnnulus
        from photutils import aperture_photometry
        
        center = (isolist[0].x0, isolist[0].y0)
        # print(center)
        
        last = np.where(isolist.stop_code == 0)[0][-1]
        isolist = isolist[last]
        
        pa = isolist.pa
        # print(pa*180/np.pi)
        
        a_outs = np.arange(1e-5, isolist.sma, isolist.sma/11)
        b_outs = a_outs*(1-isolist.eps)
        
        for i in range(len(a_outs) - 1) :
            a_in = a_outs[i]
            a_out = a_outs[i+1]
            b_in = b_outs[i]
            b_out = b_outs[i+1]
            # print(a_in, a_out, b_in, b_out)
            aper = EllipticalAnnulus(center, a_in, a_out, b_out, b_in=b_in,
                                     theta=isolist.pa)
            phot_table = aperture_photometry(data, aper, error=noise)
            flux = phot_table['aperture_sum'][0]
            flux_err = phot_table['aperture_sum_err'][0]
            # print(flux)
            # print(flux_err)
            
            annulus_mask = aper.to_mask()
            
            annulus_data = annulus_mask.multiply(data)
            # plt.display_image_simple(annulus_data, cmap=cm.viridis, norm=None)
            # print(np.sum(annulus_data))
            
            err_table = aperture_photometry(noise, aper)
            flux_err_alt = err_table['aperture_sum'][0]
            # print(flux_err)
            
            err_data = annulus_mask.multiply(noise)
            # print(np.sum(err_data))
            
            # print(flux/flux_err)
            print(flux/flux_err_alt)
            # print()
            
    return
Beispiel #18
0
def get_profile(file,pxsize,PA_disk,inc,d,size,padir,widir,dr,**kwargs):
    
    ############################################################
    # 
    # Extract a radial cut of the brightness along diffent 
    # position angles.
    # 
    # file: the fits file of the observation
    # pxsize: pixel scale (arcsec/px)
    # PA_aperture: position angle of the aperture measured east-north (deg)
    # inc: disk's inclination (deg)
    # d: distance to the source (pc)
    # size: semi-major axis of the disk (AU)
    # padir: position angle of the desired direction (deg)
    # widir: width of the cone along the desired direction (deg)
    # dr: width of the annulus (AU)
    # 
    # The ouput is a matrix whose the rows and columns represent
    # the position angle and the radial distance of the flux 
    # measurement.
    #
    ############################################################


    ############################################################
    # Load ALMA data
    if kwargs['type']=='obs':
        hdulist=fits.open(file)
        data_obs=hdulist[0].data[0][0]
        """
        xc=hdulist[0].header['CRPIX1']
        yc=hdulist[0].header['CRPIX2']
        """
        xc=data_obs.shape[1]*0.5
        yc=data_obs.shape[0]*0.5
        
    elif kwargs['type']=='mod':
        hdulist=fits.open(file)
        data_obs=hdulist[0].data
        xc=data_obs.shape[0]*0.5
        yc=data_obs.shape[1]*0.5
    

    ############################################################
    # Derived properties
    angle_annulus=((PA_disk-90.0)*units.deg).to(units.rad).value 
    if padir<270.0:
        padir=padir+90.0
    else:
        padir=padir-270.0
    e=np.sin((inc*units.deg).to(units.rad).value) 
    d_au=(d*units.pc).to(units.au).value 
    xc_array=[]
    yc_array=[]


    ############################################################
    # Creating elliptical aperture
    linear_lim=2*(size) # AU
    angular_lim=linear_lim/d_au # rad
    angular_lim=(angular_lim*units.rad).to(units.arcsec).value # arcsec
    pixel_lim=int(round(angular_lim/pxsize))
    dr=topx(dr,pxsize,d) # width of each annular aperture
    a_in_array=[]
    for i in np.arange(yc+dr,yc+0.5*pixel_lim,dr):
        a_in_array.append(i-xc)
    a_out_array=[i+dr for i in a_in_array]
    b_out_array=[i*(1-e**2)**0.5 for i in a_out_array]
    a_in_array=np.array(a_in_array)
    a_out_array=np.array(a_out_array)
    apertures=[EllipticalAnnulus((yc,xc),a_in=ain,a_out=aout,b_out=bout,theta=angle_annulus)
               for (ain,aout,bout) in zip(a_in_array,a_out_array,b_out_array)]

    print("Number of annular apertures: %d"%len(apertures))
    """
    # Do a check?
    plt.imshow(data_obs)
    apertures[-1].plot(color='red',lw=1)
    plt.show()
    """

    ############################################################
    # Determine Nbins
    Nbins=round(360.0/widir)


    ############################################################
    # Define class "Bin"
    class Bin:
        def __init__(self,ID,theta_min,theta_max,plist):
            self.ID=ID
            self.theta_min=theta_min
            self.theta_max=theta_max
            self.plist=plist

        def showFlux(self):
            i=0
            for pixel in self.plist:
                print(i,aperture_data[pixel[0],pixel[1]])
                i+=1

        def getArea(self,aperture):
            value=aperture.area/Nbins
            return value

        def getFlux(self):
            flux=0.0
            for pixel in self.plist:
                flux+=aperture_data[pixel[0],pixel[1]]
            return flux

        def getTheta(self):
            value=(self.theta_max-self.theta_min)*0.5+self.theta_min
            return value

        def getError_beam(self,aperture):
            beam_x=0.074 # arcsec
            beam_y=0.057 # arcsec
            flux_array=[]
            for pixel in self.plist:
                flux_array.append(aperture_data[pixel[0],pixel[1]])
            area=aperture.area/Nbins
            flux_array=np.array(flux_array)#/area
            sigma=np.std(flux_array)
            beam_area=np.pi*(beam_x)*(beam_y)/(4*np.log(2)) 
            Nbeam=((aperture.area*pxsize**2)/Nbins)/beam_area
            return sigma/(Nbeam)**0.5

        def getError_pixel(self,aperture):
            flux_array=[]
            for pixel in self.plist:
                flux_array.append(aperture_data[pixel[0],pixel[1]])
            area=aperture.area/Nbins
            flux_array=np.array(flux_array)/area
            sigma=np.std(flux_array)
            Npixel=len(self.plist)
            return sigma/(Npixel)**0.5
            
    M=[]
    E_beam=[]
    E_pixel=[]
    
    a_in_array=[i*pxsize*d for i in a_in_array]
    a_out_array=[i*pxsize*d for i in a_out_array]
    a_mid=np.array([(j-i)*0.5+i for (j,i) in zip(a_out_array,a_in_array)])
    
    meanpxn=[]
    for ii in range(0,len(apertures)):

        ############################################################
        # Creating bin
        sbin=Bin(ii,padir-0.5*widir,padir+0.5*widir,[])        


        ############################################################
        # Creating aperture mask
        mask=apertures[ii].to_mask(method="center")
        """
        # Do a check?
        plt.imshow(mask)
        plt.colorbar()
        plt.show()
        """

        ############################################################
        # Extracting pixels located inside the aperture
        aperture_data=mask.multiply(data_obs)
        """
        # Do a check?
        plt.imshow(aperture_data)
        plt.colorbar()
        plt.show()
        """

        ############################################################
        # Creating array of pixel's index within the aperture 
        # relative to the star
        pixel_list=[]
        ycc=int(aperture_data.shape[0]*0.5)
        xcc=int(aperture_data.shape[1]*0.5)
        for i in range(0,aperture_data.shape[1]): # Over columns 
            for j in range(0,aperture_data.shape[0]): # Over rows
                if aperture_data[j,i]!=0.0:
                    pixel_list.append((j-ycc,i-xcc))


        ############################################################
        # Filling in sbin data
        for point in pixel_list:
            phi=np.arctan2(point[0],point[1])
            if phi<0.0:
                phi=2*np.pi+phi
            phi=phi*180.0/np.pi
            if sbin.theta_min<=phi<sbin.theta_max:
                pixel=(int(point[0]+ycc),int(point[1]+xcc))
                sbin.plist.append(pixel)


        ############################################################
        # Writing result
        #value.showFlux()
        M.append(sbin.getFlux()/sbin.getArea(apertures[ii]))
        E_beam.append(sbin.getError_beam(apertures[ii]))
        E_pixel.append(sbin.getError_pixel(apertures[ii]))
        meanpxn.append(len(sbin.plist))
        #print("I have %.1f pixels"%(len(sbin.plist)))

    #print(np.mean(meanpxn))
    
    M=np.array(M)
    E_beam=np.array(E_beam)
    E_pixel=np.array(E_pixel)
    
    print()
    print("Max value (Jy/beam/bin_area): %.1e"%(max(M)))
    print("Max error (per beam): %.1e"%(np.nanmax(E_beam)))
    print("Max error (per pixel): %.1e"%(np.nanmax(E_pixel)))
    

    """
    ############################################################
    # Plotting
    fig=plt.figure(figsize=(5,12))
    ax=plt.axes()
    ax.errorbar(a_mid,M,yerr=E_beam,marker=".",fmt="-",color="red",capsize=2,elinewidth=0.5)
    #   ax.tick_params(labelleft=False,left=False)
    #    ax.set_ylabel(r"%.1f"%((midtheta[i]*units.rad).to(units.deg).value))
    ax.set_xlabel(r"$r$(AU)")
    #ax.set_ylim(0,0.0175)
    plt.show()
    """
    return a_mid,M,E_beam,E_pixel