def do_phot(image,position,radius = 5, r_in=15., r_out=20.): aperture = CircularAperture(position,r=radius) bkg_aperture = CircularAnnulus(position,r_in=r_in,r_out=r_out) # perform the photometry; the default method is 'exact' phot = aperture_photometry(image, aperture) bkg = aperture_photometry(image, bkg_aperture) # calculate the mean background level (per pixel) in the annuli bkg_mean = bkg['aperture_sum'] / bkg_aperture.area() bkg_sum = bkg_mean * aperture.area() #look at ipython notebook; his may need editing; 'phot' in second line below may need brackets with 'flux_sum' inside #phot['bkg_sum'] = bkg_sum #phot['flux_sum'] = phot['flux'] - bkg_sum #these two lines from ipython notebook flux_bkgsub = phot['aperture_sum'] - bkg_sum phot['aperture_sum_bkgsub'] = flux_bkgsub return phot
def plot_light_curves(diff_cube, unique_extracted_objects): frame_data = [i for i in range(len(diff_cube))] colors = [(random.uniform(0.5, 1),random.uniform(0.5, 1),random.uniform(0.5,1)) for i in range(len(unique_extracted_objects))] plt.figure(figsize=(20,10)) for i, extracted_obj in enumerate(unique_extracted_objects): ap_data=[] plt.figure(i, figsize=(10, 12)) for frame in diff_cube: diff_cube_test = frame.copy() flux, fluxerr, flag = sep.sum_ellipse(diff_cube_test, x=extracted_obj[0], y=extracted_obj[1], a=extracted_obj[2], b=extracted_obj[3], theta=extracted_obj[4]) #flux /= diff_cube_test.sum() ap_data.append(flux) plt.ylim((0,800)) plt.plot(frame_data, ap_data, '-o', color=colors[i],linewidth=5.0, ) plt.show() plt.figure(2, figsize=(10, 12)) plt.imshow(diff_cube[1], cmap='gray', vmin=1, vmax=12) plt.colorbar() for i, extracted_obj in enumerate(unique_extracted_objects): positions = (extracted_obj[0], extracted_obj[1]) apertures = CircularAperture(positions, r=5.) apertures.plot(color=colors[i], linewidth=10.0, lw=2.5, alpha=0.5)
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_one_annular_bg(image, center, innerRad, outerRad, metric, apMethod='exact'): """Class methods are similar to regular functions. Note: Do not include the `self` parameter in the ``Args`` section. Args: param1: The first parameter. param2: The second parameter. Returns: True if successful, False otherwise. """ innerAperture = CircularAperture(center, innerRad) outerAperture = CircularAperture(center, outerRad) inner_aper_mask = innerAperture.to_mask(method=apMethod)[0] inner_aper_mask = inner_aper_mask.to_image(image.shape).astype(bool) outer_aper_mask = outerAperture.to_mask(method=apMethod)[0] outer_aper_mask = outer_aper_mask.to_image(image.shape).astype(bool) backgroundMask = (~inner_aper_mask)*outer_aper_mask return metric(image[backgroundMask])
def measure_one_median_bg(image, center, aperRad, metric, nSig, apMethod='exact'): """Class methods are similar to regular functions. Note: Do not include the `self` parameter in the ``Args`` section. Args: param1: The first parameter. param2: The second parameter. Returns: True if successful, False otherwise. """ aperture = CircularAperture(center, aperRad) aperture = aperture.to_mask(method=apMethod)[0] aperture = aperture.to_image(image.shape).astype(bool) backgroundMask = ~aperture medFrame = median(image[backgroundMask]) madFrame = std(image[backgroundMask]) medianMask= abs(image - medFrame) < nSig*madFrame maskComb = medianMask*backgroundMask return median(image[maskComb])
def plot_peaks(box, x_peaks, y_peaks, radius=None, title=None, vmin=None, vmax=None): """ This function plots the data with peaks marked ... :param box: :param x_peaks: :param y_peaks: :return: """ # Determine the maximum value in the box and the minium value for plotting if vmin is None: vmin = max(np.nanmin(box), 0.) if vmax is None: vmax = 0.5 * (np.nanmax(box) + vmin) # Set the normalization norm = ImageNormalize(stretch=SqrtStretch()) # Make the plot plt.figure(figsize=(8,2.5)) plt.imshow(box, origin='lower', norm=norm, interpolation='nearest', vmin=vmin, vmax=vmax, cmap="viridis") if radius is None: plt.plot(x_peaks, y_peaks, ls='none', color='white', marker='+', ms=40, lw=10, mew=4) else: positions = (x_peaks, y_peaks) apertures = CircularAperture(positions, r=radius) apertures.plot(color='green', lw=1.5, alpha=0.5) plt.xlim(0, box.shape[1]-1) plt.ylim(0, box.shape[0]-1) if title is not None: plt.title(title) plt.show()
def plot(sources, data, path): positions = (sources['xcentroid'], sources['ycentroid']) apertures = CircularAperture(positions, r=4.) norm = ImageNormalize(stretch=SqrtStretch()) plt.imshow(data, cmap='Greys', origin='lower', norm=norm) apertures.plot(color='blue', lw=1.5, alpha=0.5) plt.savefig(path)
def plot_light_curves(diff_cube, unique_extracted_objects): # The diff_cube has to be byte swapped BEFORE being sent as parameter (diff_cube.byteswap(True).newbyteorder()), otherwise the method is not goint to work. Unique_extracted_objects only work for elliptic-shapped apertures # We get the number of frames from the cube frame_data = [i for i in range(len(diff_cube))] # Random colours array colours = [ (random.uniform(0.5, 1), random.uniform(0.5, 1), random.uniform(0.5, 1)) for i in range(len(unique_extracted_objects)) ] maxVal = 0 minVal = float("inf") plt.figure(2, figsize=(10, 12)) # Bonus: Show the image with the sources on the same colour than the plots. if len(diff_cube) == 1: plt.imshow(diff_cube[0], cmap="gray", vmin=1, vmax=12) else: plt.imshow(diff_cube[1], cmap="gray", vmin=1, vmax=12) plt.colorbar() for i, extracted_obj in enumerate(unique_extracted_objects): positions = (extracted_obj[0], extracted_obj[1]) apertures = CircularAperture(positions, r=5.0) apertures.plot(color=colours[i], linewidth=10.0, lw=2.5, alpha=0.5) # For every object we are going to calculate the aperture plt.figure(1, figsize=(20, 12)) for i, extracted_obj in enumerate(unique_extracted_objects): ap_data = [] # The standard size of each independent figure # plt.figure(i, figsize=(10, 12)) # For every frame... for frame in diff_cube: diff_cube_test = frame.copy() # The parameters passed in order are x, y, a, b and theta flux, fluxerr, flag = sep.sum_ellipse( diff_cube_test, x=extracted_obj[0], y=extracted_obj[1], a=extracted_obj[2], b=extracted_obj[3], theta=extracted_obj[4], ) ap_data.append(flux) maxVal = np.maximum(maxVal, np.max(ap_data)) minVal = np.minimum(minVal, np.min(ap_data)) # Hard-coded value!!! ALERT!!! # Plot every curve as a dotted line with the points visible plt.plot(frame_data, ap_data, "-o", color=colours[i], linewidth=5.0) plt.ylim((minVal * 1.1, maxVal * 0.9)) # Voila plt.show()
def show_image(self,sourceRA,sourceDEC,refRA=None,refDEC=None, ref2RA=None, ref2DEC=None): print('RED circle is the cepheid. WHITE circle is the reference object(s).') print('Add more reference stars by defining ref1aper = blahblahbelow, and ref1aper.plot(etc...)') #aper_annulus = CircularAnnulus((sourceRA, sourceDEC), r_in=6., r_out = 8.) apertures = CircularAperture((self.worldcoord.wcs_world2pix(sourceRA,sourceDEC,0)), r=10) #ref2aper = CircularAperture((worldcoord.wcs_world2pix(ref2RA,ref2DEC,0)), r=7) #ref3aper = CircularAperture((worldcoord.wcs_world2pix(ref3RA,ref3DEC,0)), r=3.5) #darkaper = CircularAperture((worldcoord.wcs_world2pix(darkRA,darkDEC,0)), r=3.5) fig = plt.figure() fig.add_subplot(111, projection = self.worldcoord) plt.imshow(self.stardata,origin='lower', cmap='jet') apertures.plot(color='red',lw=5, alpha=1) if refRA != None: ref1aper = CircularAperture((self.worldcoord.wcs_world2pix(refRA,refDEC,0)), r=10) ref1aper.plot(color='red', lw=5, alpha=1) #apertures2.plot(color='white',lw=2.0,alpha=0.5) #largeaperture.plot(color='red', lw=1.5, alpha=0.5) if ref2RA != None: ref2aper = CircularAperture((self.worldcoord.wcs_world2pix(ref2RA,ref2DEC,0)), r=10) ref2aper.plot(color='red', lw=5, alpha=1)
def starbright(fnstar,fnflat,istar,axs,fg): #%% load data data = meanstack(fnstar,100)[0] #%% flat field flatnorm = readflat(fnflat,fnstar) data = (data/flatnorm).round().astype(data.dtype) #%% background mean, median, std = sigma_clipped_stats(data, sigma=3.0) rfact=data.shape[0]//40 cfact=data.shape[1]//40 bg = Background(data,(rfact,cfact),interp_order=1, sigclip_sigma=3) # http://docs.astropy.org/en/stable/units/#module-astropy.units #dataphot = (data - bg.background)*u.ph/(1e-4*u.m**2 * u.s * u.sr) # data = (data-0.97*data.min()/bg.background.min()*bg.background) * u.ph/(u.cm**2 * u.s * u.sr) data = data* u.ph/(u.cm**2 * u.s * u.sr) #%% source extraction sources = daofind(data, fwhm=3.0, threshold=5*std) #%% star identification and quantification XY = column_stack((sources['xcentroid'], sources['ycentroid'])) apertures = CircularAperture(XY, r=4.) norm = ImageNormalize(stretch=SqrtStretch()) flux = apertures.do_photometry(data,effective_gain=camgain)[0] #%% plots fg.suptitle('{}'.format(fnflat.parent),fontsize='x-large') hi = axs[-3].imshow(flatnorm,interpolation='none',origin='lower') fg.colorbar(hi,ax=axs[-3]) axs[-3].set_title('flatfield {}'.format(fnflat.name)) hi = axs[-2].imshow(bg.background,interpolation='none',origin='lower') fg.colorbar(hi,ax=axs[-2]) axs[-2].set_title('background {}'.format(fnstar.name)) hi = axs[-1].imshow(data.value, cmap='Greys', origin='lower', norm=norm,interpolation='none') fg.colorbar(hi,ax=axs[-1]) for i,xy in enumerate(XY): axs[-1].text(xy[0],xy[1], str(i),ha='center',va='center',fontsize=16,color='w') apertures.plot(ax=axs[-1], color='blue', lw=1.5, alpha=0.5) axs[-1].set_title('star {}'.format(fnstar.name)) return flux[istar]
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 process_file(inpath, file_name, t_constant, sigma, fwhm, r, kernel_size, outpath, plot): print "Processing " + file_name hdulist = fits.open(inpath + file_name) image = hdulist[0].data if isinstance(sigma, list): threshold = calc_sigma(image, sigma[0], sigma[1]) * t_constant else: threshold = t_constant*sigma median_out = signal.medfilt(image,kernel_size) median_sub = np.subtract(image,median_out) sources = daofind(median_sub, threshold, fwhm) sources_2 = np.array(sources["id", "xcentroid", "ycentroid", "sharpness", "roundness1", "roundness2", "npix", "sky", "peak", "flux", "mag"]) print_line= (file_name+","+str(sources_2)) base_name = os.path.splitext(file_name)[0] file = open(outpath + base_name + ".out", "a") file.write(print_line) file.close() positions = (sources['xcentroid'], sources['ycentroid']) # print positions apertures = CircularAperture(positions, r) phot_table = aperture_photometry(median_sub, apertures) phot_table_2 = np.array(phot_table["aperture_sum", "xcenter", "ycenter"]) print_line= (","+str(phot_table_2)+"\n") file = open(outpath + base_name + ".out", "a") file.write(print_line) file.write("\n") file.close() hdulist[0].data = median_sub file = open(outpath + base_name + ".fits", "w") hdulist.writeto(file) file.close() if plot: median_sub[median_sub<=0]=0.0001 plt.imshow(median_sub, cmap='gray', origin='lower') apertures.plot(color='blue', lw=1.5, alpha=0.5) plt.show()
def find_stars(image, plot = False, fwhm = 20.0, threshold=3.): from astropy.stats import sigma_clipped_stats mean, median, std = sigma_clipped_stats(image, sigma=3.0) from photutils import daofind sources = daofind(image - median, fwhm=fwhm, threshold=threshold*std) # stars already found accurately, vet_sources will be implemented when working properly # vet_sources(10.0,10.0) if plot == True: # from astropy.visualization import SqrtStretch # from astropy.visualization.mpl_normalize import ImageNormalize positions = (sources['xcentroid'], sources['ycentroid']) apertures = CircularAperture(positions, r=4.) #norm = ImageNormalize(stretch=SqrtStretch()) #plt.imshow(image, cmap='Greys', origin='lower', norm=norm) qi.display_image(image) apertures.plot(color='blue', lw=1.5, alpha=0.5) return sources
def calc_bkg_rms(ap, image, src_ap_area, rpsrc, mask=None, min_ap=6): if isinstance(ap, CircularAnnulus): aback = bback = ap.r_in + rpsrc ap_theta = 0 elif isinstance(ap, EllipticalAnnulus): aback = ap.a_in + rpsrc bback = ap.b_in + rpsrc ap_theta = ap.theta ecirc = ellip_circumference(aback, bback) diam = 2*rpsrc # Estimate the number of background apertures that can fit around the source # aperture. naps = np.int(np.round(ecirc/diam)) # Use a minimum of 6 apertures naps = np.max([naps, min_ap]) #naps = 6 theta_back = np.linspace(0, 2*np.pi, naps, endpoint=False) # Get the x, y positions of the background apertures x, y = ellip_point(ap.positions[0], aback, bback, ap_theta, theta_back) # Create the background apertures and calculate flux within each bkg_aps = CircularAperture(np.vstack([x,y]).T, rpsrc) flux_bkg = aperture_photometry(image, bkg_aps, mask=mask) flux_bkg = flux_bkg['aperture_sum'] flux_bkg_adj = flux_bkg/bkg_aps.area() * src_ap_area # Use sigma-clipping to determine the RMS of the background # Scale to the area of the source aperture me, md, sd = sigma_clipped_stats(flux_bkg_adj, sigma=3) bkg_rms = sd return bkg_rms, bkg_aps
def plot(self,scale='log'): apertures = CircularAperture([self.locx,self.locy], r=self.r) z = self.copy() z -= np.nanmedian(z) if scale=='log': z = np.log10(self) z = ma.masked_invalid(z) z.mask = z.mask | (z < 0) z.fill_value = 0 z = z.filled() imshow2(z) if self.pixels is not None: for i,pos in enumerate(self.pixels): r,c = pos plt.text(c,r,i,va='center',ha='center',color='Orange') apertures.plot(color='Lime',lw=1.5,alpha=0.5) plt.xlabel('Column (pixels)') plt.ylabel('Row (pixels)')
def measure_one_circle_bg(image, center, aperRad, metric, apMethod='exact'): """Class methods are similar to regular functions. Note: Do not include the `self` parameter in the ``Args`` section. Args: param1: The first parameter. param2: The second parameter. Returns: True if successful, False otherwise. """ aperture = CircularAperture(center, aperRad) aper_mask = aperture.to_mask(method=apMethod)[0] # list of ApertureMask objects (one for each position) # backgroundMask = abs(aperture.get_fractions(np.ones(self.imageCube[0].shape))-1) backgroundMask = aper_mask.to_image(image.shape).astype(bool) backgroundMask = ~backgroundMask#[backgroundMask == 0] = False return metric(image[backgroundMask])
def measure_one_KDE_bg(image, center, aperRad, metric, apMethod='exact'): """Class methods are similar to regular functions. Note: Do not include the `self` parameter in the ``Args`` section. Args: param1: The first parameter. param2: The second parameter. Returns: True if successful, False otherwise. """ aperture = CircularAperture(center, aperRad) aperture = aperture.to_mask(method=apMethod)[0] aperture = aperture.to_image(image.shape).astype(bool) backgroundMask = ~aperture kdeFrame = kde.KDEUnivariate(image[backgroundMask]) kdeFrame.fit() return kdeFrame.support[kdeFrame.density.argmax()]
def try_dao(fitsfile, outfile='out.png'): hdulist = fits.open(fitsfile) hdu = hdulist[0] if len(hdu.data.shape) == 3: data = hdu.data[0] else: data = hdu.data mean, median, std = sigma_clipped_stats(data[800:900, 800:900], sigma=3.0, iters=5) print(mean, median, std) #data = hdu.data sources = daofind(data - median, fwhm=3.0, threshold=5.*std) print 'Found %i sources' % len(sources) positions = (sources['xcentroid'], sources['ycentroid']) apertures = CircularAperture(positions, r=4.) norm = ImageNormalize(stretch=SqrtStretch(), vmin=2000, vmax=3000) plt.imshow(data, cmap='Greys', origin='lower', norm=norm) plt.title('%i Sources from a single all-sky frame' % len(sources)) apertures.plot(color='blue', lw=1.5, alpha=0.5) plt.savefig(filename=outfile)
def measure_one_background(image, center, aperRad, metric, apMethod='exact', bgMethod='circle'): """Class methods are similar to regular functions. Note: Do not include the `self` parameter in the ``Args`` section. Args: param1: The first parameter. param2: The second parameter. Returns: True if successful, False otherwise. """ if np.ndim(aperRad) == 0: aperture = CircularAperture(center, aperRad) aperture = aperture.to_mask(method=apMethod)[0] # list of ApertureMask objects (one for each position) aperture = ~aperture.to_image(image).astype(bool) # inverse to keep 'outside' aperture else: innerRad, outerRad = aperRad innerAperture = CircularAperture(center, innerRad) outerAperture = CircularAperture(center, outerRad) inner_aper_mask = innerAperture.to_mask(method=method)[0] inner_aper_mask = inner_aper_mask.to_image(image.shape).astype(bool) outer_aper_mask = outerAperture.to_mask(method=method)[0] outer_aper_mask = outer_aper_mask.to_image(image.shape).astype(bool) aperture = (~inner_aper_mask)*outer_aper_mask if bgMethod == 'median': medFrame = median(image[aperture]) madFrame = scale.mad(image[aperture]) medianMask= abs(image - medFrame) < nSig*madFrame aperture = medianMask*aperture if bgMethod == 'kde': kdeFrame = kde.KDEUnivariate(image[aperture].ravel()) kdeFrame.fit() return kdeFrame.support[kdeFrame.density.argmax()] return metric(image[aperture])
def extraction(aornum, chnum, plnm, plnm2, radii, var_rad, var_add, basepath, fromx, to): for aor in aornum: aor=str(aor) paths = glob.glob(basepath+'r'+aor+ '/ch*') fpathout=basepath+aor[-8:] directory = os.path.dirname(fpathout) if not os.path.exists(directory): os.makedirs(directory) fpath=basepath+'r' + aor + '/ch' + str(chnum) + '/bcd/' #path to fits files filenames=glob.glob(fpath + '*bcd.fits') filenames.sort() nframes=len(filenames) print ('Analyzing over ' + str(nframes) + ' frames.') hold_pos=np.zeros(shape=(nframes*64, 2)) hold_posg=np.zeros(shape=(nframes*64, 2)) hold_pos_diff = hold_pos - hold_posg central_pix=np.zeros(shape=(5,5, nframes*64)) lightcurve=np.zeros(shape=(nframes*64, len(radii)+len(var_rad)+len(var_add))) lightcurveg=np.zeros(shape=(nframes*64, len(radii)+len(var_rad)+len(var_add))) time=np.zeros(nframes*64) beta_np=np.zeros(nframes*64) for i in range(0,nframes): if i % 10==0: os.system('clear') print(aor, i,' of ',str(nframes)) hdulist = fits.open(filenames[i]) channel=str(hdulist[0].header['CHNLNUM']) cube=hdulist[0].data exptime=hdulist[0].header['EXPTIME'] framtime=hdulist[0].header['FRAMTIME'] mmbjd=hdulist[0].header['BMJD_OBS'] for j in range(0,64): scidata=cube[j,:,:] bkgd= backgr(scidata) data=scidata-bkgd data=ma.masked_invalid(data) bnp1=np.sum(data)**2 bnp2=np.sum(np.multiply(data,data)) bnp=bnp1/bnp2 xc,yc, xcg, ycg=centroid(data) #use both centroiding position=[xc,yc] positiong = [xcg, ycg] beta_np[64*i+j]=bnp hold_pos[64*i+j, :]=position hold_posg[64*i+j, :]=positiong hold_pos_diff[64*i+j,:] = hold_pos[64*i+j, :] - hold_posg[64*i+j, :] vrad1=var_rad*np.sqrt(bnp) vrad2=var_add+np.sqrt(bnp) vrad=np.concatenate((vrad1, vrad2)) all_rad=np.concatenate((radii, vrad)) apertures = [CircularAperture(position, r=r) if r > 0 else CircularAperture(position, r=2.0) for r in all_rad] aperturesg = [CircularAperture(positiong, r=r) if r > 0 else CircularAperture(positiong, r=2.0) for r in all_rad] phot_table = aperture_photometry(scidata, apertures) phot_tableg = aperture_photometry(scidata, aperturesg) for q in range (0,len(all_rad)): if q ==0: phot=np.zeros(len(all_rad)) photg=np.zeros(len(all_rad)) phot[q]=phot_table.columns[q+3] photg[q] = phot_tableg.columns[q+3] time[64*i+j]=mmbjd+framtime*j/86400.0 lightcurve[64*i+j, :]=phot lightcurveg[64*i+j,:]=photg central_pix[:,:,64*i+j]=data[13:18, 13:18] hdulist.close() orbparams=get_orb_pars(plnm2, basepath) #pmap=pmap_corr(hold_pos, channel) - if using pmap np.savez(fpathout+'extraction', ch=channel, time=time, lc=lightcurve, lcg=lightcurveg, cp=central_pix, op=orbparams, exptime=exptime, framtime=framtime, beta_np=beta_np, hold_pos=hold_pos, hold_posg=hold_posg, hold_pos_diff = hold_pos_diff, all_rad=all_rad, pos=position, posg=positiong) t=time npix=beta_np plt.figure() plt.subplot(311) plt.title(plnm+' Ch: '+str(chnum)+'\n'+aor) plt.scatter(t, hold_pos[:,0], s=1) plt.ylim(14.5, 15.5) plt.ylabel('X position') plt.xticks([]) plt.subplot(312) plt.scatter(t, hold_pos[:,1], s=1) plt.ylim(14.5, 15.5) plt.ylabel('Y position') plt.xticks([]) plt.subplot(313) plt.scatter(t, np.sqrt(npix), s=1) plt.ylim(2, 3) plt.ylabel('Sqrt Noise Pixel') plt.xlabel('Time') plt.savefig(fpathout+'xyb_plot') plt.figure() plt.subplot(311) plt.title(plnm+' Ch: '+str(chnum)+'\n'+aor) plt.scatter(t, hold_posg[:,0], s=1) plt.ylim(14.5, 15.5) plt.ylabel('X position - Gaussian') plt.xticks([]) plt.subplot(312) plt.scatter(t, hold_posg[:,1], s=1) plt.ylim(14.5, 15.5) plt.ylabel('Y position - Gaussian') plt.xticks([]) plt.subplot(313) plt.scatter(t, np.sqrt(npix), s=1) plt.ylim(2, 3) plt.ylabel('Sqrt Noise Pixel') plt.xlabel('Time') plt.savefig(fpathout+'xyb_plot_gaussian') #send_mail('xyb_plot.png', fpathout, aor, fromx, to) return None
num_comp = len(df) - 1 coord_targetx = df['XCoord'][0] coord_targety = df['YCoord'][0] positions = [(coord_targetx, coord_targety)] comp_mag = [] for i in range(num_comp): maggy = df['Mag'][i + 1] xcoord = df['XCoord'][i + 1] ycoord = df['YCoord'][i + 1] coords = (xcoord, ycoord) positions.append(coords) comp_mag.append(maggy) ap = eval(input("Enter the aperature size: ")) # Create the aperature aperture = CircularAperture(positions, r=ap) # Run the aperature photometry for each file if oneorno != 'Yes': for i in range(len(filelist)): image = filelist[i] image = str(image) im = fits.getdata(image) phot_table = aperture_photometry(im, aperture) # Save the pixel values from the table flux = [] target_flux = phot_table[0][3] for i in range(num_comp): ff = phot_table[i + 1][3] flux.append(ff) phot_table = str(phot_table) # Create a file to save
def tso_aperture_photometry(datamodel, xcenter, ycenter, radius, radius_inner, radius_outer): """ Create a photometric catalog for NIRCam TSO imaging observations. Parameters ---------- datamodel : `CubeModel` The input `CubeModel` of a NIRCam TSO imaging observation. xcenter, ycenter : float The ``x`` and ``y`` center of the aperture. radius : float The radius (in pixels) of the circular aperture. radius_inner, radius_outer : float The inner and outer radii (in pixels) of the circular-annulus aperture, used for local background estimation. Returns ------- catalog : `~astropy.table.QTable` An astropy QTable (Quantity Table) containing the source photometry. """ if not isinstance(datamodel, CubeModel): raise ValueError('The input data model must be a CubeModel.') aper1 = CircularAperture((xcenter, ycenter), r=radius) aper2 = CircularAnnulus((xcenter, ycenter), r_in=radius_inner, r_out=radius_outer) nimg = datamodel.data.shape[0] aperture_sum = [] aperture_sum_err = [] annulus_sum = [] annulus_sum_err = [] for i in np.arange(nimg): tbl1 = aperture_photometry(datamodel.data[i, :, :], aper1, error=datamodel.err[i, :, :]) tbl2 = aperture_photometry(datamodel.data[i, :, :], aper2, error=datamodel.err[i, :, :]) aperture_sum.append(tbl1['aperture_sum'][0]) aperture_sum_err.append(tbl1['aperture_sum_err'][0]) annulus_sum.append(tbl2['aperture_sum'][0]) annulus_sum_err.append(tbl2['aperture_sum_err'][0]) # convert array of Quantities to Quantity arrays aperture_sum = u.Quantity(aperture_sum) aperture_sum_err = u.Quantity(aperture_sum_err) annulus_sum = u.Quantity(annulus_sum) annulus_sum_err = u.Quantity(annulus_sum_err) # construct metadata for output table meta = OrderedDict() meta['instrument'] = datamodel.meta.instrument.name meta['detector'] = datamodel.meta.instrument.detector meta['channel'] = datamodel.meta.instrument.channel meta['subarray'] = datamodel.meta.subarray.name meta['filter'] = datamodel.meta.instrument.filter meta['pupil'] = datamodel.meta.instrument.pupil meta['target_name'] = datamodel.meta.target.catalog_name meta['xcenter'] = xcenter meta['ycenter'] = ycenter ra_icrs, dec_icrs = datamodel.meta.wcs(xcenter, ycenter) meta['ra_icrs'] = ra_icrs meta['dec_icrs'] = dec_icrs info = ('Photometry measured in a circular aperture of r={0} pixels. ' 'Background calculated as the mean in a circular annulus with ' 'r_inner={1} pixels and r_outer={2} pixels.' .format(radius, radius_inner, radius_outer)) meta['apertures'] = info tbl = QTable(meta=meta) dt = (datamodel.meta.exposure.group_time * (datamodel.meta.exposure.ngroups + 1)) dt_arr = (np.arange(1, 1 + datamodel.meta.exposure.nints) * dt - (dt / 2.)) int_dt = TimeDelta(dt_arr, format='sec') int_times = (Time(datamodel.meta.exposure.start_time, format='mjd') + int_dt) tbl['MJD'] = int_times.mjd tbl['aperture_sum'] = aperture_sum tbl['aperture_sum_err'] = aperture_sum_err tbl['annulus_sum'] = annulus_sum tbl['annulus_sum_err'] = annulus_sum_err annulus_mean = annulus_sum / aper2.area() annulus_mean_err = annulus_sum_err / aper2.area() tbl['annulus_mean'] = annulus_mean tbl['annulus_mean_err'] = annulus_mean_err aperture_bkg = annulus_mean * aper1.area() aperture_bkg_err = annulus_mean_err * aper1.area() tbl['aperture_bkg'] = aperture_bkg tbl['aperture_bkg_err'] = aperture_bkg_err net_aperture_sum = aperture_sum - aperture_bkg net_aperture_sum_err = np.sqrt(aperture_sum_err ** 2 + aperture_bkg_err ** 2) tbl['net_aperture_sum'] = net_aperture_sum tbl['net_aperture_sum_err'] = net_aperture_sum_err return tbl
for i in np.arange(np.size(lamda)): ra = 46.852292 dec = 58.514656 data, hdr = fits.getdata(name[i]+'.fits', 0, header = True) if i in (0,1,2,4): delt = abs(hdr['PXSCAL1'])/3600. else: delt = abs(hdr['CDELT1']) r_pix = aper/delt/3600. w = wcs.WCS(hdr) if lamda[i]>=70.: coordiante = SkyCoord(ra*u.deg, dec*u.deg, frame='fk5') ra = coordiante.galactic.l.degree dec = coordiante.galactic.b.degree phot_center = w.wcs_world2pix(ra, dec, 1) aperture = CircularAperture(phot_center, r=r_pix) phot = aperture_photometry(data, aperture) # bg as median in an annulus grid = annulus_index.go([data.shape[1],data.shape[0]],phot_center,r_pix*2,r_pix) bgdata = np.ndarray(shape=data.shape) bgdata[:,:] = np.median(data[grid]) bgphot = aperture_photometry(bgdata, aperture) if i in (3,5,6,7): flux = phot['aperture_sum'].data[0] bg = bgphot['aperture_sum'].data[0] else: flux = phot['aperture_sum'].data[0]*delt**2*304.61741978670857 bg = bgphot['aperture_sum'].data[0]*delt**2*304.61741978670857 print flux
def do_detection(self): """Flag outlier pixels in DQ of input images.""" self.build_suffix(**self.outlierpars) self._convert_inputs() pars = self.outlierpars save_intermediate_results = pars['save_intermediate_results'] # Start by performing initial TSO Photometry on stack of DataModels # TODO: need information about the actual source position in # TSO imaging mode (for all subarrays). # Meanwhile, this is a placeholder representing the geometric # center of the image. nints, ny, nx = self.inputs.data.shape xcenter = (ny - 1) / 2. ycenter = (ny - 1) / 2. # all radii are in pixel units if self.inputs.meta.instrument.pupil == 'WLP8': radius = 50 radius_inner = 60 radius_outer = 70 else: radius = 3 radius_inner = 4 radius_outer = 5 apertures = CircularAperture((xcenter, ycenter), r=radius) aperture_mask = apertures.to_mask(method='center')[0] # This mask has 1 for mask region, 0 for outside of mask median_mask = aperture_mask.to_image((ny, nx)) inv_median_mask = np.abs(median_mask - 1) # Perform photometry catalog = tso_aperture_photometry(self.inputs, xcenter, ycenter, radius, radius_inner, radius_outer) # Extract net photometry for the source # This will be the value used for scaling the median image within # the aperture region phot_values = catalog['net_aperture_sum'] # Convert CubeModel into ModelContainer of 2-D DataModels for image in self.input_models: image.wht = resample_utils.build_driz_weight( image, weight_type='exptime', good_bits=pars['good_bits'] ) # Initialize intermediate products used in the outlier detection input_shape = self.input_models[0].data.shape median_model = datamodels.ImageModel(init=input_shape) median_model.meta = deepcopy(self.input_models[0].meta) base_filename = self.inputs.meta.filename median_model.meta.filename = self.make_output_path( basepath=base_filename, suffix='median' ) # Perform median combination on set of drizzled mosaics median_model.data = self.create_median(self.input_models) aper2 = CircularAnnulus((xcenter, ycenter), r_in=radius_inner, r_out=radius_outer) tbl1 = aperture_photometry(median_model.data, apertures, error=median_model.data * 0.0 + 1.0) tbl2 = aperture_photometry(median_model.data, aper2, error=median_model.data * 0.0 + 1.0) aperture_sum = u.Quantity(tbl1['aperture_sum'][0]) annulus_sum = u.Quantity(tbl2['aperture_sum'][0]) annulus_mean = annulus_sum / aper2.area() aperture_bkg = annulus_mean * apertures.area() median_phot_value = aperture_sum - aperture_bkg if save_intermediate_results: log.info("Writing out MEDIAN image to: {}".format( median_model.meta.filename)) median_model.save(median_model.meta.filename) # Scale the median image by the initial photometry (only in aperture) # to create equivalent of 'blot' images # Area outside of aperture in median will remain unchanged blot_models = datamodels.ModelContainer() for i in range(nints): scale_factor = float(phot_values[i] / median_phot_value) scaled_image = datamodels.ImageModel(init=median_model.data.shape) scaled_image.meta = deepcopy(median_model.meta) scaled_data = (median_model.data * (scale_factor * median_mask) + ( median_model.data * inv_median_mask)) scaled_image.data = scaled_data blot_models.append(scaled_image) if save_intermediate_results: log.info("Writing out Scaled Median images...") def make_output_path(ignored, idx=None): output_path = self.make_output_path( basepath=base_filename, suffix='blot', idx=idx, component_format='_{asn_id}_{idx}' ) return output_path blot_models.save(make_output_path) # Perform outlier detection using statistical comparisons between # each original input image and its blotted version of the median image self.detect_outliers(blot_models) # clean-up (just to be explicit about being finished # with these results) del median_model, blot_models
def circular_mask(self, radius=4): circ = CircularAperture(self.centroid, radius) circ_mask = circ.to_mask()[0].to_image(self.image.shape).astype(bool) return circ_mask
def radial_profile(data, x, y, step_size, fwhm, rad): ''' Function used to create a plot of the radial profile of a source at the coordinates (``x``, ``y``). Performs aperture photometry on concentric circles of radii ``step_size``. This function does not show the plot but does everything up to that point. :param data: CCDData Data of the image. :param x: float Pixel coordinate. :param y: float Pixel coordinate. :param step_size: float Radial size of each ring (concentric circles). Anything less than ``0.7`` is too pixelated and does not represent the data accurately :param fwhm: float FWHM of the image. :param rad: float Radius to extent to (actually is ``rad`` * ``fwhm``). :return: nothing Makes the plot but does not return anything. ''' radii = np.arange(step_size, rad * fwhm, step_size) # Radii of apertures x_data = np.arange( 0, rad * fwhm, step_size) # Steps (starting at zero, to 2.5 * fwhm, by step_size) apers_area = [np.pi * (step_size**2)] # Circle area = pi*(r**2) for r in radii: apers_area.append(np.pi * ((r + step_size)**2 - r**2)) # Annulus area = pi*(r_out**2 - r_in**2) apertures = [CircularAperture( (x, y), r=step_size)] # For circle aperture around center for r in radii: apertures.append(CircularAnnulus( (x, y), r_in=r, r_out=r + step_size)) # Annuli apertures rad_prof_large = aperture_photometry( data, apertures) # Radial profile photometry of new fake source sums = [ rad_prof_large[0][k] / apers_area[k - 3] for k in range(3, len(rad_prof_large[0])) ] # For radial profile w_fit = x_data f_fit = sums g, _ = curve_fit(fix_x0, w_fit, f_fit) plt.figure(1) # plt.plot(x_data, sums, 'o-', alpha=0.5, lw=2, markersize=4) plt.plot(x_data, sums, 'o-', alpha=0.5, lw=2, markersize=4) # Plot the radial profiles plt.plot(x_data, fix_x0(x_data, *g), '^-', alpha=0.5, lw=2, markersize=4) plt.title("Radial profile of target") plt.xlabel("Radial distance from centroid of source (pixels)") plt.ylabel("Count (adu per second per pixel)")
def photom(ima, pos, radius, r_in=None, r_out=None, method='median'): ''' Aperture photometry in an aperture located at pixel coordinates pos = ( (x0, y0), (x1, y1), ... ) with a radius=radius. When r_in and r_out are given, background is estimated in CircularAnnulus and subtracted. method refers to how the background is estimated within the circlar annulus. Can be 'median' or 'mean' or 'mode' ''' ima_local = np.ma.asanyarray(ima.copy()) ima_local.fill_value = np.nan mask_ = ima_local.mask ima_ = ima_local.filled() ### Do photometry - identical for each method apertures = CircularAperture(pos, r = radius) ap = aperture_photometry(ima_, apertures, mask=mask_, method='exact') # Aperture photometry on mask to estimate # of masked pixels in aperture apm = aperture_photometry(mask_.astype(int), apertures, method='exact') ap.add_columns( [apertures.area()-apm['aperture_sum'], apm['aperture_sum']], names=['aperture_area', 'aperture_badpix']) ap.add_column(ap['aperture_sum'], index=3, name='Flux') if ( r_in == None or r_out == None or not method in ('mean', 'median', 'mode') ): # Quit here if background correction is not requested return ap annulus_apertures = CircularAnnulus(pos, r_in=r_in, r_out=r_out) annulus_masks = annulus_apertures.to_mask(method='center') bg_values = [] for annulus_mask in annulus_masks: bg_ima = annulus_mask.cutout(ima_) bg_mask = annulus_mask.cutout(mask_.astype(np.int)) bg_ima = np.ma.array(bg_ima, mask= bg_mask.astype(np.bool) | ~annulus_mask.data.astype(np.bool)) if method == 'mean': bg_val = bg_ima.mean() elif method == 'median': bg_val = np.ma.median(bg_ima) elif method == 'mode': kernel = gaussian_kde(bg_ima.data[~bg_ima.mask], bw_method='silverman') mode = bg_ima.mean() std = bg_ima.std() mode = minimize_scalar(lambda x: -kernel(x), bounds=(mode-3*std, mode+3*std), method='bounded') bg_val=mode.x[0] if False: median = np.ma.median(bg_ima) h, b = np.histogram(bg_ima.data[~bg_ima.mask], bins=15, normed=True) bc = 0.5*(b[1:]+ b[:-1]) plt.figure(33); plt.clf(); plt.ioff() fig, (ax0,ax1) = plt.subplots(ncols=2, nrows=1, num=33) ax0.plot(bc, h, 'x') x = np.linspace(bc.min(), bc.max(), 100) ax0.plot(x, kernel(x)) ax0.vlines(mode.x, ax0.get_ylim()[0], ax0.get_ylim()[1]) ax0.vlines(median, ax0.get_ylim()[0], ax0.get_ylim()[1]) ax1.imshow(bg_ima) plt.show() bg_values.append(bg_val) ap.add_column(Column(data=bg_values, name = 'background')) ap['Flux'] = ap['Flux'] - ap['aperture_area']*ap['background'] return ap, bg_ima
for image_name in files: image = fits.getdata(star+"/"+image_name, ext=0) data = image[x_1:x_2, y_1:y_2] image_head = fits.getheader(star+"/"+image_name, ext=0) 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[ref][0], peaks[ref][1]]) """ x, y = centroid_1dg(image[x_1:x_2, y_1:y_2]) #fits.writeto(image_name, image[x_1:x_2, y_1:y_2], overwrite=True)""" apertures = CircularAperture(positions, r=r) annulus = CircularAnnulus(positions, r_in=12., r_out= 15.) apers = [apertures, annulus] phot_table = aperture_photometry(data, apers, error=np.sqrt(abs(data))) bkg_mean = phot_table['aperture_sum_1']/annulus.area() bkg_mean_err = 1/annulus.area() * phot_table['aperture_sum_err_1'] flux = phot_table['aperture_sum_0'] - bkg_mean * apertures.area() flux_err = np.sqrt((phot_table['aperture_sum_err_0'])**2 + (apertures.area()*bkg_mean_err)**2) #number_of_counts = np.array(phot_table['aperture_sum']) # The number of counts of the star and the reference star in an cicular area around the star #ratio_noc = number_of_counts[0]/number_of_counts[1] ratio_flux = flux[0]/flux[1] ratio_flux_err = np.sqrt((flux_err[0]/flux[1])**2 + (flux[0]*flux_err[1]/flux[1]**2)**2) magnitude = -2.5*np.log10(ratio_flux) + mag_ref # Calculate the apparent magnitude magnitude_err = 2.5/(np.log(10)*ratio_flux) * ratio_flux_err date = image_head['Date-OBS'] time = datetime(int(date[:4]), int(date[5:7]), int(date[8:10]), int(date[11:13]), int(date[14:16]), int(date[17:19]), int(float(date[19:22])*10**6))
def find_target_phot(stack, fil, fwhm, zp, zp_err, pixscale, show_phot=False, log=None, log2=None, ra=None, dec=None, x=None, y=None): ''' Function to perform photometry on a target at a specific RA and Dec. Usually used after `find_zero_point` (this finds the ``zp``, ``zp_err``, and ``fwhm``). During this process, the user has the options to change the target's location and radii used in aperture photometry (if ``show_plots`` is ``True``, user can see cutouts of target and its radial profile). Attempts to find the magnitude of the target using aperture photometry. If magnitude cannot be found at a 3 sigma confidence interval, limiting magnitude is found at the same position. Limiting magnitude is found by adding fake sources of increasing magnitude at the target's position until it is more than 3 sigma above the background. :param stack: str Name of the stack to use (include path to the stack). :param fil: str Name of the filter of the stack. :param fwhm: float FWHM of image. :param zp: float Zero point of image in AB mag. :param zp_err: float Error on the zero point of image. :param show_phot: boolean, optional Option to see the cutout of the source with apertures along with its radial profile. Default is ``False``. :param log: log, optional In-depth log. If no log is inputted, information is printed out instead of being written to ``log``. Default is ``None``. :param log2: log, optional Overview log. If no log is inputted, information is printed out instead of being written to ``log2``. Default is ``None``. :param ra: float, optional RA coordinate of target. Default is ``None``. :param dec: float, optional Dec coordinate of target. Default is ``None``. :param x: float, optional X pixel coordinate (not RA). Default is ``None``. :param y: float, optional Y pixel coordiante (not Dec). Default is ``None``. Returns ------- :return: float, float Three options: * Returns the magnitude of the target (in AB) and its error. * Returns tne limiting magnitude at the target's location (in AB) and its error. * Returns ``None``, ``None`` if a fake source of amplitude 5 (adu / sec / pixel) is not three sigma above the background. ''' with fits.open(stack) as hdr: header, data = hdr[0].header, hdr[0].data w = wcs.WCS(header) # Parse the WCS keywords in the primary HDU if ra is not None: coords = np.array( [[ra, dec]], np.float) # Array of coordinates: [[RA, Dec]] in [deg, deg] pixel_coords = w.wcs_world2pix( coords, 1)[0] # Find the pixel coordinates in the image x = pixel_coords[0] y = pixel_coords[1] elif x is not None: x -= 1 y -= 1 coords = np.array( [[x, y]], np.float) # Array of coordinates: [[RA, Dec]] in [deg, deg] pixel_coords = w.wcs_pix2world( coords, 1)[0] # Find the pixel coordinates in the image ra = pixel_coords[0] dec = pixel_coords[1] else: print("No coordinates inputted") d_x_y = 125 # Pixels above and below the target when showing image...125 corresponds to a 50" x 50" cutout if log is not None: log.info("Pixel coordinates: (%.3f, %.3f)" % (x, y)) else: print("Pixel coordinates: (%.3f, %.3f)" % (x, y)) if input('Would you like to choose the cutout size? Default is 50"x50". ' ) == "yes": try: d_x_y = int(input("Choose the radius, in arcsec: ")) * 2.5 except TypeError: pass sigma_clip = SigmaClip( sigma=3) # This section is to find the error on the background bkg_estimator = MedianBackground() bkg = Background2D(data, (120, 120), filter_size=(3, 3), sigma_clip=sigma_clip, bkg_estimator=bkg_estimator) error = calc_total_error(data, bkg.background_rms, 1) # Used later as well for limiting magnitude if log is not None: log.info("You will now get to pick the position you would like. " "Decide what pixel coordinates you would like to use") log.info( "Blue circle in image is the distance the radial profile extends to" ) else: print("You will now get to pick the position you would like. " "Decide what pixel coordinates you would like to use") print( "Blue circle in image is the distance the radial profile extends to" ) correct_position = "no" while correct_position == "no": if show_phot: radial_profile(data, x, y, 0.2, fwhm, rad=6) # Radial profile plt.axvline(6 * fwhm) print( "Double click to set the new center. Do nothing if you are ok with current coordinates." ) fig = plt.figure(2) new_coords = [] fig.canvas.mpl_connect( 'button_press_event', lambda event: onclick(event, new_coords=new_coords)) ap_in = CircularAperture((x, y), 1) # Aperture to perform photometry ap_out = CircularAperture( (x, y), 6 * fwhm) # Aperture to perform photometry ap_in.plot(color='r', lw=1) # Plot of target with apertures and annulus ap_out.plot(color='b', lw=2) norm = simple_norm(data, 'sqrt', percent=99) plt.imshow(data, norm=norm) plt.xlim(int(x) - d_x_y, int(x) + d_x_y) plt.ylim(int(y) - d_x_y, int(y) + d_x_y) plt.colorbar() plt.show() if len(new_coords) != 0: x, y = new_coords[len(new_coords) - 2], new_coords[len(new_coords) - 1] real_coords = w.wcs_pix2world( np.array([[x, y]], np.float), 1)[0] # Find the pixel coords in the image ra, dec = real_coords[0], real_coords[1] radial_profile(data, x, y, 0.2, fwhm, rad=6) # Radial profile plt.axvline(6 * fwhm) print("Showing new position.") fig = plt.figure(2) ap_in = CircularAperture((x, y), 1) # Aperture to perform photometry ap_out = CircularAperture( (x, y), 6 * fwhm) # Aperture to perform photometry ap_in.plot(color='r', lw=1) # Plot of target with apertures and annulus ap_out.plot(color='b', lw=2) norm = simple_norm(data, 'sqrt', percent=99) plt.imshow(data, norm=norm) plt.xlim(int(x) - d_x_y, int(x) + d_x_y) plt.ylim(int(y) - d_x_y, int(y) + d_x_y) plt.colorbar() plt.show() if input("Would you like to use a centroid? Type 'yes' or 'no': " ) == "yes": d_x_y = 50 d = data[int(y) - d_x_y:int(y) + d_x_y, int(x) - d_x_y:int(x) + d_x_y] # Cutout of source; upside down from normal x_mesh, y_mesh = np.meshgrid( np.linspace(0, np.shape(d)[1] - 1, np.shape(d)[1]), np.linspace(0, np.shape(d)[0] - 1, np.shape(d)[0])) popt, pcov = curve_fit(twoD_Gaussian, (x_mesh, y_mesh), d.ravel(), p0=(np.max(d), 50, 50, fwhm / 2.35482, fwhm / 2.35482, 0, 0)) x += popt[1] - d_x_y y += popt[2] - d_x_y if log: log.info('Centroid calculated position: (%.3f, %.3f)' % (x, y)) else: print('Centroid calculated position: (%.3f, %.3f)' % (x, y)) real_coords = w.wcs_pix2world( np.array([[x, y]], np.float), 1)[0] # Find the pixel coords in the image ra, dec = real_coords[0], real_coords[1] radial_profile(data, x, y, 0.2, fwhm, rad=6) # Radial profile plt.axvline(6 * fwhm) print("Showing centroid position.") fig = plt.figure(2) ap_in = CircularAperture((x, y), 1) # Aperture to perform photometry ap_out = CircularAperture( (x, y), 6 * fwhm) # Aperture to perform photometry ap_in.plot(color='r', lw=1) # Plot of target with apertures and annulus ap_out.plot(color='b', lw=2) norm = simple_norm(data, 'sqrt', percent=99) plt.imshow(data, norm=norm) plt.xlim(int(x) - d_x_y, int(x) + d_x_y) plt.ylim(int(y) - d_x_y, int(y) + d_x_y) plt.colorbar() plt.show() if input("Are you ok with this position? Type 'yes' or 'no': " ) != "yes": pass else: correct_position = "yes" if log is not None: log.info( "Coordinates chosen: (%.3f, %.3f) at RA = %.5f and Dec = %.5f" % (x, y, ra, dec)) else: print( "Coordinates chosen: (%.3f, %.3f) at RA = %.5f and Dec = %.5f" % (x, y, ra, dec)) if log2 is not None: log2.info( "Final coordinates: (%.3f, %.3f) at RA = %.5f and Dec = %.5f" % (x, y, ra, dec)) print( "You will now get to choose the radii for the circular aperture and the r_in and r_out of the annulus" ) correct_radii = "no" while correct_radii == "no": if log is not None: log.info( "Automatic radii picked by comparing to FWHM of field: rad = %.3f, r_in = %.3f, r_out = %.3f" % (2.5 * fwhm, 2.5 * fwhm, 4.5 * fwhm)) else: print( "Automatic radii picked by comparing to FWHM of field: rad = %.3f, r_in = %.3f, r_out = %.3f" % (2.5 * fwhm, 2.5 * fwhm, 4.5 * fwhm)) if input("Would you like to use these radii? Type 'yes or 'no': " ) == "yes": rad, r_in, r_out = 2.5 * fwhm, 2.5 * fwhm, 4.5 * fwhm else: if log: log.info("FWHM = %.3f pixels" % fwhm) rad = float( input("Pick a radius (in pixels) for the circular aperture: ")) r_in = float( input( "Pick an inner radius (in pixels) for the background annulus: " )) r_out = float( input( "Pick an outer radius (in pixels) for the background annulus: " )) if r_in >= r_out: r_out = r_in + 1 if log is not None: log.info( "You selected an invalid r_out value. Automatically set to %s" % r_out) else: print( "You selected an invalid r_out value. Automatically set to %s" % r_out) aperture = CircularAperture((x, y), rad) # Aperture to perform photometry annulus_aperture = CircularAnnulus((x, y), r_in=r_in, r_out=r_out) # Annulus of target annulus_mask = annulus_aperture.to_mask( method='center') # Create masks to highlight pixels in annuli annulus_data = annulus_mask.multiply(data) annulus_data_1d = annulus_data[annulus_mask.data > 0] _, median_sigclip, stddev = sigma_clipped_stats(annulus_data_1d) phot_table = aperture_photometry( data, aperture, error=error) # Photometry, error accounted for bkg_aper = median_sigclip * aperture.area if show_phot: # Radial profile out to 6 * fwhm (large just to be safe) radial_profile(data, x, y, 0.2, fwhm, rad=6) plt.axvline(rad, c='r') plt.axvline(r_in) plt.axvline(r_out) plt.figure(2) aperture.plot(color='white', lw=2) # Plot of target with apertures and annulus annulus_aperture.plot(color='b', lw=2) norm = simple_norm(data, 'sqrt', percent=99) plt.imshow(data, norm=norm) plt.xlim(int(x) - d_x_y, int(x) + d_x_y) plt.ylim(int(y) - d_x_y, int(y) + d_x_y) plt.colorbar() plt.show() correct_radii = input( "Are you ok with the previously selected radii? Type 'yes' or 'no': " ) if log is not None: log.info("Radii chosen in pixels: %.3f, %.3f, %.3f" % (rad, r_in, r_out)) else: print("Radii chosen in pixels: %.3f, %.3f, %.3f" % (rad, r_in, r_out)) if log2 is not None: log2.info("Final radii: %.3f, %.3f, %.3f" % (rad, r_in, r_out)) three_sigma = 3 # Change according to what sigma you'd like to use if (phot_table['aperture_sum']) - bkg_aper > 0: mag = -2.5 * np.log10( (phot_table['aperture_sum']) - bkg_aper) # Instrumental magnitude mag_err = 2.5 / np.log(10.) * (phot_table['aperture_sum_err']) / ( phot_table['aperture_sum']) mag += zp # Apparent magnitude (Vega) mag_err = np.sqrt(mag_err**2 + zp_err**2) if log is not None: log.info("Magnitude of target = %.3f +/- %.3f AB mag" % (mag, mag_err)) # Final mag if log2 is not None: log2.info("Magnitude of target = %.3f +/- %.3f AB mag" % (mag, mag_err)) # Final mag else: print("Magnitude of target = %.3f +/- %.3f AB mag" % (mag, mag_err)) # Final magnitude if np.abs(mag_err ) < 1 / three_sigma: # Good! No limiting magnitude needed return float(mag), float(mag_err) if log is not None: log.info("Target was not %s sigma above the background." % three_sigma) else: print("Target was not %s sigma above the background." % three_sigma) if log2 is not None: log2.info("Target not found") else: if log is not None: log.info( "Target's aperture sum was less than background aperture sum. Target was not found" ) else: print( "Target's aperture sum was less than background aperture sum. Target was not found" ) if log2 is not None: log2.info("Target not found") # Finding the limiting magnitude in the area 30" around where the target is supposed to be located if log is not None: log.info("Now finding the limiting magnitude to %s sigma." % three_sigma) else: print("Now finding the limiting magnitude to %s sigma." % three_sigma) d_x_y = int(np.round(30 / pixscale, -1) / 2) d = data[int(y) - d_x_y:int(y) + d_x_y, int(x) - d_x_y:int(x) + d_x_y] # Cutout of source; upside down from normal d_error = error[int(y) - d_x_y:int(y) + d_x_y, int(x) - d_x_y:int(x) + d_x_y] x_mesh, y_mesh = np.meshgrid( np.linspace(0, np.shape(d)[1] - 1, np.shape(d)[1]), np.linspace(0, np.shape(d)[0] - 1, np.shape(d)[0])) source_mask = make_source_mask(d, nsigma=3, npixels=5) ind = np.ma.nonzero(~source_mask) inds = [(x, y) for x, y in zip(ind[0], ind[1]) if x > 2 * fwhm and y > 2 * fwhm and x < 2 * d_x_y - 2 * fwhm and y < 2 * d_x_y - 2 * fwhm] mag_list = [] mag_err_list = [] for i in range(50): xy_fake = random.choice(inds) gauss_data = twoD_Gaussian( (x_mesh, y_mesh), 3 * error[xy_fake[1], xy_fake[0]], xy_fake[0], xy_fake[1], fwhm / 2.35482, fwhm / 2.35482, 0, 0) d += gauss_data.reshape(np.shape(d)) aperture = CircularAperture((xy_fake[0], xy_fake[1]), 2.5 * fwhm) annulus_aperture = CircularAnnulus((xy_fake[0], xy_fake[1]), r_in=2.5 * fwhm, r_out=3.5 * fwhm) annulus_mask = annulus_aperture.to_mask(method='center') annulus_data = annulus_mask.multiply(d) annulus_data_1d = annulus_data[annulus_mask.data > 0] _, median_sigclip, stddev = sigma_clipped_stats(annulus_data_1d) phot_table = aperture_photometry(d, aperture, error=d_error) bkg_aper = median_sigclip * aperture.area if (phot_table['aperture_sum']) - bkg_aper > 0: mag = -2.5 * np.log10((phot_table['aperture_sum']) - bkg_aper) mag_err = 2.5 / np.log(10.) * (phot_table['aperture_sum_err']) / ( phot_table['aperture_sum']) mag_list.append(mag[0]) mag_err_list.append(mag_err[0]) d -= gauss_data.reshape(np.shape(d)) mag_list = [ mi for i, mi in enumerate(mag_list) if mag_err_list[i] > 0.2 and mag_err_list[i] < 0.5 ] mag_err_list = [ mi for i, mi in enumerate(mag_err_list) if mag_err_list[i] > 0.2 and mag_err_list[i] < 0.5 ] mag_list = [x for _, x in sorted(zip(mag_err_list, mag_list))] mag_err_list = sorted(mag_err_list) limit3 = np.interp(0.333, mag_err_list, mag_list) + zp if log is not None: log.info("Limiting magnitude = %.3f +/- %.3f AB mag" % (limit3, 0.333)) else: print("Limiting magnitude = %.3f +/- %.3f AB mag" % (limit3, 0.333)) return float(limit3), float(0.333)
def STAR_FLUX(coord_table, OBJ, f, numb=[1, 2, 3], rad_aperture=10, standart=False,\ main_obj=False, apert=False, PSF=False, PLOT_data=False, flux_10_m=None, err_flux_10_m=None): file = f'./data/2020-08-19/{OBJ}/{OBJ}-1MHz-76mcs-PreampX4-000' + '{}' + f'{f}.fit' file_0 = file.format(numb[0]) hdu_0 = fits.open(file_0) data, head = hdu_0[0].data.astype(np.float32), hdu_0[0].header for i in numb[1:]: data += fits.open(file.format(i))[0].data.astype(np.float32) data = data / (3 * head['EXPTIME']) int_max = 0.9 * 2**16 / (head['EXPTIME']) data_clear, backgr_mean = bkg(data, SNR=5, box_size=30, filter_size=10) good_coord = (coord_table['X']>=0)&(coord_table['X']<len(data))&\ (coord_table['Y']>=0)&(coord_table['Y']<len(data)) for i, j, good, num in zip(coord_table['X'], coord_table['Y'], good_coord, range(len(coord_table))): if not good: continue cutout = Cutout2D(data, (i, j), (2 * rad_aperture + 1, 2 * rad_aperture + 1)).data # print(i, j) # plt.imshow(cutout) if np.max(cutout) > int_max: good_coord[num] = False if np.mean(np.sort(np.ravel(cutout)) [-2:]) < np.median(cutout) + 3 * np.std(cutout): good_coord[num] = False # plt.colorbar() # plt.show() # plt.close() if "good_star" not in coord_table.columns: coord_table.add_column(Column([True] * len(coord_table)), name="good_star") coord_table['good_star'] = good_coord coord_table['good_star'] = coord_table['good_star'] * good_coord if apert: FLUX = apert_photometry(data_clear, coord_table, rad_aperture=rad_aperture) if PSF: FLUX = PSF_photometry(data, coord_table, sigma_psf=rad_aperture) if PLOT_data: plt.figure(figsize=(13, 13)) plt.imshow(data, norm=LogNorm(), cmap='gray') apertures = CircularAperture(np.transpose((coord_table['X'], coord_table['Y'])),\ r=rad_aperture) apertures.plot(color='blue', lw=1., alpha=0.5) plt.colorbar() plt.show() if standart: filtr = [(coord_table[f] != -100) & (coord_table['good_star'])] col_name = f"FLUX_{f}" coord_table.add_column(Column([np.nan] * len(coord_table)), name=col_name) coord_table[col_name][filtr] = FLUX[filtr] coord_table.add_column(Column([np.nan] * len(coord_table)), name=f'10m_FLUX_{f}') coord_table[f'10m_FLUX_{f}'][ filtr] = coord_table[col_name][filtr] * 10**( (coord_table[f][filtr] - 10) / 2.5) if main_obj: col_name = f"FLUX_{f}" filtr = [coord_table['good_star']] coord_table.add_column(Column([np.nan] * len(coord_table)), name=col_name) coord_table.add_column(Column([np.nan] * len(coord_table)), name=f'MAG_{f}') coord_table.add_column(Column([np.nan] * len(coord_table)), name=f'E_MAG_{f}') coord_table[col_name][filtr] = FLUX coord_table[f'MAG_{f}'][filtr] = 10 - 2.5 * np.log10( coord_table[col_name][filtr] / flux_10_m[f]) coord_table[f'E_MAG_{f}'][filtr] = -2.5 * np.log10( 1 - err_flux_10_m[f] / flux_10_m[f]) return coord_table
DAOfound = DAOfind(img) if len(DAOfound)==0 : print ('No star was founded using DAOStarFinder\n'*3) else : # Use the object "found" for aperture photometry: print (len(DAOfound), 'stars were founded') #print('DAOfound \n', DAOfound) DAOfound.pprint(max_width=1800) # save XY coordinates: DAOfound.write(f_name[:-4]+'_DAOStarFinder.csv', overwrite=True, format='ascii.fast_csv') DAOcoord = (DAOfound['xcentroid'], DAOfound['ycentroid']) DAOannul = CircAn(positions=DAOcoord, r_in=4*FWHM, r_out=6*FWHM) # Save apertures as circular, 4 pixel radius, at each (X, Y) DAOapert = CircAp(DAOcoord, r=4.) #print('DAOapert\n ', DAOapert) DAOimgXY = np.array(DAOcoord) #print('DAOimgXY \n', DAOimgXY) plt.figure(figsize=(16,12)) ax = plt.gca() im = plt.imshow(img, vmax=0.35, origin='lower') DAOannul.plot(color='red', lw=2., alpha=0.7) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="3%", pad=0.05) plt.colorbar(im, cax=cax) plt.savefig(f_name[:-4]+'_Annulus.png', overwrite=True) plt.show()
for i in range(0, len(collection)): # 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] #calculating galaxy-wide #set up two-dimensional arrays for the a and b coefficients based on the luminosity and color #this will be in the same format ish as the table in Josh's blue notebook Ba = [-1.019, -1.113, -1.026, -.990, -1.110, -.994, -.888] Bb = [1.937, 2.065, 1.954, 1.883, 2.018, 1.804, 1.758] B_coeff = [Ba, Bb] Va = [-.759, -.853, -.766, -.730, -.850, -.734, -.628]
def symmetric_circular_aperture_photom(scidata, starts, inverted, jpeg='', plot=False, sat_adu = 16383): ''' Method to use for june2017 firmware TODO unfinished, still very experimental ''' logger = logging.getLogger() positions, radii, thetas = aperture_centers(starts) #===Asymmetric has error map and a co-ord shift for R & B bands(halving)===# #error_map = get_error_map(scidata) # get median pixel value inside the fireball bounding box median_bckgnd = np.median(get_bounding_box(scidata, starts)) #logger.debug(median_bckgnd) if plot: plt.close() fig = plt.gcf() ax = fig.gca() plt.imshow(jpeg, cmap=plt.cm.gray) #=======In asymmetric, exp_time = nan and aperture_saturated = False=======# starts['aperture_sum'] = np.nan starts['bckgng_sub_measurements'] = np.nan starts['SNR'] = np.nan starts['signal'] = np.nan starts['exp_time'] = 0.01 starts['aperture_sum_err'] = np.nan starts['aperture_sum_err_plus'] = np.nan starts['aperture_sum_err_minus'] = np.nan starts['aperture_saturated'] = np.nan #===============In asymmetric, shutter open time is calced=================# for el, pos, radius, theta in zip(starts, positions, radii, thetas): zero_order_light = scidata[int(pos[1])][int(pos[0])] if zero_order_light >= sat_adu: el['aperture_saturated'] = True else: el['aperture_saturated'] = False #============Below and above commentout swap for asymmetric============# #zero_order_saturation_level = float(zero_order_light)/sat_adu #=============Switched to RectangularAperture in asymmetric============# aperture = CircularAperture(pos, radius*2) #===In asymmetric, saturation levels assessed here, and mask applied===# # do photometry aperture_result = aperture_photometry(scidata, aperture) ## get saturated pixels once photutils 0.4 is available TODO FIXME el['aperture_sum'] = aperture_result['aperture_sum'].data #el['aperture_sum_err'] = aperture_result['aperture_sum_err'].data TODO FIXME # calculating SNR and error, should bckgng by bckgnd? el['bckgng_sub_measurements'] = el['aperture_sum'] - aperture.area()*median_bckgnd el['SNR'] = el['bckgng_sub_measurements'] / np.sqrt(el['bckgng_sub_measurements'] + aperture.area()*median_bckgnd) el['aperture_sum_err_plus'] = 1/el['SNR'] el['aperture_sum_err_minus'] = 1/el['SNR'] if plot: aperture.plot(color='white') # plotting something, find out what?? if plot: #min_x, min_y, max_x, max_y = get_bounds([p['x_image'] for p in points], pos2) margin = 100 ax.set_xlim([np.min(starts['x_image'])-margin, np.max(starts['x_image'])+margin]) ax.set_ylim([np.min(starts['y_image'])-margin, np.max(starts['y_image'])+margin]) # saving figure to file full_path = starts.meta['self_file_name'] dirname = os.path.dirname(full_path) basename = os.path.basename(full_path).split('.')[0] fname = os.path.join(dirname, basename + "_aperture_photometry.jpg") #plt.show() plt.savefig(fname, dpi=150) return starts
setup_config() config = load_config() data_path = path.join(here, 'data', 'instrument') cache_path = config['DEFAULT']['data_cache_path'] # Photometric aperture contamation calculation from PSF for make_xml_files pfile = path.join(cache_path, 'Contamination_33arcsec_aperture.p') psf_path = path.join(data_path, config['psf_file']['psf_file']) if not path.isfile(pfile) or (path.getmtime(pfile) < path.getmtime(psf_path)): radius = 33 # Aperture radius in pixels psf_x0 = config['psf_file']['x0'] psf_y0 = config['psf_file']['y0'] with open(psf_path) as fp: data = [[float(digit) for digit in line.split()] for line in fp] position0 = [psf_x0, psf_y0] aperture0 = CircularAperture(position0, r=radius) photTable0 = aperture_photometry(data, aperture0) target_flux = photTable0['aperture_sum'][0] rad = np.linspace(0.0, 125, 25, endpoint=True) contam = np.zeros_like(rad) contam[0] = 1.0 for i, r in enumerate(rad[1:]): nthe = max(4, int(round(r / 5))) the = np.linspace(0, 2 * np.pi, nthe) pos = np.array((100 + np.array(r * np.cos(the)), 100 + np.array(r * np.sin(the)))).T apertures = CircularAperture(pos, r=radius) photTable = aperture_photometry(data, apertures) contam[i + 1] = max(photTable['aperture_sum']) / target_flux contam = np.array(contam) # convert to numpy array else sphinx complains I = interp1d(rad, contam, fill_value=min(contam), bounds_error=False)
def extract_ifu(input_model, source_type, extract_params): """This function does the extraction. Parameters ---------- input_model : IFUCubeModel The input model. source_type : string "point" or "extended" extract_params : dict The extraction parameters for aperture photometry. Returns ------- ra, dec : float ra and dec are the right ascension and declination respectively at the nominal center of the image. wavelength : ndarray, 1-D The wavelength in micrometers at each pixel. net : ndarray, 1-D The count rate (counts / s) minus the background at each pixel. background : ndarray, 1-D The background count rate that was subtracted from the total source count rate to get `net`. dq : ndarray, 1-D, int32 The data quality array. """ data = input_model.data shape = data.shape if len(shape) != 3: log.error("Expected a 3-D IFU cube; dimension is %d.", len(shape)) raise RuntimeError("The IFU cube should be 3-D.") # We need to allocate net, background, and dq arrays no matter what. net = np.zeros(shape[0], dtype=np.float64) background = np.zeros(shape[0], dtype=np.float64) dq = np.zeros(shape[0], dtype=np.int32) x_center = extract_params['x_center'] y_center = extract_params['y_center'] if x_center is None: x_center = float(shape[2]) / 2. else: x_center = float(x_center) if y_center is None: y_center = float(shape[1]) / 2. else: y_center = float(y_center) method = extract_params['method'] # subpixels is only needed if method = 'subpixel'. subpixels = extract_params['subpixels'] subtract_background = extract_params['subtract_background'] smaller_axis = float(min(shape[1], shape[2])) # for defaults if source_type == 'point': radius = extract_params['radius'] if radius is None: radius = smaller_axis / 4. if subtract_background: inner_bkg = extract_params['inner_bkg'] if inner_bkg is None: inner_bkg = radius outer_bkg = extract_params['outer_bkg'] if outer_bkg is None: outer_bkg = min(inner_bkg * math.sqrt(2.), smaller_axis / 2. - 1.) if inner_bkg <= 0. or outer_bkg <= 0. or inner_bkg >= outer_bkg: log.debug("Turning background subtraction off, due to " "the values of inner_bkg and outer_bkg.") subtract_background = False width = None height = None theta = None else: width = extract_params['width'] if width is None: width = smaller_axis / 2. height = extract_params['height'] if height is None: height = smaller_axis / 2. theta = extract_params['theta'] * math.pi / 180. radius = None subtract_background = False inner_bkg = None outer_bkg = None log.debug("IFU 1-D extraction parameters:") log.debug(" x_center = %s", str(x_center)) log.debug(" y_center = %s", str(y_center)) if source_type == 'point': log.debug(" radius = %s", str(radius)) log.debug(" subtract_background = %s", str(subtract_background)) log.debug(" inner_bkg = %s", str(inner_bkg)) log.debug(" outer_bkg = %s", str(outer_bkg)) log.debug(" method = %s", method) if method == "subpixel": log.debug(" subpixels = %s", str(subpixels)) else: log.debug(" width = %s", str(width)) log.debug(" height = %s", str(height)) log.debug(" theta = %s degrees", str(extract_params['theta'])) log.debug(" subtract_background = %s", str(subtract_background)) log.debug(" method = %s", method) if method == "subpixel": log.debug(" subpixels = %s", str(subpixels)) # Check for out of bounds. # The problem with having the background aperture extend beyond the # image is that the normalization would not account for the resulting # decrease in the area of the annulus, so the background subtraction # would be systematically low. outside = False f_nx = float(shape[2]) f_ny = float(shape[1]) if x_center < 0. or x_center >= f_nx - 1. or \ y_center < 0. or y_center >= f_ny - 1.: outside = True log.error("Target location is outside the image.") if subtract_background and \ (x_center - outer_bkg < -0.5 or x_center + outer_bkg > f_nx - 0.5 or y_center - outer_bkg < -0.5 or y_center + outer_bkg > f_ny - 0.5): outside = True log.error("Background region extends outside the image.") if outside: (ra, dec) = (0., 0.) wavelength = np.zeros(shape[0], dtype=np.float64) dq[:] = dqflags.pixel['DO_NOT_USE'] return (ra, dec, wavelength, net, background, dq) # all bad if hasattr(input_model.meta, 'wcs'): wcs = input_model.meta.wcs else: log.warning("WCS function not found in input.") wcs = None if wcs is not None: x_array = np.empty(shape[0], dtype=np.float64) x_array.fill(float(shape[2]) / 2.) y_array = np.empty(shape[0], dtype=np.float64) y_array.fill(float(shape[1]) / 2.) z_array = np.arange(shape[0], dtype=np.float64) # for wavelengths ra, dec, wavelength = wcs(x_array, y_array, z_array) nelem = len(wavelength) ra = ra[nelem // 2] dec = dec[nelem // 2] else: (ra, dec) = (0., 0.) wavelength = np.arange(1, shape[0] + 1, dtype=np.float64) position = (x_center, y_center) if source_type == 'point': aperture = CircularAperture(position, r=radius) if subtract_background: annulus = CircularAnnulus(position, r_in=inner_bkg, r_out=outer_bkg) normalization = aperture.area() / annulus.area() else: aperture = RectangularAperture(position, width, height, theta) # No background is computed for an extended source. for k in range(shape[0]): phot_table = aperture_photometry(data[k, :, :], aperture, method=method, subpixels=subpixels) net[k] = float(phot_table['aperture_sum'][0]) if subtract_background: bkg_table = aperture_photometry(data[k, :, :], annulus, method=method, subpixels=subpixels) background[k] = float(bkg_table['aperture_sum'][0]) net[k] = net[k] - background[k] * normalization # Check for NaNs in the wavelength array, flag them in the dq array, # and truncate the arrays if NaNs are found at endpoints (unless the # entire array is NaN). nan_mask = np.isnan(wavelength) n_nan = nan_mask.sum(dtype=np.intp) if n_nan > 0: log.warning("%d NaNs in wavelength array.", n_nan) dq[nan_mask] = np.bitwise_or(dq[nan_mask], dqflags.pixel['DO_NOT_USE']) not_nan = np.logical_not(nan_mask) flag = np.where(not_nan) if len(flag[0]) > 0: n_trimmed = flag[0][0] + nelem - (flag[0][-1] + 1) if n_trimmed > 0: log.info("Output arrays have been trimmed by %d elements", n_trimmed) slc = slice(flag[0][0], flag[0][-1] + 1) wavelength = wavelength[slc] net = net[slc] background = background[slc] dq = dq[slc] else: dq |= dqflags.pixel['DO_NOT_USE'] return (ra, dec, wavelength, net, background, dq)
def init_centroids(first_image_path, master_flat, master_dark, target_centroid, max_number_stars=10, min_flux=0.2, plots=False): first_image = (fits.getdata(first_image_path) - master_dark) / master_flat # Clean cosmic rays mask, first_image = detect_cosmics(first_image) tophat_kernel = Tophat2DKernel(23) convolution = convolve_fft(first_image, tophat_kernel, fftn=fft2, ifftn=ifft2) convolution -= np.median(convolution) from astropy.stats import mad_std mad = mad_std(convolution) convolution[convolution < -5 * mad] = 0.0 from skimage.filters import threshold_otsu, threshold_yen from skimage.measure import label, regionprops thresh = threshold_yen(convolution) / 3.0 masked = np.ones_like(convolution) masked[convolution <= thresh] = 0 label_image = label(masked) # plt.figure() # plt.imshow(label_image, origin='lower', cmap=plt.cm.viridis) # plt.show() regions = regionprops(label_image, convolution) centroids = [region.weighted_centroid for region in regions] intensities = [region.mean_intensity for region in regions] centroids = np.array(centroids)[np.argsort(intensities)[::-1]] #positions = np.vstack([sources['xcentroid'], sources['ycentroid']]) # positions = np.array(centroids).T positions = np.vstack([[y for x, y in centroids], [x for x, y in centroids]]) if plots: apertures = CircularAperture(positions, r=12.) apertures.plot(color='r', lw=2, alpha=1) plt.imshow(first_image, vmin=np.percentile(first_image, 0.01), vmax=np.percentile(first_image, 99.9), cmap=plt.cm.viridis, origin='lower') plt.show() return positions
# 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) # positions_pix=aperture_pix.positions # r_pix=aperture_pix.r # print('r_pix =',r_pix) positions_pix = (ra_pix, dec_pix) positions_pix = np.transpose(positions_pix) aperture_pix = CircularAperture(positions_pix, r_circle) mask_circle = aperture_pix.to_mask(method='center') mask_data = mask_circle[0].multiply(imdata) # 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 phot_table['xcenter'].info.format = '%.8g' # for consistent table output
def draw_mask_map(image, seg_map, mask_deep, stars, r_core=None, r_out=None, vmin=None, vmax=None, pad=0, save=False, save_dir='./'): """ Visualize mask map """ from matplotlib import patches mu = np.nanmedian(image) std = mad_std(image) if vmin is None: vmin = mu - std if vmax is None: vmax = mu + 10 * std fig, (ax1, ax2, ax3) = plt.subplots(ncols=3, nrows=1, figsize=(20, 6), dpi=100) im1 = ax1.imshow(image, cmap='gray', norm=LogNorm(), vmin=vmin, vmax=1e4) ax1.set_title("Image") n_label = seg_map.max() ax2.imshow(seg_map, vmin=1, vmax=n_label - 2, cmap=make_rand_cmap(n_label)) ax2.set_title("Deep Mask") image2 = image.copy() image2[mask_deep] = 0 im3 = ax3.imshow(image2, norm=LogNorm(), vmin=vmin, vmax=vmax) ax3.set_title("Sky") colorbar(im3, pad=0.1, size="2%") if r_core is not None: if np.ndim(r_core) == 0: r_core = [r_core, r_core] star_pos_A = stars.star_pos_verybright + pad star_pos_B = stars.star_pos_medbright + pad aper = CircularAperture(star_pos_A, r=r_core[0]) aper.plot(color='lime', lw=2, label="", alpha=0.9, axes=ax3) aper = CircularAperture(star_pos_B, r=r_core[1]) aper.plot(color='c', lw=2, label="", alpha=0.7, axes=ax3) if r_out is not None: aper = CircularAperture(star_pos_A, r=r_out[0]) aper.plot(color='lime', lw=1.5, label="", alpha=0.9, axes=ax3) aper = CircularAperture(star_pos_B, r=r_out[1]) aper.plot(color='c', lw=1.5, label="", alpha=0.7, axes=ax3) patch_Xsize = image.shape[1] - pad * 2 patch_Ysize = image.shape[0] - pad * 2 rec = patches.Rectangle((pad, pad), patch_Xsize, patch_Ysize, facecolor='none', edgecolor='w', linewidth=2, linestyle='--', alpha=0.8) ax3.add_patch(rec) plt.tight_layout() if save: plt.savefig(os.path.join(save_dir, "Mask_dual.png"), dpi=100) plt.show() plt.close() else: plt.show()
file = glob.glob(dir + 'final_F8*sci.fits') hdu = fits.open(file[0]) data814, header814 = hdu[0].data, hdu[0].header # read in the F160W image file = glob.glob(dir + 'final_F1*sci.fits') hdu = fits.open(file[0]) data160, header160 = hdu[0].data, hdu[0].header # define positions for photometry positions = [(xcen, ycen)] # do photometry on F475W image flux475 = [0.] for radius in radii: aperture = CircularAperture(positions, radius) phot_table = aperture_photometry(data475, aperture) flux475.append(phot_table['aperture_sum'][0]) # do photometry on F814W image flux814 = [0.] for radius in radii: aperture = CircularAperture(positions, radius) phot_table = aperture_photometry(data814, aperture) flux814.append(phot_table['aperture_sum'][0]) # do photometry on F160W image flux160 = [0.] for radius in radii: aperture = CircularAperture(positions, radius) phot_table = aperture_photometry(data160, aperture)
hdulist = fits.open(inpath+file_name) image = hdulist[0].data #image = image.astype(float) - np.median(image) from photutils import daofind from astropy.stats import mad_std bkg_sigma = mad_std(image) sources = daofind(image, fwhm, threshold*bkg_sigma) #print_line= (file_name+","+str(sources_2)+"\n") sources_2 = np.array(sources["id", "xcentroid", "ycentroid", "sharpness", "roundness1", "roundness2", "npix", "sky", "peak", "flux", "mag"]) print_line= (file_name+","+str(sources_2)) file= open(outpath, "a") file.write(print_line) file.close() from photutils import aperture_photometry, CircularAperture positions = (sources['xcentroid'], sources['ycentroid']) apertures = CircularAperture(positions, r) phot_table = aperture_photometry(image, apertures) phot_table_2 = np.array(phot_table["aperture_sum", "xcenter", "ycenter"]) print_line= (","+str(phot_table_2)+"\n") file= open(outpath, "a") file.write(print_line) file.close() import matplotlib.pylab as plt im2 = image im2[im2<=0]=0.0001 plt.imshow(im2, cmap='gray', origin='lower') apertures.plot(color='blue', lw=1.5, alpha=0.5) plt.show()
groups = daogroup(intab, crit_separation=2.0*sigma_psf*gaussian_sigma_to_fwhm) plt.subplot(1, 2, 1) plt.imshow(image, origin='lower', interpolation='nearest') plt.title('Simulated data') plt.xlabel('x-position (pixel units)') plt.ylabel('y-position (pixel units)') plt.subplot(1, 2, 2) for i in range(len(groups)): for j in range(len(groups[i]['id'])): # show ids # plt.text(groups[i]['x_0'][j], groups[i]['y_0'][j], # str(groups[i]['id'][j])) aperture = CircularAperture((groups[i]['x_0'][j], groups[i]['y_0'][j]), r=sigma_psf*gaussian_sigma_to_fwhm) aperture.plot(lw=1.5, alpha=0.5) tab, residual_image = nstar(image-bkg, groups, (5,5), fitting.LevMarLSQFitter(), IntegratedGaussianPRF, sigma=2.0) tab.sort('id') tab.write('starlist_estimated.html') plt.imshow(residual_image, origin='lower', interpolation='nearest') plt.title('Residual') plt.xlabel('x-position (pixel units)') plt.ylabel('y-position (pixel units)') plt.show()
def init_centroids(first_image_path, master_flat, master_dark, target_centroid, max_number_stars=10, min_flux=0.2, plots=False): first_image = (fits.getdata(first_image_path) - master_dark) / master_flat kernel = Gaussian2DKernel(5, 5) convolution = convolve_fft(first_image, kernel, fftn=fft2, ifftn=ifft2) convolution -= np.median(convolution) mad = mad_std(convolution) convolution[convolution < -5 * mad] = 0.0 from skimage.filters import threshold_otsu, threshold_yen from skimage.measure import label, regionprops thresh = threshold_yen(convolution) / 4 # thresh = threshold_otsu(image=convolution) # Use 10 for 20171104, 15 for all other nights masked = np.ones_like(convolution) masked[convolution <= thresh] = 0 label_image = label(masked) plt.figure() plt.imshow(label_image, origin='lower', cmap=plt.cm.viridis) plt.show() regions = regionprops(label_image, convolution) # reject regions near to edge of detector buffer_pixels = 5 regions = [ region for region in regions if ((region.weighted_centroid[0] > buffer_pixels and region. weighted_centroid[0] < label_image.shape[0] - buffer_pixels) and ( region.weighted_centroid[1] > buffer_pixels and region. weighted_centroid[1] < label_image.shape[1] - buffer_pixels)) ] # TYC 3561-1538-1 is a delta Scuti variable. Remove it: # variable_star = [1790.1645248, 1153.91737674] # tol = 100 # regions = [region for region in regions # if ((region.weighted_centroid[0] > variable_star[0] + tol) or # (region.weighted_centroid[0] < variable_star[0] - tol)) and # ((region.weighted_centroid[1] > variable_star[1] + tol) or # (region.weighted_centroid[1] < variable_star[1] - tol))] centroids = np.array([region.weighted_centroid for region in regions]) intensities = np.array([region.mean_intensity for region in regions]) sort_order = np.argsort(intensities)[::-1] centroids = np.array(centroids)[sort_order] intensities = intensities[sort_order] positions = np.vstack([[y for x, y in centroids], [x for x, y in centroids]]) flux_threshold = intensities > min_flux * intensities[0] positions = positions[:, flux_threshold] if plots: apertures = CircularAperture(positions, r=12.) apertures.plot(color='r', lw=2, alpha=1) plt.imshow(first_image, vmin=np.percentile(first_image, 0.01), vmax=np.percentile(first_image, 99.9), cmap=plt.cm.viridis, origin='lower') plt.show() return positions
def init_centroids(first_image_path, master_flat, master_dark, target_centroid, max_number_stars=10, min_flux=0.2, plots=False): first_image = np.median([(fits.getdata(path) - master_dark)/master_flat for path in first_image_path], axis=0) tophat_kernel = Tophat2DKernel(5) convolution = convolve_fft(first_image, tophat_kernel, fftn=fft2, ifftn=ifft2) convolution -= np.median(convolution) mad = mad_std(convolution) convolution[convolution < -5*mad] = 0.0 from skimage.filters import threshold_yen from skimage.measure import label, regionprops thresh = threshold_yen(convolution)/4 # Use /4 for planet c, /2 for planet b #thresh = threshold_otsu(convolution)/15 masked = np.ones_like(convolution) masked[convolution <= thresh] = 0 label_image = label(masked) plt.figure() plt.imshow(label_image, origin='lower', cmap=plt.cm.viridis) plt.show() # regions = regionprops(label_image, convolution) regions = regionprops(label_image, first_image) # reject regions near to edge of detector buffer_pixels = 50 regions = [region for region in regions if ((region.weighted_centroid[0] > buffer_pixels and region.weighted_centroid[0] < label_image.shape[0] - buffer_pixels) and (region.weighted_centroid[1] > buffer_pixels and region.weighted_centroid[1] < label_image.shape[1] - buffer_pixels))] #centroids = [region.weighted_centroid for region in regions] #intensities = [region.mean_intensity for region in regions] target_intensity = regions[0].mean_intensity target_diameter = regions[0].equivalent_diameter # and region.equivalent_diameter > 0.8 * target_diameter centroids = [region.weighted_centroid for region in regions if min_flux * target_intensity < region.mean_intensity] # intensities = [region.mean_intensity for region in regions # if min_flux * target_intensity < region.mean_intensity] # centroids = np.array(centroids)[np.argsort(intensities)[::-1]] distances = [np.sqrt((target_centroid[0] - d[0])**2 + (target_centroid[1] - d[1])**2) for d in centroids] centroids = np.array(centroids)[np.argsort(distances)] positions = np.vstack([[y for x, y in centroids], [x for x, y in centroids]]) if plots: apertures = CircularAperture(positions, r=12.) apertures.plot(color='r', lw=2, alpha=1) plt.imshow(first_image, vmin=np.percentile(first_image, 0.01), vmax=np.percentile(first_image, 99.9), cmap=plt.cm.viridis, origin='lower') plt.scatter(positions[0, 0], positions[1, 0], s=150, marker='x') plt.show() return positions
def test_mrs_spec3(): """ Test the extract1d step when reducing MRS data in spec3 """ import tkinter as tk # TKinter imported for a dialog box for choosing the file from tkinter import filedialog # TKinter also seems to be needed for matplotlib plots root = tk.Tk() root.withdraw() #read in cube from cube_build step that immediately precedes extract_1d step in Level 3 cubefile = "/Users/sargent/mirisim/20180813_123620_mirisim/det_images/nod4point_ch1-short_s3d.fits" with fits.open(cubefile) as hduin: # open the cube file firstpart = cubefile[ 0:len(cubefile) - 5] #a string with the part of the file path except the .fits extension tempfilepath = firstpart + '_temp.fits' # file name for temporary file fake_data = hduin['SCI'].data # read in cube print(fake_data.shape) fake_data[0:, 0:, 0:] = 0.0 # zero out all the pixels in the cube fake_data[ 0:, 10, 10] = 100.0 # add in a fake point source continuum in the zeroed-out cube fake_data[0:, 10, 9] = 50.0 # same fake_data[0:, 9, 10] = 50.0 # same fake_data[0:, 11, 10] = 50.0 # same fake_data[0:, 10, 11] = 50.0 # same fake_data[ 399, 10, 10] = 150.0 # add in fake point source emission line in zeroed-out cube fake_data[399, 10, 9] = 75.0 # same fake_data[399, 9, 10] = 75.0 # same fake_data[399, 11, 10] = 75.0 # same fake_data[399, 10, 11] = 75.0 # same fake_data[400, 10, 10] = 200.0 # same fake_data[400, 10, 9] = 100.0 # same fake_data[400, 9, 10] = 100.0 # same fake_data[400, 11, 10] = 100.0 # same fake_data[400, 10, 11] = 100.0 # same fake_data[401, 10, 10] = 150.0 # same fake_data[401, 10, 9] = 75.0 # same fake_data[401, 9, 10] = 75.0 # same fake_data[401, 11, 10] = 75.0 # same fake_data[401, 10, 11] = 75.0 # same hduin.writeto( tempfilepath, overwrite=True) # save the file with the fake signal in the cube apphotflux = np.zeros(fake_data.shape[0]) for j in range( fake_data.shape[0] ): # go through each slice of zeroed-out cube with fake signal position = [(10, 10)] aperture = CircularAperture( position, r=3.) # perform aperture photometry on slice on fake signal phot_table = aperture_photometry(fake_data[j, :, :], aperture) apphotflux[j] = phot_table['aperture_sum'] import matplotlib.pyplot as plt # this is needed to make plots #run the extract1d step result = Extract1dStep.call( tempfilepath, config_file= "/Users/sargent/func/inst/nirspec/pipelinetesting/maria/configs72/extract_1d_mrs3.cfg" ) # perform extract_1d step on cube with fake signal outextractfile = '/Users/sargent/mirisim/20180813_123620_mirisim/det_images/extract1dmrs3out.fits' result.save(outextractfile) # save the result of the extract1d step with fits.open(outextractfile) as hdubackin: wl1d = hdubackin['EXTRACT1D'].data[ 'wavelength'] # read spectrum from extract1d step fl1d = hdubackin['EXTRACT1D'].data['flux'] er1d = hdubackin['EXTRACT1D'].data['error'] plt.plot(wl1d, fl1d, '.', color='r', markersize=4) # plot spectrum from extract1d step plt.plot(wl1d, apphotflux, '.', color='b', markersize=1) #overplot spectrum extracted plt.xlabel('wavelength (microns)' ) # by doing aperture photometry on cube slices plt.ylabel('flux (Jy)') plt.title('Spectrum from Extract1d') plt.show() # show the spectrum relerror = ( fl1d - apphotflux) / apphotflux # compute relative difference spectrum maxrelerr = max( relerror) # compute the maximum of the relative difference spectrum print("Maximum Relative Error for MRS Slit Level 3") print(maxrelerr) plt.plot(wl1d, relerror, '-', color='r') # plot the relative difference spectrum plt.xlabel('wavelength (microns)') plt.ylabel('relative error (fraction)') plt.title('Relative Error for MRS Slit Level 3') plt.show()
def photom_av(ima, pos, radius, r_in=False, r_out=False, mode='median'): ''' Aperture photometry in an aperture located at pixel coordinates pos = ( (x0, y0), (x1, y1), ... ) with a radius=radius. When r_in and r_out are given, background is estimated in CircularAnnulus and subtracted. mode refers to how the background is estimated within the circlar annulus. Can be 'median' or 'mean' Photometry is calculating by median averaging the pixels within the aperture and multiplying by the number of pixels in the aperture (including fractions of pixels). ''' # Setting up the mask if hasattr(ima, 'mask'): if ima.mask.size == 1: mask = np.zeros(ima.shape, dtype=np.bool) | ima.mask else: mask = ima.mask.copy() else: mask = np.zeros(ima.shape, dtype=np.bool) ### Performing the actual photometry - identical for each method # Median averaging of flux in aperture # Setting up the aperture apertures = CircularAperture(pos, r = radius) ap_mask = apertures.to_mask(method='center') # Setting up arrays to store data nflx = len(ap_mask) flx = np.zeros(nflx, dtype=np.float) flux_max = np.zeros(nflx, dtype=np.float) flux_min = np.zeros(nflx, dtype=np.float) # Median averaging of flux for i, am in enumerate(ap_mask): fluxmask = ~mask & am.to_image(shape=mask.shape).astype(np.bool) flx[i] = np.median(ima[fluxmask]) flux_max[i] = np.max(ima[fluxmask]) flux_min[i] = np.min(ima[fluxmask]) # Aperture photometry on mask to see how many masked pixels are in the # aperture apm = aperture_photometry(mask.astype(int), apertures) # Number of unmasked pixels in aperture ap_area = Column(name = 'area_aper', data=apertures.area() - apm['aperture_sum'].data) # Flux in aperture using median av flux and fractional no. pixels in aperture flux_init = flx*ap_area ### Two different modes for analysing the background if ( r_in and r_out and mode in ('mean', 'median') ): ### This stuff is the same regardless of method # Setting up the annulus anulus_apertures = CircularAnnulus(pos, r_in=r_in, r_out=r_out) # Performing annulus photometry on the mask bkgm = aperture_photometry(mask.astype(int), anulus_apertures) # Number of masked pixels in bkg mbkg_area = Column(name = 'bpix_bkg', data=bkgm['aperture_sum']) # Number of non-masked pixels in aperture and bkg bkg_area = Column(name = 'area_bkg', data=anulus_apertures.area() - bkgm['aperture_sum']) ### This stuff is specific to the mean if mode == 'mean': # Perform the annulus photometry on the image bkg = aperture_photometry(ima, anulus_apertures, mask=mask) # Average bkg where this divides by only number of NONMASKED pixels # as the aperture photometry ignores the masked pixels bkga = Column(name='background', data=bkg['aperture_sum']/bkg_area) # Bkg subtracted flux flux = flux_init - bkga*ap_area # Adding that data ap.add_column(bkga) elif mode == 'median': # Number of pixels in the annulus, a different method aperture_mask = anulus_apertures.to_mask(method='center') nbkg = len(aperture_mask) # Background mask bkgm = np.zeros(nbkg, dtype=np.float) # Median averaging for i, am in enumerate(aperture_mask): bmask = ~mask & am.to_image(shape=mask.shape).astype(np.bool) bkgm[i] = np.median(ima[bmask]) flux = flux_init - bkgm*ap_area bkgm = Column(name = 'background', data = bkgm) return flux, apm, flx, ap_area, flux_max, flux_min #flux, no.masked pixels in ap, median av flux
def draw_comparison_2D(data, mask, image_fit, image_stars, bkg_image, noise_image=0, r_core=None, vmin=None, vmax=None, Gain=None, cmap='gnuplot2', norm=AsinhNorm(0.05), manual_locations=None, save=False, save_dir=".", suffix=""): """ Compare data and fit in 2D """ mask_fit = getattr(mask, 'mask_comb', mask.mask_deep) std = np.std(image_fit[~mask_fit]) if vmin is None: vmin = np.mean(bkg_image) - std if vmax is None: vmax = vmin + min([10 * std, 100]) norm2 = deepcopy(norm) fig, ((ax1, ax2, ax3), (ax4, ax5, ax6)) = plt.subplots(2, 3, figsize=(19, 11)) im = ax1.imshow(data, vmin=vmin, vmax=vmax, norm=norm, cmap=cmap) ax1.set_title("Data [I$_0$]", fontsize=15) colorbar(im) im = ax2.imshow(image_fit + noise_image, vmin=vmin, vmax=vmax, norm=norm, cmap=cmap) ax2.set_title("Fit [I$_f$] + noise", fontsize=15) colorbar(im) im = ax3.imshow(image_stars, vmin=0, vmax=vmax - vmin, norm=norm2, cmap=cmap) contour = ax3.contour(image_stars, levels=[0, 1, 2, 5, 10, 25], norm=norm2, colors='w', alpha=0.7) ax3.clabel(contour, fmt='%1g', inline=1, fontsize=12, manual=manual_locations) ax3.set_title("Bright Stars [I$_{f,B}$]", fontsize=15) colorbar(im) if Gain is None: frac_diff = (image_fit - data) / data im = ax4.imshow(frac_diff, vmin=-0.1, vmax=0.1, cmap="bwr") ax4.set_title("Frac. Diff. [(I$_f$ - I$_0$)/I$_0$]", fontsize=15) colorbar(im) else: uncertainty = np.sqrt( np.std(noise_image)**2 + (image_fit - bkg_image) / Gain) chi = (image_fit - data) / uncertainty # chi[mask_fit] = 0 im = ax4.imshow(chi, vmin=-5, vmax=5, cmap="coolwarm") ax4.set_title("$\chi$ [(I$_f$ - I$_0$)/$\sigma$]", fontsize=15) colorbar(im) residual = (data - image_stars) im = ax5.imshow(residual, vmin=vmin, vmax=vmax, norm=norm, cmap=cmap) ax5.set_title("Bright Subtracted [I$_0$ - I$_{f,B}$]", fontsize=15) colorbar(im) residual[mask_fit] = 0 im = ax6.imshow(residual, vmin=vmin, vmax=vmax, norm=norm, cmap=cmap) ax6.set_title("Bright Subtracted (masked)", fontsize=15) colorbar(im) if r_core is not None: if np.ndim(r_core) == 0: r_core = [r_core, r_core] aper1 = CircularAperture(mask.stars.star_pos_verybright, r=r_core[0]) aper1.plot(color='lime', lw=2, alpha=0.95, axes=ax6) aper2 = CircularAperture(mask.stars.star_pos_medbright, r=r_core[1]) aper2.plot(color='skyblue', lw=2, label="", alpha=0.85, axes=ax6) plt.tight_layout() if save: plt.savefig(os.path.join(save_dir, "Comparison_fit_data2D%s.png" % suffix), dpi=100) plt.show() plt.close() else: plt.show()
def runPhotUtils(targname, filt, jdanUse=None, saveDir='./'): if filt == 'F606W': # EEband = 0.839 # 4 pixel EEband = 0.795 ZPT = 26.667 fils = '_f606w/' elif filt == 'F814W': # EEband = 0.830 # 4 pixels EEband = 0.77 ZPT = 26.779 fils = '_f814w/' for ff in range(len(jdanUse)): image = targname + fils + '/crClean/' + jdanUse[ff] + '_WJ2.fits' hdu = fits.open(image) sci = hdu[0].data hdr = hdu[0].header hdu.close() outname = saveDir + jdanUse[ff] + '_' + filt + 'photU.dat' # print(type(saveDir)) # print(type(jdanUse[ff])) # print(type(filt)) data = sci.copy() mean, median, std = sigma_clipped_stats(data, sigma=3.0, maxiters=10) daofind = DAOStarFinder(fwhm=2.5, threshold=5. * std) sources = daofind(data - median) loc = np.array([sources['xcentroid'], sources['ycentroid']]) positions = np.transpose(loc) apertures_r3 = CircularAperture(positions, r=3.) rawflux_r3 = aperture_photometry(data, apertures_r3) annulus_apertures = CircularAnnulus(positions, r_in=9., r_out=12.) annulus_masks = annulus_apertures.to_mask(method='center') bkg_median = [] for mask in annulus_masks: annulus_data = mask.multiply(data) annulus_data_1d = annulus_data[mask.data > 0] _, median_sigclip, _ = sigma_clipped_stats(annulus_data_1d) bkg_median.append(median_sigclip) bkg_median = np.array(bkg_median) rawflux_r3['annulus_median'] = bkg_median rawflux_r3['aper_bkg'] = bkg_median * apertures_r3.area rawflux_r3['final_phot'] = rawflux_r3['aperture_sum'] \ - rawflux_r3['aper_bkg'] mask_negative = (rawflux_r3['final_phot'] > 0) rawflux_pos_r3 = rawflux_r3[mask_negative] final_phot = -2.5 * np.log10(rawflux_pos_r3['final_phot'] / EEband) \ + 2.5 * np.log10(hdr['exptime']) + ZPT rawflux_pos_r3['magr'] = final_phot rawflux_pos_r3['id'] = np.arange(0, len(rawflux_pos_r3), 1) s0 = ' ' header = s0.join(rawflux_pos_r3.dtype.names) outname = saveDir + jdanUse[ff] + '_' + filt + 'photU.dat' np.savetxt(outname, rawflux_pos_r3, header=header) return None
def tso_aperture_photometry(datamodel, xcenter, ycenter, radius, radius_inner, radius_outer): """ Create a photometric catalog for NIRCam TSO imaging observations. Parameters ---------- datamodel : `CubeModel` The input `CubeModel` of a NIRCam TSO imaging observation. xcenter, ycenter : float The ``x`` and ``y`` center of the aperture. radius : float The radius (in pixels) of the circular aperture. radius_inner, radius_outer : float The inner and outer radii (in pixels) of the circular-annulus aperture, used for local background estimation. Returns ------- catalog : `~astropy.table.QTable` An astropy QTable (Quantity Table) containing the source photometry. """ if not isinstance(datamodel, CubeModel): raise ValueError('The input data model must be a CubeModel.') # For the SUB64P subarray with the WLP8 pupil, the circular aperture # extends beyond the image and the circular annulus does not have any # overlap with the image. In that case, we simply sum all values # in the array and skip the background subtraction. sub64p_wlp8 = False if (datamodel.meta.instrument.pupil == 'WLP8' and datamodel.meta.subarray.name == 'SUB64P'): sub64p_wlp8 = True if not sub64p_wlp8: phot_aper = CircularAperture((xcenter, ycenter), r=radius) bkg_aper = CircularAnnulus((xcenter, ycenter), r_in=radius_inner, r_out=radius_outer) aperture_sum = [] aperture_sum_err = [] annulus_sum = [] annulus_sum_err = [] nimg = datamodel.data.shape[0] if sub64p_wlp8: info = ('Photometry measured as the sum of all values in the ' 'subarray. No background subtraction was performed.') for i in np.arange(nimg): aperture_sum.append(np.sum(datamodel.data[i, :, :])) aperture_sum_err.append( np.sqrt(np.sum(datamodel.err[i, :, :]**2))) else: info = ('Photometry measured in a circular aperture of r={0} ' 'pixels. Background calculated as the mean in a ' 'circular annulus with r_inner={1} pixels and ' 'r_outer={2} pixels.'.format(radius, radius_inner, radius_outer)) for i in np.arange(nimg): aper_sum, aper_sum_err = phot_aper.do_photometry( datamodel.data[i, :, :], error=datamodel.err[i, :, :]) ann_sum, ann_sum_err = bkg_aper.do_photometry( datamodel.data[i, :, :], error=datamodel.err[i, :, :]) aperture_sum.append(aper_sum[0]) aperture_sum_err.append(aper_sum_err[0]) annulus_sum.append(ann_sum[0]) annulus_sum_err.append(ann_sum_err[0]) aperture_sum = np.array(aperture_sum) aperture_sum_err = np.array(aperture_sum_err) annulus_sum = np.array(annulus_sum) annulus_sum_err = np.array(annulus_sum_err) # construct metadata for output table meta = OrderedDict() meta['instrument'] = datamodel.meta.instrument.name meta['detector'] = datamodel.meta.instrument.detector meta['channel'] = datamodel.meta.instrument.channel meta['subarray'] = datamodel.meta.subarray.name meta['filter'] = datamodel.meta.instrument.filter meta['pupil'] = datamodel.meta.instrument.pupil meta['target_name'] = datamodel.meta.target.catalog_name meta['xcenter'] = xcenter meta['ycenter'] = ycenter ra_icrs, dec_icrs = datamodel.meta.wcs(xcenter, ycenter) meta['ra_icrs'] = ra_icrs meta['dec_icrs'] = dec_icrs meta['apertures'] = info # initialize the output table tbl = QTable(meta=meta) if hasattr(datamodel, 'int_times') and datamodel.int_times is not None: nrows = len(datamodel.int_times) else: nrows = 0 if nrows == 0: log.warning("There is no INT_TIMES table in the input file.") if nrows > 0: shape = datamodel.data.shape if len(shape) == 2: num_integ = 1 else: # len(shape) == 3 num_integ = shape[0] int_start = datamodel.meta.exposure.integration_start if int_start is None: int_start = 1 log.warning("INTSTART not found; assuming a value of %d", int_start) # Columns of integration numbers & times of integration from the # INT_TIMES table. int_num = datamodel.int_times['integration_number'] mid_utc = datamodel.int_times['int_mid_MJD_UTC'] offset = int_start - int_num[0] # both are one-indexed if offset < 0: log.warning("Range of integration numbers in science data extends " "outside the range in INT_TIMES table.") log.warning("Can't use INT_TIMES table.") del int_num, mid_utc nrows = 0 # flag as bad else: log.debug("Times are from the INT_TIMES table.") time_arr = mid_utc[offset: offset + num_integ] int_times = Time(time_arr, format='mjd', scale='utc') else: log.debug("Times were computed from EXPSTART and TGROUP.") dt = (datamodel.meta.exposure.group_time * (datamodel.meta.exposure.ngroups + 1)) dt_arr = (np.arange(1, 1 + datamodel.meta.exposure.nints) * dt - (dt / 2.)) int_dt = TimeDelta(dt_arr, format='sec') int_times = (Time(datamodel.meta.exposure.start_time, format='mjd') + int_dt) tbl['MJD'] = int_times.mjd tbl['aperture_sum'] = aperture_sum tbl['aperture_sum_err'] = aperture_sum_err if not sub64p_wlp8: tbl['annulus_sum'] = annulus_sum tbl['annulus_sum_err'] = annulus_sum_err annulus_mean = annulus_sum / bkg_aper.area() annulus_mean_err = annulus_sum_err / bkg_aper.area() tbl['annulus_mean'] = annulus_mean tbl['annulus_mean_err'] = annulus_mean_err aperture_bkg = annulus_mean * phot_aper.area() aperture_bkg_err = annulus_mean_err * phot_aper.area() tbl['aperture_bkg'] = aperture_bkg tbl['aperture_bkg_err'] = aperture_bkg_err net_aperture_sum = aperture_sum - aperture_bkg net_aperture_sum_err = np.sqrt(aperture_sum_err ** 2 + aperture_bkg_err ** 2) tbl['net_aperture_sum'] = net_aperture_sum tbl['net_aperture_sum_err'] = net_aperture_sum_err else: colnames = ['annulus_sum', 'annulus_sum_err', 'annulus_mean', 'annulus_mean_err', 'aperture_bkg', 'aperture_bkg_err'] for col in colnames: tbl[col] = np.full(nimg, np.nan) tbl['net_aperture_sum'] = aperture_sum tbl['net_aperture_sum_err'] = aperture_sum_err return tbl
kern = np.ones((growarray,growarray)) pommap2040=ndimage.convolve(pommap2040, kern, mode='constant', cval=0.0) pommap2040[np.where(pommap2040>1.0)]=1.0 #Merge the GR150C and GR150R images and shift if necessary when placing within the full detector if k==0: pommap[4+yoff:2044+yoff,4+xoff:2044+xoff]=pommap2040 pomintens[4:2044,4:2044]=grismminusmeasuredata[k]*pommap[4:2044,4:2044] else: pommap[4+yoff:2044+yoff,4+xoff:2044+xoff]=np.maximum(pommap[4+yoff:2044+yoff,4+xoff:2044+xoff],pommap2040) pomintens[4:2044,4:2044]=np.maximum(pomintens[4:2044,4:2044],(grismminusmeasuredata[k]*pommap[4:2044,4:2044])) #Set constant high value in central regions of coronagraphic spots as too noisy to measure in flats #Iterate over the four spots for k in range(4): coroaperture = CircularAperture(corocen[k,:], r=corodarkradius[k]) coro_obj_mask = coroaperture.to_mask(method='center') coro_obj_mask_corr=2.0*coro_obj_mask.data pomintens[corocenfloor[k,1]-corodarkradius[k]:corocenfloor[k,1]+corodarkradius[k]+1,corocenfloor[k,0]-corodarkradius[k]:corocenfloor[k,0]+corodarkradius[k]+1]+=coro_obj_mask_corr #Replace pixels with intensity>0.98 to 1.00 as even though centres of spots in CV3 had values of a few percent this was probably scattered w=np.where(pomintens>0.98) pomintens[w]=1.00 #Interpolate across bad pixels if at least 3 out of 4 corner neighbours are in POM mask pomintensfixbadpix=deepcopy(pomintens) for j in range(numbadpix): y=donotuseindices[0][j] x=donotuseindices[1][j] #Do not include reference pixels if y>3 and y<2044 and x>3 and x<2044:
def circle(pos, r): return CircularAperture(pos, r)
objects = sep.extract( A_rN_img, thresh=2.5, clean=True, mask=elip_mask_gal + star_mask, deblend_nthresh=8, minarea=5, deblend_cont=0.0005, ) peak_filter = np.where(objects["peak"] < 30) x_sep = objects["x"][peak_filter] y_sep = objects["y"][peak_filter] positions = [(x, y) for x, y in zip(x_sep, y_sep)] apertures = CircularAperture(positions, r=4) plt.figure(figsize=(16, 16)) plt.imshow(A_rN_img, origin="lower", cmap="CMRmap", vmin=1, vmax=8.) apertures.plot(color="green") # Add on the eliptical and star masks ax = plt.gca() elip_gal = Ellipse((xe, ye), width, length, angle=alpha * (180 / np.pi), fill=False, color="white") ax.add_artist(elip_gal) for star in galaxy_info["star_mask"]: ax.add_artist(
def limiting_magnitude_prob(syntax, image, model=None, r_table=None): ''' syntax - dict dDtionary of input paramters image - np.array Image of region of interest with target in center of image model - function - psf function from autophot ''' try: from photutils import CircularAperture import matplotlib.pyplot as plt import numpy as np import matplotlib.gridspec as gridspec import random from scipy.optimize import curve_fit import warnings from photutils.datasets import make_noise_image # from autophot.packages.functions import mag from photutils import DAOStarFinder from astropy.stats import sigma_clipped_stats # from matplotlib.ticker import MultipleLocator from mpl_toolkits.axes_grid1 import make_axes_locatable from autophot.packages.rm_bkg import rm_bkg from astropy.visualization import ZScaleInterval import logging logger = logging.getLogger(__name__) limiting_mag_figure = plt.figure(figsize=set_size(240, aspect=1.5)) gs = gridspec.GridSpec(2, 2, hspace=0.5, wspace=0.2) ax0 = limiting_mag_figure.add_subplot(gs[:, :-1]) ax1 = limiting_mag_figure.add_subplot(gs[-1, -1]) ax2 = limiting_mag_figure.add_subplot(gs[:-1, -1]) # level for detection - Rule of thumb ~ 5 is a good detection level level = syntax['lim_SNR'] logger.info('Limiting threshold: %d sigma' % level) image_no_surface, surface = rm_bkg(image, syntax, image.shape[0] / 2, image.shape[0] / 2) # ============================================================================= # find and mask sources in close up # ============================================================================= image_mean, image_median, image_std = sigma_clipped_stats( image, sigma=syntax['source_sigma_close_up'], maxiters=syntax['iters']) daofind = DAOStarFinder(fwhm=syntax['fwhm'], threshold=syntax['bkg_level'] * image_std) with warnings.catch_warnings(): warnings.simplefilter("ignore") # ignore no sources warning sources = daofind(image - image_median) if sources != None: positions = list( zip(np.array(sources['xcentroid']), np.array(sources['ycentroid']))) positions.append((image.shape[0] / 2, image.shape[1] / 2)) else: positions = [(image.shape[0] / 2, image.shape[1] / 2)] # "size" of source source_size = syntax['image_radius'] pixel_number = int(np.ceil(np.pi * source_size**2)) # Mask out target region mask_ap = CircularAperture(positions, r=source_size) mask = mask_ap.to_mask(method='center') mask_sumed = [i.to_image(image.shape) for i in mask] if len(mask_sumed) != 1: mask_sumed = sum(mask_sumed) else: mask_sumed = mask_sumed[0] mask_sumed[mask_sumed > 0] = 1 logging.info('Number of pixels in star: %d' % pixel_number) # Mask out center region mask_image = (image_no_surface) * (1 - mask_sumed) vmin, vmax = (ZScaleInterval(nsamples=1500)).get_limits(mask_image) excluded_points = mask_image == 0 exclud_x = excluded_points[0] exclud_y = excluded_points[1] exclud_zip = list(zip(exclud_x, exclud_y)) included_points = np.where(mask_image != 0) includ_x = list(included_points[0]) includ_y = list(included_points[1]) includ_zip = list(zip(includ_x, includ_y)) # ax2.scatter(exclud_y,exclud_x,color ='black',marker = 'X',alpha = 0.5 ,label = 'excluded_pixels',zorder = 1) ax2.scatter(includ_y, includ_x, color='red', marker='x', alpha=0.5, label='included_pixels', zorder=2) number_of_points = 300 fake_points = {} if len(includ_zip) < pixel_number: includ_zip = includ_zip + exclud_zip for i in range(number_of_points): fake_points[i] = [] # count = 0 random_pixels = random.sample(includ_zip, pixel_number) xp_ran = [i[0] for i in random_pixels] yp_ran = [i[1] for i in random_pixels] fake_points[i].append([xp_ran, yp_ran]) fake_sum = {} for i in range(number_of_points): fake_sum[i] = [] for j in fake_points[i]: for k in range(len(j[0])): fake_sum[i].append(image_no_surface[j[0][k]][j[1][k]]) fake_mags = {} for f in fake_sum.keys(): fake_mags[f] = np.sum(fake_sum[f]) # ============================================================================= # Histogram # ============================================================================= hist, bins = np.histogram(list(fake_mags.values()), bins=len(list(fake_mags.values())), density=True) center = (bins[:-1] + bins[1:]) / 2 sigma_guess = np.nanstd(list(fake_mags.values())) mean_guess = np.nanmean(list(fake_mags.values())) A_guess = np.nanmax(hist) def gauss(x, a, x0, sigma): return a * np.exp(-(x - x0)**2 / (2 * sigma**2)) popt, pcov = curve_fit(gauss, center, hist, p0=[A_guess, mean_guess, sigma_guess], absolute_sigma=True) mean = popt[1] std = abs(popt[2]) logging.info('Mean: %s - std: %s' % (round(mean, 3), round(std, 3))) if syntax['probable_detection_limit']: beta = float(syntax['probable_detection_limit_beta']) def detection_probability(n, sigma, beta): from scipy.special import erfinv ''' Probabilistic upper limit computation base on: http://web.ipac.caltech.edu/staff/fmasci/home/mystats/UpperLimits_FM2011.pdf Assuming Gassauin nose distribution n: commonly used threshold value integer above some background level sigma: sigma value from noise distribution found from local area around source beta: Detection probability ''' flux_upper_limit = (n + np.sqrt(2) * erfinv(2 * beta - 1)) * sigma return flux_upper_limit logging.info("Using Probable detection limit [b' = %d%% ]" % (100 * beta)) f_ul = mean + detection_probability(level, std, beta) logging.info("Flux Upper limit: %.3f" % f_ul) else: f_ul = abs(mean + level * std) logging.info('Detection at %s std: %.3f' % (level, f_ul)) # ============================================================================= # Plot histogram of background values # ============================================================================= line_kwargs = dict(alpha=0.5, color='black', ls='--') # the histogram of the data n, bins, patches = ax0.hist(list(fake_mags.values()), density=True, bins=30, facecolor='blue', alpha=1, label='Pseudo-Flux\nDistribution') ax0.axvline(mean, **line_kwargs) ax0.axvline(mean + 1 * std, **line_kwargs) ax0.text(mean + 1 * std, np.max(n), r'$1\sigma$', rotation=-90, va='top') ax0.axvline(mean + 2 * std, **line_kwargs) ax0.text(mean + 2 * std, np.max(n), r'$2\sigma$', rotation=-90, va='top') if syntax['probable_detection_limit']: ax0.axvline(f_ul, **line_kwargs) ax0.text(f_ul, np.max(n), r"$\beta'$ = %d%%" % (100 * beta), rotation=-90, va='top') else: ax0.axvline(f_ul, **line_kwargs) ax0.text(mean + level * std, np.max(n), r'$' + str(level) + r'\sigma$', rotation=-90, va='top') x_fit = np.linspace(ax0.get_xlim()[0], ax0.get_xlim()[1], 250) ax0.plot(x_fit, gauss(x_fit, *popt), label='Gaussian Fit', color='red') ax0.ticklabel_format(axis='y', style='sci', scilimits=(-2, 0)) ax0.yaxis.major.formatter._useMathText = True ax0.set_xlabel('Pseudo-Flux') ax0.set_ylabel('Normalised Probability') im2 = ax2.imshow(image - surface, origin='lower', aspect='auto', interpolation='nearest') divider = make_axes_locatable(ax2) cax = divider.append_axes("right", size="5%", pad=0.05) cb = limiting_mag_figure.colorbar(im2, cax=cax) cb.ax.set_ylabel('Counts', rotation=270, labelpad=10) cb.formatter.set_powerlimits((0, 0)) cb.ax.yaxis.set_offset_position('left') cb.update_ticks() ax2.set_title('Image - Surface') # ============================================================================= # Convert counts to magnitudes # ============================================================================= flux = f_ul / syntax['exp_time'] mag_level = -2.5 * np.log10(flux) # ============================================================================= # We now have an upper and lower estimate of the the limiting magnitude # ============================================================================= ''' Visual display of limiting case if PSF model is available use that else use a gaussian profile with the same number of counts ''' fake_sources = np.zeros(image.shape) try: if syntax['c_counts']: pass model_label = 'PSF' def mag2image(m): ''' Convert magnitude to height of PSF ''' Amplitude = (syntax['exp_time'] / (syntax['c_counts'] + syntax['r_counts'])) * ( 10**(m / -2.5)) return Amplitude # PSF model that matches close-up shape around target def input_model(x, y, flux): return model(x, y, 0, flux, r_table, pad_shape=image.shape) except: ''' if PSF model isn't available - use Gaussian instead ''' logging.info('PSF model not available - Using Gaussian') model_label = 'Gaussian' sigma = syntax['fwhm'] / 2 * np.sqrt(2 * np.log(2)) def mag2image(m): ''' Convert magnitude to height of Gaussian ''' # Volumne/counts under 2d gaussian for a magnitude m volume = (10**(m / -2.5)) * syntax['exp_time'] # https://en.wikipedia.org/wiki/Gaussian_function Amplitude = volume / (2 * np.pi * sigma**2) return Amplitude # Set up grid def input_model(x, y, A): x = np.arange(0, image.shape[0]) xx, yy = np.meshgrid(x, x) from autophot.packages.functions import gauss_2d, moffat_2d if syntax['use_moffat']: model = moffat_2d( (xx, yy), x, y, 0, A, syntax['image_params']).reshape(image.shape) else: model = gauss_2d( (xx, yy), x, y, 0, A, syntax['image_params']).reshape(image.shape) return model # ============================================================================= # What magnitude do you want this target to be? # ============================================================================= mag2image = mag2image inject_source_mag = mag2image(mag_level) # ============================================================================= # Random well-spaced points to plot # ============================================================================= random_sources = sample_with_minimum_distance( n=[int(syntax['fwhm']), int(image.shape[0] - syntax['fwhm'])], k=syntax['inject_sources_random_number'], d=int(syntax['fwhm'] / 2)) import math def PointsInCircum(r, n=100): return [(math.cos(2 * math.pi / n * x) * r + image.shape[1] / 2, math.sin(2 * math.pi / n * x) * r + image.shape[0] / 2) for x in range(0, n)] random_sources = PointsInCircum(2 * syntax['fwhm'], n=3) x = [abs(i[0]) for i in random_sources] y = [abs(i[1]) for i in random_sources] print(x) print(y) # ============================================================================= # Inject sources # ============================================================================= try: if syntax['inject_source_random']: for i in range(0, len(x)): fake_source_i = input_model(x[i], y[i], inject_source_mag) if syntax['inject_source_add_noise']: nan_idx = np.isnan(fake_source_i) fake_source_i[nan_idx] = 0 fake_source_i[fake_source_i < 0] = 0 fake_source_i = make_noise_image( fake_source_i.shape, distribution='poisson', mean=fake_source_i, random_state=np.random.randint(0, 1e3)) # fake_source_i[nan_idx] = np.nan1 fake_sources += fake_source_i ax1.scatter(x[i], y[i], marker='o', s=150, facecolors='none', edgecolors='r', alpha=0.5) ax1.annotate(str(i), (x[i], -.5 + y[i]), color='r', alpha=0.5, ha='center') if syntax['inject_source_on_target']: fake_source_on_target = input_model(image.shape[1] / 2, image.shape[0] / 2, inject_source_mag) if syntax['inject_source_add_noise']: nan_idx = np.isnan(fake_source_on_target) fake_source_on_target[nan_idx] = 1e-6 fake_source_on_target[fake_source_on_target < 0] = 0 fake_source_on_target = make_noise_image( fake_source_on_target.shape, distribution='poisson', mean=fake_source_on_target, random_state=np.random.randint(0, 1e3)) fake_sources += fake_source_on_target ax1.scatter(image.shape[1] / 2, image.shape[0] / 2, marker='o', s=150, facecolors='none', edgecolors='black', alpha=0.5) ax1.annotate('On\nTarget', (image.shape[1] / 2, -1 + image.shape[0] / 2), color='black', alpha=0.5, ha='center') im1 = ax1.imshow( image - surface + fake_sources, # vmin = vmin, # vmax = vmax, aspect='auto', # norm = norm, origin='lower', interpolation='nearest') ax1.set_title(' Fake [%s] Sources ' % model_label) except Exception as e: logging.exception(e) im1 = ax1.imshow( image - surface, origin='lower', aspect='auto', ) ax1.set_title('[ERROR] Fake Sources [%s]' % model_label) # plt.colorbar(im1,ax=ax1) divider = make_axes_locatable(ax1) cax = divider.append_axes("right", size="5%", pad=0.05) cb = limiting_mag_figure.colorbar(im1, cax=cax) cb.ax.set_ylabel('Counts', rotation=270, labelpad=10) # cb = fig.colorbar(im) cb.formatter.set_powerlimits((0, 0)) cb.ax.yaxis.set_offset_position('left') cb.update_ticks() ax0.legend(loc='lower center', bbox_to_anchor=(0.5, 1.02), ncol=2, frameon=False) limiting_mag_figure.savefig( syntax['write_dir'] + 'limiting_mag_porb.pdf', # box_extra_artists=([l]), bbox_inches='tight', format='pdf') plt.close('all') # master try/except except Exception as e: print('limit issue') logging.exception(e) syntax['maglim_mean'] = mean syntax['maglim_std'] = std return mag_level, syntax
data = fits.getdata(cubename, ext=1) t = Table.read(cubename) t['FILTER'].tolist() idx = t['FILTER'].tolist().index('R') rband = data[idx, :, :] #Creating Aperture Objects positions = np.array([0.5 * rband.shape[0], 0.5 * rband.shape[1]]) radii = np.linspace(1, rband.shape[0] / 2., 30) # apertures = [CircularAperture(positions, r=r) for r in radii] apertures = [] plt.subplot(1, 2, 1) vmin = np.percentile(rband, 10) vmax = np.percentile(rband, 95) plt.imshow(rband, vmin=vmin, vmax=vmax) for r in radii: aperture = CircularAperture(positions, r=r) apertures.append(aperture) aperture.plot(color='r', lw=1) plt.subplot(1, 2, 2) # Colocar código para máscara aqui ### ### mask = np.zeros_like(rband) # Performing Aperture Photometry phot_table = aperture_photometry(rband, apertures, mask=mask) # Lendo os valores da table phot = [float(phot_table["aperture_sum_{}".format(i)]) for i in range(30)] table = Table([radii, phot], names=["r", "photsum"]) table.write("photometry_R.fits", overwrite=True) plt.plot(radii, phot, "o") plt.savefig('CUBE_FOTOMETRIA_R.png')
#plt.subplot(4,4,13) plt.subplot(427) plt.imshow(np.log(stamp11)) vari_funcs.no_ticks() plt.title('11B') #plt.subplot(4,4,15) plt.subplot(428) plt.imshow(np.log(stamp12)) vari_funcs.no_ticks() plt.title('12B') plt.savefig(str(obnum) + 'PSFs.png') ### Run aperture phot to see if flux curve is the same ### centre = [29, 29] pixelr = (1.5 / 3600) / const aperture = CircularAperture(centre, pixelr) aper05 = aperture_photometry(stamp05, aperture) aper06 = aperture_photometry(stamp06, aperture) aper07 = aperture_photometry(stamp07, aperture) aper08 = aperture_photometry(stamp08, aperture) aper09 = aperture_photometry(stamp09, aperture) aper10 = aperture_photometry(stamp10, aperture) aper11 = aperture_photometry(stamp11, aperture) aper12 = aperture_photometry(stamp12, aperture) aperflux = np.array([ aper05['aperture_sum'][0], aper06['aperture_sum'][0], aper07['aperture_sum'][0], aper08['aperture_sum'][0], aper09['aperture_sum'][0], aper10['aperture_sum'][0], aper11['aperture_sum'][0], aper12['aperture_sum'][0] ]) plt.figure(1)
for xStar, yStar in zip(xStars, yStars): lf, rt = xStar - 10, xStar + 10 bt, tp = yStar - 10, yStar + 10 patch = stokesI.arr[lf:rt, bt:tp] saturatedStars.append(np.sum(np.logical_or(patch > 9e3, patch < -100)) > 1) # Check for stars near the edge of the image ny, nx = stokesI.arr.shape edgeStars = np.logical_or( np.logical_or(xStars < 40, xStars > (nx - 40)), np.logical_or(yStars < 40, yStars > (ny - 40))) # Now let's do aperture photometry on the remaining sources in the image # 1. Setup the apertures sourcePos = [xStars, yStars] apertures = CircularAperture(sourcePos, r = 6.0) annulus_apertures = CircularAnnulus(sourcePos, r_in=12., r_out=14.) # 2. Perform the basic photometry rawflux_table = aperture_photometry(stokesI.arr, apertures) bkgflux_table = aperture_photometry(stokesI.arr, annulus_apertures) phot_table = hstack([rawflux_table, bkgflux_table], table_names=['raw', 'bkg']) # 3. Compute background contribution and subtract from raw photometry bkg_mean = phot_table['aperture_sum_bkg'] / annulus_apertures.area() bkg_sum = bkg_mean * apertures.area() final_sum = phot_table['aperture_sum_raw'] - bkg_sum phot_table['residual_aperture_sum'] = final_sum # Compute the signal-to-noise ratio and find the stars with SNR < 3.0 SNR = final_sum/bkg_sum bkgDominated = SNR < 1.0
def photometry_on_directory(directory_with_images, object_of_interest, star_locs, aperture_rad, inner_annulus, outer_annulus, max_adu, star_ids, gain, read_noise, dark_current): """ Perform aperture photometry on a directory of images. Parameters ---------- directory_with_images : str Folder containing the images on which to do photometry. Photometry will only be done on images that contain the ``object_of_interest``. object_of_interest : str Name of the object of interest. The only files on which photometry will be done are those whose header contains the keyword ``OBJECT`` whose value is ``object_of_interest``. star_locs : tuple of numpy array The first entry in the tuple should be the right ascension of the sources, in degrees. The second should be the declination of the sources, in degrees. aperture_rad : int Radius of the aperture to use when performing photometry. inner_annulus : int Inner radius of annulus to use in for performing local sky subtraction. outer_annulus : int Outer radius of annulus to use in for performing local sky subtraction. max_adu : int Maximum allowed pixel value before a source is considered saturated. star_ids : array-like Unique identifier for each source in ``star_locs``. gain : float Gain, in electrons/ADU, of the camera that took the image. The gain is used in calculating the instrumental magnitude. read_noise : float Read noise of the camera in electrons. Used in the CCD equation to calculate error. dark_current : float Dark current, in electron/sec. Used in the CCD equation to calculate error. """ ifc = ImageFileCollection(directory_with_images) phots = [] missing_stars = [] for a_ccd, fname in ifc.ccds(object=object_of_interest, return_fname=True): print('on image ', fname) try: # Convert RA/Dec to pixel coordinates for this image pix_coords = a_ccd.wcs.all_world2pix(star_locs[0], star_locs[1], 0) except AttributeError: print(' ....SKIPPING THIS IMAGE, NO WCS') continue xs, ys = pix_coords # Remove anything that is too close to the edges/out of frame padding = 3 * aperture_rad out_of_bounds = ((xs < padding) | (xs > (a_ccd.shape[1] - padding)) | (ys < padding) | (ys > (a_ccd.shape[0] - padding))) in_bounds = ~out_of_bounds # Find centroids of each region around star that is in_bounds xs_in = xs[in_bounds] ys_in = ys[in_bounds] print(' ...finding centroids') try: xcen, ycen = centroid_sources(a_ccd.data, xs_in, ys_in, box_size=2 * aperture_rad + 1) except NoOverlapError: print(' ....SKIPPING THIS IMAGE, CENTROID FAILED') continue # Calculate offset between centroid in this image and the positions # based on input RA/Dec. Later we will set the magnitude of those with # large differences to an invalid value (maybe). center_diff = np.sqrt((xs_in - xcen)**2 + (ys_in - ycen)**2) # Set up apertures and annuli based on the centroids in this image. aps = CircularAperture((xcen, ycen), r=aperture_rad) anuls = CircularAnnulus((xcen, ycen), inner_annulus, outer_annulus) # Set any clearly bad values to NaN a_ccd.data[a_ccd.data > max_adu] = np.nan print(' ...doing photometry') # Do the photometry... pho = aperture_photometry(a_ccd.data, (aps, anuls), mask=a_ccd.mask, method='center') # We may have some stars we did not do photometry for because # those stars were out of bounds. # Add the ones we missed to the list of missing missed = star_ids[out_of_bounds] missing_stars.append(missed) # Add all the extra goodies to the table print(' ...adding extra columns') add_to_photometry_table(pho, a_ccd, anuls, aps, fname=fname, star_ids=star_ids[in_bounds], gain=1.47) # And add the final table to the list of tables phots.append(pho) # ### Combine all of the individual photometry tables into one all_phot = vstack(phots) # ### Eliminate any stars that are missing from one or more images # # This makes life a little easier later... uniques = set() for miss in missing_stars: uniques.update(set(miss)) actually_bad = sorted([u for u in uniques if u in all_phot['star_id']]) len(uniques), len(actually_bad) all_phot.add_index('star_id') if actually_bad: bad_rows = all_phot.loc_indices[actually_bad] try: bad_rows = list(bad_rows) except TypeError: bad_rows = [bad_rows] all_phot.remove_indices('star_id') all_phot.remove_rows(sorted(bad_rows)) all_phot.remove_indices('star_id') snr = (gain * all_phot['aperture_net_flux'] / np.sqrt(gain * all_phot['aperture_net_flux'].value + all_phot['aperture_area'] * (1 + all_phot['aperture_area'] / all_phot['annulus_area']) * (gain * all_phot['sky_per_pix_avg'].value + gain * dark_current * all_phot['exposure'].value + read_noise**2 ) )) all_phot['mag_error'] = 1.085736205 / snr return all_phot
def extract_ifu(input_model, source_type, extract_params): """This function does the extraction. Parameters ---------- input_model : IFUCubeModel The input model. source_type : string "point" or "extended" extract_params : dict The extraction parameters for aperture photometry. Returns ------- ra, dec : float ra and dec are the right ascension and declination respectively at the nominal center of the image. wavelength : ndarray, 1-D The wavelength in micrometers at each pixel. net : ndarray, 1-D The count rate (or flux) minus the background at each pixel. background : ndarray, 1-D The background count rate that was subtracted from the total source count rate to get `net`. npixels : ndarray, 1-D, float64 For each slice, this is the number of pixels that were added together to get `net`. dq : ndarray, 1-D, uint32 The data quality array. """ data = input_model.data shape = data.shape if len(shape) != 3: log.error("Expected a 3-D IFU cube; dimension is %d.", len(shape)) raise RuntimeError("The IFU cube should be 3-D.") # We need to allocate net, background, npixels, and dq arrays # no matter what. We may need to divide by npixels, so the default # is 1 rather than 0. net = np.zeros(shape[0], dtype=np.float64) background = np.zeros(shape[0], dtype=np.float64) npixels = np.ones(shape[0], dtype=np.float64) dq = np.zeros(shape[0], dtype=np.uint32) x_center = extract_params['x_center'] y_center = extract_params['y_center'] if x_center is None: x_center = float(shape[2]) / 2. else: x_center = float(x_center) if y_center is None: y_center = float(shape[1]) / 2. else: y_center = float(y_center) method = extract_params['method'] # subpixels is only needed if method = 'subpixel'. subpixels = extract_params['subpixels'] subtract_background = extract_params['subtract_background'] smaller_axis = float(min(shape[1], shape[2])) # for defaults radius = None inner_bkg = None outer_bkg = None if source_type == 'point': radius = extract_params['radius'] if radius is None: radius = smaller_axis / 4. if subtract_background: inner_bkg = extract_params['inner_bkg'] if inner_bkg is None: inner_bkg = radius outer_bkg = extract_params['outer_bkg'] if outer_bkg is None: outer_bkg = min(inner_bkg * math.sqrt(2.), smaller_axis / 2. - 1.) if inner_bkg <= 0. or outer_bkg <= 0. or inner_bkg >= outer_bkg: log.debug("Turning background subtraction off, due to " "the values of inner_bkg and outer_bkg.") subtract_background = False width = None height = None theta = None else: width = extract_params['width'] if width is None: width = smaller_axis / 2. height = extract_params['height'] if height is None: height = smaller_axis / 2. theta = extract_params['theta'] * math.pi / 180. subtract_background = False log.debug("IFU 1-D extraction parameters:") log.debug(" x_center = %s", str(x_center)) log.debug(" y_center = %s", str(y_center)) if source_type == 'point': log.debug(" radius = %s", str(radius)) log.debug(" subtract_background = %s", str(subtract_background)) log.debug(" inner_bkg = %s", str(inner_bkg)) log.debug(" outer_bkg = %s", str(outer_bkg)) log.debug(" method = %s", method) if method == "subpixel": log.debug(" subpixels = %s", str(subpixels)) else: log.debug(" width = %s", str(width)) log.debug(" height = %s", str(height)) log.debug(" theta = %s degrees", str(extract_params['theta'])) log.debug(" subtract_background = %s", str(subtract_background)) log.debug(" method = %s", method) if method == "subpixel": log.debug(" subpixels = %s", str(subpixels)) # Check for out of bounds. # The problem with having the background aperture extend beyond the # image is that the normalization would not account for the resulting # decrease in the area of the annulus, so the background subtraction # would be systematically low. outside = False f_nx = float(shape[2]) f_ny = float(shape[1]) if x_center < 0. or x_center >= f_nx - 1. or \ y_center < 0. or y_center >= f_ny - 1.: outside = True log.error("Target location is outside the image.") if subtract_background and \ (x_center - outer_bkg < -0.5 or x_center + outer_bkg > f_nx - 0.5 or y_center - outer_bkg < -0.5 or y_center + outer_bkg > f_ny - 0.5): outside = True log.error("Background region extends outside the image.") if outside: (ra, dec) = (0., 0.) wavelength = np.zeros(shape[0], dtype=np.float64) dq[:] = dqflags.pixel['DO_NOT_USE'] return (ra, dec, wavelength, net, background, npixels, dq) # all bad x0 = float(shape[2]) / 2. y0 = float(shape[1]) / 2. (ra, dec, wavelength) = get_coordinates(input_model, x0, y0) position = (x_center, y_center) if source_type == 'point': aperture = CircularAperture(position, r=radius) if subtract_background: annulus = CircularAnnulus(position, r_in=inner_bkg, r_out=outer_bkg) normalization = aperture.area() / annulus.area() else: aperture = RectangularAperture(position, width, height, theta) # No background is computed for an extended source. npixels[:] = aperture.area() for k in range(shape[0]): phot_table = aperture_photometry(data[k, :, :], aperture, method=method, subpixels=subpixels) net[k] = float(phot_table['aperture_sum'][0]) if subtract_background: bkg_table = aperture_photometry(data[k, :, :], annulus, method=method, subpixels=subpixels) background[k] = float(bkg_table['aperture_sum'][0]) net[k] = net[k] - background[k] * normalization # Check for NaNs in the wavelength array, flag them in the dq array, # and truncate the arrays if NaNs are found at endpoints (unless the # entire array is NaN). (wavelength, net, background, npixels, dq) = \ nans_in_wavelength(wavelength, net, background, npixels, dq) return (ra, dec, wavelength, net, background, npixels, dq)
def photutils_stellar_photometry(ccd_image, sources, aperture_radius, inner_annulus, outer_annulus, gain=1.0, N_R=0, N_dark_pp=0, reject_background_outliers=True): """ Perform aperture photometry on an image, with a few options for estimating the local background from an annulus around the aperture. Parameters ---------- ccd_image : `~ccdproc.CCDData` Image on which to perform aperture photometry. sources : `~astropy.table.Table` Table of extracted sources. Assumed to be the output of `~photutils.daofind()` source extraction function. aperture_radius : float Radius of aperture(s) in pixels. inner_annulus : float Inner radius of the annulus in pixels. outer_annulus : float Outer radius of the annulus in pixels. gain : float Gain of the CCD. In units of electrons per DN. N_R : float Read noise of the CCD in electrons per pixel. N_dark_pp : float Number of dark counts per pixel. reject_background_outliers : bool, optional If ``True``, sigma clip the pixels in the annulus to reject outlying pixels (e.g. like stars in the annulus) Returns ------- phot_table : `~astropy.table.Table` Astropy table with columns for flux, x/y coordinates of center, RA/dec coordinates of center, sky background per pixel, net flux, aperture and annulus radii used, and flux error. """ # check that the outer radius is greater or equal the inner radius # for annulus if inner_annulus >= outer_annulus: raise ValueError("outer_annulus must be greater than inner_annulus") # check that the annulus inner radius is greater or equal # the aperture radius if aperture_radius >= inner_annulus: raise ValueError("inner_radius must be greater than aperture_radius") # Extract x,y coordinates from sources table, construct aperture and # annulus objects from coordinates, and perform aperture photometry coords = (sources['xcentroid'], sources['ycentroid']) apertures = CircularAperture(coords, aperture_radius) annulus = CircularAnnulus(coords, inner_annulus, outer_annulus) phot_table = aperture_photometry(ccd_image, apertures) phot_table_1 = aperture_photometry(ccd_image, annulus) # Obtain the local background/pixel and net flux between the aperture and # annulus objects n_pix_ap = apertures.area n_pix_ann = annulus.area if reject_background_outliers: annulus_masks = annulus.to_mask() bkgd_pp = [] for mask in annulus_masks: annulus_data = mask.cutout(ccd_image) bool_mask = mask.data < 1 # Only include whole pixels in the estimate of the background bkgd, _, _ = sigma_clipped_stats(annulus_data * mask, mask=bool_mask) bkgd_pp.append(bkgd) bkgd_pp = np.array(bkgd_pp) else: bkgd_pp = phot_table_1['aperture_sum'] / n_pix_ann net_flux = phot_table['aperture_sum'] - (n_pix_ap * bkgd_pp) phot_table['background_per_pixel'] = bkgd_pp phot_table['net_flux'] = net_flux # Return a columns with the aperture radius and # the inner/outer annulus radii phot_table['aperture_radius'] = \ np.ones(len(phot_table['aperture_sum'])) * aperture_radius phot_table['inner_radius'] = \ np.ones(len(phot_table['aperture_sum'])) * inner_annulus phot_table['outer_radius'] = \ np.ones(len(phot_table['aperture_sum'])) * outer_annulus # Obtain RA/Dec coordinates and add them to table try: ra, dec = convert_pixel_wcs(ccd_image, coords[0], coords[1], 1) phot_table['RA_center'] = ra phot_table['Dec_center'] = dec except AttributeError: pass # Obtain flux error and add column to return table noise = np.sqrt(gain * net_flux + n_pix_ap * (1 + (n_pix_ap / n_pix_ann)) * (gain * (bkgd_pp + N_dark_pp) + (N_R**2))) phot_table['aperture_sum_err'] = noise return phot_table
def draw_mask_map_strip(image, seg_comb, mask_comb, stars, ma_example=None, r_core=None, vmin=None, vmax=None, pad=0, save=False, save_dir='./'): """ Visualize mask map w/ strips """ from matplotlib import patches star_pos_A = stars.star_pos_verybright + pad star_pos_B = stars.star_pos_medbright + pad mu = np.nanmedian(image) std = mad_std(image) if vmin is None: vmin = mu - std if vmax is None: vmax = mu + 10 * std fig, (ax1, ax2, ax3) = plt.subplots(ncols=3, nrows=1, figsize=(20, 6), dpi=100) if ma_example is not None: mask_strip, mask_cross = ma_example mask_strip[mask_cross.astype(bool)] = 0.5 ax1.plot(star_pos_A[0][0], star_pos_A[0][1], "r*", ms=18) else: mask_strip = np.zeros_like(image) ax1.imshow(mask_strip, cmap="gray_r") ax1.set_title("Strip/Cross") n_label = seg_comb.max() ax2.imshow(seg_comb, vmin=1, vmax=n_label - 3, cmap=make_rand_cmap(n_label)) ax2.plot(star_pos_A[:, 0], star_pos_A[:, 1], "r*", ms=18) ax2.set_title("Mask Comb.") image3 = image.copy() image3[mask_comb] = 0 im3 = ax3.imshow(image3, norm=LogNorm(), vmin=vmin, vmax=vmax) ax3.plot(star_pos_A[:, 0], star_pos_A[:, 1], "r*", ms=18) ax3.set_title("Sky") colorbar(im3, pad=0.1, size="2%") if r_core is not None: if np.ndim(r_core) == 0: r_core = [r_core, r_core] aper = CircularAperture(star_pos_A, r=r_core[0]) aper.plot(color='lime', lw=2, label="", alpha=0.9, axes=ax3) aper = CircularAperture(star_pos_B, r=r_core[1]) aper.plot(color='c', lw=2, label="", alpha=0.7, axes=ax3) patch_Xsize = image.shape[1] - pad * 2 patch_Ysize = image.shape[0] - pad * 2 rec = patches.Rectangle((pad, pad), patch_Xsize, patch_Ysize, facecolor='none', edgecolor='w', linewidth=2, linestyle='--', alpha=0.8) ax3.add_patch(rec) plt.tight_layout() if save: plt.savefig(os.path.join(save_dir, "Mask_strip.png"), dpi=100) plt.show() plt.close() else: plt.show()
mosaic_area = fits.getdata(dir + '/Mosaic_B/mosaic_area.fits') #mosaic area plot: plt.figure(1) plt.imshow(mosaic_area, origin='lower') plt.xlabel('Pixels', fontsize=15) plt.ylabel('Pixels', fontsize=15) mosaic_area_cropped = mosaic_area[400:1490, 380:1610] raw_cropped = sourcesB = daofind(nosky_crop, fwhm=5.0, threshold=1.5*bkg_sigma) #background subtraction: #phot_table = aperture_photometry(data - bkg, apertures) data = apertures = CircularAperture(positions, r=3) annulus_apertures = CircularAnnulus(positions, r_in=6, r_out=8) rawflux_table = aperture_photometry(data, apertures) bkgflux_table = aperture_photometry(data, annulus_apertures) phot_table = hstack([rawflux_table, bkgflux_table], table_names=['raw', 'bkg']) aperture_area = np.pi*3**2 annulus_area = np.pi*(8**2-6**2) final_sum = (phot_table['aperture_sum_raw']-phot_table['aperture_sum_bkg'] * aperture_area/annulus_area) phot_table = ['residual_aperture_sum']