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)
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)
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
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'
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
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
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()
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
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
#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()
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
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
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}
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
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