def autocorr(self, ell_mask_scale=2, aperture_radius=5, annulus_width=4): # Compute 2D autocorrelation function try: masked_image = self.masked_image.copy() if ell_mask_scale > 0: masked_image.mask |= ~self.elliptical_mask(ell_mask_scale) masked_image = masked_image.filled(0.0) fft_imgae = np.fft.fft2(masked_image) acorr_image = np.fft.ifft2(fft_imgae * np.conjugate(fft_imgae)).real acorr_image = np.fft.ifftshift(acorr_image) ny, nx = masked_image.shape yy, xx = np.mgrid[:ny, :nx] circ = CircularAperture([nx // 2, ny // 2], r=aperture_radius) ann = CircularAnnulus([nx // 2, ny // 2], r_in=aperture_radius, r_out=aperture_radius + annulus_width) ann_mean = aperture_photometry( acorr_image, ann)['aperture_sum'][0] / ann.area() circ_mean = aperture_photometry( acorr_image, circ)['aperture_sum'][0] / circ.area() except: acorr_image = np.nan circ_mean = np.nan ann_mean = np.nan return acorr_image, circ_mean, ann_mean
def measure_fluxes(dataset): dataA = pf.getdata(dataset.filenameA)[0,0,:,:] dataB = pf.getdata(dataset.filenameA)[0,0,:,:] positions_A = [ (dataset.pos_A_pix["A_core"][0], dataset.pos_A_pix["A_core"][1]), (dataset.pos_A_pix["A_jet"][0], dataset.pos_A_pix["A_jet"][1])] positions_B = [ (dataset.pos_B_pix["B_core"][0], dataset.pos_B_pix["B_core"][1]), (dataset.pos_B_pix["B_jet"][0], dataset.pos_B_pix["B_jet"][1])] apertures_A = EllipticalAperture( positions_A, dataset.beam_size_A[0] / dataset.pixel_scale_A, dataset.beam_size_A[1] / dataset.pixel_scale_A, dataset.beam_PA_A) apertures_B = EllipticalAperture( positions_B, dataset.beam_size_B[0] / dataset.pixel_scale_B, dataset.beam_size_B[1] / dataset.pixel_scale_B, dataset.beam_PA_B) phot_table_A = aperture_photometry(dataA, apertures_A)#, error=data_error) phot_table_B = aperture_photometry(dataB, apertures_B)#, error=data_error) print "A fluxes in mJy" print phot_table_A['aperture_sum'] * 1e3 / (dataset.beam_size_A[0] * 3600.e3 * dataset.beam_size_A[1] * 3600.e3 * math.pi) print "B fluxes in mJy" print phot_table_B['aperture_sum'] * 1e3 / (dataset.beam_size_B[0] * 3600.e3 * dataset.beam_size_B[1] * 3600.e3 * math.pi)
def calculate_fluxes(self,stardata,apertures,aper_annulus): ''' Calculates the photon flux in an aperture, and an annulus around the aperture to subtract the background. As far as I can tell, the output value is still just a 'photon count', not technically a photon flux. Possible modifications will start here, maybe uncommenting the apertures.area() which calculates the aperture phot_count divided by area of aperture. giving photons per area. I think we would further have to supplement that by dividing by the exposure time, and some other wavelength value I cant think of, to get PHOTON FLUX ( photons per sec per cm^2 per wavelength) ''' flux_table = aperture_photometry(stardata, apertures) bkg_table = aperture_photometry(stardata, aper_annulus) phot_table = hstack([flux_table, bkg_table], table_names=['raw','bkg']) bkg_mean = phot_table['aperture_sum_bkg'] / aper_annulus.area() bkg_sum = bkg_mean * apertures.area() final_sum = phot_table['aperture_sum_raw'] - bkg_sum phot_table['residual_aperture_sum'] = final_sum #phot_table['res_aper_div_area'] = final_sum/apertures.area() #print(phot_table) return self.cut_vals(phot_table)
def frame_phot(hdu, cat_objects, phot_file, filter_name, exp_time, mag_zero=0, aperture_radius=5, annulus_radius=None, cut_vars={}): print('total objects:',len(cat_objects)) for key, cut_var in cut_vars.items(): cat_objects = cat_objects[(cat_objects[key]>cut_var['min']) & (cat_objects[key]<cut_var['max'])] print('good objects:', len(cat_objects)) cat_objects = Table(cat_objects) aperture_area = np.pi * aperture_radius**2 if annulus_radius is None: annulus_radius = aperture_radius+2 annulus_area = np.pi * (annulus_radius**2 - aperture_radius**2) objects = zip(cat_objects['x'],cat_objects['y']) apertures = photutils.CircularAperture(objects, aperture_radius) annulus_apertures = photutils.CircularAnnulus(objects, aperture_radius, annulus_radius) flux = photutils.aperture_photometry(hdu.data, apertures) bkg_flux = photutils.aperture_photometry(hdu.data, annulus_apertures) total_flux = flux-bkg_flux*aperture_area/annulus_area instrumental_mag = mag_zero - (2.5*np.log10(total_flux/exp_time)) cat_objects[filter_name] = instrumental_mag cat_array=np.array(cat_objects) np.save(phot_file, cat_array) return cat_objects
def _aperture_phot(self, x, y, data, radsize=1, sky_inner=5, skywidth=5, method="subpixel", subpixels=4): """Perform sky subtracted aperture photometry, uses photutils functions, photutil must be installed Parameters ---------- radsize: int Size of the radius sky_inner: int Inner radius of the sky annulus skywidth: int Width of the sky annulus method: string Pixel sampling method to use subpixels: int How many subpixels to use Notes ----- background is taken from sky annulus pixels, check into masking bad pixels """ if not photutils_installed: print("Install photutils to enable") else: apertures = photutils.CircularAperture((x, y), radsize) rawflux_table = photutils.aperture_photometry( data, apertures, subpixels=1, method="center") outer = sky_inner + skywidth annulus_apertures = photutils.CircularAnnulus( (x, y), r_in=sky_inner, r_out=outer) bkgflux_table = photutils.aperture_photometry( data, annulus_apertures) # to calculate the mean local background, divide the circular annulus aperture sums # by the area fo the circular annuls. The bkg sum with the circular aperture is then # then mean local background tims the circular apreture area. aperture_area = apertures.area() annulus_area = annulus_apertures.area() bkg_sum = ( bkgflux_table['aperture_sum'] * aperture_area / annulus_area)[0] skysub_flux = rawflux_table['aperture_sum'][0] - bkg_sum return ( float(rawflux_table['aperture_sum'][0]), bkg_sum, skysub_flux)
def do_test(data_shape=None, apertures=None, method=None, subpixels=None, error=None): data = np.ones(data_shape) if error: error = np.ones(data_shape) else: error = None aperture_photometry(data, apertures, method=method, error=error, subpixels=subpixels)
def photometry_local(data, x, y, aperture_radius, sky_radius_inner, sky_radius_outer): logger.debug('Sky annulus radii: %s -> %s', sky_radius_inner, sky_radius_outer) apertures = ph.CircularAperture((x, y), r=aperture_radius) annulus_apertures = ph.CircularAnnulus((x, y), r_in=sky_radius_inner, r_out=sky_radius_outer) rawflux_table = ph.aperture_photometry(data, apertures) bkgflux_table = ph.aperture_photometry(data, annulus_apertures) bkg_mean = bkgflux_table['aperture_sum'] / annulus_apertures.area() bkg_sum = bkg_mean * apertures.area() final_sum = rawflux_table['aperture_sum'] - bkg_sum return np.array(final_sum)
def doPhot(image, median, Xs, Ys, hdr): # Maybe implement PSF photometry sometime in the future #print(ph.psf.create_prf(imageData, positions, 3)) #Gauss = ph.psf.GaussianPSF(sigma = sources['fwhm'][index1]/2.355s, x_0=Xs[index1], y_0=Ys[index1]) # Fix the masked values so they are just 0. This is not working in photutils, image.filled(0) # Figure out how big the aperture should be (when the change is < 1% we can stop) radii = [] for j in range(len(Xs)): # Loop over every extracted source for i in range(1,20): apertures = ph.CircularAperture((Xs[j], Ys[j]), r=i) phot_table1 = ph.aperture_photometry(image, apertures)#, mask=mask) flux1 = phot_table1['aperture_sum'] apertures = ph.CircularAperture((Xs[j], Ys[j]), r=i+1) phot_table2 = ph.aperture_photometry(image, apertures)#, mask=mask) flux2 = phot_table2['aperture_sum'] if 100 - (flux1/flux2 *100) < 1: radii.append(float(i)) break # Now we grab the most common aperture size try: radius = sp.stats.mode(radii)[0][0] except: radius = 10 # This is the typical optimal value print('Radius size:', radius) # Show the objects and the aperture size fig = plt.figure(10, figsize=(12,12)) ax = fig.add_subplot(111) apertures = ph.CircularAperture((Xs,Ys), r=radius) fig.canvas.mpl_connect('button_press_event', onclickclose) ax.imshow(image, cmap='Greys', norm=LogNorm()) apertures.plot(color='red', lw=1.5, alpha=0.5) plt.show() # Now let's do the photometry apertures = ph.CircularAperture((Xs, Ys), r=radius) # Create circular apertures for each source phot_table = ph.aperture_photometry(image, apertures)#, mask=mask) #print(phot_table) # Compute the instrumental magnitude and associated error inM = -2.5*np.log10(phot_table['aperture_sum'].data / hdr['EXPTIME']) #print(inM) sigma_mag = 1.0857 * np.sqrt( phot_table['aperture_sum'].data*Gain + 2*np.pi*radius**2 * (median*Gain + (RN*Gain)**2) ) / (phot_table['aperture_sum'].data*Gain) #print(sigma_mag) #print(ObjName2, band2, hdr2['EXPTIME'], inM, sigma_mag) return inM, sigma_mag
def photometry(): filters = ['I','B','V','R'] #filter names # create a table here for Photometry results photo_table=Table(names=('Residuals','Error','Time')) Photometry = open('photometry_'+str(sn_name)+'.txt','w') for f in filters: #create a txt file where the Photometry Results table will be saved #join the two paths given above search_str = os.path.join(date_search_path,str(sn_name)+str(f)+'.fits') #names will be the supernova fits files for different filters for name in glob(search_str): with fits.open(name) as analysis: N = analysis[0].header['NCOMBINE'] # number of images stacked in the fit file final_date = convert_time(analysis) # The Time series must be MJD #Position of Supernova as coordinate, aperture is calculated with the coordinate cordinate = SkyCoord('01:48:08.66 +37:33:29.22', unit = (u.hourangle, u.deg)) #coordinates = SkyCoord('01:48:08.66 +37:33:29.22',unit = (u.hourangle, u.deg)) #exp_time= analysis[0].header['EXPTIME'] #data_error = np.sqrt(N*analysis[0].data) aperture = SkyCircularAperture(cordinate, r=5*u.arcsec) annulus_apertures = SkyCircularAnnulus(cordinate, r_in=6*u.arcsec, r_out=8*u.arcsec) aperture_area = np.pi * 3 ** 2 annulus_area = np.pi * (8 ** 2 - 6 ** 2) rawflux_table = aperture_photometry(analysis[0], aperture) bkgflux_table = aperture_photometry(analysis[0], annulus_apertures ) residual_sum = rawflux_table[0]['aperture_sum'] - bkgflux_table[0]['aperture_sum'] * aperture_area / annulus_area error=np.sqrt(np.abs(residual_sum)*N) photo_table.add_row((residual_sum,error,final_date)) print "***** Photometry Results without Calibration ****" print photo_table print >> Photometry, photo_table Photometry.close() calibration(N)
def zero_check(self, fits_file, cordinate, r): ''' Perform photometry on a exp type .fits file and check if there are data pixels in an aperture. Return a number code that corresponds to the result: 0 = no exp file found, 1 = data pixels found inside the aperture, 2 = no data pixels found in the aperture Args: fits_file (str) : File path of an int type .fits file cordinate (SkyCoord): Coordinate of a supernova in degrees r (Quantity): Radius of a photometry aperture in arcmin Returns: result (int): A number code as outlined in the description ''' if os.path.isfile(fits_file.replace("d-int", "d-exp")): with fits.open(fits_file.replace("d-int", "d-exp")) as exp_file: aperture = SkyCircularAperture(cordinate, r) phot_table = aperture_photometry(exp_file[0], aperture) if phot_table[0][0] != 0: result = 1 elif phot_table[0][0] == 0: result = 2 else: result = 0 return(result)
def getFluxesForRADec(radecList, image, the_wcs, bkg_level = 0, apRadius = 3.5): """Get the aperture flux at the (RA, Dec) position for the radecList array""" pix_ctr = [] good_pix_mask = [] h, w = image.shape for aPoint in radecList: try: pixPoint = the_wcs.all_world2pix([aPoint],0,tolerance=1E-3)[0] x,y = pixPoint.astype('int') xmin, xmax = max(0, x - apRadius), min(w, x + apRadius) ymin, ymax = max(0, y - apRadius), min(h, x + apRadius) if(x > w or x < 0 or y < 0 or y > h): good_pix_mask.append(False) elif(image.mask[ymin:ymax,xmin:xmax].any() == True): good_pix_mask.append(False) else: pix_ctr.append(pixPoint) good_pix_mask.append(True) except: good_pix_mask.append(False) pix_ctr = np.array(pix_ctr) good_pix_mask = np.array(good_pix_mask) apertures = CircularAperture(pix_ctr, apRadius) fluxes = np.array(aperture_photometry(image, apertures)['aperture_sum']) fluxes -= bkg_level * np.pi * apRadius**2 return fluxes, good_pix_mask
def photometry(): filters=['I','B','V','R'] #filter names for f in filters: All_data=Table(names=('Count','Error','Time')) file=open('photometry_'+str(sn_name)+str(f)+'.txt','w') super_lotis_path='/Users/zeynepyaseminkalender/Documents/MyFiles_Pyhton/SuperLOTIS_final' date_search_path=os.path.join(super_lotis_path, '13*') search_str=os.path.join(date_search_path,str(sn_name)+str(f)+'.fits') for name in glob(search_str): date=extract_date_from_fullpath(name) final_date=convert_time(date) with fits.open(name) as analysis: z = .086 r = 1 * u.kpc / cosmo.kpc_comoving_per_arcmin(z) cordinate = SkyCoord('01:48:08.66 +37:33:29.22', unit = (u.hourangle, u.deg)) aperture = SkyCircularAperture(cordinate, r) exp_time= analysis[0].header['EXPTIME'] # error calculation data_error = np.sqrt(analysis[0].data*exp_time) / exp_time tbl=Table(aperture_photometry(analysis[0],aperture,error=data_error),names=('Count','Count_Error','x_center','y_center','center_input')) tbl.keep_columns(['Count','Count_Error']) count=tbl[0]['Count'] error=tbl[0]['Count_Error'] All_data.add_row((count,error,final_date)) print >> file , All_data file.close() plot(filters)
def circ_flux(image, maskmap, ap_center, ap_radii, max_rad=None): """ Calculate flux in a circular aperture at the given set of aperture radii. """ mean, median, std = sigma_clipped_stats(image, mask=(maskmap==0), sigma=3.0, iters=3) # Calculate the background level bkgd_flux = median ap_fluxes = np.zeros(len(ap_radii))*np.nan bkgd_fluxes = np.zeros(len(ap_radii))*np.nan if max_rad is None: max_rad = max(np.shape(maskmap)) / 2.0 # Compute fluxes and background levels for every given radius for i, rad in enumerate(ap_radii): # If the radius is bigger than half the image, the photometry # will fail (because the aperture will fall off the image) if rad > max_rad: continue # Just take bkgd as median of whole image # Otherwise no background left with big apertures bkgd_fluxes[i] = bkgd_flux bkgd_subtracted = image - bkgd_fluxes[i] # Now do the aperture photometry itself aperture = photutils.CircularAperture(ap_center, r=rad) phot_table = photutils.aperture_photometry(bkgd_subtracted, aperture) ap_fluxes[i] = phot_table["aperture_sum"][0] return ap_fluxes, bkgd_fluxes
def ellip_flux(image, maskmap, ap_center, ap_radii, a, b, theta, background, max_rad=None): """ Calculate flux in an elliptical aperture at the given set of aperture radii. """ ap_fluxes = np.zeros(len(ap_radii))*np.nan if max_rad is None: mshape = np.shape(maskmap) max_rad = np.sqrt(mshape[0]**2 + mshape[1]**2) # Compute fluxes and background levels for every given radius for i, rad in enumerate(ap_radii): # If the radius is bigger than half the image, the photometry # will fail (because the aperture will fall off the image) if a*rad > max_rad: continue bkgd_subtracted = image - background # Now do the aperture photometry itself aperture = photutils.EllipticalAperture(ap_center, rad*a, rad*b, theta=theta) phot_table = photutils.aperture_photometry(bkgd_subtracted, aperture) ap_fluxes[i] = phot_table["aperture_sum"][0] return ap_fluxes
def photometry(image2d, cen_x, cen_y, mask, index = 0, shape = 'Circ', rad = None, r_in = None, r_out = None, ht = None, wid = None, w_in = None, w_out = None, h_out = None, ang = 0.0): """ Takes: image2d = 2 dimensional image array. Type = ndarray cen_x, cen_y = x & y center position. Type = ndarray/list mask = mask that blocks out NaNs. Type = ndarray index = if cen_x and cen_Y is a list of more than 1 element, specify the desired index. Type = Integer shape = 'Circ':CircularAperture, 'Rect':RectangularAperture, 'CircAnn':CircularAnnulus, 'RectAnn':RectangularAnnulus rad, r_in, r_out, ht, wid, w_in, w_out, h_out, ang = Astropy's aperture parameters Returns: flux = flux of the image extracted by the aperture described in the "shape" parameter. Type = Float aperture = aperture object created by astropy """ if shape == 'Circ': aperture = CircularAperture((cen_x[index], cen_y[index]), r = rad) elif shape == 'Rect': aperture = RectangularAperture((cen_x[index], cen_y[index]), w = wid, h = ht, theta = ang) elif shape == 'CircAnn': aperture = CircularAnnulus((cen_x[index], cen_y[index]), r_in = r_in, r_out = r_out) elif shape == 'RectAnn': aperture = RectangularAnnulus((cen_x[index], cen_y[index]), w_in = w_in, w_out = w_out, h_out = h_out, theta = ang) phot_table = aperture_photometry(image2d, aperture, mask = mask) flux = phot_table[0][0] return flux, aperture
def psf_norm(array, size, fwhm): """ Scales a PSF, so the 1*FWHM aperture flux equals 1. Parameters ---------- array: array_like The relative path to the psf fits image. size : int Size of the squared subimage. fwhm: float The size of the Full Width Half Maximum in pixel. Returns ------- psf_norm: array_like The scaled psf. """ psfs = frame_crop(array, size) fwhm_aper = photutils.CircularAperture((frame_center(psfs)), fwhm/2.) fwhm_aper_phot = photutils.aperture_photometry(psfs, fwhm_aper) fwhm_flux = np.array(fwhm_aper_phot['aperture_sum']) if fwhm_flux>1.1 or fwhm_flux<0.9: psf_norm = psfs/np.array(fwhm_aper_phot['aperture_sum']) else: psf_norm = psfs return psf_norm
def do_photometry(hdu, extensions=None, threshold=5, fwhm=2.5): if extensions is None: extensions = np.arange(1, len(hdu)) if not isiterable(extensions): extensions = (extensions, ) output = {} for ext in extensions: header = hdu[ext].header data = hdu[ext].data image_wcs = WCS(header) background = mad_std(data) sources = daofind(data, threshold=threshold * background, fwhm=fwhm) positions = (sources['xcentroid'], sources['ycentroid']) sky_positions = pixel_to_skycoord(*positions, wcs=image_wcs) apertures = CircularAperture(positions, r=2.) photometry_table = aperture_photometry(data, apertures) photometry_table['sky_center'] = sky_positions output[str(ext)] = photometry_table return output
def get_concentration_ell(self, image): ''' To calculate the conctration we need to find the radius -- which encloses 20% of the total light -- which encloses 80% of the total light So we need a running sum of the total pixel counts in increasing radii We also need to know the total flux -- define as the total pixel counts within an aperture of one petrosian radius Divide the running sum by the fixed total flux value and see where this ratio crosses .2 and .8 #''' print "calculating Concentration..." a = 10*np.logspace(-1.0, np.log10(np.min([self.xc,self.yc])/10.),num=20) b = a/self.e position = [self.Ax, self.Ay] annuli = np.hstack([EllipticalAnnulus(position, a[idx], a[idx+1], b[idx+1], self.theta) \ for idx, radius in enumerate(a[:-1])]) counts = np.hstack([aperture_photometry(image, an, method='exact') \ for an in annuli])['aperture_sum'] cum_sum = np.cumsum(counts)[:-1] tot_aper = EllipticalAperture(position, 1.5*self.Rp, 1.5*self.Rp/self.e, self.theta) tot_flux = float(aperture_photometry(image, tot_aper, method='center')['aperture_sum']) # ratio of the cumulative counts over the total counts in the galaxy ratio = cum_sum/tot_flux # now we need to find the intersection of ratio with 0.2 and 0.8 interp_radii, interp_ratio = morph.get_interp(a[1:-1], ratio) if not np.any(np.isnan(interp_ratio)): r20 = morph.get_intersect(interp_ratio, 0.2, interp_radii) r50 = morph.get_intersect(interp_ratio, 0.5, interp_radii) r80 = morph.get_intersect(interp_ratio, 0.8, interp_radii) else: r20 = r50 = r80 = np.nan conc = 5*np.log10(np.divide(r80, r20)) return r20, r50, r80, conc
def aperphot(image_data,ape_radius,cx,cy): ape_sum=np.zeros(64) for i in range(64): position=[cx[i],cy[i]] aperture=CircularAperture(position,r=ape_radius) phot_table=aperture_photometry(image_data[i,:,:],aperture) temp=phot_table['aperture_sum'] ape_sum[i]=phot_table['aperture_sum'] return ape_sum
def check_rmse_subtracted_image(subtracted_image, ref_sources, aperRad = 4.0): ref_positions = (ref_sources['xcentroid'], ref_sources['ycentroid']) ref_apertures = CircularAperture(ref_positions, r=aperRad) subtracted_aperture_phot = aperture_photometry(subtracted_image, ref_apertures) # print(subtracted_aperture_phot['aperture_sum_err']) # median_aperture_background = nanmedian(subtracted_image) + np.zeros(subtracted_image.shape) # median_aperture_background = aperture_photometry(median_aperture_background, ref_apertures)['aperture_sum'].data return nansum((subtracted_aperture_phot['aperture_sum'].data)**2) / len(ref_apertures)
def phot(self, image, objpos, aper): """ Aperture photometry using Astropy's photutils. Parameters ---------- image : numpy array 2D image array objpos : list of tuple Object poistions as list of tuples aper : float Aperture radius in pixels Returns ------- phot_table : astropy table Output table with stellar photometry """ try: from astropy.table import hstack from photutils import aperture_photometry, CircularAnnulus, CircularAperture except ImportError: pass apertures = CircularAperture(objpos, r = aper) annulus_apertures = CircularAnnulus(objpos, r_in = self.inner_radius, r_out = self.outer_radius) rawflux_table = aperture_photometry(image, apertures = apertures, method = self.method) bkgflux_table = aperture_photometry(image, apertures = annulus_apertures, method = self.method) phot_table = hstack([rawflux_table, bkgflux_table], table_names = ["raw", "bkg"]) bkg = phot_table["aperture_sum_bkg"] / annulus_apertures.area() phot_table["msky"] = bkg phot_table["area"] = apertures.area() phot_table["nsky"] = annulus_apertures.area() bkg_sum = bkg * apertures.area() final_sum = phot_table["aperture_sum_raw"] - bkg_sum phot_table["flux"] = final_sum return phot_table
def aper_phot(self,x,y): """Perform aperture photometry, uses photutils functions Rapert, sum, area and flux are the radius of the aperture in pixels, the total number of counts including sky in the aperture, the area of the aperture in square pixels, and the total number of counts in the aperture excluding sky. Mag and merr are the magnitude and error in the magnitude in the aperture (see below). flux = sum - area * msky mag = zmag - 2.5 * log10 (flux) + 2.5 * log10 (itime) merr = 1.0857 * error / flux error = sqrt (flux / epadu + area * stdev**2 + area**2 * stdev**2 / nsky) """ sigma=0. #no centering amp=0. #no centering if self.aperphot_pars["center"][0]: center=True delta=10 popt=self.gauss_center(x,y,delta) if 5 > popt.count(0) > 1: #an error occurred in centering warnings.warn("Problem fitting center, using original coordinates") else: amp,x,y,sigma,offset=popt radius=int(self.aperphot_pars["radius"][0]) width=int(self.aperphot_pars["width"][0]) inner=int(self.aperphot_pars["skyrad"][0]) subsky=bool(self.aperphot_pars["subsky"][0]) aper_flux=photutils.aperture_photometry(self._data,x,y,apertures=photutils.CircularAperture(radius),subpixels=1,method="center") aperture_area = np.pi * (radius)**2 if subsky: outer=inner + width annulus_sky=photutils.annulus_circular(self._data,x,y,inner,outer) annulus_area = np.pi * (outer**2 - inner**2) total_flux=aper_flux - annulus_sky * (aperture_area / annulus_area) else: total_flux=aper_flux #compute the magnitude of the sky corrected flux magzero=float(self.aperphot_pars["zmag"][0]) mag=magzero-2.5*(np.log10(total_flux)) pheader=("x\ty\tradius\tflux\tmag(zpt={0:0.2f})\tsky".format(magzero)) if center: pheader+=("\tfwhm") pstr="\n{0:.2f}\t{1:0.2f}\t{2:d}\t{3:0.2f}\t{4:0.2f}\t{5:0.2f}\t{6:0.2f}".format(x,y,radius,total_flux,mag,annulus_sky/annulus_area,math_helper.gfwhm(sigma)) else: pstr="\n{0:0.2f}\t{1:0.2f}\t{2:d}\t{3:0.2f}\t{4:0.2f}\t{5:0.2f}".format(x,y,radius,total_flux,mag,annulus_sky/annulus_area,) print(pheader+pstr) logging.info(pheader + pstr)
def psf_norm_2d(array, fwhm, size, threshold, mask_core, full_output, verbose): """ 2d case """ if size is not None: if size < array.shape[0]: psfs = frame_crop(array, size, force=True, verbose=False) else: psfs = array.copy() else: psfs = array.copy() # we check if the psf is centered and fix it if needed cy, cx = frame_center(psfs, verbose=False) xcom, ycom = photutils.centroid_com(psfs) if not (np.allclose(cy, ycom, atol=1e-2) or np.allclose(cx, xcom, atol=1e-2)): # first we find the centroid and put it in the center of the array centry, centrx = fit_2d(psfs) shiftx, shifty = centrx - cx, centry - cy psfs = frame_shift(array, -shifty, -shiftx, imlib=imlib, interpolation=interpolation) if size is not None: psfs = frame_crop(psfs, size, force=True, verbose=False) for _ in range(2): centry, centrx = fit_2d(psfs) cy, cx = frame_center(psfs, verbose=False) shiftx, shifty = centrx - cx, centry - cy psfs = frame_shift(psfs, -shifty, -shiftx, imlib=imlib, interpolation=interpolation) # we check whether the flux is normalized and fix it if needed fwhm_aper = photutils.CircularAperture((frame_center(psfs)), fwhm/2) fwhm_aper_phot = photutils.aperture_photometry(psfs, fwhm_aper, method='exact') fwhm_flux = np.array(fwhm_aper_phot['aperture_sum']) if fwhm_flux > 1.1 or fwhm_flux < 0.9: psf_norm_array = psfs / np.array(fwhm_aper_phot['aperture_sum']) else: psf_norm_array = psfs if threshold is not None: psf_norm_array[np.where(psf_norm_array < threshold)] = 0 if mask_core is not None: psf_norm_array = get_circle(psf_norm_array, radius=mask_core) if verbose: print("Flux in 1xFWHM aperture: {:.3f}".format(fwhm_flux[0])) if full_output: return psf_norm_array, fwhm_flux, fwhm else: return psf_norm_array
def aperphot(image_data,ape_radius,cx,cy,op): if(op==1): ape_sum=np.zeros(len(image_data)) print "Radius:",ape_radius for i in range(len(image_data)): position=[cx[i],cy[i]] aperture=CircularAperture(position,r=ape_radius) phot_table=aperture_photometry(image_data[i,:,:],aperture) temp=phot_table['aperture_sum'] ape_sum[i]=phot_table['aperture_sum'] else: ape_sum=np.zeros(len(image_data)) print "Radius:",ape_radius for i in range(len(image_data)): position=[cx[i],cy[i]] aperture=CircularAperture(position,r=ape_radius) phot_table=aperture_photometry(image_data[i,:,:],aperture,method='subpixel', subpixels=5) temp=phot_table['aperture_sum'] ape_sum[i]=phot_table['aperture_sum'] return ape_sum
def _apphot_one((irad, band, rad, img, sigma, isimage, apxy)): import photutils result = [irad, band, isimage] aper = photutils.CircularAperture(apxy, rad) p = photutils.aperture_photometry(img, aper, error=sigma) result.append(p.field('aperture_sum')) if sigma is not None: result.append(p.field('aperture_sum_err')) else: result.append(None) return result
def dophot(data,x,y,rad): positions=[] for i in range(len(x)): positions.append((x[i],y[i])) apertures=phot.CircularAperture(positions,r=rad) phot_table=phot.aperture_photometry(data,apertures) sum=phot_table['aperture_sum'] return sum
def test_aper_phot(capsys): """Check that apertures are as expected from photutils""" apertures = photutils.CircularAperture((50, 50), 5) aperture_area = apertures.area() assert_equal(aperture_area, 78.53981633974483) rawflux_table = photutils.aperture_photometry( test_data, apertures, subpixels=1, method="center") total_flux = float(rawflux_table['aperture_sum'][0]) assert_equal(total_flux, 207.)
def aper_phot(self, x, y): """Perform aperture photometry, uses photutils functions, photutils must be available """ if not photutils_installed: print("Install photutil to enable") else: sigma = 0. # no centering amp = 0. # no centering if self.aperphot_pars["center"][0]: center = True delta = 10 popt = self.gauss_center(x, y, delta) if 5 > popt.count(0) > 1: # an error occurred in centering warnings.warn("Problem fitting center, using original coordinates") else: amp, x, y, sigma, offset = popt radius = int(self.aperphot_pars["radius"][0]) width = int(self.aperphot_pars["width"][0]) inner = int(self.aperphot_pars["skyrad"][0]) subsky = bool(self.aperphot_pars["subsky"][0]) aper_flux = photutils.aperture_photometry( self._data, x, y, apertures=photutils.CircularAperture(radius), subpixels=1, method="center") aperture_area = np.pi * (radius) ** 2 if subsky: outer = inner + width annulus_sky = photutils.annulus_circular(self._data, x, y, inner, outer) annulus_area = np.pi * (outer ** 2 - inner ** 2) total_flux = aper_flux - annulus_sky * (aperture_area / annulus_area) else: total_flux = aper_flux # compute the magnitude of the sky corrected flux magzero = float(self.aperphot_pars["zmag"][0]) mag = magzero - 2.5 * (np.log10(total_flux)) pheader = ( "x\ty\tradius\tflux\tmag(zpt={0:0.2f})\tsky\t".format(magzero)).expandtabs(15) if center: pheader += ("fwhm") pstr = "\n{0:.2f}\t{1:0.2f}\t{2:d}\t{3:0.2f}\t{4:0.2f}\t{5:0.2f}\t{6:0.2f}".format( x + 1, y + 1, radius, total_flux, mag, annulus_sky / annulus_area, math_helper.gfwhm(sigma)).expandtabs(15) else: pstr = "\n{0:0.2f}\t{1:0.2f}\t{2:d}\t{3:0.2f}\t{4:0.2f}\t{5:0.2f}".format( x + 1, y + 1, radius, total_flux, mag, annulus_sky / annulus_area,).expandtabs(15) print(pheader + pstr) logging.info(pheader + pstr)
def aperture_flux(array, yc, xc, fwhm, ap_factor=1, mean=False, verbose=False): """ Returns the sum of pixel values in a circular aperture centered on the input coordinates. The radius of the aperture is set as (ap_factor*fwhm)/2. Parameters ---------- array : array_like Input frame. yc, xc : list or 1d arrays List of y and x coordinates of sources. fwhm : float FWHM in pixels. ap_factor : int, optional Diameter of aperture in terms of the FWHM. Returns ------- flux : list of floats List of fluxes. Note ---- From Photutils documentation, the aperture photometry defines the aperture using one of 3 methods: 'center': A pixel is considered to be entirely in or out of the aperture depending on whether its center is in or out of the aperture. 'subpixel': A pixel is divided into subpixels and the center of each subpixel is tested (as above). 'exact': (default) The exact overlap between the aperture and each pixel is calculated. """ n_obj = len(yc) flux = np.zeros((n_obj)) for i, (y, x) in enumerate(zip(yc, xc)): if mean: ind = circle(y, x, (ap_factor*fwhm)/2) values = array[ind] obj_flux = np.mean(values) else: aper = photutils.CircularAperture((x, y), (ap_factor*fwhm)/2) obj_flux = photutils.aperture_photometry(array, aper, method='exact') obj_flux = np.array(obj_flux['aperture_sum']) flux[i] = obj_flux if verbose: print('Coordinates of object {} : ({},{})'.format(i, y, x)) print('Object Flux = {:.2f}'.format(flux[i])) return flux
def doPhot(image, median, Xs, Ys, hdr): # Maybe implement PSF photometry sometime in the future #print(ph.psf.create_prf(imageData, positions, 3)) #Gauss = ph.psf.GaussianPSF(sigma = sources['fwhm'][index1]/2.355s, x_0=Xs[index1], y_0=Ys[index1]) # Fix the masked values so they are just 0. This is not working in photutils, image.filled(0) # Figure out how big the aperture should be (when the change is < 1% we can stop) # WE CAN CLEAN THIS UP BY DOING MULTIPLE APERTURES AT ONCE AND COMPARING AT THE END, AS AN ENSEMBLE radius = None for i in range(1,20): apertures = ph.CircularAperture((Xs, Ys), r=i) phot_table1 = ph.aperture_photometry(image, apertures)#, mask=mask) flux1 = phot_table1['aperture_sum'] apertures = ph.CircularAperture((Xs, Ys), r=i+1) phot_table2 = ph.aperture_photometry(image, apertures)#, mask=mask) flux2 = phot_table2['aperture_sum'] if 100 - (flux1/flux2 *100) < 1: radius = float(i) break if radius == None: radius=10 # This is the optimal aperture size historically. This is just a fix for contaminted areas. fig = plt.figure(10, figsize=(12,12)) ax = fig.add_subplot(111) apertures = ph.CircularAperture((Xs,Ys), r=radius) fig.canvas.mpl_connect('button_press_event', onclickclose) ax.imshow(image, cmap='Greys', norm=LogNorm()) apertures.plot(color='red', lw=1.5, alpha=0.5) plt.show() apertures = ph.CircularAperture((Xs, Ys), r=radius) phot_table = ph.aperture_photometry(image, apertures)#, mask=mask) #print(phot_table) # Compute the instrumental magnitude and associated error inM = -2.5*np.log10(phot_table['aperture_sum'].data / hdr['EXPTIME']) sigma_mag = 1.0857 * np.sqrt( phot_table['aperture_sum'].data*Gain + 2*np.pi*radius**2 * (median1*Gain + (RN*Gain)**2) ) / (phot_table['aperture_sum'].data*Gain) return inM, sigma_mag
# create a "postage stamp" image centered on the science target stamp160 = data160[round(ycen - dy):round(ycen + dy), round(xcen - dx):round(xcen + dx)] # plot the "postage stamp" ax = fig.add_subplot(2, 3, 3) plot_image(stamp160) plt.title('F160W') # plot F160W photometric curve of growth positions = [(xcen, ycen)] radii = np.arange(dx) + 1 flux = [] for radius in radii: aperture = CircularAperture(positions, radius) phot_table = aperture_photometry(data160, aperture) flux.append(phot_table['aperture_sum'][0]) ax = fig.add_subplot(2, 3, 6) ax.plot(radii, flux, 'ro') plt.ylim([0, 3e6]) plt.xlabel('Aperture Radius (pixels)') plt.ylabel('Flux (data values)') plt.tick_params(axis='both', which='major', labelsize=8) fluxtot1 = flux[40] plt.tight_layout() # plot F814W photometric curve of growth positions = [(xcen, ycen)] radii = np.arange(dx) + 1 flux = [] for radius in radii:
def contrast_limit( path_images: str, path_psf: str, noise: np.ndarray, mask: np.ndarray, parang: np.ndarray, psf_scaling: float, extra_rot: float, pca_number: int, threshold: Tuple[str, float], aperture: float, residuals: str, snr_inject: float, position: Tuple[float, float]) -> Tuple[float, float, float, float]: """ Function for calculating the contrast limit at a specified position for a given sigma level or false positive fraction, both corrected for small sample statistics. Parameters ---------- path_images : str System location of the stack of images (3D). path_psf : str System location of the PSF template for the fake planet (3D). Either a single image or a stack of images equal in size to science data. noise : numpy.ndarray Residuals of the PSF subtraction (3D) without injection of fake planets. Used to measure the noise level with a correction for small sample statistics. mask : numpy.ndarray Mask (2D). parang : numpy.ndarray Derotation angles (deg). psf_scaling : float Additional scaling factor of the planet flux (e.g., to correct for a neutral density filter). Should have a positive value. extra_rot : float Additional rotation angle of the images in clockwise direction (deg). pca_number : int Number of principal components used for the PSF subtraction. threshold : tuple(str, float) Detection threshold for the contrast curve, either in terms of 'sigma' or the false positive fraction (FPF). The value is a tuple, for example provided as ('sigma', 5.) or ('fpf', 1e-6). Note that when sigma is fixed, the false positive fraction will change with separation. Also, sigma only corresponds to the standard deviation of a normal distribution at large separations (i.e., large number of samples). aperture : float Aperture radius (pix) for the calculation of the false positive fraction. residuals : str Method used for combining the residuals ('mean', 'median', 'weighted', or 'clipped'). snr_inject : float Signal-to-noise ratio of the injected planet signal that is used to measure the amount of self-subtraction. position : tuple(float, float) The separation (pix) and position angle (deg) of the fake planet. Returns ------- float Separation (pix). float Position angle (deg). float Contrast (mag). float False positive fraction. """ images = np.load(path_images) psf = np.load(path_psf) # Cartesian coordinates of the fake planet yx_fake = polar_to_cartesian(images, position[0], position[1] - extra_rot) # Determine the noise level noise_apertures = compute_aperture_flux_elements(image=noise[0, ], x_pos=yx_fake[1], y_pos=yx_fake[0], size=aperture, ignore=False) t_noise = np.std(noise_apertures, ddof=1) * \ math.sqrt(1 + 1 / (noise_apertures.shape[0])) # get sigma from fpf or fpf from sigma # Note that the number of degrees of freedom is given by nu = n-1 with n the number of samples. # See Section 3 of Mawet et al. (2014) for more details on the Student's t distribution. if threshold[0] == 'sigma': sigma = threshold[1] # Calculate the FPF for a given sigma level fpf = t.sf(sigma, noise_apertures.shape[0] - 1, loc=0., scale=1.) elif threshold[0] == 'fpf': fpf = threshold[1] # Calculate the sigma level for a given FPF sigma = t.isf(fpf, noise_apertures.shape[0] - 1, loc=0., scale=1.) else: raise ValueError('Threshold type not recognized.') # Aperture properties im_center = center_subpixel(images) # Measure the flux of the star ap_phot = CircularAperture((im_center[1], im_center[0]), aperture) phot_table = aperture_photometry(psf_scaling * psf[0, ], ap_phot, method='exact') star = phot_table['aperture_sum'][0] # Magnitude of the injected planet flux_in = snr_inject * t_noise mag = -2.5 * math.log10(flux_in / star) # Inject the fake planet fake = fake_planet(images=images, psf=psf, parang=parang, position=(position[0], position[1]), magnitude=mag, psf_scaling=psf_scaling) # Run the PSF subtraction _, im_res = pca_psf_subtraction(images=fake * mask, angles=-1. * parang + extra_rot, pca_number=pca_number) # Stack the residuals im_res = combine_residuals(method=residuals, res_rot=im_res) flux_out_frame = im_res[0, ] - noise[0, ] # Measure the flux of the fake planet after PCA # the first element is the planet flux_out = compute_aperture_flux_elements(image=flux_out_frame, x_pos=yx_fake[1], y_pos=yx_fake[0], size=aperture, ignore=False)[0] # Calculate the amount of self-subtraction attenuation = flux_out / flux_in # the throughput can not be negative. However, this can happen due to numerical inaccuracies if attenuation < 0: attenuation = 0 # Calculate the detection limit contrast = (sigma * t_noise + np.mean(noise_apertures)) / (attenuation * star) # The flux_out can be negative, for example if the aperture includes self-subtraction regions if contrast > 0.: contrast = -2.5 * math.log10(contrast) else: contrast = np.nan # Separation [pix], position angle [deg], contrast [mag], FPF return position[0], position[1], contrast, fpf
def stack(cutout, radiusStack, gain, zeroPoint, wavelenght): """ Print out pdf with stamp stacking and plot graph magnitude in function of wavelenght Parameters ---------_ cutout: list array of images N filt x N sources radiusStack: float radius in pixel zeroPoint: float Zero point of your image gain: float The gain of your image wavelenght: float wavelenght of each filters """ # define the resulting stacked image as a cutout with the same dimension of the input cutouts o = 0 # Create pdf where are storing stack stamp and graph pdfOut = PdfPages(dirpath + 'stacking.pdf') fig, axs = plt.subplots(1, len(filters), figsize=(5, 5)) # Saving magnitude and error mag = [[0.0 for i in range(len(filters))] for j in range(2)] for i in cutout: # i is a list of galaxies print('Photometry ' + filters[o]) # Assuming that the shape is the same for all galaxies #this is now a tuple, e.g. (25,25), so the code will work also for rectangular stamps sizeStack = i[0].shape #this is now a tuple, e.g. (25,25), so the code will work also for rectangular stamps print(sizeStack) #just for testing stackImg = np.zeros(sizeStack) #LOOP over pixels: (I changed a lot here) # fait tous les pixel x for x in range(sizeStack[0]): # fait tous les pixel y for y in range(sizeStack[1]): # for the given pixels, collect the flux from all stamps into a list pxl = [] #use an empty list, but it can be also np.zeros() for stamp in i: pxl.append(stamp.data[x, y]) # caluclate the median: stackImg[x, y] = np.median(pxl) axs[o].set_title(filters[o], fontsize=5, pad=2.5) axs[o].get_xaxis().set_visible(False) axs[o].get_yaxis().set_visible(False) mappa = axs[o].imshow(stackImg, cmap='afmhot', origin='lower', interpolation='nearest') zrange = zscale.zscale(stackImg) mappa.set_clim(zrange) # Mask sources mask = make_source_mask(stackImg, snr=1, npixels=3, dilate_size=3) # Derive the background and the rms image bkg = Background2D( stackImg, int(sizeStack[0] / 10), filter_size=1, sigma_clip=None, bkg_estimator=SExtractorBackground(SigmaClip(sigma=2.5)), bkgrms_estimator=StdBackgroundRMS(SigmaClip(sigma=2.5)), exclude_percentile=90, mask=mask) if gain[o] == 0.: gain[o] = 1000000000000000000000000000. # Calculate the total error error = calc_total_error(stackImg, bkg.background_rms, gain[o]) # Define a cicularAperture in the wcs position of your objects apertures = CircularAperture( (int(sizeStack[0] / 2), int(sizeStack[1] / 2)), r=radiusStack[o]) # Derive the flux and error flux photometry = aperture_photometry(stackImg - bkg.background, apertures, error=error) # Saving magnitude and error mag[0][o] = -2.5 * np.log10( photometry['aperture_sum'][0]) + zeroPoint[o] mag[1][o] = 1.0857 * (photometry['aperture_sum_err'][0] / photometry['aperture_sum'][0]) o = o + 1 plt.savefig(pdfOut, format='pdf') # Plot plt.clf() y = mag[0] x = wavelenght plt.plot(x, y, 'ro') xlimL = wavelenght[0] - 1000 xlimR = wavelenght[len(wavelenght) - 1] + 1000 plt.xlim(xlimL, xlimR) plt.ylim(32, 22) plt.errorbar(wavelenght, mag[0], yerr=mag[1], fmt='none', capsize=10, ecolor='blue', zorder=1) plt.xlabel('wavelenght(Å)') plt.ylabel('magnitude') plt.title('') plt.savefig(pdfOut, format='pdf') pdfOut.close() np.savetxt(dirpath + 'fluxStack.txt', mag, header='Ligne1: mag, Ligne2: mag_err') return
print('Failed:') traceback.print_exc() continue h,w = im.get_image_shape() for x,y in [(0,0), (0,h), (w,0), (w,h), (w/2, h/2)]: psfimg = psf.getImage(x, y) print('PSF image at', (x,y))#, ':', psfimg) print('sum', psfimg.sum()) ph,pw = psfimg.shape print('psf img shape', psfimg.shape) apertures = [1., 3., 3.75, 5., 6., 7., 7.5, 8., 9., 10., 12.5, 15.] #apxy = np.array([[pw/2., ph/2.]]) for apxy in [np.array([[pw/2., ph/2.]]), np.array([[pw/2, ph/2]])]: print('apxy', apxy) ap = [] for rad in apertures: aper = photutils.CircularAperture(apxy, rad) p = photutils.aperture_photometry(psfimg, aper) ap.append(p.field('aperture_sum')) ap = np.vstack(ap).T print('Aperture fluxes:', ap)
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
from tqdm import tqdm, trange from itertools import repeat import os rng = np.random.seed(11256) data = np.random.randn(512, 512) + 10 rows = [] for r in trange(1, 201, 5): ap = CircularAperture((255.5, 255.5), r) ts = [] for i in range(5): t0 = datetime.now() t = aperture_photometry(data, ap, method="exact") t1 = datetime.now() time = (t1 - t0).total_seconds() ts.append(time) time = sum(ts) / 5 rows.append((r, time)) df = pd.DataFrame(rows, columns=["r", "time"]) path = os.path.dirname(__file__) df.to_csv(os.path.join(path, "python_aperture_size.csv"), index=False) ## Ellipse rows = []
plt.show() # Calculate the flux and uncertainties data_cut.shape rms_12CO10 = 0.0016 chan_width = 10 beam_area = 2.186 * 1.896 * 1.1331 beam_area_pix = beam_area / 0.09 error_value = rms_12CO10 * 10 * sqrt(50 / beam_area_pix) error_12CO10 = np.full((180, 140), error_value) data_cut = data_cut / beam_area_pix for region in regions: stat12[region]['flux'] = aperture_photometry( data_cut, apertures=apertures[region]['pix'], error=error_12CO10, mask=mask)['aperture_sum'][0] stat12[region]['uncertainty'] = aperture_photometry( data_cut, apertures=apertures[region]['pix'], error=error_12CO10, mask=mask)['aperture_sum_err'][0] ############################## # Calculate the flux and uncertainty of 13CO1-0 fitsimage = image_13CO10 + '.fits' # input the 13CO1-0 data hdr = fits.open(fitsimage)[0].header wcs = WCS(hdr).celestial
def extract_ifu(input_model, source_type, extract_params): """This function does the extraction. Parameters ---------- input_model : IFUCubeModel The input model. source_type : string "POINT" or "EXTENDED" extract_params : dict The extraction parameters for aperture photometry. Returns ------- ra, dec : float ra and dec are the right ascension and declination respectively at the nominal center of the image. wavelength : ndarray, 1-D The wavelength in micrometers at each plane of the IFU cube. temp_flux : ndarray, 1-D The sum of the data values in the extraction aperture minus the sum of the data values in the background region (scaled by the ratio of areas), for each plane. The data values are in units of surface brightness, so this value isn't really the flux, it's an intermediate value. Dividing by `npixels` (to compute the average) will give the value for the `surf_bright` (surface brightness) column, and multiplying by the solid angle of a pixel will give the flux for a point source. background : ndarray, 1-D The background count rate that was subtracted from the total source data values to get `temp_flux`. npixels : ndarray, 1-D, float64 For each slice, this is the number of pixels that were added together to get `temp_flux`. dq : ndarray, 1-D, uint32 The data quality array. npixels_annulus : ndarray, 1-D, float64 For each slice, this is the number of pixels that were added together to get `temp_flux` for an annulus region. radius_match: ndarray,1-D, float64 The size of the extract radius in pixels used at each wavelength of the IFU cube x_center, y_center : float The x and y center of the extraction region """ data = input_model.data weightmap = input_model.weightmap shape = data.shape if len(shape) != 3: log.error("Expected a 3-D IFU cube; dimension is %d.", len(shape)) raise RuntimeError("The IFU cube should be 3-D.") # We need to allocate temp_flux, background, npixels, and dq arrays # no matter what. We may need to divide by npixels, so the default # is 1 rather than 0. temp_flux = np.zeros(shape[0], dtype=np.float64) background = np.zeros(shape[0], dtype=np.float64) npixels = np.ones(shape[0], dtype=np.float64) npixels_annulus = np.ones(shape[0], dtype=np.float64) dq = np.zeros(shape[0], dtype=np.uint32) # For an extended target, the entire aperture will be extracted, so # it makes no sense to shift the extraction location. if source_type != "EXTENDED": ra_targ = input_model.meta.target.ra dec_targ = input_model.meta.target.dec locn = locn_from_wcs(input_model, ra_targ, dec_targ) if locn is None or np.isnan(locn[0]): log.warning("Couldn't determine pixel location from WCS, so " "source offset correction will not be applied.") x_center = float(shape[-1]) / 2. y_center = float(shape[-2]) / 2. else: (x_center, y_center) = locn log.info("Using x_center = %g, y_center = %g, based on " "TARG_RA and TARG_DEC.", x_center, y_center) method = extract_params['method'] subpixels = extract_params['subpixels'] subtract_background = extract_params['subtract_background'] radius = None inner_bkg = None outer_bkg = None width = None height = None theta = None # pull wavelength plane out of input data. # using extract 1d wavelength, interpolate the radius, inner_bkg, outer_bkg to match input wavelength # find the wavelength array of the IFU cube x0 = float(shape[2]) / 2. y0 = float(shape[1]) / 2. (ra, dec, wavelength) = get_coordinates(input_model, x0, y0) # interpolate the extraction parameters to the wavelength of the IFU cube radius_match = None if source_type == 'POINT': wave_extract = extract_params['wavelength'].flatten() inner_bkg = extract_params['inner_bkg'].flatten() outer_bkg = extract_params['outer_bkg'].flatten() radius = extract_params['radius'].flatten() frad = interp1d(wave_extract, radius, bounds_error=False, fill_value="extrapolate") radius_match = frad(wavelength) # radius_match is in arc seconds - need to convert to pixels # the spatial scale is the same for all wavelengths do we only need to call compute_scale once. if locn is None: locn_use = (input_model.meta.wcsinfo.crval1, input_model.meta.wcsinfo.crval2, wavelength[0]) else: locn_use = (ra_targ, dec_targ, wavelength[0]) scale_degrees = compute_scale( input_model.meta.wcs, locn_use, disp_axis=input_model.meta.wcsinfo.dispersion_direction) scale_arcsec = scale_degrees*3600.00 radius_match /= scale_arcsec finner = interp1d(wave_extract, inner_bkg, bounds_error=False, fill_value="extrapolate") inner_bkg_match = finner(wavelength)/scale_arcsec fouter = interp1d(wave_extract, outer_bkg, bounds_error=False, fill_value="extrapolate") outer_bkg_match = fouter(wavelength)/scale_arcsec elif source_type == 'EXTENDED': # Ignore any input parameters, and extract the whole image. width = float(shape[-1]) height = float(shape[-2]) x_center = width / 2. - 0.5 y_center = height / 2. - 0.5 theta = 0. subtract_background = False log.debug("IFU 1-D extraction parameters:") log.debug(" x_center = %s", str(x_center)) log.debug(" y_center = %s", str(y_center)) if source_type == 'POINT': log.debug(" method = %s", method) if method == "subpixel": log.debug(" subpixels = %s", str(subpixels)) else: log.debug(" width = %s", str(width)) log.debug(" height = %s", str(height)) log.debug(" theta = %s degrees", str(theta)) log.debug(" subtract_background = %s", str(subtract_background)) log.debug(" method = %s", method) if method == "subpixel": log.debug(" subpixels = %s", str(subpixels)) position = (x_center, y_center) # get aperture for extended it will not change with wavelength if source_type == 'EXTENDED': aperture = RectangularAperture(position, width, height, theta) annulus = None for k in range(shape[0]): inner_bkg = None outer_bkg = None if source_type == 'POINT': radius = radius_match[k] # this radius has been converted to pixels aperture = CircularAperture(position, r=radius) inner_bkg = inner_bkg_match[k] outer_bkg = outer_bkg_match[k] if inner_bkg <= 0. or outer_bkg <= 0. or inner_bkg >= outer_bkg: log.debug("Turning background subtraction off, due to " "the values of inner_bkg and outer_bkg.") subtract_background = False if subtract_background and inner_bkg is not None and outer_bkg is not None: annulus = CircularAnnulus(position, r_in=inner_bkg, r_out=outer_bkg) else: annulus = None subtract_background_plane = subtract_background # Compute the area of the aperture and possibly also of the annulus. # for each wavelength bin (taking into account empty spaxels) normalization = 1. temp = weightmap[k,:,:] temp[temp>1] = 1 aperture_area = 0 annulus_area = 0 # aperture_photometry - using weight map phot_table = aperture_photometry(temp, aperture, method=method, subpixels=subpixels) aperture_area = float(phot_table['aperture_sum'][0]) if LooseVersion(photutils.__version__) >= '0.7': log.debug("aperture.area = %g; aperture_area = %g", aperture.area, aperture_area) else: log.debug("aperture.area() = %g; aperture_area = %g", aperture.area(), aperture_area) if(aperture_area ==0 and aperture.area > 0): aperture_area = aperture.area if subtract_background and annulus is not None: # Compute the area of the annulus. phot_table = aperture_photometry(temp, annulus, method=method, subpixels=subpixels) annulus_area = float(phot_table['aperture_sum'][0]) if LooseVersion(photutils.__version__) >= '0.7': log.debug("annulus.area = %g; annulus_area = %g", annulus.area, annulus_area) else: log.debug("annulus.area() = %g; annulus_area = %g", annulus.area(), annulus_area) if(annulus_area ==0 and annulus.area > 0): annulus_area = annulus.area if annulus_area > 0.: normalization = aperture_area / annulus_area else: log.warning("Background annulus has no area, so background " "subtraction will be turned off. %g" ,k) subtract_background_plane = False del temp npixels[k] = aperture_area npixels_annulus[k] = 0.0 if annulus is not None: npixels_annulus[k] = annulus_area # aperture_photometry - using data phot_table = aperture_photometry(data[k, :, :], aperture, method=method, subpixels=subpixels) temp_flux[k] = float(phot_table['aperture_sum'][0]) if subtract_background_plane: bkg_table = aperture_photometry(data[k, :, :], annulus, method=method, subpixels=subpixels) background[k] = float(bkg_table['aperture_sum'][0]) temp_flux[k] = temp_flux[k] - background[k] * normalization # Check for NaNs in the wavelength array, flag them in the dq array, # and truncate the arrays if NaNs are found at endpoints (unless the # entire array is NaN). (wavelength, temp_flux, background, npixels, dq, npixels_annulus) = \ nans_in_wavelength(wavelength, temp_flux, background, npixels, dq, npixels_annulus) return (ra, dec, wavelength, temp_flux, background, npixels, dq, npixels_annulus, radius_match, x_center, y_center)
def process(self): self.info('Processing has been started') for image in self.images_list: self.info('Processing image: {}'.format(image.name)) apertures, sigma_values_table = self._create_apertures( image, self.stars_coordinates[image.savart], image.shape) out_table = [] counts_tab = [] counts_error_tab = [] for aperture, sigma_value in zip(apertures, sigma_values_table): rawflux_table = aperture_photometry(image.data, aperture[0]) bkgflux_table = aperture_photometry(image.data, aperture[1]) phot_table = hstack([rawflux_table, bkgflux_table], table_names=['raw', 'bkg']) if self.config_section.get('bkg_annulus'): self.info( 'Mean background value from annulus has been used.') bkg_mean = phot_table['aperture_sum_bkg'] / \ aperture[1].area() bkg_sum = bkg_mean * aperture[0].area() self.info('Mean background value\n {}'.format(bkg_mean)) else: self.info('Mean background value from mask \ sigma clipped stats has been used.') bkg_mean = sigma_value.median bkg_sum = bkg_mean * aperture[0].area() self.info('Mean background value\n {}'.format(bkg_mean)) final_sum = phot_table['aperture_sum_raw'] - bkg_sum phot_table['residual_aperture_sum'] = final_sum final_sum_error = self._calc_phot_error(image.hdr, aperture, phot_table, bkgflux_table, sigma_value.std) phot_table.add_column( Column(name='residual_aperture_err_sum', data=[final_sum_error])) phot_table['xcenter_raw'].shape = 1 phot_table['ycenter_raw'].shape = 1 phot_table['xcenter_bkg'].shape = 1 phot_table['ycenter_bkg'].shape = 1 out_table.append(phot_table) counts_tab.append(final_sum) counts_error_tab.append(final_sum_error) out_table = vstack(out_table) self.measurements.append( SavartCounts(image.savart, image.jd, counts_tab, counts_error_tab)) if self.config_section.get('plot_images'): self._make_image_plot(image.data, apertures, image.name) self._save_image_output(out_table, image.name + '.csv') self._save_polarizaton_results()
def master_photometry(hdul, dtype=np.float32, method=None, sigma=3, fwhm=4, kappa=5, r=3, r_in=5, r_out=9, save_format="fits", saveto=None, overwrite=False): r""" Generate statistics, positions and more fore a given hdul object. This uses photutils package, see it for more information, also astropy tables could be relevant to look at. Parameters ---------- hdul : astropy.io.fits.HDUList Image to process. dtype : data-type, optional Type to use for computing, defaults to np.float32. method : str, optional Method to use for normalization if value is not None. Valid values/metods are 'mean' or 'median'. Pay attention if you already used this with master_science, it's the same thing! sigma : float, optional Sigma level for mean, median and standard deviation, defaults to 3. fwhm : float, optional Expected FWHM in pixels, defaults to 4. kappa : float, optional Sigma level for source detection above background, defaults to 5. r : float, optional Aperture radius, defaults to 3. r_in : float, optional Inner sky annulus radius, defaults to 5. r_out : float, optional Outer sky annulus radius, defaults to 9. save_format : str, optional Format to save the table with, defaults to 'fits', has no effect if saveto is None. saveto : str, optional If this is not set (None, default) files won't be saved. If this is set to a string, save the file with the string as name. overwrite : bool, optional While saving, overwrite existing files? Defaults to False. Returns ------- table : photutils.aperture_photometry """ data = normalize(hdul[0].data.astype(dtype), method) mean, median, std = sigma_clipped_stats(data, sigma=sigma) DAOfind = DAOStarFinder(fwhm=fwhm, threshold=kappa*std) positions = DAOfind(data-median) centroid = (positions["xcentroid"], positions["ycentroid"]) aperture = CircularAperture(centroid, r) annulus = CircularAnnulus(centroid, r_in, r_out) apertures = [aperture, annulus] table = aperture_photometry(data, apertures) bg_mean = table["aperture_sum_1"] / annulus.area() bg_sum = bg_mean * aperture.area() table["residual_aperture_sum"] = table["aperture_sum_0"] - bg_sum table["mag"] = - 2.5 * np.log10(table["residual_aperture_sum"]) if saveto is not None: # TODO: dtype? table.write(saveto, overwrite=overwrite, format=save_format) return table
# r_inner=20. # r_outer=25. # r_inner_as=r_inner*u.arcsec # r_outer_as=r_outer*u.arcsec # print(r_inner_as,r_outer_as) # sys.exit(0) # time.sleep(1) # print(WCS.world_axis_physical_types) aperture_pix = aperture.to_pixel(wcs) # print(aperture_pix) r_pix = aperture_pix.r print('r_pix =', r_pix) # phot_table = aperture_photometry(imdata, aperture,wcs=wcs) phot_table = aperture_photometry(imdata, aperture_pix) # print(phot_table) # print(phot_table.colnames) # print(phot_table['sky_center']) # print(phot_table['xcenter']) # print(phot_table['ycenter']) aper_sum = phot_table['aperture_sum'] phot_table[ 'aperture_sum'].info.format = '%.8g' # for consistent table output aper_annu = SkyCircularAnnulus(positions, r_inner_as, r_outer_as) # print(aper_annu) # print(aper_annu.r_in) # print(aper_annu.r_out) aper_annu_pix = aper_annu.to_pixel(wcs) # print(aper_annu_pix)
def noise_per_annulus(array, separation, fwhm, init_rad=None, wedge=(0, 360), verbose=False, debug=False, mask=None): """ Measures the noise as the standard deviation of apertures defined in each annulus with a given separation. Parameters ---------- array : array_like Input frame. separation : float Separation in pixels of the centers of the annuli measured from the center of the frame. fwhm : float FWHM in pixels. init_rad : float Initial radial distance to be used. If None then the init_rad = FWHM. wedge : tuple of floats, optional Initial and Final angles for using a wedge. For example (-90,90) only considers the right side of an image. Be careful when using small wedges, this leads to computing a standard deviation of very small samples (<10 values). verbose : bool, optional If True prints information. debug : bool, optional If True plots the positioning of the apertures. Returns ------- noise : array_like Vector with the noise value per annulus. vector_radd : array_like Vector with the radial distances values. """ # dprint(fwhm) def find_coords(rad, sep, init_angle, fin_angle): angular_range = fin_angle - init_angle npoints = (np.deg2rad(angular_range) * rad) / sep #(2*np.pi*rad)/sep ang_step = angular_range / npoints #360/npoints x = [] y = [] for i in range(int(npoints)): newx = rad * np.cos(np.deg2rad(ang_step * i + init_angle)) newy = rad * np.sin(np.deg2rad(ang_step * i + init_angle)) x.append(newx) y.append(newy) return np.array(y), np.array(x) ### if array.ndim != 2: raise TypeError('Input array is not a frame or 2d array') if not isinstance(wedge, tuple): raise TypeError('Wedge must be a tuple with the initial and final ' 'angles') init_angle, fin_angle = wedge centery, centerx = frame_center(array) n_annuli = int(np.floor((centery) / separation)) - 1 noise = [] vector_radd = [] if verbose: print('{} annuli'.format(n_annuli)) if init_rad is None: init_rad = fwhm if debug: _, ax = plt.subplots(figsize=(6, 6)) ax.imshow(array, origin='lower', interpolation='nearest', alpha=0.5, cmap='gray') for i in range(n_annuli): y = centery + init_rad + separation * i rad = dist(centery, centerx, y, centerx) yy, xx = find_coords(rad, fwhm, init_angle, fin_angle) yy += centery xx += centerx apertures = photutils.CircularAperture((xx, yy), fwhm / 2) mask = np.bool_(mask) # quick2D(mask) if mask: fluxes = photutils.aperture_photometry(array, apertures, mask=mask) else: fluxes = photutils.aperture_photometry(array, apertures) fluxes = np.array(fluxes['aperture_sum']) noise_ann = np.std(fluxes) noise.append(noise_ann) vector_radd.append(rad) # if debug: # if i == 1: # plt.plot(fluxes) # plt.figure() # plt.hist(fluxes, bins=50) if debug: for j in range(xx.shape[0]): # Circle takes coordinates as (X,Y) aper = plt.Circle((xx[j], yy[j]), radius=fwhm / 2, color='r', fill=False, alpha=0.8) ax.add_patch(aper) cent = plt.Circle((xx[j], yy[j]), radius=0.8, color='r', fill=True, alpha=0.5) ax.add_patch(cent) if verbose: print('Radius(px) = {}, Noise = {:.3f} '.format(rad, noise_ann)) return np.array(noise), np.array(vector_radd)
flux_r = np.zeros(len(a), 'f') flux_ha = np.zeros(len(a), 'f') if args.mask: maskdat = fits.getdata(args.mask) maskdat = np.array(maskdat, 'bool') for i in range(len(a)): if args.verbose: print('defining elliptical aperture ' + str(i) + ' ap size = ', str(a[i])) ap = EllipticalAperture(position, a[i], b[i], theta) #,ai,bi,theta) for ai,bi in zip(a,b)] if args.mask: phot_table_r = aperture_photometry(imdat_r, ap, mask=maskdat) phot_table_ha = aperture_photometry(imdat_ha, ap, mask=maskdat) else: phot_table_r = aperture_photometry(imdat_r, ap) phot_table_ha = aperture_photometry(imdat_ha, ap) if args.verbose: print('measuring flux in aperture ' + str(i) + ' ap size = ', str(a[i])) flux_r[i] = phot_table_r['aperture_sum'][0] flux_ha[i] = phot_table_ha['aperture_sum'][0] # plot image with outer ellipse if args.plot: if args.verbose: print('plotting results \n')
# aper_annu_pix[j1]=CircularAnnulus(ra_pix[j1],dec_pix[j1],r_inner_as,r_outer_as) aperture_pix[j1] = aperture[j1].to_pixel(wcs) # phot_table = aperture_photometry(imdata, aperture_pix[i],error=err_imdata) aper_annu_pix[j1] = aper_annu[j1].to_pixel(wcs) # print(aper_annu_pix[j1]) r_pix = aperture_pix[j1].r r_in_pix = aper_annu_pix[j1].r_in r_out_pix = aper_annu_pix[j1].r_out # print(r_in_pix,r_out_pix) # position_pix=(ra_pix[j1],dec_pix[j1]) # position_pix=np.transpose(positions_pix) # r_pix=aperture_pix[i].r # print('r_pix =',r_pix) apper = [aperture_pix[j1], aper_annu_pix[j1]] # phot_annu_table = aperture_photometry(imdata, apper) phot_annu_table = aperture_photometry(imdata, apper, error=err_imdata) # phot_annu_table = aperture_photometry(imdata, aperture_pix[i],error=err_imdata) aper_annu_sum0 = phot_annu_table['aperture_sum_0'] print('... aper_annu_sum0 =', '%.2f' % aper_annu_sum0) aper_annu_sum1 = phot_annu_table['aperture_sum_1'] print('... aper_annu_sum1 =', '%.2f' % aper_annu_sum1) aper_sum0[k][j1] = aper_annu_sum0 aper_sum1[k][j1] = aper_annu_sum1 aper_annu_sum_err0 = phot_annu_table['aperture_sum_err_0'] print('... aper_annu_sum_err0 =', '%.2f' % aper_annu_sum_err0) aper_annu_sum_err1 = phot_annu_table['aperture_sum_err_1'] print('... aper_annu_sum_err1 =', '%.2f' % aper_annu_sum_err1) aper_sum_err0[k][j1] = aper_annu_sum_err0 aper_sum_err1[k][j1] = aper_annu_sum_err1
def brightnessProfile(imageName): image = fits.open(imageName) newData, header = image[0].data, image[0].header #print (header) height = header['NAXIS2'] width = header['NAXIS1'] image.close() #Begin placing aperture and annulus xAxis = (width) / 2 #Center point X-axis yAxis = height / 2 #Center point Y-axis positions = [(xAxis, yAxis)] #Center point plotted aperture = CircularAperture(positions, r=1) phot_table_ap = aperture_photometry(newData, aperture) r_in = np.linspace(1, 11, 110) #Inner radii per pixel r_out = np.linspace(2, 12, 120) #Outer radii per pixel fluxArray = [phot_table_ap['aperture_sum'] / aperture.area()] radArray = [1] for i in range(0, len(r_in)): rIn = r_in[i] rOut = r_out[i] annulus_apertures = CircularAnnulus(positions, rIn, rOut) phot_table = aperture_photometry(newData, annulus_apertures) fluxArray.append(phot_table['aperture_sum'] / annulus_apertures.area()) rMean = (rOut + rIn) / 2 radArray.append(rMean) sumFlux = sum(fluxArray) #Plot flux as radius increases plt.clf() plt.plot(radArray, fluxArray, label=imageName) plt.legend() plt.savefig(imageName + "_Radial_Profile.png") plt.show() fluxFrac = [] percentSum = 0 for f in fluxArray: percentSum += f fluxFrac.append(percentSum / sumFlux) #Find the radius at 50% enclosed radius50 = 1.0 for i in range(0, len(fluxFrac)): if (fluxFrac[i] < .50): radius50 += 1 / 10 #Radius 50% enclosed print("50 percent enclosed:", radius50) #Find the radius at 90% encolsed radius90 = 1.0 for i in range(0, len(fluxFrac)): if (fluxFrac[i] < .90): radius90 += 1 / 10 #Radius 90% enclosed print("90 percent enclosed:", radius90) """ #Gaussian Blur imgBlur = ndimage.gaussian_filter(newData, sigma=(2,2), order=0) plt.imshow(imgBlur) plt.savefig('Annuli_' + imageName + '.png', dpi=100) plt.subplots_adjust(right=2.0) plt.subplots_adjust(top=1.0) plt.show() """ fig = plt.figure() ax = fig.add_subplot(1, 1, 1) circle50 = plt.Circle((xAxis, yAxis), radius=radius50, color='m', fill=False, lw=2) circle90 = plt.Circle((xAxis, yAxis), radius=radius90, color='r', fill=False, lw=2) plt.imshow(newData, cmap='gray') ax.add_patch(circle50) #50% enclosed ax.add_patch(circle90) #90% enclosed #ax.text(left, top, galRedshift, horizontalalignment='left', verticalalignment='top', fontsize=12, color='red') #ax.text(left, bottom, hFlux, horizontalalignment='left', verticalalignment='bottom', fontsize=14, color='green') plt.savefig('Annuli_' + imageName + '.png', dpi=100) plt.show()
def do_aperture_photometry(filename): fwhm,filename=iraf_fwhm() xpix,ypix=source_list(filename) #ast=AstrometryNet() #ast.api_key= 'iqmqwvazpvolmjmn' data,header=fits.getdata(filename,header=True) exposure_time=header['EXPOSURE'] sigma_clip = SigmaClip(sigma=3., maxiters=10) bkg_estimator = MedianBackground() bkg = Background2D(data, (10,10), filter_size=(3, 3),sigma_clip=sigma_clip, bkg_estimator=bkg_estimator) back=bkg.background # this is the background we need for the background subtraction. back2=np.median(bkg.background) mask = data == 0 unit = u.electron / u.s xdf_image = CCDData(data, unit=unit, meta=header, mask=mask) norm_image = ImageNormalize(vmin=1e-4, vmax=5e-2, stretch=LogStretch(), clip=False) xdf_image_clipped = np.clip(xdf_image, 1e-4, None) mean, median, std = sigma_clipped_stats(xdf_image.data, sigma=3.0, maxiters=20, mask=xdf_image.mask) print('Finding the sources') #daofind = DAOStarFinder(fwhm=fwhm, threshold=5*std) # 3 sigma above the background. #sources = daofind(data - median) #sources_findpeaks = find_peaks(xdf_image.data, mask=xdf_image.mask, threshold=30.*std, box_size=30, centroid_func=centroid_2dg) #print('We have found:',len(sources),' sources') #print(sources) #print(sources['xcentroid'], sources['ycentroid'],sources['fwhm']) #positions=sources['xcentroid'], sources['ycentroid'] positions=np.genfromtxt('co_ordinates_list_1.txt',unpack=True,usecols=(0,1)) #print(positions) radii=[ fwhm,2*fwhm, 4*fwhm, 6*fwhm] #positions=(sources['xcentroid'], sources['ycentroid']) apertures = [CircularAperture(positions, r=r) for r in radii] an_ap = CircularAnnulus(positions, r_in=8*fwhm, r_out=10*fwhm) #apers = [apertures, annulus_apertures] #bkg_sigma=mad_std(data) effective_gain=exposure_time error=calc_total_error(data,back,effective_gain) #error=0.1*data phot_table = aperture_photometry(data, apertures,error=error) phot_table2=aperture_photometry(data,an_ap) bkg_mean = phot_table2['aperture_sum'] / an_ap.area() bkg_sum = bkg_mean * an_ap.area() final_sum0=phot_table['aperture_sum_0']-bkg_sum final_sum1=phot_table['aperture_sum_1']-bkg_sum final_sum2=phot_table['aperture_sum_2']-bkg_sum final_sum3=phot_table['aperture_sum_3']-bkg_sum mag_0=-2.5*np.log10(final_sum0/exposure_time)+25 mag_1=-2.5*np.log10(final_sum1/exposure_time)+25 mag_2=-2.5*np.log10(final_sum2/exposure_time)+25 mag_3=-2.5*np.log10(final_sum3/exposure_time)+25 fig=plt.figure() plt.imshow(data,cmap='gray',origin='lower',vmin=50,vmax=400) colors=['red','green','yellow','blue'] for i in range(len(apertures)): apertures[i].plot(color=colors[i], alpha=0.7) an_ap.plot(color='green', alpha=0.7) plt.show() for i in range (len(phot_table)): print(mag_0[i],mag_1[i],mag_2[i],mag_3[i]) ''' mag=-2.5*np.log10(final_sum/30)+25 flux=final_sum flux_err=phot_table['aperture_sum_err_0'] mag_err=1.09*flux_err/flux x=[phot.value for phot in phot_table['xcenter']] y=[phot.value for phot in phot_table['ycenter']] #with open('result.dat', 'w') as f: #with open('out.txt', 'w') as f: for i in range(len(x)): print(x[i],y[i],'\t',mag[i],mag_err[i]) outfile=' ' for i in range (len(phot_table)): outfile+=x[i]+ " "+ y[i]+" "+ mag[i]+" " +mag_err[i] outfile+='\n' out=open('result.txt','w') out.write(outfile,overwrite=True) out.close() ''' '''
### Convert FWHM into a sigma ### sigmaold = np.array([FWHM2sigma(fwhm, const) for fwhm in oldavgFWHM]) sigmabroad = sigmaold[aimind] phot = {} flux = np.zeros(8) oldphot = {} oldflux = np.zeros(8) pixelr = (1.5 / 3600) / const aperture = CircularAperture(centre, pixelr) for n, sem in enumerate(semesters): ### Determine flux within 3 arcsec apertures ### phot[sem] = aperture_photometry(psf[sem], aperture) flux[n] = phot[sem]['aperture_sum'][0] oldphot[sem] = aperture_photometry(oldpsf[sem], aperture) oldflux[n] = oldphot[sem]['aperture_sum'][0] plt.figure() plt.plot(oldflux, 'bs') plt.plot(flux, 'ro') plt.ylabel('Flux within 3 arcsec aperture') plt.figure() ax = plt.subplot(111) plt.plot(oldavgFWHM, 'bs') plt.plot(avgFWHM, 'ro') plt.ylabel('FWHM') ax.invert_yaxis() ### testing the extra factor method ###
def run_forced_phot(cat, tim, ceres=True, derivs=False, agn=False, do_forced=True, do_apphot=True, get_model=False, ps=None, timing=False, fixed_also=False, ceres_threads=1): ''' fixed_also: if derivs=True, also run without derivatives and report that flux too? ''' if timing: tlast = Time() if ps is not None: import pylab as plt opti = None forced_kwargs = {} if ceres: from tractor.ceres_optimizer import CeresOptimizer B = 8 try: opti = CeresOptimizer(BW=B, BH=B, threads=ceres_threads) except: if ceres_threads > 1: raise RuntimeError( 'ceres_threads requested but not supported by tractor.ceres version' ) opti = CeresOptimizer(BW=B, BH=B) #forced_kwargs.update(verbose=True) # nsize = 0 for src in cat: src.freezeAllBut('brightness') src.getBrightness().freezeAllBut(tim.band) #print('Limited the size of', nsize, 'large galaxy models') if derivs: realsrcs = [] derivsrcs = [] Iderivs = [] for i, src in enumerate(cat): from tractor import PointSource realsrcs.append(src) if not isinstance(src, PointSource): continue realmod = src.getUnitFluxModelPatch(tim) if realmod is None: continue Iderivs.append(i) brightness_dra = src.getBrightness().copy() brightness_ddec = src.getBrightness().copy() brightness_dra.setParams(np.zeros(brightness_dra.numberOfParams())) brightness_ddec.setParams( np.zeros(brightness_ddec.numberOfParams())) brightness_dra.freezeAllBut(tim.band) brightness_ddec.freezeAllBut(tim.band) dsrc = SourceDerivatives(src, [brightness_dra, brightness_ddec], tim, ps) derivsrcs.append(dsrc) Iderivs = np.array(Iderivs) if fixed_also: pass else: # For convenience, put all the real sources at the front of # the list, so we can pull the IVs off the front of the list. cat = realsrcs + derivsrcs if agn: from tractor.galaxy import ExpGalaxy, DevGalaxy from tractor import PointSource from tractor.sersic import SersicGalaxy from legacypipe.survey import RexGalaxy realsrcs = [] agnsrcs = [] iagn = [] for i, src in enumerate(cat): realsrcs.append(src) if isinstance(src, RexGalaxy): continue if isinstance(src, (ExpGalaxy, DevGalaxy, SersicGalaxy)): iagn.append(i) bright = src.getBrightness().copy() bright.setParams(np.zeros(bright.numberOfParams())) bright.freezeAllBut(tim.band) agn = PointSource(src.pos, bright) agn.freezeAllBut('brightness') #print('Adding "agn"', agn, 'to', src) #print('agn params:', agn.getParamNames()) agnsrcs.append(src) iagn = np.array(iagn) cat = realsrcs + agnsrcs print('Added AGN to', len(iagn), 'galaxies') tr = Tractor([tim], cat, optimizer=opti) tr.freezeParam('images') disable_galaxy_cache() F = fits_table() if do_forced: if timing and (derivs or agn): t = Time() print('Setting up:', t - tlast) tlast = t if derivs: if fixed_also: print('Forced photom with fixed positions:') R = tr.optimize_forced_photometry(variance=True, fitstats=False, shared_params=False, priors=False, **forced_kwargs) F.flux_fixed = np.array([ src.getBrightness().getFlux(tim.band) for src in cat ]).astype(np.float32) N = len(cat) F.flux_fixed_ivar = R.IV[:N].astype(np.float32) if timing: t = Time() print('Forced photom with fixed positions finished:', t - tlast) tlast = t cat = realsrcs + derivsrcs tr.setCatalog(Catalog(*cat)) print('Forced photom with position derivatives:') if ps is None and not get_model: forced_kwargs.update(wantims=False) R = tr.optimize_forced_photometry(variance=True, fitstats=True, shared_params=False, priors=False, **forced_kwargs) if ps is not None or get_model: (data, mod, ie, chi, _) = R.ims1[0] if ps is not None: ima = dict(vmin=-2. * tim.sig1, vmax=5. * tim.sig1, interpolation='nearest', origin='lower', cmap='gray') imchi = dict(interpolation='nearest', origin='lower', vmin=-5, vmax=5, cmap='RdBu') plt.clf() plt.imshow(data, **ima) plt.title('Data: %s' % tim.name) ps.savefig() plt.clf() plt.imshow(mod, **ima) plt.title('Model: %s' % tim.name) ps.savefig() plt.clf() plt.imshow(chi, **imchi) plt.title('Chi: %s' % tim.name) ps.savefig() if derivs: trx = Tractor([tim], realsrcs) trx.freezeParam('images') modx = trx.getModelImage(0) chix = (data - modx) * tim.getInvError() plt.clf() plt.imshow(modx, **ima) plt.title('Model without derivatives: %s' % tim.name) ps.savefig() plt.clf() plt.imshow(chix, **imchi) plt.title('Chi without derivatives: %s' % tim.name) ps.savefig() if derivs or agn: cat = realsrcs N = len(cat) F.flux = np.array([ src.getBrightness().getFlux(tim.band) for src in cat ]).astype(np.float32) F.flux_ivar = R.IV[:N].astype(np.float32) F.fracflux = R.fitstats.profracflux[:N].astype(np.float32) F.fracin = R.fitstats.fracin[:N].astype(np.float32) F.rchisq = R.fitstats.prochi2[:N].astype(np.float32) F.fracmasked = R.fitstats.promasked[:N].astype(np.float32) if derivs: F.flux_dra = np.zeros(len(F), np.float32) F.flux_ddec = np.zeros(len(F), np.float32) F.flux_dra[Iderivs] = np.array( [src.getParams()[0] for src in derivsrcs]).astype(np.float32) F.flux_ddec[Iderivs] = np.array( [src.getParams()[1] for src in derivsrcs]).astype(np.float32) F.flux_dra_ivar = np.zeros(len(F), np.float32) F.flux_ddec_ivar = np.zeros(len(F), np.float32) F.flux_dra_ivar[Iderivs] = R.IV[N::2].astype(np.float32) F.flux_ddec_ivar[Iderivs] = R.IV[N + 1::2].astype(np.float32) if agn: F.flux_agn = np.zeros(len(F), np.float32) F.flux_agn_ivar = np.zeros(len(F), np.float32) if len(iagn): F.flux_agn[iagn] = np.array( [src.getParams()[0] for src in agnsrcs]) F.flux_agn_ivar[iagn] = R.IV[N:].astype(np.float32) if timing: t = Time() print('Forced photom:', t - tlast) tlast = t if do_apphot: import photutils img = tim.getImage() ie = tim.getInvError() with np.errstate(divide='ignore'): imsigma = 1. / ie imsigma[ie == 0] = 0. apimg = [] apimgerr = [] # Aperture photometry locations -- this is using the Tractor wcs infrastructure, # so pixel positions are 0-indexed. apxy = np.vstack( [tim.wcs.positionToPixel(src.getPosition()) for src in cat]) apertures = apertures_arcsec / tim.wcs.pixel_scale() # The aperture photometry routine doesn't like pixel positions outside the image H, W = img.shape Iap = np.flatnonzero((apxy[:, 0] >= 0) * (apxy[:, 1] >= 0) * (apxy[:, 0] <= W - 1) * (apxy[:, 1] <= H - 1)) print('Aperture photometry for', len(Iap), 'of', len(apxy[:, 0]), 'sources within image bounds') for rad in apertures: aper = photutils.CircularAperture(apxy[Iap, :], rad) p = photutils.aperture_photometry(img, aper, error=imsigma) apimg.append(p.field('aperture_sum')) apimgerr.append(p.field('aperture_sum_err')) ap = np.vstack(apimg).T ap[np.logical_not(np.isfinite(ap))] = 0. F.apflux = np.zeros((len(F), len(apertures)), np.float32) F.apflux[Iap, :] = ap.astype(np.float32) apimgerr = np.vstack(apimgerr).T apiv = np.zeros(apimgerr.shape, np.float32) apiv[apimgerr != 0] = 1. / apimgerr[apimgerr != 0]**2 F.apflux_ivar = np.zeros((len(F), len(apertures)), np.float32) F.apflux_ivar[Iap, :] = apiv if timing: print('Aperture photom:', Time() - tlast) if get_model: return F, mod return F
def flux(nddata, tbl, zeroPoint, gain, radius): """ Derive the flux and the magnitude within circular aperture Parameters ---------- nddata: numpy array Numpy array where is saved the data and the sky coordinates wcs. tbl: table Table where the first column is the id, the second the ra coordinate, the third is dec coordinate and the four the skycoordinate. zeroPoint: float Zero point of your image gain: float The gain of your image radius: float The radius of your circle in arcsec to derive the flux Return ------ Table with id, skycoord, flux, flux error, magnitude, magnitude error """ # By convention, sextractor if gain == 0.: gain = 1000000000000000000000000000. result = tbl['id', 'skycoord'] result['flux'] = float(np.size(tbl)) result['flux_err'] = float(np.size(tbl)) for i in range(np.size(tbl)): # Recover the position for each object position = tbl['skycoord'][i] if hdr['NAXIS1'] >= 50 and hdr['NAXIS2'] >= 50: # size of the background map sizeBkg = 50 # cut the mosaic in stamp to the wcs coordinate of your objects cutout = Cutout2D(nddata.data, position, (sizeBkg, sizeBkg), wcs=nddata.wcs) # Recover new data and wcs of the stamp data = cutout.data wcs = cutout.wcs else: # size of the background map sizeBkg = min(hdr['NAXIS1'], hdr['NAXIS2']) # Keep data and wcs of the initial image data = nddata.data wcs = nddata.wcs ######################### ####### Background ###### ######################### # Mask sources mask = make_source_mask(data, snr=1, npixels=3, dilate_size=3) # Derive the background and the rms image bkg = Background2D( data, int(sizeBkg / 10), filter_size=1, sigma_clip=None, bkg_estimator=SExtractorBackground(SigmaClip(sigma=2.5)), bkgrms_estimator=StdBackgroundRMS(SigmaClip(sigma=2.5)), exclude_percentile=60, mask=mask) ########################### ###### Aperture Flux ###### ########################### nddataStamp = NDData(data=data - bkg.background, wcs=wcs) # Calculate the total error error = calc_total_error(cutout.data, bkg.background_rms, gain) # Define a cicularAperture in the wcs position of your objects apertures = SkyCircularAperture(position, r=radius * u.arcsec) # Derive the flux and error flux phot_table = aperture_photometry(nddataStamp, apertures, error=error) phot_table['aperture_sum'].info.format = '%.8g' phot_table['aperture_sum_err'].info.format = '%.8g' # Recover data result['flux'][i] = phot_table['aperture_sum'][0] result['flux_err'][i] = phot_table['aperture_sum_err'][0] ########################### ######## Magnitude ######## ########################### # convert flux into magnitude result['mag'] = -2.5 * np.log10(result['flux']) + zeroPoint # convert flux error into magnitude error result['mag_err'] = 1.0857 * (result['flux_err'] / result['flux']) return result
# --- measure PSF profile if make_profile: Ndim = img_sub.shape[0] centre = (Ndim // 2, Ndim // 2) radii_pix = np.arange(1, 500., 1) radii_arcsec = radii_pix * ( flare.observatories.filter_info[f]['pixel_scale'] / sampling) apertures = [CircularAperture(centre, r=r) for r in radii_pix] #r in pixels phot_table = aperture_photometry(img_sub, apertures) frac = np.array([ phot_table['aperture_sum_{0}'.format(i)][0] for i, r in enumerate(radii_pix) ]) for efrac in [0.5, 0.8]: print('EE(f={0}): {1:0.2f}"'.format( efrac, np.interp(efrac, frac, radii_arcsec))) for r in [0.35 / 2.]: print('EE(r<{0}): {1:0.2f}'.format( r, np.interp(r, radii_arcsec, frac))) ax_profile.plot(radii_arcsec, frac, label=f)
# read in the images file = glob.glob(dir + 'J0905_final_' + collection[i] + '*sci.fits') hdu = fits.open(file[0]) data[i], header[i] = hdu[0].data, hdu[0].header fnu[i] = header[i]['PHOTFNU'] exp[i] = header[i]['EXPTIME'] #define positions for photometry positions = [(xcen, ycen)] #do photometry on images #convert to proper units for j in range(0, len(radii)): aperture = CircularAperture(positions, radii[j]) phot_table = aperture_photometry(data[i], aperture) flux[i, j] = phot_table['aperture_sum'][0] * (fnu[i] / exp[i]) if j == 0: subflux[i, j] = flux[i, j] else: subflux[i, j] = flux[i, j] - flux[i, j - 1] #set up the plot ax = fig.add_subplot(1, 1, 1) cax = ax.scatter( -2.5 * np.log10(subflux[1] / subflux[2]), -2.5 * np.log10(subflux[0] / subflux[1]), c=radii, vmin=radii[0], vmax=radii[-1], cmap=cm.coolwarm,
def psf_norm(array, fwhm=4, size=None, threshold=None, mask_core=None, full_output=False, verbose=False): """ Scales a PSF, so the 1*FWHM aperture flux equals 1. Parameters ---------- array: array_like The psf 2d array. fwhm: float, optional The the Full Width Half Maximum in pixels. size : int or None, optional If int it will correspond to the size of the squared subimage to be cropped form the psf array. threshold : None of float, optional Sets to zero small values, trying to leave only the core of the PSF. mask_core : None of float, optional Sets the radius of a circular aperture for the core of the PSF, everything else will be set to zero. Returns ------- psf_norm: array_like The normalized psf. """ if size is not None: psfs = frame_crop(array, min(int(size), array.shape[0]), verbose=False) else: psfs = array.copy() # If frame size is even we drop last row and last column if psfs.shape[0] % 2 == 0: psfs = psfs[:-1, :] if psfs.shape[1] % 2 == 0: psfs = psfs[:, :-1] # we check if the psf is centered and fix it if needed cy, cx = frame_center(psfs, verbose=False) if cy != np.where(psfs == psfs.max())[0] or cx != np.where( psfs == psfs.max())[1]: # first we find the centroid and put it in the center of the array centroidy, centroidx = fit_2dgaussian(psfs, fwhmx=fwhm, fwhmy=fwhm) shiftx, shifty = centroidx - cx, centroidy - cy psfs = frame_shift(psfs, -shifty, -shiftx) for _ in range(2): centroidy, centroidx = fit_2dgaussian(psfs, fwhmx=fwhm, fwhmy=fwhm) cy, cx = frame_center(psfs, verbose=False) shiftx, shifty = centroidx - cx, centroidy - cy psfs = frame_shift(psfs, -shifty, -shiftx) # we check whether the flux is normalized and fix it if needed fwhm_aper = photutils.CircularAperture((frame_center(psfs)), fwhm / 2.) fwhm_aper_phot = photutils.aperture_photometry(psfs, fwhm_aper, method='exact') fwhm_flux = np.array(fwhm_aper_phot['aperture_sum']) if verbose: print "Flux in 1xFWHM aperture: {}".format(fwhm_flux) if fwhm_flux > 1.1 or fwhm_flux < 0.9: psf_norm_array = psfs / np.array(fwhm_aper_phot['aperture_sum']) else: psf_norm_array = psfs if threshold is not None: psf_norm_array[np.where(psf_norm_array < threshold)] = 0 if mask_core is not None: psf_norm_array = get_circle(psf_norm_array, radius=mask_core) if full_output: return psf_norm_array, fwhm_flux else: return psf_norm_array
# Random aperture positions positions = [ np.random.randint(0 + int(np.ceil(r)), cutoutwidth - int(np.ceil(r)), N), np.random.randint(0 + int(np.ceil(r)), cutoutwidth - int(np.ceil(r)), N) ] # Creating apertures aperture = CircularAperture(positions, r=r) aperture.plot(color='red', lw=1., alpha=0.5) plt.show() # Measuring photometry in the random apertures phot_table = aperture_photometry(img.bkg / img.nJy_to_es, aperture, method='subpixel') phot_table['aperture_sum'].info.format = '%.8g' print('') print('Printout of random aperture values (nJy)') #print(phot_table) aperture_sums = np.asarray(phot_table['aperture_sum']) print( f'mean aperture flux = {np.mean(aperture_sums):.2f}, std = {np.std(aperture_sums):.2f}' ) # plotting a normalised histogram of the aperture fluxes
y_2 = 4090 for image_name in files[0:1]: image = fits.getdata(star + "/" + image_name, ext=0) data = image[x_1:x_2, y_1:y_2] tbl = find_peaks(data, 300, box_size=50) pe = np.array(tbl['peak_value']) pe_x = np.array(tbl['x_peak']) pe_y = np.array(tbl['y_peak']) peaks = np.array((pe_x, pe_y, pe)).T peaks = peaks.tolist() peaks = sorted(peaks, key=lambda t: t[2], reverse=True) positions = (peaks[0][0], peaks[0][1] ) #[peaks[0][0], peaks[0][1]], [peaks[1][0], peaks[1][1]] apertures = lambda r: CircularAperture(positions, r=r) phot_table = lambda r: aperture_photometry(data, apertures(r)) rad = [0.0] numcounts = [0.0] noise = 10000 i = 0 while (noise >= 5000): rad.append(rad[i] + 1.0) numcounts.append(phot_table(rad[i + 1])['aperture_sum']) noise = numcounts[i + 1] - numcounts[i] i += 1 rad = np.array(rad) numcounts = np.array(numcounts) radius = np.array([ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0 ])
yloc = int(input("Yloc?")) AP2 = input( "Do you want to enter the annulus aperture values? (Y) or (N) ") if AP2 == 'Y': r_in = float(input("Inner radius factor? ")) r_out = float(input("Outter radius factor? ")) else: r_in = r * 3 r_out = r * 4.5 positions = (xloc, yloc) apertures = CircularAperture(positions, r) annulus_apertures = CircularAnnulus(positions, r_in, r_out) apers = [apertures, annulus_apertures] phot_table = aperture_photometry(image, apers) print("BB Phot table 2018 ") print(phot_table) print() print("Apertures Area is / Annulus Area is", apertures.area(), annulus_apertures.area()) bkg_mean = phot_table['aperture_sum_1'] / annulus_apertures.area() bkg_sum = bkg_mean * apertures.area() final_sum = phot_table['aperture_sum_0'] - bkg_sum phot_table['Aperture_final'] = final_sum print("Final sum is ", final_sum, phot_table[0][5]) print(phot_table)
def compare_rate_images(subarray_file, fullframe_file, out_dir='./', subarray_threshold=100, fullframe_threshold=100, max_separation=3., aperture_radius=5, bkgd_in_radius=6, bkgd_out_radius=8, subarray_rate_file=None, fullframe_rate_file=None): """MAIN FUNCTiON FOR COMPARING SOURCE RATES IN RATE FILES Parameters ---------- subarray_file : str Fits file containing the subarray data to be compared fullframe_file : sr Fits file containing the full frame data to be compared out_dir : str Output directory into which products are saved subarray_threshold : float Number of sigma above the background needed to identify a source fullframe_threshold : float Number of sigma above the background needed to identify a source max_separation : float Maximum allowed separation between sources, in pixels, between the subarray and full frame data in order for a source to be considered a match. aperture_radius : int Aperture radius (in pixels) to use for photometry bkgd_in_radius : int Inner radius (in pixels) to use for photometry background subtraction bkgd_out_radius : int Outer radius (in pixels) to use for photometry background subtraction Returns ------- sub_sources : astropy.table.Table Table of source positions, equivalent full frame positions, and photometry results from the data """ # Read in data subarray = datamodels.open(subarray_file) fullframe = datamodels.open(fullframe_file) # Quick test to see if using the rate files rather than the cal files # makes any difference in the LW discrepancy between fullframe and subarray data #if subarray_rate_file is not None: # subarray_rate = datamodels.open(subarray_rate_file) #else: # subarray_rate = subarray #if fullframe_rate_file is not None: # fullframe_rate = datamodels.open(fullframe_rate_file) #else: # fullframe_rate = fullframe # Define coord transform functions sub_xy_to_radec = subarray.meta.wcs.get_transform('detector', 'world') ff_radec_to_xy = fullframe.meta.wcs.get_transform('world', 'detector') ff_xy_to_radec = fullframe.meta.wcs.get_transform('detector', 'world') # Check to be sure the two images overlap ff_min_x = 0 ff_min_y = 0 ff_max_x = fullframe.meta.subarray.xsize - 1 ff_max_y = fullframe.meta.subarray.ysize - 1 cornerx = [ 0, 0, subarray.meta.subarray.xsize, subarray.meta.subarray.xsize ] cornery = [ 0, subarray.meta.subarray.ysize, subarray.meta.subarray.ysize, 0 ] cornerra, cornerdec = sub_xy_to_radec(cornerx, cornery) ffcornerx, ffcornery = ff_radec_to_xy(cornerra, cornerdec) overlap = False for fcx, fcy in zip(ffcornerx, ffcornery): if ((fcx > ff_min_x) & (fcx < ff_max_x) & (fcy > ff_min_y) and (fcy < ff_max_y)): overlap = True if not overlap: print( "Suabrray file and full frame file do not overlap. Quitting.\n\n") return 0 # Locate sources sub_fwhm = get_fwhm(subarray.meta.instrument.filter) sub_source_image = os.path.join( out_dir, '{}_subarray_source_map_countrate_compare.png'.format( os.path.basename(subarray_file))) #sub_sources = find_sources(subarray.data, threshold=subarray_threshold, fwhm=sub_fwhm, show_sources=True, save_sources=True, plot_name=sub_source_image) sub_sources = find_sources(subarray_rate.data, threshold=subarray_threshold, fwhm=sub_fwhm, show_sources=True, save_sources=True, plot_name=sub_source_image) ff_fwhm = get_fwhm(fullframe.meta.instrument.filter) full_source_image = os.path.join( out_dir, '{}_fullframe_map_datamodels.png'.format( os.path.basename(fullframe_file))) #ff_sources = find_sources(fullframe.data, threshold=fullframe_threshold, fwhm=ff_fwhm, show_sources=True, save_sources=True, plot_name=full_source_image) ff_sources = find_sources(fullframe_rate.data, threshold=fullframe_threshold, fwhm=ff_fwhm, show_sources=True, save_sources=True, plot_name=full_source_image) if sub_sources is None: print("No subarray sources to compare.") return 0 if ff_sources is None: print("No full frame sources to compare") return 0 # Put subarray sources in full frame detector coordinates # 1. Transform to RA, Dec # 2. Use WCS of full frame file to put coordinates in full frame coords # Transform subarray x,y -> RA, Dec -> full frame x, y ra, dec = sub_xy_to_radec(sub_sources['xcentroid'], sub_sources['ycentroid']) ffx, ffy = ff_radec_to_xy(ra, dec) # Add RA, Dec and fullframe equivalent x,y to the subarray source catalog sub_sources['RA'] = ra sub_sources['Dec'] = dec sub_sources['fullframe_x'] = ffx sub_sources['fullframe_y'] = ffy # Find RA, Dec of sources in full frame catalog ffra, ffdec = ff_xy_to_radec(ff_sources['xcentroid'], ff_sources['ycentroid']) ff_sources['RA'] = ffra ff_sources['Dec'] = ffdec # Match catalogs ff_cat = SkyCoord(ra=ffra * u.degree, dec=ffdec * u.degree) sub_cat = SkyCoord(ra=ra * u.degree, dec=dec * u.degree) idx, d2d, d3d = sub_cat.match_to_catalog_3d(ff_cat) # Remove bad matches pscale = subarray.meta.wcsinfo.cdelt1 if pscale is None: pscale = np.abs(subarray.meta.wcsinfo.cd1_1) pix_scale = pscale * 3600. max_sep = max_separation * pix_scale * u.arcsec # Matches must be within a pixel sep_constraint = d2d < max_sep sub_catalog_matches = sub_sources[sep_constraint] ff_catalog_matches = ff_sources[idx[sep_constraint]] num_matched = len(ff_catalog_matches) print('Found {} matching sources in the two input files.'.format( num_matched)) if num_matched == 0: print("No matching sources found. Quitting.\n\n\n") return 0, 0 # What if we just do photometry on the sources in the subarray and their # calculated positions in the full frame? sub_pos = [] ff_pos = [] good_indexes = [] non_zero_sub_dq = [] non_zero_full_dq = [] for i, line in enumerate(sub_catalog_matches): if ((line['fullframe_x'] > 5) & (line['fullframe_x'] < 2039) & \ (line['fullframe_y'] > 5) & (line['fullframe_y'] < 2039)): sub_pos.append((line['xcentroid'], line['ycentroid'])) #ff_pos.append((line['fullframe_x'], line['fullframe_y'])) ff_pos.append((ff_catalog_matches[i]['xcentroid'], ff_catalog_matches[i]['ycentroid'])) good_indexes.append(i) # Make a note if there are any non-zero DQ flags within the apertures # During development, found some cases with NO_LIN_CORR and NO_FLAT_FIELD # that were screwing up photometry yc_sub = int(np.round(line['ycentroid'])) xc_sub = int(np.round(line['xcentroid'])) sub_dq = subarray.dq[yc_sub - 3:yc_sub + 4, xc_sub - 3:xc_sub + 4] if np.sum(sub_dq) > 0: non_zero_sub_dq.append(True) else: non_zero_sub_dq.append(False) yc = int(np.round(line['fullframe_x'])) xc = int(np.round(line['fullframe_y'])) sub_dq = fullframe.dq[yc - 1:yc + 2, xc - 1:xc + 2] if np.sum(sub_dq) > 0: non_zero_full_dq.append(True) else: non_zero_full_dq.append(False) print('Performing photometry on a total of {} sources.'.format( len(sub_pos))) # Now perform aperture photometry on the sources in the subarray # and full frame data. Keep the aperture small since the difference # in exposure time and SNR will be large #sub_pos = [(m['xcentroid'], m['ycentroid']) for m in sub_catalog_matches] #ff_pos = [(m['xcentroid'], m['ycentroid']) for m in ff_catalog_matches] sub_aperture = CircularAperture(sub_pos, r=aperture_radius) ff_aperture = CircularAperture(ff_pos, r=aperture_radius) sub_annulus = CircularAnnulus(sub_pos, r_in=bkgd_in_radius, r_out=bkgd_out_radius) full_annulus = CircularAnnulus(ff_pos, r_in=bkgd_in_radius, r_out=bkgd_out_radius) # Photometry #sub_phot_table = aperture_photometry(subarray.data, sub_aperture) #ff_phot_table = aperture_photometry(fullframe.data, ff_aperture) sub_phot_table = aperture_photometry(subarray_rate.data, sub_aperture) ff_phot_table = aperture_photometry(fullframe_rate.data, ff_aperture) sub_annulus_masks = sub_annulus.to_mask(method='center') full_annulus_masks = full_annulus.to_mask(method='center') #sub_bkg_median = median_background(sub_annulus_masks, subarray.data) sub_bkg_median = median_background(sub_annulus_masks, subarray_rate.data) sub_phot_table['annulus_median'] = sub_bkg_median sub_phot_table['aper_bkg'] = sub_bkg_median * sub_aperture.area sub_phot_table['aper_sum_bkgsub'] = sub_phot_table[ 'aperture_sum'] - sub_phot_table['aper_bkg'] #full_bkg_median = median_background(full_annulus_masks, fullframe.data) full_bkg_median = median_background(full_annulus_masks, fullframe_rate.data) ff_phot_table['annulus_median'] = full_bkg_median ff_phot_table['aper_bkg'] = full_bkg_median * ff_aperture.area ff_phot_table['aper_sum_bkgsub'] = ff_phot_table[ 'aperture_sum'] - ff_phot_table['aper_bkg'] # Compare photometry results delta_phot = ff_phot_table['aper_sum_bkgsub'].data - sub_phot_table[ 'aper_sum_bkgsub'].data delta_phot_perc = delta_phot / ff_phot_table['aper_sum_bkgsub'].data * 100. sub_phot_table['delta_from_fullframe'] = delta_phot sub_phot_table['delta_from_fullframe_percent'] = delta_phot_perc # Keep track of whether there are bad pixels in the apertures #sub_dq = np.zeros(len(sub_sources), dtype=bool) #sub_dq[good_indexes] = non_zero_sub_dq #sub_sources['sub_dq'] = sub_dq #full_dq = np.zeros(len(sub_sources), dtype=bool) #full_dq[good_indexes] = non_zero_full_dq #sub_sources['full_dq'] = full_dq sub_dq = np.zeros(len(sub_catalog_matches), dtype=bool) sub_dq[good_indexes] = non_zero_sub_dq sub_catalog_matches['sub_dq'] = sub_dq full_dq = np.zeros(len(sub_catalog_matches), dtype=bool) full_dq[good_indexes] = non_zero_full_dq sub_catalog_matches['full_dq'] = full_dq # Add photometry to the table #sub_phot_data = np.zeros(len(sub_sources)) #sub_phot_data[good_indexes] = sub_phot_table['aper_sum_bkgsub'].data #ff_phot_data = np.zeros(len(sub_sources)) #ff_phot_data[good_indexes] = ff_phot_table['aper_sum_bkgsub'].data #delta_phot_col = np.zeros(len(sub_sources)) #delta_phot_col[good_indexes] = delta_phot #delta_phot_perc_col = np.zeros(len(sub_sources)) #delta_phot_perc_col[good_indexes] = delta_phot_perc sub_phot_data = np.zeros(len(sub_catalog_matches)) sub_phot_data[good_indexes] = sub_phot_table['aper_sum_bkgsub'].data ff_phot_data = np.zeros(len(sub_catalog_matches)) ff_phot_data[good_indexes] = ff_phot_table['aper_sum_bkgsub'].data delta_phot_col = np.zeros(len(sub_catalog_matches)) delta_phot_col[good_indexes] = delta_phot delta_phot_perc_col = np.zeros(len(sub_catalog_matches)) delta_phot_perc_col[good_indexes] = delta_phot_perc #sub_sources['sub_phot'] = sub_phot_data #sub_sources['ff_phot'] = ff_phot_data #sub_sources['d_phot'] = delta_phot_col #sub_sources['d_phot_p'] = delta_phot_perc_col #sub_sources['xcentroid'].info.format = '7.3f' #sub_sources['ycentroid'].info.format = '7.3f' #sub_sources['fullframe_x'].info.format = '7.3f' #sub_sources['fullframe_y'].info.format = '7.3f' #sub_sources['sub_phot'].info.format = '7.3f' #sub_sources['ff_phot'].info.format = '7.3f' #sub_sources['d_phot'].info.format = '7.3f' #sub_sources['d_phot_p'].info.format = '7.3f' #print(sub_sources['xcentroid', 'ycentroid', 'fullframe_x', 'fullframe_y', 'sub_phot', 'ff_phot', 'd_phot_p', 'sub_dq', 'full_dq']) sub_catalog_matches['sub_phot'] = sub_phot_data sub_catalog_matches['ff_phot'] = ff_phot_data sub_catalog_matches['d_phot'] = delta_phot_col sub_catalog_matches['d_phot_p'] = delta_phot_perc_col sub_catalog_matches['xcentroid'].info.format = '7.3f' sub_catalog_matches['ycentroid'].info.format = '7.3f' sub_catalog_matches['fullframe_x'].info.format = '7.3f' sub_catalog_matches['fullframe_y'].info.format = '7.3f' sub_catalog_matches['sub_phot'].info.format = '7.3f' sub_catalog_matches['ff_phot'].info.format = '7.3f' sub_catalog_matches['d_phot'].info.format = '7.3f' sub_catalog_matches['d_phot_p'].info.format = '7.3f' final_sub_cat = sub_catalog_matches[good_indexes] print(final_sub_cat['xcentroid', 'ycentroid', 'fullframe_x', 'fullframe_y', 'sub_phot', 'ff_phot', 'd_phot_p', 'sub_dq', 'full_dq']) print('') # Save the complete table sub_base = os.path.basename(subarray_file).replace('.fits', '') full_base = os.path.basename(fullframe_file).replace('.fits', '') table_name = os.path.join( out_dir, 'photometry_comparison_{}_{}.txt'.format(sub_base, full_base)) ascii.write(final_sub_cat, table_name, overwrite=True) print('Photometry results saved to: {}'.format(table_name)) # Try filtering out sources where there is a pixel flagged in the full # frame or subarray DQ mask at the source location clean = [] for row in final_sub_cat: clean.append(row['sub_dq'] == False and row['full_dq'] == False) if np.sum(clean) > 0: clean_table = final_sub_cat[clean] print('Excluding sources with a pixel flagged in the DQ array:') med_clean_diff = np.around(np.median(clean_table['d_phot_p']), 1) print( 'Median photometry difference between subarray and full frame sources is: {}%\n\n\n' .format(med_clean_diff)) else: clean_table = None print('No sources without a flagged pixel in the DQ arrays.') return final_sub_cat, clean_table
def aperture_photometry(calibratable, ra, dec, apply_calibration=False, assume_background_subtracted=False, use_cutout=False, direct_load=None): import photutils from astropy.coordinates import SkyCoord from astropy.io import fits from astropy.table import vstack from astropy.wcs import WCS ra = np.atleast_1d(ra) dec = np.atleast_1d(dec) coord = SkyCoord(ra, dec, unit='deg') if not use_cutout: wcs = calibratable.wcs apertures = photutils.SkyCircularAperture(coord, r=APERTURE_RADIUS) # something that is photometerable implements mask, background, and wcs if not assume_background_subtracted: pixels_bkgsub = calibratable.background_subtracted_image.data else: pixels_bkgsub = calibratable.data bkgrms = calibratable.rms_image.data mask = calibratable.mask_image.data phot_table = photutils.aperture_photometry(pixels_bkgsub, apertures, error=bkgrms, wcs=wcs) phot_table['zp'] = calibratable.header['MAGZP'] + calibratable.header[ 'APCOR4'] phot_table['obsjd'] = calibratable.header['OBSJD'] phot_table['filtercode'] = 'z' + calibratable.header['FILTER'][-1] pixap = apertures.to_pixel(wcs) annulus_masks = pixap.to_mask(method='center') maskpix = [ annulus_mask.cutout(mask.data) for annulus_mask in annulus_masks ] else: phot_table = [] maskpix = [] for s in coord: if direct_load is not None and 'sci' in direct_load: sci_path = direct_load['sci'] else: if assume_background_subtracted: sci_path = calibratable.local_path else: sci_path = calibratable.background_subtracted_image.local_path if direct_load is not None and 'mask' in direct_load: mask_path = direct_load['mask'] else: mask_path = calibratable.mask_image.local_path if direct_load is not None and 'rms' in direct_load: rms_path = direct_load['rms'] else: rms_path = calibratable.rms_image.local_path with fits.open(sci_path, memmap=True) as f: wcs = WCS(f[0].header) pixcoord = wcs.all_world2pix([[s.ra.deg, s.dec.deg]], 0)[0] pixx, pixy = pixcoord nx = calibratable.header['NAXIS1'] ny = calibratable.header['NAXIS2'] xmin = max(0, pixx - 1.5 * APERTURE_RADIUS.value) xmax = min(nx, pixx + 1.5 * APERTURE_RADIUS.value) ymin = max(0, pixy - 1.5 * APERTURE_RADIUS.value) ymax = min(ny, pixy + 1.5 * APERTURE_RADIUS.value) ixmin = int(np.floor(xmin)) ixmax = int(np.ceil(xmax)) iymin = int(np.floor(ymin)) iymax = int(np.ceil(ymax)) ap = photutils.CircularAperture([pixx - ixmin, pixy - iymin], APERTURE_RADIUS.value) # something that is photometerable implements mask, background, and wcs with fits.open(sci_path, memmap=True) as f: pixels_bkgsub = f[0].data[iymin:iymax, ixmin:ixmax] with fits.open(rms_path, memmap=True) as f: bkgrms = f[0].data[iymin:iymax, ixmin:ixmax] with fits.open(mask_path, memmap=True) as f: mask = f[0].data[iymin:iymax, ixmin:ixmax] pt = photutils.aperture_photometry(pixels_bkgsub, ap, error=bkgrms) annulus_mask = ap.to_mask(method='center') mp = annulus_mask.cutout(mask.data) maskpix.append(mp) phot_table.append(pt) phot_table = vstack(phot_table) if apply_calibration: magzp = calibratable.header['MAGZP'] apcor = calibratable.header[APER_KEY] phot_table['mag'] = -2.5 * np.log10( phot_table['aperture_sum']) + magzp + apcor phot_table['magerr'] = 1.0826 * phot_table[ 'aperture_sum_err'] / phot_table['aperture_sum'] # check for invalid photometry on masked pixels phot_table['flags'] = [ int(np.bitwise_or.reduce(m, axis=(0, 1))) for m in maskpix ] # rename some columns phot_table.rename_column('aperture_sum', 'flux') phot_table.rename_column('aperture_sum_err', 'fluxerr') return phot_table
def fit_ellipse_for_source( friendid=None, detectid=None, coords=None, shotid=None, subcont=True, convolve_image=False, pixscale=pixscale, imsize=imsize, wave_range=None, ): if detectid is not None: global deth5 detectid_obj = detectid if detectid_obj <= 2190000000: det_info = deth5.root.Detections.read_where("detectid == detectid_obj")[0] linewidth = det_info["linewidth"] wave_obj = det_info["wave"] redshift = wave_obj / (1216) - 1 else: det_info = conth5.root.Detections.read_where("detectid == detectid_obj")[0] redshift = 0 wave_obj = 4500 coords_obj = SkyCoord(det_info["ra"], det_info["dec"], unit="deg") shotid_obj = det_info["shotid"] fwhm = surveyh5.root.Survey.read_where("shotid == shotid_obj")["fwhm_virus"][0] amp = det_info["multiframe"] if wave_range is not None: wave_range_obj = wave_range else: if detectid_obj <= 2190000000: wave_range_obj = [wave_obj - 2 * linewidth, wave_obj + 2 * linewidth] else: wave_range_obj = [4100, 4200] if coords is not None: coords_obj = coords if shotid is not None: shotid_obj = shotid fwhm = surveyh5.root.Survey.read_where("shotid == shotid_obj")[ "fwhm_virus" ][0] try: hdu = make_narrowband_image( coords=coords_obj, shotid=shotid_obj, wave_range=wave_range_obj, imsize=imsize * u.arcsec, pixscale=pixscale * u.arcsec, subcont=subcont, convolve_image=convolve_image, include_error=True, ) except: print("Could not make narrowband image for {}".format(detectid)) return np.nan, np.nan elif friendid is not None: global friend_cat sel = friend_cat["friendid"] == friendid group = friend_cat[sel] coords_obj = SkyCoord(ra=group["icx"][0] * u.deg, dec=group["icy"][0] * u.deg) wave_obj = group["icz"][0] redshift = wave_obj / (1216) - 1 linewidth = group["linewidth"][0] shotid_obj = group["shotid"][0] fwhm = group["fwhm"][0] amp = group["multiframe"][0] if wave_range is not None: wave_range_obj = wave_range else: wave_range_obj = [wave_obj - 2 * linewidth, wave_obj + 2 * linewidth] if shotid is not None: shotid_obj = shotid fwhm = surveyh5.root.Survey.read_where("shotid == shotid_obj")[ "fwhm_virus" ][0] try: hdu = make_narrowband_image( coords=coords_obj, shotid=shotid_obj, wave_range=wave_range_obj, imsize=imsize * u.arcsec, pixscale=pixscale * u.arcsec, subcont=subcont, convolve_image=convolve_image, include_error=True, ) except: print("Could not make narrowband image for {}".format(friendid)) return None elif coords is not None: coords_obj = coords if wave_range is not None: wave_range_obj = wave_range else: print( "You need to supply wave_range=[wave_start, wave_end] for collapsed image" ) if shotid is not None: shotid_obj = shotid fwhm = surveyh5.root.Survey.read_where("shotid == shotid_obj")[ "fwhm_virus" ][0] else: print("Enter the shotid to use (eg. 20200123003)") hdu = make_narrowband_image( coords=coords_obj, shotid=shotid_obj, wave_range=wave_range_obj, imsize=imsize * u.arcsec, pixscale=pixscale * u.arcsec, subcont=subcont, convolve_image=convolve_image, include_error=True, ) else: print("You must provide a detectid, friendid or coords/wave_range/shotid") return np.nan, np.nan w = wcs.WCS(hdu[0].header) if friendid is not None: sel_friend_group = friend_cat["friendid"] == friendid group = friend_cat[sel_friend_group] eps = 1 - group["a2"][0] / group["b2"][0] pa = group["pa"][0] * np.pi / 180.0 - 90 sma = group["a"][0] * 3600 / pixscale coords = SkyCoord(ra=group["icx"][0] * u.deg, dec=group["icy"][0] * u.deg) wave_obj = group["icz"][0] redshift = wave_obj / (1216) - 1 linewidth = np.nanmedian(group["linewidth"]) shotid_obj = group["shotid"][0] fwhm = group["fwhm"][0] geometry = EllipseGeometry( x0=w.wcs.crpix[0], y0=w.wcs.crpix[0], sma=sma, eps=eps, pa=pa ) else: geometry = EllipseGeometry( x0=w.wcs.crpix[0], y0=w.wcs.crpix[0], sma=20, eps=0.2, pa=20.0 ) geometry = EllipseGeometry( x0=w.wcs.crpix[0], y0=w.wcs.crpix[0], sma=20, eps=0.2, pa=20.0 ) # geometry.find_center(hdu.data) # aper = EllipticalAperture((geometry.x0, geometry.y0), geometry.sma, # geometry.sma*(1 - geometry.eps), geometry.pa) # plt.imshow(hdu.data, origin='lower') # aper.plot(color='white') ellipse = Ellipse(hdu[0].data) isolist = ellipse.fit_image() iso_tab = isolist.to_table() if len(iso_tab) == 0: geometry.find_center(hdu[0].data, verbose=False, threshold=0.5) ellipse = Ellipse(hdu[0].data, geometry) isolist = ellipse.fit_image() iso_tab = isolist.to_table() if len(iso_tab) == 0: return np.nan, np.nan, np.nan try: # compute iso's manually in steps of 3 pixels ellipse = Ellipse(hdu[0].data) # reset ellipse iso_list = [] for sma in np.arange(1, 60, 2): iso = ellipse.fit_isophote(sma) if np.isnan(iso.intens): # print('break at {}'.format(sma)) break else: iso_list.append(iso) isolist = IsophoteList(iso_list) iso_tab = isolist.to_table() except: return np.nan, np.nan, np.nan try: model_image = build_ellipse_model(hdu[0].data.shape, isolist) residual = hdu[0].data - model_image except: return np.nan, np.nan, np.nan sma = iso_tab["sma"] * pixscale const_arcsec_to_kpc = cosmo.kpc_proper_per_arcmin(redshift).value / 60.0 def arcsec_to_kpc(sma): dist = const_arcsec_to_kpc * sma return dist def kpc_to_arcsec(dist): sma = dist / const_arcsec_to_kpc return sma dist_kpc = ( sma * u.arcsec.to(u.arcmin) * u.arcmin * cosmo.kpc_proper_per_arcmin(redshift) ) dist_arcsec = kpc_to_arcsec(dist_kpc) # print(shotid_obj, fwhm) # s_exp1d = models.Exponential1D(amplitude=0.2, tau=-50) alpha = 3.5 s_moffat = models.Moffat1D( amplitude=1, gamma=(0.5 * fwhm) / np.sqrt(2 ** (1.0 / alpha) - 1.0), x_0=0.0, alpha=alpha, fixed={"amplitude": False, "x_0": True, "gamma": True, "alpha": True}, ) s_init = models.Exponential1D(amplitude=0.2, tau=-50) fit = fitting.LevMarLSQFitter() s_r = fit(s_init, dist_kpc, iso_tab["intens"]) # Fitting can be done using the uncertainties as weights. # To get the standard weighting of 1/unc^2 for the case of # Gaussian errors, the weights to pass to the fitting are 1/unc. # fitted_line = fit(line_init, x, y, weights=1.0/yunc) # s_r = fit(s_init, dist_kpc, iso_tab['intens'])#, weights=iso_tab['intens']/iso_tab['intens_err'] ) print(s_r) try: r_n = -1.0 * s_r.tau # _0 #* const_arcsec_to_kpc except: r_n = np.nan # r_n = -1. * s_r.tau_0 try: sel_iso = np.where(dist_kpc >= 2 * r_n)[0][0] except: sel_iso = -1 aper = EllipticalAperture( (isolist.x0[sel_iso], isolist.y0[sel_iso]), isolist.sma[sel_iso], isolist.sma[sel_iso] * (1 - isolist.eps[sel_iso]), isolist.pa[sel_iso], ) phottable = aperture_photometry(hdu[0].data, aper, error=hdu[1].data) flux = phottable["aperture_sum"][0] * 10 ** -17 * u.erg / (u.cm ** 2 * u.s) flux_err = phottable["aperture_sum_err"][0] * 10 ** -17 * u.erg / (u.cm ** 2 * u.s) lum_dist = cosmo.luminosity_distance(redshift).to(u.cm) lum = flux * 4.0 * np.pi * lum_dist ** 2 lum_err = flux_err * 4.0 * np.pi * lum_dist ** 2 if detectid: name = detectid elif friendid: name = friendid # Get Image data from Elixer catlib = catalogs.CatalogLibrary() try: cutout = catlib.get_cutouts( position=coords_obj, side=imsize, aperture=None, dynamic=False, filter=["r", "g", "f606W"], first=True, allow_bad_image=False, allow_web=True, )[0] except: print("Could not get imaging for " + str(name)) zscale = ZScaleInterval(contrast=0.5, krej=1.5) vmin, vmax = zscale.get_limits(values=hdu[0].data) fig = plt.figure(figsize=(20, 12)) fig.suptitle( "{} ra={:3.2f}, dec={:3.2f}, wave={:5.2f}, z={:3.2f}, mf={}".format( name, coords_obj.ra.value, coords_obj.dec.value, wave_obj, redshift, amp ), fontsize=22, ) ax1 = fig.add_subplot(231, projection=w) plt.imshow(hdu[0].data, vmin=vmin, vmax=vmax) plt.xlabel("RA") plt.ylabel("Dec") plt.colorbar() plt.title("Image summed across 4*linewidth") ax2 = fig.add_subplot(232, projection=w) plt.imshow(model_image, vmin=vmin, vmax=vmax) plt.xlabel("RA") plt.ylabel("Dec") plt.colorbar() plt.title("model") ax3 = fig.add_subplot(233, projection=w) plt.imshow(residual, vmin=vmin, vmax=vmax) plt.xlabel("RA") plt.ylabel("Dec") plt.colorbar() plt.title("residuals (image-model)") # fig = plt.figure(figsize=(10,5)) im_zscale = ZScaleInterval(contrast=0.5, krej=2.5) im_vmin, im_vmax = im_zscale.get_limits(values=cutout["cutout"].data) ax4 = fig.add_subplot(234, projection=cutout["cutout"].wcs) plt.imshow( cutout["cutout"].data, vmin=im_vmin, vmax=im_vmax, origin="lower", cmap=plt.get_cmap("gray"), interpolation="none", ) plt.text( 0.8, 0.9, cutout["instrument"] + cutout["filter"], transform=ax4.transAxes, fontsize=20, color="w", ) plt.contour(hdu[0].data, transform=ax4.get_transform(w)) plt.xlabel("RA") plt.ylabel("Dec") aper.plot( color="white", linestyle="dashed", linewidth=2, transform=ax4.get_transform(w) ) ax5 = fig.add_subplot(235) plt.errorbar( dist_kpc.value, iso_tab["intens"], yerr=iso_tab["intens_err"] * iso_tab["intens"], linestyle="none", marker="o", label="Lya SB profile", ) plt.plot(dist_kpc, s_r(dist_kpc), color="r", label="Lya exp SB model", linewidth=2) plt.xlabel("Semi-major axis (kpc)") # plt.xlabel('Semi-major axis (arcsec)') plt.ylabel("Flux ({})".format(10 ** -17 * (u.erg / (u.s * u.cm ** 2)))) plt.text(0.4, 0.7, "r_n={:3.2f}".format(r_n), transform=ax5.transAxes, fontsize=16) plt.text( 0.4, 0.6, "L_lya={:3.2e}".format(lum), transform=ax5.transAxes, fontsize=16 ) secax = ax5.secondary_xaxis("top", functions=(kpc_to_arcsec, kpc_to_arcsec)) secax.set_xlabel("Semi-major axis (arcsec)") # secax.set_xlabel('Semi-major axis (kpc)') plt.xlim(0, 100) # plt.plot(sma, s_r(sma), label='moffat psf') # plt.plot(dist_kpc.value, s1(kpc_to_arcsec(dist_kpc.value)), # linestyle='dashed', linewidth=2, # color='green', label='PSF seeing:{:3.2f}'.format(fwhm)) # These two are the exact same # s1 = models.Moffat1D() # s1.amplitude = iso_tab['intens'][0] # alpha=3.5 # s1.gamma = 0.5*(fwhm*const_arcsec_to_kpc)/ np.sqrt(2 ** (1.0 / alpha) - 1.0) # s1.alpha = alpha # plt.plot(r_1d, moffat_1d, color='orange') # plt.plot(dist_kpc.value, (s1(dist_kpc.value)), # linestyle='dashed', linewidth=2, # color='blue', label='PSF seeing:{:3.2f}'.format(fwhm)) E = Extract() E.load_shot(shotid_obj) moffat_psf = E.moffat_psf(seeing=fwhm, boxsize=imsize, scale=pixscale) moffat_shape = np.shape(moffat_psf) xcen = int(moffat_shape[1] / 2) ycen = int(moffat_shape[2] / 2) moffat_1d = ( moffat_psf[0, xcen:-1, ycen] / moffat_psf[0, xcen, ycen] * iso_tab["intens"][0] ) r_1d = moffat_psf[1, xcen:-1, ycen] E.close() plt.plot( arcsec_to_kpc(pixscale * np.arange(80)), iso_tab["intens"][0] * (moffat_psf[0, 80:-1, 80] / moffat_psf[0, 80, 80]), linestyle="dashed", color="green", label="PSF seeing:{:3.2f}".format(fwhm), ) plt.legend() if friendid is not None: ax6 = fig.add_subplot(236, projection=cutout["cutout"].wcs) plot_friends(friendid, friend_cat, cutout, ax=ax6, label=False) plt.savefig("fit2d_{}.png".format(name)) # filename = 'param_{}.txt'.format(name) # np.savetxt(filename, (r_n.value, lum.value)) return r_n, lum, lum_err
world = np.array([[308.15274048, 46.58061218]]) refpix = w.wcs_world2pix(world, 1) positions = [(targetpix[0, 0], targetpix[0, 1]), (refpix[0, 0], refpix[0, 1])] aperture = CircularAperture(positions, r=r_source) annulus = CircularAnnulus(positions, r_in, r_out) # define the apertures apertures = CircularAperture(positions, r=7) annulus_apertures = CircularAnnulus(positions, r_in=10, r_out=13) # call aperture functions for aperture and annulus rawflux_table = aperture_photometry(data, apertures) bkgflux_table = aperture_photometry(data, annulus_apertures) # hstack just combines two arrays phot_table = hstack([rawflux_table, bkgflux_table], table_names=['raw', 'bkg']) print( "================================================================================" ) print(phot_table) print( "================================================================================" ) #store the flux values from the phot_table
def FitCircularAperture( hdu=None, coords=None, radius=1.5 * u.arcsec, annulus=[5, 7] * u.arcsec, plot=False, plottitle=None, ): """ Fit a circular aperture with either an HDU object or and """ im = hdu[0].data error = hdu[1].data w = wcs.WCS(hdu[0].header) # create mask (set True for where you want to mask) im_mask = im == 0 # define circular aperture and annulus aperture for background subtraction aper = SkyCircularAperture(coords, r=radius) aper_annulus = SkyCircularAnnulus(coords, annulus[0], annulus[1]) mask = aper_annulus.to_pixel(w).to_mask(method="center").data annulus_data = aper_annulus.to_pixel(w).to_mask(method="center").multiply(im) annulus_data_1d = annulus_data[mask > 0] annulus_mask = aper_annulus.to_pixel(w).to_mask(method="center").multiply(im_mask) annulus_mask_1d = annulus_mask[mask > 0] # determine fractional fiber coverage apcor_im = aper.to_pixel(w).to_mask(method="center").multiply( im_mask ) / aper.to_pixel(w).to_mask(method="center").multiply(np.ones_like(im)) apcor = np.sum(apcor_im == 0) / np.sum(np.isfinite(apcor_im)) # get median and standard deviation in background mean_sigclip, median_sigclip, stddev_sigclip = sigma_clipped_stats( annulus_data_1d, mask=annulus_mask_1d ) bkg_median = median_sigclip * aper.to_pixel(w).area * apcor bkg_stddev = stddev_sigclip * aper.to_pixel(w).area * apcor phottable = aperture_photometry( hdu[0].data, [aper, aper_annulus], error=hdu[1].data, mask=im_mask, wcs=wcs.WCS(hdu[0].header), ) if np.abs(bkg_median) > 2 * bkg_stddev: flux = (phottable["aperture_sum_0"][0] - bkg_median) * u.Unit( "10^-17 erg cm-2 s-1" ) else: flux = (phottable["aperture_sum_0"][0]) * u.Unit("10^-17 erg cm-2 s-1") flux_err = phottable["aperture_sum_err_0"][0] * u.Unit("10^-17 erg cm-2 s-1") if plot: plt.subplot(111, projection=w) plt.imshow(im, vmin= -1 * stddev_sigclip, vmax=4 * stddev_sigclip) aper.to_pixel(w).plot(color="white") # for SkyCircularAperture aper_annulus.to_pixel(w).plot(color="red", linestyle="dashed") plt.xlabel("RA") plt.ylabel("Dec") plt.colorbar() if plottitle is not None: plt.title(plottitle) return flux, flux_err, bkg_stddev * u.Unit("10^-17 erg cm-2 s-1"), apcor