def phot(self, image_path, x_coor, y_coor, aper_radius=3.0, gain=0.57): """ Photometry of given coordinates. @param image_path: Path of FITS file. @type image_path: path @param x_coor: X coordinate of object @type x_coor: float @param y_coor: Y coordinate of object @type y_coor: float @param aper_radius: Aperture radius @type aper_radius: float @return: tuple """ if image_path: hdu = fits.open(image_path)[0] else: print("FITS image has not been provided by the user!") raise SystemExit data = hdu.data.astype(float) bkg = sep.Background(data) # bkg_image = bkg.back() # bkg_rms = bkg.rms() data_sub = data - bkg flux, fluxerr, flag = sep.sum_circle(data_sub, x_coor, y_coor, aper_radius=aper_radius, err=bkg.globalrms, gain=gain) return ({"flag": flag, "flux": flux, "fluxerr": fluxerr})
def sep_phot(data, ap, th): """ Preforms photometry by SEP, similar to source extractor """ # Measure a spatially variable background of some image data (np array) try: bkg = sep.Background(data) # , mask=mask, bw=64, bh=64, fw=3, fh=3) # optional parameters except ValueError: data = data.byteswap(True).newbyteorder() bkg = sep.Background(data) # , mask=mask, bw=64, bh=64, fw=3, fh=3) # optional parameters # Directly subtract the background from the data in place bkg.subfrom(data) # for the background subtracted data, detect objects in data given some threshold thresh = th * bkg.globalrms # ensure the threshold is high enough wrt background objs = sep.extract(data, thresh) # calculate the Kron radius for each object, then we perform elliptical aperture photometry within that radius kronrad, krflag = sep.kron_radius(data, objs['x'], objs['y'], objs['a'], objs['b'], objs['theta'], ap) flux, fluxerr, flag = sep.sum_ellipse(data, objs['x'], objs['y'], objs['a'], objs['b'], objs['theta'], 2.5 * kronrad, subpix=1) flag |= krflag # combine flags into 'flag' r_min = 1.75 # minimum diameter = 3.5 use_circle = kronrad * np.sqrt(objs['a'] * objs['b']) < r_min x = objs['x'] y = objs['y'] cflux, cfluxerr, cflag = sep.sum_circle(data, x[use_circle], y[use_circle], r_min, subpix=1) flux[use_circle] = cflux fluxerr[use_circle] = cfluxerr flag[use_circle] = cflag return objs
def photometry(self, file, x_coor, y_coor, zmag=25.0, aper_radius=15.0, gain=1.21): """Python photometry""" try: data = self.data(file) bkg = Background(data) data_sub = data - bkg flx, ferr, flag = sum_circle(data_sub, x_coor, y_coor, aper_radius, err=bkg.globalrms, gain=gain) mag, merr = self.sma.flux_to_mag(flx, ferr) return [ str(x_coor), str(y_coor), str(float(flx)), str(float(ferr)), str(float(flag)), str(mag + zmag), str(merr) ] except Exception as e: self.logger.error(e)
def AperaturePhoto(self,filter,objs): print 'Running Aperature Photometry on %s......'%filter kronrad, krflag = sep.kron_radius(self.dataList[filter], objs['x'], objs['y'], objs['a'], objs['b'], objs['theta'], 6.0) flux, fluxerr, flag = sep.sum_ellipse(self.dataList[filter], objs['x'], objs['y'], objs['a'], objs['b'], objs['theta'], 2.5*kronrad, subpix=1, err=self.bkgRMS[filter]) #use circular aperature photometry if the kronradius is too small. see http://sep.readthedocs.org/en/v0.2.x/apertures.html r_min = 1.75 # minimum diameter = 3.5 use_circle = kronrad * np.sqrt(objs['a']*objs['b']) < r_min cflux, cfluxerr, cflag = sep.sum_circle(self.dataList[filter], objs['x'][use_circle], objs['y'][use_circle], r_min, subpix=1,err=self.bkgRMS[filter]) flux[use_circle] = cflux fluxerr[use_circle] = cfluxerr flag[use_circle] = cflag #convert flux to magnitudes using the appropriate zeropoint #absolute flux measurement (AB for Z-PEG) mag = -2.5*np.log10(flux)+self.zeroPoints[filter] #calculate magerr fluxdown = flux - fluxerr fluxup = flux + fluxerr magup = -2.5*np.log10(fluxdown) + self.zeroPoints[filter] magdown = -2.5*np.log10(fluxup) + self.zeroPoints[filter] magerr = ((magup - mag) + (mag-magdown))/2. return mag, magerr
def test_apertures_exact(): """Test area as measured by exact aperture modes on array of ones""" theta = np.random.uniform(-np.pi/2., np.pi/2., naper) ratio = np.random.uniform(0.2, 1.0, naper) r = 3. for dt in SUPPORTED_IMAGE_DTYPES: data = np.ones(data_shape, dtype=dt) for r in [0.5, 1., 3.]: flux, fluxerr, flag = sep.sum_circle(data, x, y, r, subpix=0) assert_allclose(flux, np.pi*r**2) rout = r*1.1 flux, fluxerr, flag = sep.sum_circann(data, x, y, r, rout, subpix=0) assert_allclose(flux, np.pi*(rout**2 - r**2)) flux, fluxerr, flag = sep.sum_ellipse(data, x, y, 1., ratio, theta, r=r, subpix=0) assert_allclose(flux, np.pi*ratio*r**2) rout = r*1.1 flux, fluxerr, flag = sep.sum_ellipann(data, x, y, 1., ratio, theta, r, rout, subpix=0) assert_allclose(flux, np.pi*ratio*(rout**2 - r**2))
def aperture_photometry(image_data: np.ndarray, background: sep.Background) -> List[Star]: """ performs aperture photometry on an image :param image_data: data of the image :param background: background of the image :return: a list of extracted stars """ # extract objects using source extractor objects = sep.extract(image_data, AperturePhotometry.threshold, err=background.globalrms) # perform aperture photometry aperture = sep.sum_circle( image_data, objects["x"], objects["y"], AperturePhotometry.radius, err=background.globalrms, gain=AperturePhotometry.gain, ) # create and return a list of star objects return [ Star(x, y, flux, fluxerr) for x, y, flux, fluxerr, _ in zip( objects["x"], objects["y"], *aperture) ]
def test_apertures_all(): """Test that aperture subpixel sampling works""" data = np.random.rand(*data_shape) r = 3. rtol = 1.e-8 for subpix in [0, 1, 5]: flux_ref, fluxerr_ref, flag_ref = sep.sum_circle(data, x, y, r, subpix=subpix) flux, fluxerr, flag = sep.sum_circann(data, x, y, 0., r, subpix=subpix) assert_allclose(flux, flux_ref, rtol=rtol) flux, fluxerr, flag = sep.sum_ellipse(data, x, y, r, r, 0., subpix=subpix) assert_allclose(flux, flux_ref, rtol=rtol) flux, fluxerr, flag = sep.sum_ellipse(data, x, y, 1., 1., 0., r=r, subpix=subpix) assert_allclose(flux, flux_ref, rtol=rtol)
def timeEvolveFITSNoDrift(data, coords, x_drift, y_drift, r, stars, x_length, y_length, t): x = [coords[ind, 0] for ind in range(0, stars)] y = [coords[ind, 1] for ind in range(0, stars)] bkg = np.median(data) * np.pi * r * r fluxes = (sep.sum_circle(data, x, y, r)[0] - bkg).tolist() coords = zip(x, y, fluxes, [t] * len(x)) return coords
def catalog(ccd, bgf, catf, db, config, logger): bg = fits.open(bgf) im = ccd.data - bg['background'].data ps = ccd.meta['SCALE'] * ccd.meta.get('REBIN', 1) bgrms = bg['background'].header['bgrms'] objects = sep.extract(im, 2, err=bgrms, mask=ccd.mask) logger.info('Found {} sources.'.format(len(objects))) rap = max(ccd.meta['SEEING'] * 2, 5 / ps) flux, fluxerr, flag = sep.sum_circle(im, objects['x'], objects['y'], rap, err=bgrms) # avoid theta rounding error theta = np.maximum(np.minimum(objects['theta'], np.pi / 2.00001), -np.pi / 2.00001) kronrad, krflag = sep.kron_radius(im, objects['x'], objects['y'], objects['a'], objects['b'], theta, 6.0) krflux, krfluxerr, _flag = sep.sum_ellipse(im, objects['x'], objects['y'], objects['a'], objects['b'], theta, 2.5 * kronrad, subpix=1, err=bgrms) krflag |= _flag # an additional background estimate, which should help when there are # large extended sources in scene: IN TESTS, THIS DID NOT AFFECT RESULTS # for i in range(len(objects)): # krflux[i], krfluxerr[i] = bg_subtract2(im, objects[i], krflux[i], # krfluxerr[i]) # flux[i], fluxerr[i] = bg_subtract2(im, objects[i], flux[i], # fluxerr[i], r=rap) if ccd.wcs.wcs.crval[0] == ccd.wcs.wcs.crval[1]: ra, dec = np.zeros((2, len(objects))) else: ra, dec = ccd.wcs.all_pix2world(objects['x'], objects['y'], 0) tab = Table( (objects['x'], objects['y'], ra, dec, flux, fluxerr, flag, objects['a'], objects['b'], theta, kronrad, krflux, krfluxerr, krflag), names=('x', 'y', 'ra', 'dec', 'flux', 'fluxerr', 'flag', 'a', 'b', 'theta', 'kronrad', 'krflux', 'krfluxerr', 'krflag')) hdu = fits.HDUList() hdu.append(fits.BinTableHDU(tab, name='cat')) hdu['cat'].header['RADIUS'] = (rap * ps, 'aperture photometry radius, arcsec') hdu.writeto(catf, overwrite=True)
def photskycoord(self, image_path, ra, dec, aper_radius=3.0, gain=0.57): """ Photometry of given coordinates. @param image_path: Path of FITS file. @type image_path: path @param ra: RA coordinate of object @type ra: string @param dec: DEC coordinate of object @type dec: string @param aper_radius: Aperture radius @type aper_radius: float @param gain: gain value for the image expressed in electrons per adu. @type gain: float @return: tuple """ if image_path: hdu = fits.open(image_path)[0] else: print("FITS image has not been provided by the user!") raise SystemExit data = hdu.data.astype(float) fo = FitsOps(image_path) header = hdu.header w = WCS(header) naxis1 = fo.get_header('naxis1') naxis2 = fo.get_header('naxis2') c = coordinates.SkyCoord('{0} {1}'.format( ra, dec), unit=(u.hourangle, u.deg), frame='icrs') # object's X and Y coor a_x, a_y = w.wcs_world2pix(c.ra.degree, c.dec.degree, 1) if naxis1 < a_x or naxis2 < a_y or a_x < 0 or a_y < 0: print("Provided coordinates are out of frame!") return(False) else: bkg = sep.Background(data) data_sub = data - bkg flux, fluxerr, flag = sep.sum_circle(data_sub, a_x, a_y, aper_radius=aper_radius, err=bkg.globalrms, gain=gain) return({"flag": flag, "flux": flux, "fluxerr": fluxerr})
def do_stage(self, image): # identify emission feature (pixel, order) positions. # we use daofind (which is inside of identify_features) to get every feature with S/N > min_S/N - 1 # Then later on in this do_stage, we will rigorously cut every feature with S/N < min_S/N (using # sep.sum_circle to rigorously estimate the Signal contained in the 2d feature. features = identify_features(image.data, image.uncertainty, image.mask, nsigma=self.nsigma - 1, fwhm=self.fwhm, sigma_radius=4) features = group_features_by_trace(features, image.traces) features = features[ features['id'] != 0] # throw out features that are outside of any trace. # get total flux in each emission feature. For now just sum_circle, although we should use sum_ellipse. features['flux'], features['fluxerr'], _ = sep.sum_circle( image.data, features['xcentroid'], features['ycentroid'], self.fwhm, gain=1.0, err=image.uncertainty, mask=image.mask) if image.blaze is not None: logger.info('Blaze correcting emission feature fluxes', image=image) # blaze correct the emission features fluxes. This speeds up and improves overlap fitting in xwavecal. features['corrected_flux'] = features['flux'] features['corrected_flux'] /= image.blaze['blaze'][ np.array(features['id'], dtype=int) - 1, np.array(features['xcentroid'], dtype=int)] # cutting which lines to keep: # calculate the error in the centroids provided by identify_features() features['centroid_err'] = self.fwhm / np.sqrt(features['flux']) # Filter features that pass the signal to noise check. # only keep features with S/N > min S/N. valid_features = features['flux'] / features['fluxerr'] > self.nsigma features = features[valid_features] logger.info('{0} valid emission features found on this image'.format( len(features)), image=image) features = self.limit_features_per_fiber(features, self.num_features_max) # report statistics logger.info('{0} emission features on this image will be used'.format( len(features)), image=image) if len(features) == 0: logger.error('No emission features found on this image!', image=image) # save the features to the image. image.add_or_update(DataTable(features, name='FEATURES')) return image
def get_fluxes(object1, data1, iR, oR, G, rN): """ Preconditions: Expects a sep extracted list of objects and the image data the objectlist is from. Can also take the inner radius, outer radius, gain, and read noise. Postcontions: Returns the flux and flux error for each object in the list. """ flux, fluxerr, flag = sep.sum_circle(data1, object1["x"], object1["y"], 16.0, bkgann=(iR, oR), gain=G, err=rN) return flux, np.sqrt(fluxerr)
def _measure(self, img, sources, mask=None): logger.info('measuring source parameters') # HACK: issues with numerical precision # must have pi/2 <= theta <= npi/2 sources[np.abs(np.abs(sources['theta']) - np.pi/2) < 1e-6] = np.pi/2 for p in ['x', 'y', 'a', 'b', 'theta']: sources = sources[~np.isnan(sources[p])] # calculate "AUTO" parameters kronrad, krflag = sep.kron_radius( img, sources['x'], sources['y'], sources['a'], sources['b'], sources['theta'], 6.0, mask=mask) flux, fluxerr, flag = sep.sum_ellipse( img, sources['x'], sources['y'], sources['a'], sources['b'], sources['theta'], 2.5*kronrad, subpix=5, mask=mask) flag |= krflag # combine flags into 'flag' sources = sources[~np.isnan(flux)] flux = flux[~np.isnan(flux)] sources = sources[flux > 0] flux = flux[flux > 0] mag_auto = utils.zpt - 2.5*np.log10(flux) r, flag = sep.flux_radius( img, sources['x'], sources['y'], 6.*sources['a'], 0.5, normflux=flux, subpix=5, mask=mask) sources['mag_auto'] = mag_auto sources['flux_auto'] = flux sources['flux_radius'] = r * utils.pixscale # approximate fwhm r_squared = sources['a']**2 + sources['b']**2 sources['fwhm'] = 2 * np.sqrt(np.log(2) * r_squared) * utils.pixscale q = sources['b'] / sources['a'] area = np.pi * q * sources['flux_radius']**2 sources['mu_ave_auto'] = sources['mag_auto'] + 2.5 * np.log10(2*area) area_arcsec = np.pi * (self.psf_fwhm/2)**2 * utils.pixscale**2 flux, fluxerr, flag = sep.sum_circle( img, sources['x'], sources['y'], self.psf_fwhm/2, subpix=5, mask=mask) flux[flux<=0] = np.nan mu_0 = utils.zpt - 2.5*np.log10(flux / area_arcsec) sources['mu_0_aper'] = mu_0 return sources
def test_aperture_bkgann_overlapping(): """Test bkgann functionality in circular & elliptical apertures.""" # If bkgann overlaps aperture exactly, result should be zero # (with subpix=1) data = np.random.rand(*data_shape) r = 5. f, _, _ = sep.sum_circle(data, x, y, r, bkgann=(0., r), subpix=1) assert_allclose(f, 0., rtol=0., atol=1.e-13) f, _, _ = sep.sum_ellipse(data, x, y, 2., 1., np.pi/4., r=r, bkgann=(0., r), subpix=1) assert_allclose(f, 0., rtol=0., atol=1.e-13)
def find_flux(tbdat_sub, objects, kronrad, kronflag): flux, fluxerr, flag = sep.sum_ellipse(tbdat_sub, objects['x'], objects['y'], objects['a'], objects['b'], objects['theta'], pho_auto_A = (2.5*kronrad), err = bkg.globalrms, subpix=1) flag |=kronflag #combines all flags r_min = 1.75 #minimum diameter = 3.5 use_circle = kronrad * np.sqrt(a * b) < r_min cflux, cfluxerr, cflag = sep.sum_circle(tbdat_sub, objects['x'][use_circle], objects['y'][use_circle], r_min, subpix=1) flux[use_circle] = cflux fluxerr[use_circle] = cfluxerr flag[use_circle] = cflag r, rflag = sep.flux_radius(data, x, y, 6.0*objects['a'], rmax = 0.5, normflux = flux, subpix =5) sig = 2.0 / (2.35*r) # r from sep.flux_radius() above, with fluxfrac = 0.5 xwin, ywin, wflag = sep.winpos(tbdat_sub, objects['x'], objects['y'], sig) return flux, fluxerr, flag, r, xwin, ywin
def test_aperture_bkgann_ones(): """Test bkgann functionality with flat data""" data = np.ones(data_shape) r=5. bkgann=(6., 8.) # On flat data, result should be zero for any bkgann and subpix f, _, _ = sep.sum_circle(data, x, y, r, bkgann=bkgann) assert_allclose(f, 0., rtol=0., atol=1.e-13) f, _, _ = sep.sum_ellipse(data, x, y, 2., 1., np.pi/4., r, bkgann=bkgann) assert_allclose(f, 0., rtol=0., atol=1.e-13)
def photskycoord(self, image_path, ra, dec, aper_radius=3.0, gain=0.57): """ Photometry of given coordinates. @param image_path: Path of FITS file. @type image_path: path @param ra: RA coordinate of object @type ra: string @param dec: DEC coordinate of object @type dec: string @param aper_radius: Aperture radius @type aper_radius: float @param gain: gain value for the image expressed in electrons per adu. @type gain: float @return: tuple """ if image_path: hdu = fits.open(image_path)[0] else: print("FITS image has not been provided by the user!") raise SystemExit data = hdu.data.astype(float) fo = FitsOps(image_path) header = hdu.header w = WCS(header) naxis1 = fo.get_header('naxis1') naxis2 = fo.get_header('naxis2') c = coordinates.SkyCoord('{0} {1}'.format(ra, dec), unit=(u.hourangle, u.deg), frame='icrs') # object's X and Y coor a_x, a_y = w.wcs_world2pix(c.ra.degree, c.dec.degree, 1) if naxis1 < a_x or naxis2 < a_y or a_x < 0 or a_y < 0: print("Provided coordinates are out of frame!") return (False) else: bkg = sep.Background(data) data_sub = data - bkg flux, fluxerr, flag = sep.sum_circle(data_sub, a_x, a_y, aper_radius=aper_radius, err=bkg.globalrms, gain=gain) return ({"flag": flag, "flux": flux, "fluxerr": fluxerr})
def test_aperture_dtypes(): """Ensure that all supported image dtypes work in sum_circle() and give the same answer""" r = 3. fluxes = [] for dt in SUPPORTED_IMAGE_DTYPES: data = np.ones(data_shape, dtype=dt) flux, fluxerr, flag = sep.sum_circle(data, x, y, r) fluxes.append(flux) for i in range(1, len(fluxes)): assert_allclose(fluxes[0], fluxes[i])
def sextractor(im,err=None,mask=None,nsig=5.0,gain=1.0): # Check byte order, SEP needs little endian if im.dtype.byteorder == '>': data = im.byteswap().newbyteorder() else: data = im # Background estimation and subtraction bkg = sep.Background(data, mask, bw=256, bh=256, fw=3, fh=3) bkg_image = bkg.back() data_sub = data-bkg #data_sub[data>50000]=0.0 # Detect and extract objects if err is None: objects = sep.extract(data_sub, nsig, err=bkg.globalrms, mask=mask) else: objects = sep.extract(data_sub, nsig, err=err, mask=mask) # Get mag_auto in 2 steps kronrad, krflag = sep.kron_radius(data_sub, objects['x'], objects['y'], objects['a'], objects['b'], objects['theta'], 6.0, mask=mask) flux, fluxerr, flag = sep.sum_ellipse(data_sub, objects['x'], objects['y'], objects['a'], objects['b'], objects['theta'], 2.5*kronrad, subpix=1, err=err, mask=mask, gain=gain) flag |= krflag # combine flags into 'flag' # Use circular aperture if Kron radius is too small r_min = 1.75 # minimum diameter = 3.5 use_circle = kronrad * np.sqrt(objects['a'] * objects['b']) < r_min if np.sum(use_circle)>0: cflux, cfluxerr, cflag = sep.sum_circle(data_sub, objects['x'][use_circle], objects['y'][use_circle], r_min, subpix=1, err=err, mask=mask, gain=gain) flux[use_circle] = cflux fluxerr[use_circle] = cfluxerr flag[use_circle] = cflag mag_auto = -2.5*np.log10(flux)+25.0 magerr_auto = 1.0857*fluxerr/flux # Make the final catalog newdt = np.dtype([('kronrad',float),('flux_auto',float),('fluxerr_auto',float),('mag_auto',float),('magerr_auto',float)]) cat = dln.addcatcols(objects,newdt) cat['flag'] |= flag cat['kronrad'] = kronrad cat['flux_auto'] = flux cat['fluxerr_auto'] = fluxerr cat['mag_auto'] = mag_auto cat['magerr_auto'] = magerr_auto return cat
def flux(path, aperture): import sep, numpy as np from astropy.io import fits # Reading the fits image alongwith its header galaxy = fits.open(path) data = galaxy[0].data # This step seems meaningless but it works. The issue is the change of byte order which will increase the computation time so I had this workaround! data = data + 0 # subtracting the background. It's a good idea to ckech the image of background! bkg = sep.Background(data) back = bkg.back() data2 = data - back # it will be really helpful if we see the image at this point. It is background subtracted so the difference should be noticable. # printing the global background as well as the rms of background. #print(bkg.globalback) #print(bkg.globalrms) # defining the threshold, it is necessary for flux estimation. thresh = 10 * bkg.globalback #print(thresh) # finding out the objects, it will store all the objects found out in the frame determined by the threshold. objects = sep.extract(data2, thresh, err=bkg.globalrms) #The most important, flux and its error determination. This will take a given aperture and calculate the flux in that aperture around the centroid of the object. flux, fluxerr, flag = sep.sum_circle(data2, objects['x'], objects['y'], aperture, err=bkg.globalrms, gain=1.4) #printing the flux values. l = len(objects) flux = np.max(flux) fluxerr = np.max(fluxerr) return (l, flux, fluxerr)
def extract(data): bkg = sep.Background(data, bw=64, bh=64, fw=3, fh=3) bkg.subfrom(data) objs = sep.extract(data, 1.5*bkg.globalrms) flux, fluxerr, flag = sep.sum_circle(data, objs['x'], objs['y'], 5., err=bkg.globalrms) kr, flag = sep.kron_radius(data, objs['x'], objs['y'], objs['a'], objs['b'], objs['theta'], 6.0) eflux, efluxerr, eflag = sep.sum_ellipse(data, objs['x'], objs['y'], objs['a'], objs['b'], objs['theta'], r=2.5 * kr, err=bkg.globalrms, subpix=1) retstr = "" for i in range(len(objs['x'])): retstr = retstr+(str(objs['x'][i])+"\t"+str(objs['y'][i])+"\t"+str(flux[i])+"\t"+str(fluxerr[i])+"\t"+str(kr[i])+"\t"+str(eflux[i])+"\t"+str(efluxerr[i])+"\t"+str(flag[i])+"\n") return retstr
def do(self, data, x_coor, y_coor, aper_radius=10.0, gain=1.21): self.etc.log( "Starting Photometry for x({}), y({}) with aperture({}) and gain({})" .format(x_coor, y_coor, aper_radius, gain)) try: bkg = Background(data) data_sub = data - bkg flux, fluxerr, flag = sum_circle(data_sub, x_coor, y_coor, aper_radius, err=bkg.globalrms, gain=gain) return (flux, fluxerr, flag) except Exception as e: self.eetc.log(e)
def run(self, image): if self.fwhm_scale: r_in = self.annulus_inner_radius * image.fwhm r_out = self.annulus_outer_radius * image.fwhm r = self.apertures * image.fwhm else: r_in = self.annulus_inner_radius r_out = self.annulus_outer_radius r = self.apertures self.n_stars = len(image.stars_coords) image.fluxes = np.zeros((self.n_apertures, self.n_stars)) data = image.data.copy().byteswap().newbyteorder() for i, _r in enumerate(r): image.fluxes[i, :], fluxerr, flag = sep.sum_circle( data, *image.stars_coords.T, _r, bkgann=(r_in, r_out), subpix=0) image.sky = 0 image.apertures_area = np.pi * r**2 image.annulus_area = np.pi * (r_out**2 - r_in**2) # fluxes = np.zeros((self.n_apertures, self.n_stars)) # bkg = np.zeros((self.n_apertures, self.n_stars)) # for i, _r in enumerate(r): # fluxes[i, :], _, _ = sep.sum_circle( # data, # *image.stars_coords.T, # _r, bkgann=(r_in, r_out), subpix=0) # bkg[i, :], _, _ = sep.sum_circann(data, *image.stars_coords.T, r_in, r_out, subpix=0) # image.fluxes = fluxes - bkg # image.sky = np.mean(bkg) # image.apertures_area = np.pi * r**2 # image.annulus_area = np.pi * (r_out**2 - r_in**2) # image.header["sky"] = np.mean(image.sky) self.compute_error(image)
def timeEvolveFITS(data, coords, x_drift, y_drift, r, stars, x_length, y_length, t): """ Adjusts aperture based on star drift and calculates flux in aperture""" x = [coords[ind, 0] + x_drift[ind] for ind in range(0, stars)] y = [coords[ind, 1] + y_drift[ind] for ind in range(0, stars)] inds = clipCutStars(x, y, x_length, y_length) inds = list(set(inds)) inds.sort() xClip = np.delete(np.array(x), inds) yClip = np.delete(np.array(y), inds) bkg = np.median(data) * np.pi * r * r fluxes = (sep.sum_circle(data, xClip, yClip, r)[0] - bkg).tolist() for a in inds: fluxes.insert(a, 0) coords = zip(x, y, fluxes, [t] * len(x)) return coords
def get_fluxes(object1, data1, iR, oR, G, rN): """ Preconditions: Expects a sep extracted list of objects and the image data the objectlist is from. Can also take the inner radius, outer radius, gain, and read noise. Postcontions: Returns the flux and flux error for each object in the list. """ flux, fluxerr, flag = sep.sum_circle(data1, object1['x'], object1['y'], 16.0, bkgann=(iR, oR), gain=G, err=rN) return flux, np.sqrt(fluxerr)
def AperPhot(self, r_aper=[1.5, 2.0, 4.0], write=True): ra, dec = self.wcs.all_pix2world(self.src['x'] + 1, self.src['y'] + 1, 1) df = pd.DataFrame( data={ 'x': self.src['x'], 'y': self.src['y'], 'ra': ra, 'dec': dec, 'a': self.src['a'], 'b': self.src['b'], 'theta': self.src['theta'] }) for i in np.arange(len(r_aper)): flux, fluxerr, flag = sep.sum_circle(self.dat, self.src['x'], self.src['y'], r_aper[i], err=self.skysigma, gain=self.gain, subpix=0) mag = self.zmag - 2.5 * np.log10(flux) magerr = (2.5 / np.log(10.0)) * (fluxerr / flux) df['r' + f'{i+1:d}'] = r_aper[i] df['flux' + f'{i+1:d}'] = flux df['e_flux' + f'{i+1:d}'] = fluxerr df['mag' + f'{i+1:d}'] = mag df['e_mag' + f'{i+1:d}'] = magerr if write: df.to_csv(ip.tmp_dir + 'aper_' + self.img.split('.fits')[0] + '.csv') f = open(ip.tmp_dir + 'src_' + self.img.split('.fits')[0] + '.reg', 'w') for i in np.arange(self.nsrc): f.write('{0:.3f} {1:.3f}\n'.format(self.src['x'][i] + 1, self.src['y'][i] + 1)) f.close() return df
def test_aperture_bkgann_ones(): """Test bkgann functionality with flat data""" data = np.ones(data_shape) r=5. bkgann=(6., 8.) # On flat data, result should be zero for any bkgann and subpix f, fe, _ = sep.sum_circle(data, x, y, r, bkgann=bkgann, gain=1.) assert_allclose(f, 0., rtol=0., atol=1.e-13) # for all ones data and no error array, error should be close to # sqrt(Npix_aper + Npix_ann * (Npix_aper**2 / Npix_ann**2)) aper_area = np.pi * r**2 bkg_area = np.pi * (bkgann[1]**2 - bkgann[0]**2) expected_error = np.sqrt(aper_area + bkg_area * (aper_area/bkg_area)**2) assert_allclose(fe, expected_error, rtol=0.1) f, _, _ = sep.sum_ellipse(data, x, y, 2., 1., np.pi/4., r, bkgann=bkgann) assert_allclose(f, 0., rtol=0., atol=1.e-13)
def findSpot(data, sigma): image=data #m, s = np.mean(image), np.std(image) bkg = sep.Background(image, bw=32, bh=32, fw=3, fh=3) objs = sep.extract(image-bkg, sigma, err=bkg.globalrms) aper_radius=3 # Calculate the Kron Radius kronrad, krflag = sep.kron_radius(image, objs['x'], objs['y'], \ objs['a'], objs['b'], objs['theta'], aper_radius) r_min = 3 use_circle = kronrad * np.sqrt(objs['a'] * objs['b']) cinx=np.where(use_circle <= r_min) einx=np.where(use_circle > r_min) # Calculate the equivalent of FLUX_AUTO flux, fluxerr, flag = sep.sum_ellipse(image, objs['x'][einx], objs['y'][einx], \ objs['a'][einx], objs['b'][einx], objs['theta'][einx], 2.5*kronrad[einx],subpix=1) cflux, cfluxerr, cflag = sep.sum_circle(image, objs['x'][cinx], objs['y'][cinx], objs['a'][cinx], subpix=1) # Adding half pixel to measured coordinate. objs['x'] = objs['x']+0.5 objs['y'] = objs['y']+0.5 objs['flux'][einx]=flux objs['flux'][cinx]=cflux r, flag = sep.flux_radius(image, objs['x'], objs['y'], \ 6*objs['a'], 0.3,normflux=objs['flux'], subpix=5) flag |= krflag objs=rfn.append_fields(objs, 'r', data=r, usemask=False) objects=objs[:] return objects
def phot(self, image_path, x_coor, y_coor, aper_radius=3.0, gain=0.57): """ Photometry of given coordinates. @param image_path: Path of FITS file. @type image_path: path @param x_coor: X coordinate of object @type x_coor: float @param y_coor: Y coordinate of object @type y_coor: float @param aper_radius: Aperture radius @type aper_radius: float @return: tuple """ if image_path: hdu = fits.open(image_path)[0] else: print("FITS image has not been provided by the user!") raise SystemExit data = hdu.data.astype(float) bkg = sep.Background(data) # bkg_image = bkg.back() # bkg_rms = bkg.rms() data_sub = data - bkg flux, fluxerr, flag = sep.sum_circle(data_sub, x_coor, y_coor, aper_radius=aper_radius, err=bkg.globalrms, gain=gain) return({"flag": flag, "flux": flux, "fluxerr": fluxerr})
def sextract_magnitudes( data, aperture_radius, buffer_radius, background_radius, bkg=None, objects=None, sigma=3.0, ): aperture_area = np.pi * (aperture_radius**2) buffer_area = np.pi * (buffer_radius**2) background_area = (np.pi * (background_radius**2)) - buffer_area if bkg is None: data, bkg = sextract_bkg(data) if objects is None: objects = sextract_objects(data, sigma, bkg) aperture_list, _, _ = sep.sum_circle(data, objects["x"], objects["y"], aperture_radius, err=bkg.globalrms, gain=1.0) background_list, _, _ = sep.sum_circann( data, objects["x"], objects["y"], buffer_radius, background_radius, err=bkg.globalrms, gain=1.0, ) background_densities = [ annulus_sum / background_area for annulus_sum in background_list ] fluxes = np.array([ aperture_list[i] - (aperture_area * background_densities[i]) for i in range(len(aperture_list)) ]) return fluxes
def test_apertures_all(): """Test that aperture subpixel sampling works""" data = np.random.rand(*data_shape) r = 3. rtol=1.e-8 for subpix in [0, 1, 5]: flux_ref, fluxerr_ref, flag_ref = sep.sum_circle(data, x, y, r, subpix=subpix) flux, fluxerr, flag = sep.sum_circann(data, x, y, 0., r, subpix=subpix) assert_allclose(flux, flux_ref, rtol=rtol) flux, fluxerr, flag = sep.sum_ellipse(data, x, y, r, r, 0., subpix=subpix) assert_allclose(flux, flux_ref, rtol=rtol) flux, fluxerr, flag = sep.sum_ellipse(data, x, y, 1., 1., 0., r=r, subpix=subpix) assert_allclose(flux, flux_ref, rtol=rtol)
def mphotometry(self, file, coors, zmag=25.0, apertures=[10.0, 15.0], gain=1.21): """Python multiple photometry""" try: data = self.data(file) bkg = Background(data) data_sub = data - bkg ret = [] for coor in coors: try: x_coor, y_coor = list(map(int, coor)) for aper in apertures: flx, ferr, flag = sum_circle(data_sub, x_coor, y_coor, aper, err=bkg.globalrms, gain=gain) mag, merr = self.sma.flux_to_mag(flx, ferr) ret.append([ str(x_coor), str(y_coor), str(aper), str(float(flx)), str(float(ferr)), str(float(flag)), str(mag + zmag), str(merr) ]) except Exception as e: self.logger.error(e) return ret except Exception as e: self.logger.error(e)
def aperture_photometry(data, x, y, r, r_in, r_out, elipse = False, abtheta = None, rms = None, *args, **kwargs): ''' Do the aperture photometry with local sky subtraction. Parameters: data : ~numpy.ndarray~ 2D image data. x, y : list of list of float The list containing the pairs (x,y) of the objects. r : float The radius of the circular aperture to do the sum. r_in : float The internal radius of the sky annulus. r_out : float The external radius of the sky annulus. elipse : bool Tell the program if you want to do the photometry with eliptical aperture. If True, you have to pass the 'abtheta' argument, giving the elipse properties. **The kwargs will be passed integrally to the sep functions. Returns: flux, fluxerr, flags : ~numpy.ndarray~ The sum of the aperture, with annulus sky subtraction, and its error. ''' data = _fix_data(data) if elipse: if abtheta is None: raise ValueError("You must give the 'abtheta' argument if you want elipse photometry.") a, b, theta = _extract_abtheta(abtheta) return sep.sum_ellipse(data, x, y, a, b, theta, r, err=rms, bkgann=(r_in, r_out), **kwargs) else: return sep.sum_circle(data, x, y, r, err=rms, bkgann=(r_in, r_out), **kwargs)
def do_phot(data, x, y, r_aper=PHOT_RADIUS): """ Extract photometry from the reference positions, altered by the shifts from donuts Parameters ---------- data : array-like data array to extract photometry from x : array-like list of x positions to extract y : array-like list of y positions to extract r_aper : float radius used for the aperture photometry Returns ------- new_fluxes : array-like new flux measurements at these positions Raises ------ None """ bkg = sep.Background(data) data_new = data - bkg flux_new = [] for i, j in zip(x, y): flux, _, _ = sep.sum_circle(data_new, i, j, r_aper, subpix=0, gain=GAIN) flux_new.append(flux) return np.array(flux_new)
def forcephot(image,x,y,rad,skyreg=[10,20],show=False,mask=None): """ Compute the photometry on a MUSE reconstructed image within an aperture Treat limits as 2sigma x,y -> position of the aperture in pixels radap -> radius of the aperture in pixels skyreg -> radius of inner/outer sky region in pixel mask -> mask to avoid pixels show -> if true, show what's appening """ from astropy.io import fits import matplotlib.pyplot as plt import sep import numpy as np #open the image image=fits.open(image) data = image[1].data.byteswap().newbyteorder() var = image[2].data.byteswap().newbyteorder() #grab the zp zp=image[0].header['ZPAB'] flux, err, flg = sep.sum_circle(data,x,y,rad,var=var,bkgann=skyreg,mask=mask) #compute magnitudes if(flux < 2*err): mag=-2.5*np.log10(2*err)+zp errmag=99 else: mag=-2.5*np.log10(flux)+zp errmag=2.5*np.log10(1.+err/flux) #if show if(show): #display field median=np.median(data) stddev=np.std(data) plt.imshow(data,clim=[median-0.2*stddev,median+stddev],origin='low') #now the aperture circ=plt.Circle((x,y),radius=rad, color='red', fill=False) ax=plt.gca() ax.add_patch(circ) if(skyreg): circ1=plt.Circle((x,y),radius=skyreg[0], color='red', fill=False) circ2=plt.Circle((x,y),radius=skyreg[1], color='red', fill=False) ax.add_patch(circ1) ax.add_patch(circ2) plt.show() return mag, errmag
def do_stage(self, images): for i, image in enumerate(images): try: # Set the number of source pixels to be 5% of the total. This keeps us safe from # satellites and airplanes. sep.set_extract_pixstack(int(image.nx * image.ny * 0.05)) data = image.data.copy() error = (np.abs(data) + image.readnoise ** 2.0) ** 0.5 mask = image.bpm > 0 # Fits can be backwards byte order, so fix that if need be and subtract # the background try: bkg = sep.Background(data, mask=mask, bw=32, bh=32, fw=3, fh=3) except ValueError: data = data.byteswap(True).newbyteorder() bkg = sep.Background(data, mask=mask, bw=32, bh=32, fw=3, fh=3) bkg.subfrom(data) # Do an initial source detection # TODO: Add back in masking after we are sure SEP works sources = sep.extract(data, self.threshold, minarea=self.min_area, err=error, deblend_cont=0.005) # Convert the detections into a table sources = Table(sources) # We remove anything with a detection flag >= 8 # This includes memory overflows and objects that are too close the edge sources = sources[sources['flag'] < 8] sources = array_utils.prune_nans_from_table(sources) # Calculate the ellipticity sources['ellipticity'] = 1.0 - (sources['b'] / sources['a']) # Fix any value of theta that are invalid due to floating point rounding # -pi / 2 < theta < pi / 2 sources['theta'][sources['theta'] > (np.pi / 2.0)] -= np.pi sources['theta'][sources['theta'] < (-np.pi / 2.0)] += np.pi # Calculate the kron radius kronrad, krflag = sep.kron_radius(data, sources['x'], sources['y'], sources['a'], sources['b'], sources['theta'], 6.0) sources['flag'] |= krflag sources['kronrad'] = kronrad # Calcuate the equivilent of flux_auto flux, fluxerr, flag = sep.sum_ellipse(data, sources['x'], sources['y'], sources['a'], sources['b'], np.pi / 2.0, 2.5 * kronrad, subpix=1, err=error) sources['flux'] = flux sources['fluxerr'] = fluxerr sources['flag'] |= flag # Do circular aperture photometry for diameters of 1" to 6" for diameter in [1, 2, 3, 4, 5, 6]: flux, fluxerr, flag = sep.sum_circle(data, sources['x'], sources['y'], diameter / 2.0, gain=1.0, err=error) sources['fluxaper{0}'.format(diameter)] = flux sources['fluxerr{0}'.format(diameter)] = fluxerr sources['flag'] |= flag # Calculate the FWHMs of the stars: fwhm = 2.0 * (np.log(2) * (sources['a'] ** 2.0 + sources['b'] ** 2.0)) ** 0.5 sources['fwhm'] = fwhm # Cut individual bright pixels. Often cosmic rays sources = sources[fwhm > 1.0] # Measure the flux profile flux_radii, flag = sep.flux_radius(data, sources['x'], sources['y'], 6.0 * sources['a'], [0.25, 0.5, 0.75], normflux=sources['flux'], subpix=5) sources['flag'] |= flag sources['fluxrad25'] = flux_radii[:, 0] sources['fluxrad50'] = flux_radii[:, 1] sources['fluxrad75'] = flux_radii[:, 2] # Calculate the windowed positions sig = 2.0 / 2.35 * sources['fluxrad50'] xwin, ywin, flag = sep.winpos(data, sources['x'], sources['y'], sig) sources['flag'] |= flag sources['xwin'] = xwin sources['ywin'] = ywin # Calculate the average background at each source bkgflux, fluxerr, flag = sep.sum_ellipse(bkg.back(), sources['x'], sources['y'], sources['a'], sources['b'], np.pi / 2.0, 2.5 * sources['kronrad'], subpix=1) #masksum, fluxerr, flag = sep.sum_ellipse(mask, sources['x'], sources['y'], # sources['a'], sources['b'], np.pi / 2.0, # 2.5 * kronrad, subpix=1) background_area = (2.5 * sources['kronrad']) ** 2.0 * sources['a'] * sources['b'] * np.pi # - masksum sources['background'] = bkgflux sources['background'][background_area > 0] /= background_area[background_area > 0] # Update the catalog to match fits convention instead of python array convention sources['x'] += 1.0 sources['y'] += 1.0 sources['xpeak'] += 1 sources['ypeak'] += 1 sources['xwin'] += 1.0 sources['ywin'] += 1.0 sources['theta'] = np.degrees(sources['theta']) image.catalog = sources['x', 'y', 'xwin', 'ywin', 'xpeak', 'ypeak', 'flux', 'fluxerr', 'peak', 'fluxaper1', 'fluxerr1', 'fluxaper2', 'fluxerr2', 'fluxaper3', 'fluxerr3', 'fluxaper4', 'fluxerr4', 'fluxaper5', 'fluxerr5', 'fluxaper6', 'fluxerr6', 'background', 'fwhm', 'a', 'b', 'theta', 'kronrad', 'ellipticity', 'fluxrad25', 'fluxrad50', 'fluxrad75', 'x2', 'y2', 'xy', 'flag'] # Add the units and description to the catalogs image.catalog['x'].unit = 'pixel' image.catalog['x'].description = 'X coordinate of the object' image.catalog['y'].unit = 'pixel' image.catalog['y'].description = 'Y coordinate of the object' image.catalog['xwin'].unit = 'pixel' image.catalog['xwin'].description = 'Windowed X coordinate of the object' image.catalog['ywin'].unit = 'pixel' image.catalog['ywin'].description = 'Windowed Y coordinate of the object' image.catalog['xpeak'].unit = 'pixel' image.catalog['xpeak'].description = 'X coordinate of the peak' image.catalog['ypeak'].unit = 'pixel' image.catalog['ypeak'].description = 'Windowed Y coordinate of the peak' image.catalog['flux'].unit = 'counts' image.catalog['flux'].description = 'Flux within a Kron-like elliptical aperture' image.catalog['fluxerr'].unit = 'counts' image.catalog['fluxerr'].description = 'Error on the flux within Kron aperture' image.catalog['peak'].unit = 'counts' image.catalog['peak'].description = 'Peak flux (flux at xpeak, ypeak)' for diameter in [1, 2, 3, 4, 5, 6]: image.catalog['fluxaper{0}'.format(diameter)].unit = 'counts' image.catalog['fluxaper{0}'.format(diameter)].description = 'Flux from fixed circular aperture: {0}" diameter'.format(diameter) image.catalog['fluxerr{0}'.format(diameter)].unit = 'counts' image.catalog['fluxerr{0}'.format(diameter)].description = 'Error on Flux from circular aperture: {0}"'.format(diameter) image.catalog['background'].unit = 'counts' image.catalog['background'].description = 'Average background value in the aperture' image.catalog['fwhm'].unit = 'pixel' image.catalog['fwhm'].description = 'FWHM of the object' image.catalog['a'].unit = 'pixel' image.catalog['a'].description = 'Semi-major axis of the object' image.catalog['b'].unit = 'pixel' image.catalog['b'].description = 'Semi-minor axis of the object' image.catalog['theta'].unit = 'degrees' image.catalog['theta'].description = 'Position angle of the object' image.catalog['kronrad'].unit = 'pixel' image.catalog['kronrad'].description = 'Kron radius used for extraction' image.catalog['ellipticity'].description = 'Ellipticity' image.catalog['fluxrad25'].unit = 'pixel' image.catalog['fluxrad25'].description = 'Radius containing 25% of the flux' image.catalog['fluxrad50'].unit = 'pixel' image.catalog['fluxrad50'].description = 'Radius containing 50% of the flux' image.catalog['fluxrad75'].unit = 'pixel' image.catalog['fluxrad75'].description = 'Radius containing 75% of the flux' image.catalog['x2'].unit = 'pixel^2' image.catalog['x2'].description = 'Variance on X coordinate of the object' image.catalog['y2'].unit = 'pixel^2' image.catalog['y2'].description = 'Variance on Y coordinate of the object' image.catalog['xy'].unit = 'pixel^2' image.catalog['xy'].description = 'XY covariance of the object' image.catalog['flag'].description = 'Bit mask of extraction/photometry flags' image.catalog.sort('flux') image.catalog.reverse() logging_tags = logs.image_config_to_tags(image, self.group_by_keywords) logs.add_tag(logging_tags, 'filename', os.path.basename(image.filename)) # Save some background statistics in the header mean_background = stats.sigma_clipped_mean(bkg.back(), 5.0) image.header['L1MEAN'] = (mean_background, '[counts] Sigma clipped mean of frame background') logs.add_tag(logging_tags, 'L1MEAN', float(mean_background)) median_background = np.median(bkg.back()) image.header['L1MEDIAN'] = (median_background, '[counts] Median of frame background') logs.add_tag(logging_tags, 'L1MEDIAN', float(median_background)) std_background = stats.robust_standard_deviation(bkg.back()) image.header['L1SIGMA'] = (std_background, '[counts] Robust std dev of frame background') logs.add_tag(logging_tags, 'L1SIGMA', float(std_background)) # Save some image statistics to the header good_objects = image.catalog['flag'] == 0 seeing = np.median(image.catalog['fwhm'][good_objects]) * image.pixel_scale image.header['L1FWHM'] = (seeing, '[arcsec] Frame FWHM in arcsec') logs.add_tag(logging_tags, 'L1FWHM', float(seeing)) mean_ellipticity = stats.sigma_clipped_mean(sources['ellipticity'][good_objects], 3.0) image.header['L1ELLIP'] = (mean_ellipticity, 'Mean image ellipticity (1-B/A)') logs.add_tag(logging_tags, 'L1ELLIP', float(mean_ellipticity)) mean_position_angle = stats.sigma_clipped_mean(sources['theta'][good_objects], 3.0) image.header['L1ELLIPA'] = (mean_position_angle, '[deg] PA of mean image ellipticity') logs.add_tag(logging_tags, 'L1ELLIPA', float(mean_position_angle)) self.logger.info('Extracted sources', extra=logging_tags) except Exception as e: logging_tags = logs.image_config_to_tags(image, self.group_by_keywords) logs.add_tag(logging_tags, 'filename', os.path.basename(image.filename)) self.logger.error(e, extra=logging_tags) return images
def aperture_photometry(data, objects, radii): #TODO aperture corrected flux: take the ratio of the Flux in the bigger to the flux in the smaller, average them to find the correction, then multiply each of the smaller fluxes to the correction. Do the same thing for errors. Depending on what you set your GAIN to be, this is either background only or background and Poisson. If GAIN is set to 0 its only background error. http://www.galex.caltech.edu/researcher/techdoc-ch5.html Or you could use the apertures in Figure 1... The value for the correction shouldn't change much for GALEX since the PSF doesn't change across the CCDs. flux_min, fluxerr_min, flag_min = sep.sum_circle(data, objects[0], objects[1], min(radii)) flux_max, fluxerr_max, flag_max = sep.sum_circle(data, objects[0], objects[1], max(radii)) return flux_min
def test_vs_sextractor(): data = np.copy(image_data) # make an explicit copy so we can 'subfrom' bkg = sep.Background(data, bw=64, bh=64, fw=3, fh=3) # Test that SExtractor background is same as SEP: bkgarr = bkg.back(dtype=np.float32) assert_allclose(bkgarr, image_refback, rtol=1.e-5) # Extract objects bkg.subfrom(data) objs = sep.extract(data, 1.5*bkg.globalrms) objs = np.sort(objs, order=['y']) # Read SExtractor result refobjs = np.loadtxt(IMAGECAT_FNAME, dtype=IMAGECAT_DTYPE) refobjs = np.sort(refobjs, order=['y']) # Found correct number of sources at the right locations? assert_allclose(objs['x'], refobjs['x'] - 1., atol=1.e-3) assert_allclose(objs['y'], refobjs['y'] - 1., atol=1.e-3) # Test aperture flux flux, fluxerr, flag = sep.sum_circle(data, objs['x'], objs['y'], 5., err=bkg.globalrms) assert_allclose(flux, refobjs['flux_aper'], rtol=2.e-4) assert_allclose(fluxerr, refobjs['fluxerr_aper'], rtol=1.0e-5) # check if the flags work at all (comparison values assert ((flag & sep.APER_TRUNC) != 0).sum() == 4 assert ((flag & sep.APER_HASMASKED) != 0).sum() == 0 # Test "flux_auto" kr, flag = sep.kron_radius(data, objs['x'], objs['y'], objs['a'], objs['b'], objs['theta'], 6.0) flux, fluxerr, flag = sep.sum_ellipse(data, objs['x'], objs['y'], objs['a'], objs['b'], objs['theta'], r=2.5 * kr, err=bkg.globalrms, subpix=1) # For some reason, object at index 59 doesn't match. It's very small # and kron_radius is set to 0.0 in SExtractor, but 0.08 in sep. # Most of the other values are within 1e-4 except one which is only # within 0.01. This might be due to a change in SExtractor between # v2.8.6 (used to generate "truth" catalog) and v2.18.11. kr[59] = 0.0 flux[59] = 0.0 fluxerr[59] = 0.0 assert_allclose(2.5*kr, refobjs['kron_radius'], rtol=0.01) assert_allclose(flux, refobjs['flux_auto'], rtol=0.01) assert_allclose(fluxerr, refobjs['fluxerr_auto'], rtol=0.01) # Test ellipse representation conversion cxx, cyy, cxy = sep.ellipse_coeffs(objs['a'], objs['b'], objs['theta']) assert_allclose(cxx, objs['cxx'], rtol=1.e-4) assert_allclose(cyy, objs['cyy'], rtol=1.e-4) assert_allclose(cxy, objs['cxy'], rtol=1.e-4) a, b, theta = sep.ellipse_axes(objs['cxx'], objs['cyy'], objs['cxy']) assert_allclose(a, objs['a'], rtol=1.e-4) assert_allclose(b, objs['b'], rtol=1.e-4) assert_allclose(theta, objs['theta'], rtol=1.e-4) #test round trip cxx, cyy, cxy = sep.ellipse_coeffs(a, b, theta) assert_allclose(cxx, objs['cxx'], rtol=1.e-4) assert_allclose(cyy, objs['cyy'], rtol=1.e-4) assert_allclose(cxy, objs['cxy'], rtol=1.e-4) # test flux_radius fr, flags = sep.flux_radius(data, objs['x'], objs['y'], 6.*refobjs['a'], [0.1, 0.5, 0.6], normflux=refobjs['flux_auto'], subpix=5) assert_allclose(fr, refobjs["flux_radius"], rtol=0.04, atol=0.01) # test winpos sig = 2. / 2.35 * fr[:, 1] # flux_radius = 0.5 xwin, ywin, flag = sep.winpos(data, objs['x'], objs['y'], sig) assert_allclose(xwin, refobjs["xwin"] - 1., rtol=0., atol=0.0025) assert_allclose(ywin, refobjs["ywin"] - 1., rtol=0., atol=0.0025)
def alma_source(): """ Model a source detected in alma """ import grizli.utils # ALMA source if False: # zero-out nearby object ix = np.where(ids == 1019)[0][0] _xx = _x[0] _xx[Nbg + ix] = 0 h_model2 = _Af.T.dot(_xx).reshape(h_sm.shape) full_model = irac_im.data * 0 full_model[isly, islx] += h_model2 pyfits.writeto('{0}-ch{1}_model.fits'.format(root, ch), data=full_model, header=irac_im.header, overwrite=True) ######### import sep rg, dg = 205.5360413, 9.478936196 rq, dq = 205.5337798, 9.477328082 rr, dd = rg, dg phot = grizli.utils.read_catalog( '{0}irac_phot_apcorr.fits'.format(root)) irac_im = pyfits.open('{0}-ch{1}_drz_sci.fits'.format(root, ch))[0] irac_wht = pyfits.open('{0}-ch{1}_drz_wht.fits'.format(root, ch))[0].data irac_wcs = pywcs.WCS(irac_im.header) full_model = pyfits.open('{0}-ch1_model.fits'.format(root))[0].data irac_psf, psf_nexp = irac.evaluate_irac_psf(ch=ch, scale=0.1, ra=rg, dec=dg) xy_ap = irac_wcs.all_world2pix(np.array([[rg, dg]]), 0).T apers = np.append(4, np.arange(2, 10.1, 0.5)) _res = sep.sum_circle(irac_im.data - full_model, xy_ap[0], xy_ap[1], apers, var=1 / irac_wht) sh_psf = irac_psf.shape _res_psf = sep.sum_circle(irac_psf, [sh_psf[1] // 2 - 1], [sh_psf[0] // 2 - 1], apers * 5, var=irac_psf * 0. + 1) ch1_flux = (_res[0] / _res_psf[0])[0] ch1_err = (_res[1] / _res_psf[0])[0] parent = ['ch1'] wave = [3.6] fnu = [1.7927988] fnu_sum = [1.7927988] efnu = [0.2448046] pixscale = [0.5] parent += ['ch2'] wave += [4.5] fnu += [3.060] fnu_sum += [3.06] efnu += [0.3203] pixscale += [0.5] width = [0.25] * 2 alm = grizli.utils.read_catalog('alma.info', format='ascii') alm['wave'] = 2.99e8 / alm['CRVAL3'] / 1.e-6 * u.micron alm['wave'].format = '.1f' # ALMA images files = glob.glob('ALMA/*spw2?.mfs*fits') files += glob.glob('ALMA/*spw??_*fits') files.sort() for file in files: print(file) alma = pyfits.open(file) alma_wcs = pywcs.WCS(alma[0].header) pscale = np.abs(alma_wcs.wcs.cdelt[0] * 3600.) alma_xy = alma_wcs.all_world2pix(np.array([[rr, dd, 0, 0]]), 0).flatten() yp, xp = np.indices(np.squeeze(alma[0].data).shape) R = np.sqrt((xp - alma_xy[0])**2 + (yp - alma_xy[1])**2) < 1.3 / pscale R &= np.isfinite(np.squeeze(alma[0].data)) fnu.append(np.squeeze(alma[0].data)[R].max() * 1.e6) fnu_sum.append(np.squeeze(alma[0].data)[R].sum() * 1.e6) wave.append(2.999e8 / alma[0].header['CRVAL3'] * 1.e6) width.append(alma[0].header['CDELT3'] / alma[0].header['CRVAL3'] * wave[-1]) parent.append(file) msk = np.isfinite(alma[0].data) efnu.append(grizli.utils.nmad(alma[0].data[msk]) * 1.e6) pixscale.append(pscale) plt.errorbar(wave, fnu, xerr=width, yerr=efnu, marker='o', alpha=0.5, linestyle='None', color='k') #plt.scatter(wave, fnu, c=np.log10(np.array(width)/np.array(wave)), marker='o', alpha=0.8, zorder=100, cmap='plasma_r') #plt.errorbar(wave, fnu_sum, efnu, marker='o', alpha=0.1, linestyle='None') plt.xlabel(r'$\lambda_\mathrm{obs}$, $\mu\mathrm{m}$') plt.ylabel(r'flux, $\mu$Jy') plt.loglog() width_lim = [0.1] * 3 wave_lim = [1.25, 1.05, 0.81] efnu_lim = [ np.median(phot['f{0}w_etot_1'.format(b)][ phot['f{0}w_etot_1'.format(b)] > 0]) for b in ['125', '105', '814'] ] np.random.seed(3) fnu_lim = list(np.random.normal(size=3) * np.array(efnu_lim)) plt.errorbar(wlim, fnu_lim, efnu_lim, marker='v', alpha=0.5, linestyle='None', color='k') parent_lim = ['f125w_limit', 'f105w_limit', 'f814w_limit'] tab = grizli.utils.GTable() tab['wave'] = wave + wave_lim tab['wave'].unit = u.micron tab['dw'] = width + width_lim tab['dw'].unit = u.micron tab['fnu'] = fnu + fnu_lim tab['fnu'].unit = u.microJansky tab['efnu'] = efnu + efnu_lim tab['efnu'].unit = u.microJansky tab['parent'] = parent + parent_lim tab.meta['RA'] = (rg, 'Target RA') tab.meta['DEC'] = (dg, 'Target Dec') tab.meta['TIME'] = (time.ctime(), 'Timestamp of file generation') tab['wave'].format = '.1f' tab['dw'].format = '.1f' for c in tab.colnames: if 'fnu' in c: tab[c].format = '.3f' jname = grizli.utils.radec_to_targname( ra=rg, dec=dg, round_arcsec=(0.01, 0.01 * 15), precision=2, targstr='j{rah}{ram}{ras}.{rass}{sign}{ded}{dem}{des}.{dess}', header=None) so = np.argsort(tab['wave']) tab[so].write('alma_serendip_{0}.fits'.format(jname), overwrite=True) tab[so].write('alma_serendip_{0}.ipac'.format(jname), format='ascii.ipac', overwrite=True) if False: plt.scatter( 1.25, 3 * np.median(phot['f125w_etot_1'][phot['f125w_etot_1'] > 0]), marker='v', color='k', alpha=0.8) plt.scatter( 1.05, 3 * np.median(phot['f105w_etot_1'][phot['f105w_etot_1'] > 0]), marker='v', color='k', alpha=0.8) plt.scatter( 0.81, 3 * np.median(phot['f814w_etot_1'][phot['f814w_etot_1'] > 0]), marker='v', color='k', alpha=0.8) plt.xlim(0.4, 5000) plt.ylim(01.e-5, 1.e4) plt.gca().set_yticks(10**np.arange(-5, 4.1)) plt.grid() ### FSPS import fsps import astropy.constants as const import astropy.units as u from astropy.cosmology import Planck15 try: print(sp.params['dust2']) except: sp = fsps.StellarPopulation(zcontinuous=True, dust_type=2, sfh=4, tau=0.1) dust2 = 6 z = 1.5 tage = 0.2 sp.params['dust2'] = dust2 sp.params['add_neb_emission'] = True wsp, flux = sp.get_spectrum(tage=tage, peraa=False) flux = (flux / (1 + z) * const.L_sun).to(u.erg / u.s).value * 1.e23 * 1.e6 dL = Planck15.luminosity_distance(z).to(u.cm).value flux /= 4 * np.pi * dL**2 yi = np.interp(3.6e4, wsp * (1 + z), flux) label = 'z={0:.1f} tage={1:.1f}'.format( z, tage) + '\n' + 'dust2={0:.1f}, logM={1:.1f} SFR={2:.1f}'.format( dust2, np.log10(sp.stellar_mass * fnu[0] / yi), sp.sfr_avg() * fnu[0] / yi) plt.plot(wsp * (1 + z) / 1.e4, flux / yi * fnu[0], alpha=0.6, zorder=-1, label=label) plt.legend() plt.tight_layout() plt.savefig('alma_serendip_{0}.pdf'.format(jname)) # Cubes alma = pyfits.open( 'ALMA/member.uid___A001_X1296_X96a.Pisco_sci.spw27.cube.I.pbcor.fits' ) cube_files = glob.glob('ALMA/*cube*fits') cube_files.sort() alma = pyfits.open(cube_files[ci]) alma_wcs = pywcs.WCS(alma[0].header) pscale = np.abs(alma_wcs.wcs.cdelt[0] * 3600.) alma_xy = alma_wcs.all_world2pix(np.array([[rr, dd, 0, 0]]), 0).flatten() yp, xp = np.indices(alma[0].data[0, 0, :, :].shape) R = np.sqrt((xp - alma_xy[0])**2 + (yp - alma_xy[1])**2) < 0.5 / pscale fin = np.isfinite(alma[0].data) alma[0].data[~fin] = 0 clip = alma[0].data[0, :, :] * R fnu_max = clip.max(axis=1).max(axis=1) freq = (np.arange(alma_wcs._naxis[2]) + 1 - alma_wcs.wcs.crpix[2] ) * alma_wcs.wcs.cdelt[2] + alma_wcs.wcs.crval[2] dv = np.gradient(freq) / freq * 3.e5 ng = 20. / np.median(dv) sm = nd.gaussian_filter(fnu_max, ng) plt.plot(freq / 1.e9, sm) plt.plot(freq / 1.e9, fnu_max, color='k', alpha=0.1) if False: # candidate ix = ids == 588 coeffs = _x[0] * (~ix) h_m2 = _A.T.dot(coeffs).reshape(h_sm.shape) ds9.frame(16) ds9.view(irac_im.data[isly, islx] - h_m2, header=utils.get_wcs_slice_header(irac_wcs, islx, isly))
def test_vs_sextractor(): """Test behavior of sep versus sextractor. Note: we turn deblending off for this test. This is because the deblending algorithm uses a random number generator. Since the sequence of random numbers is not the same between sextractor and sep or between different platforms, object member pixels (and even the number of objects) can differ when deblending is on. Deblending is turned off by setting DEBLEND_MINCONT=1.0 in the sextractor configuration file and by setting deblend_cont=1.0 in sep.extract(). """ data = np.copy(image_data) # make an explicit copy so we can 'subfrom' bkg = sep.Background(data, bw=64, bh=64, fw=3, fh=3) # Test that SExtractor background is same as SEP: bkgarr = bkg.back(dtype=np.float32) assert_allclose(bkgarr, image_refback, rtol=1.e-5) # Extract objects (use deblend_cont=1.0 to disable deblending). bkg.subfrom(data) objs = sep.extract(data, 1.5*bkg.globalrms, deblend_cont=1.0) objs = np.sort(objs, order=['y']) # Read SExtractor result refobjs = np.loadtxt(IMAGECAT_FNAME, dtype=IMAGECAT_DTYPE) refobjs = np.sort(refobjs, order=['y']) # Found correct number of sources at the right locations? assert_allclose(objs['x'], refobjs['x'] - 1., atol=1.e-3) assert_allclose(objs['y'], refobjs['y'] - 1., atol=1.e-3) # Test aperture flux flux, fluxerr, flag = sep.sum_circle(data, objs['x'], objs['y'], 5., err=bkg.globalrms) assert_allclose(flux, refobjs['flux_aper'], rtol=2.e-4) assert_allclose(fluxerr, refobjs['fluxerr_aper'], rtol=1.0e-5) # check if the flags work at all (comparison values assert ((flag & sep.APER_TRUNC) != 0).sum() == 4 assert ((flag & sep.APER_HASMASKED) != 0).sum() == 0 # Test "flux_auto" kr, flag = sep.kron_radius(data, objs['x'], objs['y'], objs['a'], objs['b'], objs['theta'], 6.0) flux, fluxerr, flag = sep.sum_ellipse(data, objs['x'], objs['y'], objs['a'], objs['b'], objs['theta'], r=2.5 * kr, err=bkg.globalrms, subpix=1) # For some reason, one object doesn't match. It's very small # and kron_radius is set to 0.0 in SExtractor, but 0.08 in sep. # Could be due to a change in SExtractor between v2.8.6 (used to # generate "truth" catalog) and v2.18.11 (from which sep was forked). i = 56 # index is 59 when deblending is on. kr[i] = 0.0 flux[i] = 0.0 fluxerr[i] = 0.0 # We use atol for radius because it is reported to nearest 0.01 in # reference objects. assert_allclose(2.5*kr, refobjs['kron_radius'], atol=0.01, rtol=0.) assert_allclose(flux, refobjs['flux_auto'], rtol=0.0005) assert_allclose(fluxerr, refobjs['fluxerr_auto'], rtol=0.0005) # Test ellipse representation conversion cxx, cyy, cxy = sep.ellipse_coeffs(objs['a'], objs['b'], objs['theta']) assert_allclose(cxx, objs['cxx'], rtol=1.e-4) assert_allclose(cyy, objs['cyy'], rtol=1.e-4) assert_allclose(cxy, objs['cxy'], rtol=1.e-4) a, b, theta = sep.ellipse_axes(objs['cxx'], objs['cyy'], objs['cxy']) assert_allclose(a, objs['a'], rtol=1.e-4) assert_allclose(b, objs['b'], rtol=1.e-4) assert_allclose(theta, objs['theta'], rtol=1.e-4) #test round trip cxx, cyy, cxy = sep.ellipse_coeffs(a, b, theta) assert_allclose(cxx, objs['cxx'], rtol=1.e-4) assert_allclose(cyy, objs['cyy'], rtol=1.e-4) assert_allclose(cxy, objs['cxy'], rtol=1.e-4) # test flux_radius fr, flags = sep.flux_radius(data, objs['x'], objs['y'], 6.*refobjs['a'], [0.1, 0.5, 0.6], normflux=refobjs['flux_auto'], subpix=5) assert_allclose(fr, refobjs["flux_radius"], rtol=0.04, atol=0.01) # test winpos sig = 2. / 2.35 * fr[:, 1] # flux_radius = 0.5 xwin, ywin, flag = sep.winpos(data, objs['x'], objs['y'], sig) assert_allclose(xwin, refobjs["xwin"] - 1., rtol=0., atol=0.0025) assert_allclose(ywin, refobjs["ywin"] - 1., rtol=0., atol=0.0025)
def get_sources(img_data, dqmask_data=None, wtmap_data=None, exptime=None, sex_params={}, objects=None, subtract_bkg=False, gain=None, wcs=None, aper_radius=None, windowed=True, edge_val=1, origin=0, transform='wcs'): """ Load sources from an image and if a data quality mask is provided, included a bitmap of flags in the output catalog. This using SEP to detect sources using SExtractor functions (unless an input catalog is provided) and by default calculates the windowed position (see SExtractor or SEP docs for more details). Parameters ---------- img_data: array-like Image to use for search dqmask_data: array-like, optional Data quality mask array. If this is included the output catalog will include a ``flags`` column that gives a binary flag for bad pixels in the image. wtmap: array-like, optional Not currently implemented exptime: float, optional Exposure time. If ``exptime`` is not given, then no magnitudes will be calculated sex_params: dict, optional Dictionary of SExtractor parameters to pass to the `~sep.extract` function. objects: `~astropy.table.Table`, optional If a catalog of sources has already been generated, SExtraction will be skipped and the input catalog will be used for aperture photometry. The input catalog must contain a list of sources either ``ra,dec`` or ``x,y`` as columns. subtract_bkg: bool, optional Whether or not to subtract the background gain: float, optional Gain of the detector, used to calculate the magnitude error wcs: `~astropy.wcs.WCS`, optional World coordinates to calculate RA,DEC from image X,Y. If ``wcs`` is not given then the output catalog will only contain cartesian coordinates for each source. aper_radius: int, optional Radius of the aperture to use for photometry. If no ``aperture_radius`` is specified, only the Kron flux will be included in the final catalog windowed: bool, optional Whether or not to use SExtractors window algorithm to calculate a more precise position. *Default=True* edge_val: integer Value to use for pixels outside the edge of the image transform: string, optional Type of transform to use. Either 'wcs','sip', or 'all'. *Default=wcs* """ import sep # Estimate the background and subtract it (in place) from the image # Note: we might not need to do background subtraction due to the # community pipeline bkg = sep.Background(img_data, dqmask_data) if subtract_bkg: bkg.subfrom(img_data) bkg = sep.Background(img_data, dqmask_data) # Find the objects if objects is None: if 'extract' not in sex_params: sex_params['extract'] = {'thresh': 1.5*bkg.globalrms} if 'thresh' not in sex_params['extract']: if 'thresh' in sex_params: sex_params['extract']['thresh'] = \ sex_params['thresh']*bkg.globalrms else: raise Exception( "You must provide a threshold parameter" " for source extraction") sources = sep.extract(img_data, **sex_params['extract']) objects = table.Table(sources) # Remove sources with a>>b (usually cosmic rays) #objects = objects[objects['a']<objects['b']*5] # Set WCS or X, Y if necessary if wcs is not None: if transform=='wcs': transform_method = wcs.wcs_pix2world elif transform=='all': transform_method = wcs.all_pix2world elif transform=='sip': transform_method = wcs.sip_pix2foc if 'ra' not in objects.columns.keys() and wcs is not None: objects['ra'], objects['dec'] = transform_method( objects['x'], objects['y'], 0) if 'x' not in objects.columns.keys(): if wcs is None: raise Exception("You must provide a wcs transformation if " "specifying ra and dec") objects['x'], objects['y'] = wcs.all_world2pix( objects['ra'], objects['dec'], 0) if windowed: logger.info("using kron to get windowed positions") objects['xwin'], objects['ywin'] = get_winpos( img_data, objects['x'], objects['y'], objects['a']) if wcs is not None: objects['rawin'], objects['decwin'] = transform_method( objects['xwin'], objects['ywin'],0) # Calculate aperture flux if aper_radius is not None: objects['aper_radius'] = aper_radius flux, flux_err, flag = sep.sum_circle( img_data, objects['x'], objects['y'], aper_radius, gain=gain) objects['aper_flux'] = flux objects['aper_flux_err'] = flux_err objects['aper_flag'] = flag objects['aper_mag'] = -2.5*np.log10(objects['aper_flux']/exptime) if gain is not None: objects['aper_mag_err'] = 1.0857*np.sqrt( 2*np.pi*aper_radius**2*bkg.globalrms**2+ objects['aper_flux']/gain)/objects['aper_flux'] else: objects['aper_mag_err'] = 1.0857*np.sqrt( 2*np.pi*aper_radius**2*bkg.globalrms**2)/objects['aper_flux'] # Get the pipeline flags for the image if dqmask_data is not None: objects['flags'] = get_img_flags(dqmask_data, objects['x'], objects['y'], (2*aper_radius+1, 2*aper_radius+1), edge_val) # Calculate the positional error # See SExtractor Documentation for more on # ERRX2 and ERRY2 # Ignore for now since this is very computationally # expensive with little to gain if False: back_data = bkg.back() err_x = np.zeros((len(objects,)), dtype=float) err_y = np.zeros((len(objects,)), dtype=float) err_xy = np.zeros((len(objects,)), dtype=float) for n, src in enumerate(objects): X = np.linspace(src['x']-aper_radius, src['x']+aper_radius, 2*aper_radius+1) Y = np.linspace(src['y']-aper_radius, src['y']+aper_radius, 2*aper_radius+1) X,Y = np.meshgrid(X,Y) flux = extract_array(img_data, (2*aper_radius+1, 2*aper_radius+1), (src['y'], src['x'])) back = extract_array(back_data, (2*aper_radius+1, 2*aper_radius+1), (src['y'], src['x'])) if gain is not None and gain > 0: sigma2 = back**2 + flux/gain else: sigma2 = back**2 flux2 = np.sum(flux)**2 err_x[n] = np.sum(sigma2*(X-src['x'])**2)/flux2 err_y[n] = np.sum(sigma2*(Y-src['y'])**2)/flux2 err_xy[n] = np.sum(sigma2*(X-src['x'])*(Y-src['y']))/flux2 objects['ERRX2'] = err_x objects['ERRY2'] = err_y objects['ERRXY'] = err_xy # include an index for each source that might be useful later on in # post processing objects['src_idx'] = [n for n in range(len(objects))] return objects, bkg
bkg = sep.Background(data) #calculate the background #Set a detection threshold for stars to be 1.5x RMS of background thresh = 1.5 * bkg.globalrms #Find all objects that are above threshold in a frame which is the background subtracted data objects = sep.extract(data - bkg.back(), thresh) #Table with list of object coords and fluxes stars = Table([objects['x'], objects['y'], objects['flux']], names=['x', 'y', 'sepflux']) #Do the sky subtraction using the average for the frame #data_sub = sky subtracted data fluxes, fluxerrs, flag = sep.sum_circle((data - bkg), stars['x'], stars['y'], aper, err=bkg.globalrms, gain=gain) #Do sky subtraction using annuli #fluxes, fluxerrs, flag = sep.sum_circle( data, stars['x'], stars['y'], aper, err=bkg.globalrms, gain=gain, bkgann=(ann_in_pix,ann_out_pix) ) #Add fluxes and uncertainties to table stars.add_column(Column(fluxes, name='flux')) stars.add_column(Column(fluxerrs, name='flux_err')) #Calculate instrumental magnitudes expt = float(obj['Exp_time']) mags = [ -2.5 * math.log10(line / expt) if line > 0 else float('nan') for line in fluxes
def check_photometry(frames, sf_data, seeing_fwhm, step=0, border=300, extinction=0.0, check_photometry_levels=[0.5, 0.8], check_photometry_actions=['warn', 'warn', 'default'], figure=None): # Check photometry of few objects weigthmap = 'weights4rms.fits' wmap = numpy.ones_like(sf_data[0], dtype='bool') # Center of the image wmap[border:-border, border:-border] = 0 # fits.writeto(weigthmap, wmap.astype('uintt8'), overwrite=True) basename = 'result_i%0d.fits' % (step) data_res = fits.getdata(basename) data_res = data_res.byteswap().newbyteorder() bkg = sep.Background(data_res) data_sub = data_res - bkg _logger.info('Runing source extraction tor in %s', basename) objects = sep.extract(data_sub, 1.5, err=bkg.globalrms, mask=wmap) # if seeing_fwhm is not None: # sex.config['SEEING_FWHM'] = seeing_fwhm * sex.config['PIXEL_SCALE'] # sex.config['PARAMETERS_LIST'].append('CLASS_STAR') # sex.config['CATALOG_NAME'] = 'master-catalogue-i%01d.cat' % step LIMIT_AREA = 5000 idx_small = objects['npix'] < LIMIT_AREA objects_small = objects[idx_small] NKEEP = 15 idx_flux = objects_small['flux'].argsort() objects_nth = objects_small[idx_flux][-NKEEP:] # set of indices of the N first objects fluxes = [] errors = [] times = [] airmasses = [] for idx, frame in enumerate(frames): imagename = name_skysub_proc(frame.baselabel, step) #sex.config['CATALOG_NAME'] = ('catalogue-%s-i%01d.cat' % # (frame.baselabel, step)) # Lauch SExtractor on a FITS file # om double image mode _logger.info('Runing sextractor in %s', imagename) with fits.open(imagename) as hdul: header = hdul[0].header airmasses.append(header['airmass']) times.append(header['tstamp']) data_i = hdul[0].data data_i = data_i.byteswap().newbyteorder() bkg_i = sep.Background(data_i) data_sub_i = data_i - bkg_i # objects_i = sep.extract(data_sub_i, 1.5, err=bkg_i.globalrms, mask=wmap) flux_i, fluxerr_i, flag_i = sep.sum_circle(data_sub_i, objects_nth['x'], objects_nth['y'], 3.0, err=bkg_i.globalrms) # Extinction correction excor = pow(10, -0.4 * frame.airmass * extinction) flux_i = excor * flux_i fluxerr_i = excor * fluxerr_i fluxes.append(flux_i) errors.append(fluxerr_i) fluxes_a = numpy.array(fluxes) errors_a = numpy.array(errors) fluxes_n = fluxes_a / fluxes_a[0] errors_a = errors_a / fluxes_a[0] # sigma w = 1.0 / (errors_a) ** 2 # weighted mean of the flux values wdata = numpy.average(fluxes_n, axis=1, weights=w) wsigma = 1 / numpy.sqrt(w.sum(axis=1)) levels = check_photometry_levels actions = check_photometry_actions x = list(six.moves.range(len(frames))) vals, (_, sigma) = check_photometry_categorize( x, wdata, levels, tags=actions) # n sigma level to plt nsig = 3 if True: figure = plt.figure() ax = figure.add_subplot(111) plot_photometry_check(ax, vals, wsigma, check_photometry_levels, nsig * sigma) plt.savefig('figure-relative-flux_i%01d.png' % step) for x, _, t in vals: try: action = _dactions[t] except KeyError: _logger.warning('Action named %s not recognized, ignoring', t) action = default_action for p in x: action(frames[p])
def auto_fit(image_data, xpos, ypos): """ Refit algorithm :param image_data: fits image data 2D array {Numpy 2D array} xpos: centered position of the regions on the x axis {integer} ypos: centered position of the region on the y axis {integer} ############################################################## :return: Dictionary of values { radii [Ap] -- Aperture radius {float} an[0] [InAn] -- Inner annulus radius {float} an[1] [OutAn] -- Outer annulus radius {float} radii_disagree [disagree] -- The difference between the directly returned radius from SEP and the radius from SEP flux sums {float} } """ an_width = 18 # defines annulus width | TODO Make this a free parameter in the auto fit function temp_image_data = image_data # creates non mutable version of array internally internal_image_data = temp_image_data.byteswap(True).newbyteorder() # SEP requires that data be byte swaped bkg = sep.Background(internal_image_data) thresh = 1.5 * bkg.globalback objects = sep.extract(internal_image_data, thresh) center_x = internal_image_data.shape[0]/2.0 center_y = internal_image_data.shape[1]/2.0 center = [center_x, center_y] smallest_dFoc = 1000000000 # big distance so it can only go down radii = 21 radii_sep = 21 sdev = np.std(internal_image_data) count = 0 # Finds radius of center target from the min and max x and y pixel locations of that target returned from SEP for i, j in zip(objects['x'], objects['y']): pos = [i, j] dFoc = math.sqrt(((pos[0]-center[0])**2) + ((pos[1]-center[1])**2)) if abs(dFoc) < smallest_dFoc: smallest_dFoc = dFoc minx = objects['xmin'][count] miny = objects['ymin'][count] maxx = objects['xmax'][count] maxy = objects['ymax'][count] radii_sep = abs(math.sqrt(((maxx-minx)**2)+((maxy-miny)**2))) else: pass count += 1 i = 1 # Finds optimal inner and outer annulus radii based off SEP flux sums while i < 90: area = (2*np.pi*((i+an_width)**2))-(2*np.pi*(i**2)) flux, fluxerr, flag = sep.sum_circann(internal_image_data, prev_x, prev_y, i, i+an_width) metric = ((flux/area) - bkg.globalback) if i > 1: if metric < smallest_metric: smallest_metric = metric annulus = [i, i+an_width] else: smallest_metric = metric annulus = [i, i+an_width] i += 1 i = 1 # Finds radius of center target using SEP flux sums while i < 90: area = 2*np.pi*(i**2) flux, fluxerr, flag = sep.sum_circle(internal_image_data, prev_x, prev_y, i) flux = sum(flux) metric = flux/area if metric > sdev + bkg.globalback: radii = i i += 1 # used more pixels an = [math.ceil(x) for x in annulus] # sanity checks for size if radii > an[0]: radii = an[0] - 0.5 if radii > 30: radii = 30 else: pass if an[0] > an[1]: an[0] = an[1] - 0.1 * an[1] radii_disagree = abs(radii-radii_sep) return {'Ap': radii, 'InAn': an[0], 'OutAn': an[1], 'disagree': radii_disagree}
def im_phot(directory,gain,im_file,aperture): """ Perform photometry on the image """ # Read in fits image file and create array with wcs coordinates os.chdir(directory) hdulist = fits.open(im_file) w = WCS(im_file) data = hdulist[0].data data[np.isnan(data)] = 0 hdulist.close() # Calculate center point of image (RA, Dec) if not input by user targetra, targetdec = w.all_pix2world(len(data[:,0])/2,len(data[0,:])/2,0) # Use SEP for background subtraction and source detection datasw = data.byteswap().newbyteorder().astype('float64') bkg = sep.Background(datasw) data_bgs = data - bkg data_bgs[data_bgs < 0] = 0 mean = np.mean(data_bgs) median = np.median(data_bgs) std = bkg.globalrms objects = sep.extract(data_bgs,3,err=bkg.globalrms) objra, objdec = w.all_pix2world(objects['x'],objects['y'],0) # Find dummy magnitudes using aperture photometry and plot images fig, ax = plt.subplots() image = plt.imshow(data_bgs,cmap='gray',vmin=(mean-3*std), vmax=(mean+3*std),origin='lower') sepmag = [] sepmagerr = [] ra = [] dec = [] xpixel = [] ypixel = [] for i in range(len(objects)): # Perform circular aperture photometry flux,fluxerr,flag = sep.sum_circle(data_bgs,objects['x'][i], objects['y'][i],aperture,err=std,gain=gain) mag = -2.5*np.log10(flux) maglimit1 = -2.5*np.log10((flux+fluxerr)) maglimit2 = -2.5*np.log10((flux-fluxerr)) magerr1 = np.abs(mag-maglimit1) magerr2 = np.abs(mag-maglimit2) magerr = (magerr1+magerr2)/2 # Save object properties to arrays sepmag.append(mag) sepmagerr.append(magerr) ra.append(objra[i]) dec.append(objdec[i]) xpixel.append(objects['x'][i]) ypixel.append(objects['y'][i]) # Plot the detections on the image out = Circle(xy=(objects['x'][i],objects['y'][i]),radius=aperture) out.set_facecolor('none') out.set_edgecolor('red') ax.add_artist(out) plt.savefig(directory+'detections.png') return targetra,targetdec,sepmag,sepmagerr,ra,dec,xpixel,ypixel
def _measure(self, img, sources, mask=None): logger.info('measuring source parameters') # HACK: issues with numerical precision # must have pi/2 <= theta <= npi/2 sources[np.abs(np.abs(sources['theta']) - np.pi / 2) < 1e-6] = np.pi / 2 for p in ['x', 'y', 'a', 'b', 'theta']: sources = sources[~np.isnan(sources[p])] # calculate "AUTO" parameters kronrad, krflag = sep.kron_radius(img, sources['x'], sources['y'], sources['a'], sources['b'], sources['theta'], 6.0, mask=mask) flux, fluxerr, flag = sep.sum_ellipse(img, sources['x'], sources['y'], sources['a'], sources['b'], sources['theta'], 2.5 * kronrad, subpix=5, mask=mask) flag |= krflag # combine flags into 'flag' sources = sources[~np.isnan(flux)] flux = flux[~np.isnan(flux)] sources = sources[flux > 0] flux = flux[flux > 0] mag_auto = self.zpt - 2.5 * np.log10(flux) r, flag = sep.flux_radius(img, sources['x'], sources['y'], 6. * sources['a'], 0.5, normflux=flux, subpix=5, mask=mask) sources['mag_auto'] = mag_auto sources['flux_auto'] = flux sources['flux_radius'] = r * self.pixscale # approximate fwhm r_squared = sources['a']**2 + sources['b']**2 sources['fwhm'] = 2 * np.sqrt(np.log(2) * r_squared) * self.pixscale q = sources['b'] / sources['a'] area = np.pi * q * sources['flux_radius']**2 sources['mu_ave_auto'] = sources['mag_auto'] + 2.5 * np.log10(2 * area) area_arcsec = np.pi * (self.psf_fwhm / 2)**2 * self.pixscale**2 flux, fluxerr, flag = sep.sum_circle(img, sources['x'], sources['y'], self.psf_fwhm / 2, subpix=5, mask=mask) flux[flux <= 0] = np.nan mu_0 = self.zpt - 2.5 * np.log10(flux / area_arcsec) sources['mu_0_aper'] = mu_0 return sources
def sourcephot(catalogue,image,segmap,detection,instrument='MUSE',dxp=0.,dyp=0., noise=[False],zpab=False, kn=2.5, circap=1.0): """ Get a source catalogue from findsources and a fits image with ZP and compute magnitudes in that filter catalogue -> source cat from findsources image -> fits image with ZP in header segmap -> fits of segmentation map detection -> the detection image, used to compute Kron radius instrument -> if not MUSE, map positions from detection to image dxp,dyp -> shifts in pixel of image to register MUSE and image astrometry noise -> if set to a noise model, use equation noise[0]*noise[1]*npix**noise[2] to compute the error zpab -> if ZPAB (zeropoint AB) not stored in header, must be supplied kn -> factor to be used when scaling Kron apertures [sextractor default 2.5] circap -> radius in arcsec for aperture photmetry to be used when Kron aperture fails """ from astropy.io import fits import numpy as np import sep import matplotlib.pyplot as plt from astropy.table import Table from astropy import wcs #grab root name rname=((image.split('/')[-1]).split('.fits'))[0] print ('Working on {}'.format(rname)) #open the catalogue/fits cat=fits.open(catalogue) img=fits.open(image) seg=fits.open(segmap) det=fits.open(detection) #grab reference wcs from detection image wref=wcs.WCS(det[0].header) psref=wref.pixel_scale_matrix[1,1]*3600. print ('Reference pixel size {}'.format(psref)) #if not handling MUSE, special cases for format of data if('MUSE' not in instrument): #handle instrument cases if('LRIS' in instrument): #data imgdata=img[1].data #place holder for varaince as will use noise model below vardata=imgdata*0+1 vardata=vardata.byteswap(True).newbyteorder() #grab wcs image wimg=wcs.WCS(img[1].header) psimg=wimg.pixel_scale_matrix[1,1]*3600. #store the ZP if(zpab): img[0].header['ZPAB']=zpab else: print 'Instrument not supported!!' exit() else: #for muse, keep eveything the same imgdata=img[0].data vardata=img[1].data psimg=psref #grab flux and var dataflx=np.nan_to_num(imgdata.byteswap(True).newbyteorder()) datavar=np.nan_to_num(vardata.byteswap(True).newbyteorder()) #grab detection and seg mask detflx=np.nan_to_num(det[0].data.byteswap(True).newbyteorder()) #go back to 1d segmask=(np.nan_to_num(seg[0].data.byteswap(True).newbyteorder()))[0,:,:] #if needed, map the segmap to new image with transformation if('MUSE' not in instrument): #allocate space for transformed segmentation map segmasktrans=np.zeros(dataflx.shape) print "Remapping segmentation map to new image..." #loop over original segmap and map to trasformed one #Just use nearest pixel, and keep only 1 when multiple choices for xx in range(segmask.shape[0]): for yy in range(segmask.shape[1]): #go to world radec=wref.wcs_pix2world([[yy,xx]],0) #back to new instrument pixel newxy=wimg.wcs_world2pix(radec,0) #apply shift to register WCS newxy[0][1]=newxy[0][1]+dyp newxy[0][0]=newxy[0][0]+dxp segmasktrans[newxy[0][1],newxy[0][0]]=segmask[xx,yy] #grow buffer as needed by individual instruments #This accounts for resampling to finer pixel size if('LRIS' in instrument): segmasktrans[newxy[0][1]+1,newxy[0][0]+1]=segmask[xx,yy] segmasktrans[newxy[0][1]-1,newxy[0][0]-1]=segmask[xx,yy] segmasktrans[newxy[0][1]+1,newxy[0][0]-1]=segmask[xx,yy] segmasktrans[newxy[0][1]-1,newxy[0][0]+1]=segmask[xx,yy] segmasktrans[newxy[0][1]+1,newxy[0][0]]=segmask[xx,yy] segmasktrans[newxy[0][1]-1,newxy[0][0]]=segmask[xx,yy] segmasktrans[newxy[0][1],newxy[0][0]-1]=segmask[xx,yy] segmasktrans[newxy[0][1],newxy[0][0]+1]=segmask[xx,yy] #dump the transformed segmap for checking hdumain = fits.PrimaryHDU(segmasktrans,header=img[1].header) hdulist = fits.HDUList(hdumain) hdulist.writeto("{}_segremap.fits".format(rname),clobber=True) else: #no transformation needed segmasktrans=segmask #source to extract nsrc=len(cat[1].data) print('Extract photometry for {} sources'.format(nsrc)) phot = Table(names=('ID', 'MAGAP', 'MAGAP_ERR','FXAP', 'FXAP_ERR', 'RAD', 'MAGSEG', 'MAGSEG_ERR', 'FXSEG', 'FXSEG_ERR','ZP'), dtype=('i4','f4','f4','f4','f4','f4','f4','f4','f4','f4','f4')) #create check aperture mask checkaperture=np.zeros(dataflx.shape) print('Computing photometry for objects...') #loop over each source for idobj in range(nsrc): ######### #Find positions etc and transform as appropriate ######### #extract MUSE source paramaters x= cat[1].data['x'][idobj] y= cat[1].data['y'][idobj] a= cat[1].data['a'][idobj] b= cat[1].data['b'][idobj] theta= cat[1].data['theta'][idobj] #compute kron radius on MUSE detection image #Kron rad in units of a,b tmpdata=np.copy(detflx) tmpmask=np.copy(segmask) #mask all other sources to avoid overlaps but keep desired one pixels=np.where(tmpmask == idobj+1) tmpmask[pixels]=0 #compute kron radius [pixel of reference image] kronrad, flg = sep.kron_radius(tmpdata,x,y,a,b,theta,6.0,mask=tmpmask) #plt.imshow(np.log10(tmpdata+1),origin='low') #plt.show() #exit() #now check if size is sensible in units of MUSE data rmin = 2.0 #MUSE pix use_circle = kronrad * np.sqrt(a*b) < rmin #use circular aperture of 2" in muse pixel unit rcircap = circap/psref #now use info to compute photometry and apply #spatial transformation if needed if('MUSE' not in instrument): #map centre of aperture - +1 reference #go to world radec=wref.wcs_pix2world([[x,y]],1) #back to new instrument pixel newxy=wimg.wcs_world2pix(radec,1) #apply shift to register WCS xphot=newxy[0][0]+dxp yphot=newxy[0][1]+dyp #scale radii to new pixel size rminphot=rcircap*psref/psimg aphot=a*psref/psimg bphot=b*psref/psimg #Kron radius in units of a,b else: #for muse, transfer to same units xphot=x yphot=y rminphot=rcircap aphot=a bphot=b ##### #Compute local sky ##### skyreg=kn*kronrad*np.sqrt(aphot*bphot)+15 cutskymask=segmasktrans[yphot-skyreg:yphot+skyreg,xphot-skyreg:xphot+skyreg] cutskydata=dataflx[yphot-skyreg:yphot+skyreg,xphot-skyreg:xphot+skyreg] skymedian=np.nan_to_num(np.median(cutskydata[np.where(cutskymask < 1.0)])) #print skymedian #plt.imshow(cutskymask,origin='low') #plt.show() #if(idobj > 30): # exit() ######### #Now grab the Kron mag computed using detection image ######### #mask all other objects to avoid blending tmpdata=np.copy(dataflx) #apply local sky subtraction tmpdata=tmpdata-skymedian tmpvar=np.copy(datavar) tmpmask=np.copy(segmasktrans) pixels=np.where(tmpmask == idobj+1) tmpmask[pixels]=0 #plt.imshow(tmpmask,origin='low') #plt.show() #exit() #circular aperture if(use_circle): #flux in circular aperture flux_kron, err, flg = sep.sum_circle(tmpdata,xphot,yphot,rminphot,mask=tmpmask) #propagate variance fluxvar, err, flg = sep.sum_circle(tmpvar,xphot,yphot,rminphot,mask=tmpmask) #store Rused in arcsec rused=rminphot*psimg #update check aperture tmpcheckaper=np.zeros(dataflx.shape,dtype=bool) sep.mask_ellipse(tmpcheckaper,xphot,yphot,1.,1.,0.,r=rminphot) checkaperture=checkaperture+tmpcheckaper*(idobj+1) #kron apertures else: #kron flux flux_kron, err, flg = sep.sum_ellipse(tmpdata,xphot, yphot, aphot, bphot, theta, kn*kronrad, mask=tmpmask) #propagate variance fluxvar, err, flg = sep.sum_ellipse(tmpvar,xphot,yphot, aphot, bphot, theta, kn*kronrad, mask=tmpmask) #translate in radius rused=kn*kronrad*psimg*np.sqrt(aphot*bphot) #update check aperture tmpcheckaper=np.zeros(dataflx.shape,dtype=bool) sep.mask_ellipse(tmpcheckaper,xphot,yphot,aphot,bphot,theta,r=kn*kronrad) checkaperture=checkaperture+tmpcheckaper*(idobj+1) #compute error for aperture if(noise[0]): #use model appix=np.where(tmpcheckaper > 0) errflux_kron=noise[0]*noise[1]*len(appix[0])**noise[2] else: #propagate variance errflux_kron=np.sqrt(fluxvar) #go to mag if(flux_kron > 0): mag_aper=-2.5*np.log10(flux_kron)+img[0].header['ZPAB'] errmg_aper=2.5*np.log10(1.+errflux_kron/flux_kron) else: mag_aper=99.0 errmg_aper=99.0 #find out if non detections if(errflux_kron >= flux_kron): errmg_aper=9 mag_aper=-2.5*np.log10(2.*errflux_kron)+img[0].header['ZPAB'] ####### #grab the photometry in the segmentation map ##### #This may not work well for other instruments #if images are not well aligned pixels=np.where(segmasktrans == idobj+1) #add flux in pixels tmpdata=np.copy(dataflx) #apply sky sub tmpdata=tmpdata-skymedian flux_seg=np.sum(tmpdata[pixels]) #compute noise from model or adding variance if(noise[0]): #from model errfx_seg=noise[0]*noise[1]*len(pixels[0])**noise[2] else: #add variance in pixels to compute error errfx_seg=np.sqrt(np.sum(datavar[pixels])) #go to mag with calibrations if(flux_seg > 0): mag_seg=-2.5*np.log10(flux_seg)+img[0].header['ZPAB'] errmg_seg=2.5*np.log10(1.+errfx_seg/flux_seg) else: mag_seg=99.0 errmg_seg=99.0 #find out if non detections if(errfx_seg >= flux_seg): errmg_seg=9 mag_seg=-2.5*np.log10(2.*errfx_seg)+img[0].header['ZPAB'] #stash by id phot.add_row((idobj+1,mag_aper,errmg_aper,flux_kron,errflux_kron,rused,mag_seg,errmg_seg, flux_seg,errfx_seg,img[0].header['ZPAB'])) #dump the aperture check image hdumain = fits.PrimaryHDU(checkaperture,header=img[1].header) hdulist = fits.HDUList(hdumain) hdulist.writeto("{}_aper.fits".format(rname),clobber=True) #close cat.close() img.close() seg.close() det.close() return phot
def get_spec_with_err(redshift, exp_time, phase = 0, gal_flamb = lambda x:0., pixel_scale = 0.075, slice_in_pixels = 2, show_plots = 0, dark_current = 0.01, offset_i = 0, offset_j = 0, mdl = 'hsiao', PSFs = None, photon_count_rates = None, output_dir = "output", othername = "", IFURfl = "IFU_R_Content.txt", min_wave = 6000., max_wave = 20000., zodifl = "aldering.txt", effareafl = "IFU_effective_area_160513.txt", thermalfl = None, source_dir = "input/", read_noise = None, read_noise_floor = 4., aper_rad_fn = None, waves = None, fine_waves = None, restframe_bins = [3000., 4000., 5000., 6000., 8000., 10000., 12000.], obsframe_bins = [7000, 8000., 10200, 12850, 16050, 20000.], TTel = 282., IPC = 0.02, nframe = None, use_R07_noise = False): if hasattr(effareafl, '__call__'): effective_meters2 = effareafl else: effective_meters2 = interpfile(source_dir + "/" + effareafl, bounds_error = False) if hasattr(zodifl, '__call__'): zodi_flamb = zodifl else: zodi_flamb = interpfile(source_dir + "/" + zodifl) #galaxy_flamb = interpfile(source_dir + "/" + "NGC_7591_beta_spec.dat", norm = True) AB_mags = [0., 20., 25.] # AB mags to generate if read_noise == None: read_noise = sqrt(read_noise_floor**2 + 3.* 15.**2. / (exp_time/2.6) ) # Starting model: waves, dwaves = resolution_to_wavelengths(source_dir, IFURfl, min_wave, max_wave, waves) print "waves ", waves.min(), waves.max(), len(waves) if show_plots: savetxt("output/wavelengths.txt", zip(arange(1, len(waves + 1)), waves), fmt = ["%i", "%f"]) if fine_waves == None: fine_waves = arange(3000., 22001., 10.) try: mdl_len = len(mdl) except: mdl_len = 0 if mdl_len == len(waves): f_lamb_SN = mdl f_lamb_SN_fine = interp1d(waves, mdl, bounds_error = False, fill_value = 0)(fine_waves) sntype = "Unknown" mdl = "Unknown" elif glob.glob(source_dir + "/" + mdl) == []: f_lamb_SN, f_lamb_SN_fine, sntype, NA = get_sncosmo(mdl, redshift, waves, fine_waves, phase) else: # Okay. Reading from file. flambfn = interpfile(source_dir + "/" + mdl) mu = None sntype = "NA" f_lamb_SN = flambfn(waves) f_lamb_SN_fine = flambfn(fine_waves) f_lamb_SN_at_max = flambfn(waves) if PSFs == None: PSFs = initialize_PSFs(scales = [int(round(pixel_scale/0.005))]) # For reference: waves, dwaves = resolution_to_wavelengths(source_dir, IFURfl, min_wave, max_wave, waves) oneD_PSFs, PSFs = get_1D_pixelized_sliced_PSFs(PSFs, scale = int(round(pixel_scale/0.005)), waves = waves, IPC = IPC, slice_in_pixels = slice_in_pixels, offset_i = offset_i, offset_j = offset_j) #print "f_lamb_SN ", f_lamb_SN try: plt_root = "%s_z=%.2f_exp=%.1f_ph=%.1f_gal=%.1g_PSF=%s_pxsl=%.3f_slicepix=%i_mdl=%s_type=%s_%s_zodi=%s_offi=%ij=%i_RN=%.1f" % (othername, redshift, exp_time, phase, gal_flamb(15000.), PSFs["PSF_source"], pixel_scale, slice_in_pixels, mdl.split("/")[-1].split(".")[0], sntype, IFURfl.split("/")[-1].split(".")[0], zodifl.split("/")[-1].split(".")[0], offset_i, offset_j, read_noise) except: plt_root = "" if show_plots: savetxt(output_dir + "/SN_template_z=%.2f_ph=%.1f_mdl=%s_type=%s.txt" % (redshift, 0., mdl.split("/")[-1].split(".")[0], sntype), transpose(array( [fine_waves, f_lamb_SN_fine] )), fmt = ["%f", "%g"]) photons_SN_per_sec = flamb_to_photons_per_wave(f_lamb_SN, effective_meters2(waves), waves, dwaves) if photon_count_rates != None: # This is a dictionary of wavelength range, photon_count_rate for waverange in photon_count_rates: inds = where((waves >= waverange[0])*(waves < waverange[1])) norm_factor = photon_count_rates[waverange]/sum(photons_SN_per_sec[inds]) print waverange, "norm_factor", norm_factor f_lamb_SN[inds] *= norm_factor f_lamb_SN_at_max[inds] *= norm_factor photons_SN_per_sec[inds] *= norm_factor model = None # Prevent the now incorrect model from being used again zodi_photons_per_sec_perarcsec2 = flamb_to_photons_per_wave(10.**(zodi_flamb(waves)), effective_meters2(waves), waves, dwaves) galaxy_photons_per_sec_perarcsec2 = flamb_to_photons_per_wave(gal_flamb(waves), effective_meters2(waves), waves, dwaves) if thermalfl == None: thermal_background_per_pix_per_sec = get_thermal_background_per_pix_per_sec(waves, dwaves, pixel_scale, TTel = TTel, throughput = effective_meters2(waves)/(pi*1.2**2.)) thermal_flamb_arcsec2 = photons_per_wave_to_flamb(get_thermal_background_per_pix_per_sec(waves = waves, dwaves = 1., pixel_scale = 1., TTel = TTel, throughput = effective_meters2(waves)/(pi*1.2**2.)), effective_meters2(waves), waves = waves, dwaves = 1.) # For pixel scale 1, get thermal background else: thermal_flamb_arcsec2 = interpfile(source_dir + "/" + thermalfl) thermal_flamb_arcsec2 = 10.**(thermal_flamb_arcsec2(waves)) thermal_background_per_pix_per_sec = flamb_to_photons_per_wave(thermal_flamb_arcsec2, effective_meters2(waves), waves, dwaves)*pixel_scale**2. AB_mag_per_sec = {} for AB_mag in AB_mags: AB_mag_per_sec[AB_mag] = flamb_to_photons_per_wave(0.10884806248 * 10**(-0.4*AB_mag) /waves**2., effective_meters2(waves), waves, dwaves) SN_photon_image = transpose(transpose(oneD_PSFs)*photons_SN_per_sec)*exp_time zodi_image = transpose(transpose(zeros(oneD_PSFs.shape, dtype=float64)) + zodi_photons_per_sec_perarcsec2*exp_time*pixel_scale**2.)*slice_in_pixels gal_image = transpose(transpose(zeros(oneD_PSFs.shape, dtype=float64)) + galaxy_photons_per_sec_perarcsec2*exp_time*pixel_scale**2.)*slice_in_pixels thermal_image = transpose(transpose(zeros(oneD_PSFs.shape, dtype=float64)) + thermal_background_per_pix_per_sec*exp_time)*slice_in_pixels dark_current_image = zeros(oneD_PSFs.shape, dtype=float64) + dark_current*exp_time AB_mag_images = {} for AB_mag in AB_mags: AB_mag_images[AB_mag] = transpose(transpose(oneD_PSFs)*AB_mag_per_sec[AB_mag])*exp_time total_image = SN_photon_image + zodi_image + gal_image + thermal_image + dark_current_image #assert all(total_image < 6.e4), "Saturated pixels found!" if not use_R07_noise: total_noise = sqrt(total_image + read_noise**2.) else: total_noise = get_R07_noise(electron_count_rate = total_image/exp_time, t_int = exp_time, nframe = nframe) sim_noise = random.normal(size = total_noise.shape)*total_noise sim_weight = 1./total_noise**2. SN_image_with_noise = SN_photon_image + sim_noise # Make the cubes. Signal cubes should be scaled by 1/slice_in_pixels to preserve flux. Noise cubes should be scaled by 1/sqrt(sice_in_pixels) to preserve noise. SN_with_noise_cube = image_to_cube(SN_image_with_noise, slice_in_pixels)/float(slice_in_pixels) total_noise_cube = image_to_cube(total_noise, slice_in_pixels)/sqrt(float(slice_in_pixels)) SN_photon_cube = image_to_cube(SN_photon_image, slice_in_pixels)/float(slice_in_pixels) PSF_cube = image_to_cube(oneD_PSFs, slice_in_pixels)/float(slice_in_pixels) SN_photon_mean2d = mean(SN_photon_cube, axis = 0) sn_sep = sep.extract(SN_photon_mean2d, thresh = 0.001) SN_aperture_StoN = [] SN_aperture_signal = [] aper_rad_by_wave = [] aper_EE = [] for i, wave in enumerate(waves): PSFsig = PSFs[(int(round(pixel_scale/0.005)), "sigmaFN")](wave) if aper_rad_fn == None: aper_rad = 2.5*PSFsig/float(pixel_scale/0.005) else: aper_rad = aper_rad_fn(wave)/float(pixel_scale) signal, noise, NA = sep.sum_circle(SN_photon_cube[i], x = sn_sep["x"], y = sn_sep["y"], r = aper_rad, err = total_noise_cube[i], subpix = 0) apsum, NA, NA = sep.sum_circle(PSF_cube[i], x = sn_sep["x"], y = sn_sep["y"], r = aper_rad, subpix = 0) try: aper_EE.append(apsum[0]) SN_aperture_StoN.append(signal[0]/noise[0]) SN_aperture_signal.append(signal[0]) except: aper_EE.append(-1) SN_aperture_StoN.append(-1) SN_aperture_signal.append(-1) aper_rad_by_wave.append(aper_rad) if show_plots: save_img(oneD_PSFs, output_dir + "/oneD_PSFs_" + plt_root + ".fits") save_img(SN_photon_image, output_dir + "/SN_image_" + plt_root + ".fits") save_img(zodi_image, output_dir + "/zodi_image_" + plt_root + ".fits") save_img(gal_image, output_dir + "/gal_image_" + plt_root + ".fits") save_img(thermal_image, output_dir + "/thermal_image_" + plt_root + ".fits") save_img(total_image, output_dir + "/total_image_" + plt_root + ".fits") save_img(total_noise, output_dir + "/total_noise_" + plt_root + ".fits") save_img(total_image + sim_noise, output_dir + "/image_with_noise_" + plt_root + ".fits") save_img(SN_with_noise_cube, output_dir + "/SN_with_noise_" + plt_root + "_cube.fits") save_img(SN_photon_mean2d, output_dir + "/SN_image_" + plt_root + "_mean2d.fits") plt.plot(waves, PSFs[(int(round(pixel_scale/0.005)), "sigmaFN")](waves)) plt.savefig(output_dir + "/psfsigma_" + plt_root + ".pdf", bbox_inches = 'tight') plt.close() extract_denom = sum(sim_weight*oneD_PSFs*oneD_PSFs, axis = 1) extracted_SN = sum(sim_weight*SN_image_with_noise*oneD_PSFs, axis = 1)/extract_denom extracted_noise = 1./sqrt(sum(sim_weight*oneD_PSFs*oneD_PSFs, axis = 1)) extracted_zodinoise = sqrt(sum(sim_weight*zodi_image*oneD_PSFs, axis = 1)/extract_denom) extracted_darknoise = sqrt(sum(sim_weight*dark_current_image*oneD_PSFs, axis = 1)/extract_denom) extracted_readnoise = sqrt(sum(sim_weight*read_noise**2. * oneD_PSFs, axis = 1)/extract_denom) extracted_thermalnoise = sqrt(sum(sim_weight*thermal_image*oneD_PSFs, axis = 1)/extract_denom) extracted_galnoise = sqrt(sum(sim_weight*gal_image*oneD_PSFs, axis = 1)/extract_denom) extracted_SNnoise = sqrt(sum(sim_weight*SN_photon_image*oneD_PSFs, axis = 1)/extract_denom) eff_noise = 1./sqrt(sum(oneD_PSFs*oneD_PSFs, axis = 1)) yerr_flamb = photons_per_wave_to_flamb(extracted_noise/exp_time, effective_meters2(waves), waves, dwaves) yvalswitherr_flamb = photons_per_wave_to_flamb(extracted_SN/exp_time, effective_meters2(waves), waves, dwaves) signal_to_noises = {"obs_frame_band": {}, # band-integrated "obs_frame": {}, # per resolution element "rest_frame_band_S/N": {}, "rest_frame_mean_S/N": {}, "thermal_flamb_arcsec-2": thermal_flamb_arcsec2, "plt_root": plt_root, "PSFs": PSFs, "PSF_enclosed_flux": sum(oneD_PSFs, axis = 1), "rest_frame_band_mag": {}, "photons/s_obs": {}, "dark_photnoise": {}, "n_reselmnts": {}, "thermal_photnoise": {}, "zodi_photnoise": {}, "read_noise": {}, "SN_photnoise": {}, "f_lamb_SN": f_lamb_SN, "extracted_SN": extracted_SN, "obs_waves": waves, "obs_dwaves": dwaves, "spec_S/N": f_lamb_SN/yerr_flamb, "spec_aperture_StoN": array(SN_aperture_StoN), "spec_aperture_signal": array(SN_aperture_signal), "aper_rad_by_wave": aper_rad_by_wave, "aperture_EE": aper_EE, "PSF_wghtd_e_SN": sum(oneD_PSFs*SN_photon_image, axis = 1), "PSF_wghtd_e_allbutdark": sum(oneD_PSFs*(SN_photon_image + zodi_image + gal_image + thermal_image), axis = 1), "phot/s_image": (SN_photon_image + zodi_image + gal_image + thermal_image)/exp_time, "noise_sources": {"total": extracted_noise, "zodi": extracted_zodinoise, "thermal": extracted_thermalnoise, "dark": extracted_darknoise, "read": extracted_readnoise, "SN": extracted_SNnoise, "galaxy": extracted_galnoise} } for i in range(len(obsframe_bins) - 1): inds = where((waves >= obsframe_bins[i])*(waves < obsframe_bins[i+1])) obskey = (obsframe_bins[i], obsframe_bins[i+1]) signal_to_noises["n_reselmnts"][obskey] = float(len(inds[0]))*0.5 signal_to_noises["dark_photnoise"][obskey] = sqrt(dot(extracted_darknoise[inds], extracted_darknoise[inds])) # Quadrature sum signal_to_noises["read_noise"][obskey] = sqrt(dot(extracted_readnoise[inds], extracted_readnoise[inds])) # Quadrature sum signal_to_noises["zodi_photnoise"][obskey] = sqrt(dot(extracted_zodinoise[inds], extracted_zodinoise[inds])) # Quadrature sum signal_to_noises["thermal_photnoise"][obskey] = sqrt(dot(extracted_thermalnoise[inds], extracted_thermalnoise[inds])) # Quadrature sum signal_to_noises["SN_photnoise"][obskey] = sqrt(dot(extracted_SNnoise[inds], extracted_SNnoise[inds])) # Quadrature sum this_errs = sqrt(sum((yerr_flamb[inds]*dwaves[inds]*waves[inds])**2.)) this_photons = sum(f_lamb_SN[inds]*dwaves[inds]*waves[inds]) #weighted_photons = sum(these_weights*these_photons)/sum(these_weights) #weighted_errs = 1./sqrt(sum(these_weights)) nresl = 0.5*float(len(inds[0])) print "MeanS/N", obsframe_bins[i], obsframe_bins[i+1], this_photons/this_errs, this_photons/this_errs/sqrt(nresl) signal_to_noises["obs_frame"][obskey] = this_photons/this_errs/sqrt(nresl) signal_to_noises["obs_frame_band"][obskey] = this_photons/this_errs signal_to_noises["photons/s_obs"][obskey] = sum(photons_SN_per_sec[inds]) s_to_n_tmp = integrate_spec(waves, dwaves, redshift, restframe_bins, f_lamb_SN, yerr_flamb) for key in s_to_n_tmp: signal_to_noises[key] = s_to_n_tmp[key] if show_plots: binwaves = arange(min(waves), max(waves), 150.) #clip(exp(arange(log(min(waves)), log(max(waves)), 1./80.)), min(waves), max(waves)) f_lamb_SN_bin, f_lamb_SN_binerr = bin_vals_fixed_bins(waves, yvalswitherr_flamb, yerr_flamb, binwaves) plt.plot(waves, f_lamb_SN, color = 'k', zorder = 1) plt.errorbar(binwaves, f_lamb_SN_bin, yerr = f_lamb_SN_binerr, fmt = '.', label = plt_root, capsize = 0, color = 'b'*(1 - dark_background) + dark_background*'w') plt.legend(loc = 'best', fontsize = 8) plt.ylabel("$f_{\lambda}$") plt.xlabel("Observer-Frame Wavelength (Binned)") ylim = list(plt.ylim()) ylim[0] = 0 plt.ylim(ylim) plt.savefig(output_dir + "/spec_binned_" + plt_root + ".pdf", bbox_inches = 'tight') plt.close() plt.plot(waves, eff_noise) plt.savefig(output_dir + "/eff_noise_" + plt_root + ".pdf") plt.close() plt.errorbar(waves, yvalswitherr_flamb, yerr = yerr_flamb, fmt = '.', label = plt_root, capsize = 0) plt.legend(loc = 'best', fontsize = 8) plt.ylabel("$f_{\lambda}$") plt.xlabel("Observer-Frame Wavelength") plt.ylim(ylim) plt.savefig(output_dir + "/spec_" + plt_root + ".pdf", bbox_inches = 'tight') plt.close() plt.plot(waves, f_lamb_SN/yerr_flamb, '.', color = 'k'*(1 - dark_background) + 'w'*dark_background, label = plt_root) plt.ylabel("Signal-to-Noise per Wavelength (half resolution element)") plt.xlabel("Observer-Frame Wavelength") plt.legend(loc = 'best', fontsize = 8) plt.savefig(output_dir + "/spec_StoN_" + plt_root + ".pdf", bbox_inches = 'tight') plt.close() plt.plot(waves, signal_to_noises["spec_aperture_StoN"], '.', color = 'k'*(1 - dark_background) + 'w'*dark_background, label = plt_root) plt.ylabel("Aperture Signal-to-Noise per Wavelength (half resolution element)") plt.xlabel("Observer-Frame Wavelength") plt.legend(loc = 'best', fontsize = 8) plt.savefig(output_dir + "/spec_aperture_StoN_" + plt_root + ".pdf", bbox_inches = 'tight') plt.close() savetxt(output_dir + "/sim_spectrum_" + plt_root + ".txt", transpose(array([waves, f_lamb_SN, yerr_flamb])), header = "#waves template err", fmt = ["%f", "%g", "%g"]) savetxt(output_dir + "/sim_noise_" + plt_root + ".txt", transpose(array([waves] + [photons_per_wave_to_flamb(item/exp_time, effective_meters2(waves), waves, dwaves) for item in [extracted_zodinoise, extracted_darknoise, extracted_readnoise, extracted_SNnoise]] )), header = "#waves zodi dark read SN", fmt = ["%f"] + ["%g"]*4) return signal_to_noises
e = Ellipse(xy=(objects['x'][i], objects['y'][i]), width=6 * objects['a'][i], height=6 * objects['b'][i], angle=objects['theta'][i] * 180. / np.pi) e.set_facecolor('none') e.set_edgecolor('red') ax.add_artist(e) #pl.draw() #pl.show() # available fields #print objects.dtype.names flux, fluxerr, flag = sep.sum_circle(data_sub, objects['x'], objects['y'], 3.0, gain=1.0) xval = objects['x'] yval = objects['y'] #print objects['x'], objects['y'] for j in range(len(objects)): print("object {:d}: flux = {:f} {:f}".format( j, flux[j], fluxerr[j], xval[j], yval[j])) #before loop #f=file.open('fluxout.txt,'w') #in loop #outline="%s %s\n"%(var1,var)
if CONDENSED: r_list = [5.] subpix_list = [(5, "subpixel", "subpix=5"), (0, "exact", "exact")] else: r_list = [3., 5., 10., 20.] subpix_list = [(1, "center", "subpix=1"), (5, "subpixel", "subpix=5"), (0, "exact", "exact")] for r in r_list: for subpix, method, label in subpix_list: line = "| circles r={0:2d} {1:8s} |".format(int(r), label) t0 = time.time() flux, fluxerr, flag = sep.sum_circle(data, x, y, r, subpix=subpix) t1 = time.time() t_sep = (t1-t0) * 1.e6 / naper / nloop line += " {0:7.2f} us/aper |".format(t_sep) if HAVE_PHOTUTILS: apertures = photutils.CircularAperture((x, y), r) t0 = time.time() res = photutils.aperture_photometry( data, apertures, method=method, subpixels=subpix) t1 = time.time() t_pu = (t1-t0) * 1.e6 / naper line += " {0:7.2f} us/aper | {1:6.2f} |".format(t_pu, t_pu/t_sep) print(line)
def asteroids_phot(self, image_path, multi_object=True, target=None, aper_radius=None, plot_aper_test=False, radius=11, exposure=None, sqlite_file=None, table_name="asteroids", gain=0.57, max_mag=20, comp_snr=50): """ Photometry of asteroids. @param image_path: Path of FITS file. @type image_path: path @param multi_object: Apply photometry for other asteroids in the frame? @type multi_object: float @param target: Target object that photometry applied. If None, will be taken form FITS header. @type target: float @param radius: Aperture radius @type radius: float @param exposure: Exposure keyword of phot images. @type exposure: float @param plot_aper_test: Plot aperture test graph @type plot_aper_test: bloean @param exportdb: Export results SQLite3 database @type exportdb: path @param db_table: SQLite3 database table @type db_table: path @param gain: gain value for the image expressed in electrons per adu. @type gain: float @param max_mag: Faintest object limit. @type max_mag: float @param comp_snr: Minimum SNR of detected comparison star. @type comp_snr: float @return: bolean and file """ if ".fit" in os.path.basename(image_path): fitslist = sorted(glob.glob(image_path)) if fitslist == 0: print('No image FITS found in the {0}'.format(image_path)) raise SystemExit else: fitslist = sorted(glob.glob(image_path + '/*.fit?')) if fitslist == 0: print('No image FITS found in the {0}'.format(image_path)) raise SystemExit # aper_trigger check count aper_count = 0 for id, fitsfile in enumerate(fitslist): if fitsfile: hdu = fits.open(fitsfile)[0] else: print("FITS image has not been provided by the user!") raise SystemExit sb = Query() ac = AstCalc() to = TimeOps() fo = FitsOps(fitsfile) header = hdu.header w = WCS(header) naxis1 = fo.get_header('naxis1') naxis2 = fo.get_header('naxis2') odate = fo.get_header('date-obs') t1 = Time("{0}".format(odate), out_subfmt="date") dt = TimeDelta(12 * 3600, format='sec') onight = t1 - dt exptime = fo.get_header('exptime') if exptime is not None and exposure is not None: if float(exptime) != exposure: continue if aper_count == 0: aper_trigger = id aper_count += 1 if target is None: objct = fo.get_header('object') else: objct = str(target) filter = fo.get_header('filter').replace(" ", "_") # t1 = Time(odate.replace('T', ' ')) # exptime = fo.get_header('exptime') # dt = TimeDelta(exptime / 2.0, format='sec') # odate_middle = t1 + dt # jd = to.date2jd(odate_middle.value) jd = to.date2jd(odate) ra_dec = ac.center_finder(fitsfile, wcs_ref=True) image = f2n.fromfits(fitsfile, verbose=False) image.setzscale('auto', 'auto') image.makepilimage('log', negative=False) request = sb.find_skybot_objects(odate, ra_dec[0].degree, ra_dec[1].degree, radius=radius) if request[0]: if multi_object: asteroids = Table(np.sort(request[1][::-1], order=['m_v'])) else: asteroids = Table(np.sort(request[1], order=['num'])) mask = asteroids['num'] == str(objct).upper() asteroids = asteroids[mask] elif request[0] is False: print(request[1]) raise SystemExit data = hdu.data.astype(float) bkg = sep.Background(data) data_sub = data - bkg for i in range(len(asteroids)): if float(asteroids['m_v'][i]) <= max_mag: c = coordinates.SkyCoord('{0} {1}'.format( asteroids['ra(h)'][i], asteroids['dec(deg)'][i]), unit=(u.hourangle, u.deg), frame='icrs') # asteroid's X and Y coor a_x, a_y = w.wcs_world2pix(c.ra.degree, c.dec.degree, 1) if naxis1 < a_x or naxis2 < a_y or a_x < 0 or a_y < 0: continue # phot asteroids flux, fluxerr, flag = sep.sum_circle( data_sub, a_x, a_y, 6, err=bkg.globalrms, gain=gain) if flux == 0.0 or fluxerr == 0.0: print("Bad asteroid selected (out of frame!)!") raise SystemExit if id == aper_trigger: snr = [] for aper in range(30): # phot asteroids flux_test, fluxerr_test, flag_test = sep.sum_circle( data_sub, a_x, a_y, aper, err=bkg.globalrms, gain=gain) snr.append([aper, (flux_test/fluxerr_test)]) npsnr = np.array(snr) maxtab, mintab = peakdet(npsnr[:, 1], 0.1) try: aper_radius = maxtab[:, 0][0] print("Aperture calculated: {0} px".format( aper_radius)) except IndexError: continue if plot_aper_test: plt.title(asteroids['num'][i]) plt.xlabel('Aperture (px)') plt.ylabel('SNR') plt.scatter(npsnr[:, 0], npsnr[:, 1]) plt.scatter(maxtab[:, 0], maxtab[:, 1], color='red') plt.scatter(mintab[:, 0], mintab[:, 1], color='yellow') plt.show() magt_i = ac.flux2mag(flux, float(exptime)) magt_i_err = fluxerr / flux * 2.5 / math.log(10) min_mag_ast = float(asteroids['m_v'][i]) - 2 label = '{0}'.format(asteroids['num'][i]) image.drawcircle(a_x, a_y, r=aper_radius, colour=(255, 0, 0), label=label) if i == 0 and id == aper_trigger: comptable = sb.query_color(c.ra.degree, c.dec.degree, 5.0 / 60.0, min_mag=min_mag_ast, max_mag=19.5) s_comptable = sb.sort_stars(comptable, min_mag_ast) if len(s_comptable) == 0: continue phot_res_list = [] # phot comp. stars for j in range(len(s_comptable)): # star's X and Y coor s_x, s_y = w.wcs_world2pix(s_comptable['RAJ2000'][j], s_comptable['DEJ2000'][j], 1) if naxis1 < s_x or naxis2 < s_y or s_x < 0 or s_y < 0: continue # print('Circle', s_x, s_y, 10) flux, fluxerr, flag = sep.sum_circle( data_sub, s_x, s_y, aper_radius, err=bkg.globalrms, gain=gain) if flux == 0.0 or fluxerr == 0.0: print("Bad star selected!") raise SystemExit if (flux / fluxerr) <= comp_snr: continue magc_i = ac.flux2mag(flux, float(exptime)) magc_i_err = fluxerr / flux * 2.5 / math.log(10) try: magt = (float(magt_i) - float(magc_i)) + s_comptable['Rmag'][j] magt_err = math.sqrt( math.pow(float(magt_i_err), 2) + math.pow(float(magc_i_err), 2)) except: continue label = '{0}'.format(s_comptable['NOMAD1'][j]) image.drawcircle(s_x, s_y, r=aper_radius, colour=(0, 255, 0), label=label) phot_res_list.append([asteroids['num'][i], jd, onight.iso, float(magt_i), float(magt_i_err), float(magc_i), float(magc_i_err), float(magt), float(magt_err), asteroids['m_v'][i], s_comptable['NOMAD1'][j], s_comptable['Rmag'][j]]) np_phot_res = np.array(phot_res_list) if len(np_phot_res) == 0: continue # magnitude average magt_avr = np.average(np_phot_res[:, 7].astype(float), weights=np_phot_res[:, 8].astype( float)) # magt_std calc. magt_std = np.std(np_phot_res[:, 7].astype(float)) np_magt_avr_std = [[magt_avr, magt_std, filter, exptime] for i in range( len(np_phot_res))] k = np.array(np_magt_avr_std).reshape( len(np_magt_avr_std), 4) # numpy array with magt_avr np_phot_res_avg_std = np.concatenate( (np_phot_res, k), axis=1) phot_res_table = Table(np_phot_res_avg_std, names=('ast_num', 'jd', 'onight', 'magt_i', 'magt_i_err', 'magc_i', 'magc_i_err', 'magt', 'magt_err', 'ast_mag_cat', 'nomad1', 'star_Rmag', 'magt_avr', 'magt_std', 'filter', 'exposure'), dtype=('U10', 'S25', 'U10', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'U20', 'f8', 'f8', 'f8', 'U20', 'f8')) phot_res_table['magt_i'].format = '.3f' phot_res_table['magt_i_err'].format = '.3f' phot_res_table['magc_i'].format = '.3f' phot_res_table['magc_i_err'].format = '.3f' phot_res_table['magt'].format = '.3f' phot_res_table['magt_err'].format = '.3f' phot_res_table['magt_avr'].format = '.3f' phot_res_table['magt_std'].format = '.3f' with open('{0}/{1}.txt'.format( os.getcwd(), asteroids['num'][i]), 'a') as f_handle: f_handle.seek(0, os.SEEK_END) if not os.path.isfile(str(f_handle)): phot_res_table.write( f_handle, format='ascii.commented_header') else: phot_res_table.write(f_handle, format='ascii.no_header') if sqlite_file is not None: self.table_to_database(phot_res_table, sqlite_file=sqlite_file, table_name=table_name) # Test time.sleep(0.2) self.update_progress( "Photometry is done for: {0}".format(fitsfile), id / len(fitslist)) image.writetitle(os.path.basename(fitsfile)) fitshead, fitsextension = os.path.splitext(fitsfile) image.writeinfo([odate], colour=(255, 100, 0)) image.tonet('{0}.png'.format(fitshead)) self.update_progress("Photometry done!", 1) return(True)