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 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 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
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}