def _getCircularFraction(image: np.ndarray, centroid: List[float], radius: float, fraction: float) -> float: '''Function determines the radius of a circle that encloses a fraction of the total light. Parameters ---------- image : float, 2d np.ndarray Image of galaxy centroid : List[float] Location of the brightest pixel radius : float Radius in which to measure galaxy light out to. This is usually Rmax. fraction : float The fraction of the total galaxy light for the circle to enclose. Returns ------- radiusOut : float The radius of the circle that encloses fraction of light ''' apeture_total = CircularAperture(centroid, radius) totalSum = apeture_total.do_photometry(image, method="exact")[0][0] # number of points for grid npoints = float(200) # grid spacing deltaRadius = (radius / npoints) * 2. radiusCurrent = radius - deltaRadius radiusMin = 0 radiusMax = 0 # loop until bracketing values are found for the root at which is # our desired radius. while True: apCur = CircularAperture(centroid, radiusCurrent) currentSum = apCur.do_photometry(image, method="exact")[0][0] currentFraction = currentSum / totalSum if currentFraction <= fraction: radiusMin = radiusCurrent radiusMax = radiusCurrent + deltaRadius break radiusCurrent -= deltaRadius radiusOut = brentq(_fractionTotalFLuxCircle, radiusMin, radiusMax, args=(image, centroid, totalSum, fraction)) return radiusOut
def measure_source_fwhm(detection, data, rmax=10): """ TO USE CAREFULLY Function used to estimate the FWHM of a source. It performs aperture photometry with inscreasing radius from the source position, and then, tries to find where half of the maximum of flux is reached. Parameters ---------- detection : :class:`~pandas:pandas.Series` Row of a DataFrame containing detected sources. Should have columns ``xcentroid`` and ``ycentroid``, in classic convention (not astropy) data : 2D :class:`~numpy:numpy.ndarray` Flux map used for the photometry """ x, y = np.array(detection[['xcentroid', 'ycentroid']]) photo_flux = np.zeros(rmax) for r in range(rmax): if r == 0: aper = CircularAperture((x, y), 1.) else: aper = CircularAnnulus((x, y), r, r + 1) photo_flux[r] = aper.do_photometry(data)[0] / aper.area() def get_fwhm(flux): #We assume max is on 0. If not, source is probably contaminated flux = flux - flux.min() spline = UnivariateSpline(np.arange(rmax), flux - flux[0] / 2., s=0) if spline.roots().shape != (1, ): return np.nan return spline.roots()[0] return (get_fwhm(photo_flux))
def snr_astropy(image,sx,sy,r,r_in,r_out): """ Returns signal to noise ratio, signal value, noise value using Astropy's Photutils module Args: image (2d float array): Image array extracted from fits file sx,sy (float): x and y pixel locations for the center of the source r (float): radius for aperture r_in,r_out (float): inner and outer radii for annulus Return: snr (float): signal-to-noise ratio signal (float): sum of all pixel values within the specified aperture minus sky background noise (float): noise in the signal calculated as std deviation of pixels in the sky annulus times sqrt of the area of the signal aperture poisson_noise (float): snr determined from the poisson noise in the source signal. Poisson noise = sqrt(counts) [because variance of a poisson distribution is the parameter itself]. Poisson snr = Signal/sqrt(signal) = sqrt(signal) Written by: Logan Pearce, 2018 """ import warnings warnings.filterwarnings('ignore') from photutils import CircularAperture, CircularAnnulus positions = (cx-1,cy-1) ap = CircularAperture(positions,r=r) skyan = CircularAnnulus(positions,r_in=11,r_out=14) apsum = ap.do_photometry(image)[0] skysum = skyan.do_photometry(image)[0] averagesky = skysum/skyan.area() signal = (apsum - ap.area()*averagesky)[0] n = ap.area() ap_an = aperture_annulus(sx,sy,r,r_in,r_out) skyan = ap_an[1] poisson_noise = np.sqrt(signal) noise = noise = np.std(image[skyan[1],skyan[0]]) noise = noise*np.sqrt(n) snr = signal/noise return snr,signal,noise,poisson_noise
def estimate_photometric_precision_full(image: np.ndarray, sources: Table, fwhm: float, effective_gain: float = 1): """ Estimate the possible position precision for stars in an image based on the SNR and the PSF FWHM. The signal is summed over a circular aperture with radius = fwhm, the error the geometric mean within this aperture. see. Lindegren, Lennart. “Photoelectric Astrometry - A Comparison of Methods for Precise Image Location.” :param image: input exposure :param sources: table with 'x' and 'y' columns in pixel coordinates :param fwhm: Full width at half maximum for the PSF of the image :param effective_gain: gain/quantum_efficiency :return: list of computed σ_pos same order as sources in table """ # Idea: use aperture photometry to sum the signal, internally it will perform quadratic mean # of pixel errors, so for each star we have signal and error. mean, median, std = sigma_clipped_stats(image, sigma=3.0) bkg_error = std error_img = calc_total_error(image, bkg_error, effective_gain) xy = np.array((sources['x'], sources['y'])).T apertures = CircularAperture(xy, r=fwhm) signals, errors = apertures.do_photometry(image-median, error_img) # sometimes signal is negative over FWHM, avoid negative sigma sigma_pos = np.abs(fwhm/(signals/errors)) return sigma_pos
def do_Circ_phot(pos, FWHM, ap_min=3., ap_factor=1.5, rin=None, rout=None, \ sky_nsigma=3., sky_iter=10): ''' In rigorous manner, we should use error = sqrt (flux / epadu + area * stdev**2 + area**2 * stdev**2 / nsky) as in http://stsdas.stsci.edu/cgi-bin/gethelp.cgi?phot . Here flux == aperture_sum - sky, i.e., flux from image_reduc. stdev should include sky error AND ronoise. ''' if rin == None: rin = 4 * FWHM if rout == None: rout = 6 * FWHM N = len(pos) if pos.ndim == 1: N = 1 an = CircAn(pos, r_in=rin, r_out=rout) ap_size = np.max([ap_min, ap_factor*FWHM]) aperture = CircAp(pos, r=ap_size) flux = aperture.do_photometry(image_reduc, method='exact')[0] # do phot and get sum from aperture. [0] is sum and [1] is error. #For test: #N=len(pos_star_fit) #an = CircAn(pos_star_fit, r_in=4*FWHM_moffat, r_out=6*FWHM_moffat) #ap_size = 1.5*FWHM_moffat #aperture = CircAp(pos_star_fit, r=ap_size) #flux = aperture.do_photometry(image_reduc, method='exact')[0] flux_ss = np.zeros(N) error = np.zeros(N) for i in range(0, N): mask_an = (an.to_mask(method='center'))[i] # cf: test = mask_an.cutout(image_reduc) <-- will make cutout image. sky_an = mask_an.apply(image_reduc) all_sky = sky_an[np.nonzero(sky_an)] # only annulus region will be saved as np.ndarray msky, stdev, nsky, nrej = sky_fit(all_sky, method='Mode', mode_option='sex') area = aperture.area() flux_ss[i] = flux[i] - msky*area # sky subtracted flux error[i] = np.sqrt( flux_ss[i]/gain \ + area * stdev**2 \ + area**2 * stdev**2 / nsky ) # To know rejected number, uncomment the following. # plt.imshow(sky_an, cmap='gray_r', vmin=-20) # plt.colorbar() # plt.show() # mask_ap = (aperture.to_mask(method='exact'))[i] # star_ap = mask_ap.apply(image_reduc) # plt.imshow(star_ap) # plt.colorbar() # plt.show() # plt.cla() if pos.ndim > 1: print('\t[{x:7.2f}, {y:7.2f}], {nsky:3d} {nrej:3d} {msky:7.2f} {stdev:7.2f} {flux:7.1f} {ferr:3.1f}'.format(\ x=pos[i][0], y=pos[i][1], \ nsky=nsky, nrej=nrej, msky=msky, stdev=stdev,\ flux=flux_ss[i], ferr=error[i])) return flux_ss, error
def starbright(fnstar, fnflat, istar, axs, fg): # %% load data data = meanstack(fnstar, 100)[0] # %% flat field flatnorm = readflat(fnflat, fnstar) data = (data / flatnorm).round().astype(data.dtype) # %% background mean, median, std = sigma_clipped_stats(data, sigma=3.0) rfact = data.shape[0] // 40 cfact = data.shape[1] // 40 bg = Background(data, (rfact, cfact), interp_order=1, sigclip_sigma=3) # http://docs.astropy.org/en/stable/units/#module-astropy.units # dataphot = (data - bg.background)*u.ph/(1e-4*u.m**2 * u.s * u.sr) # data = (data-0.97*data.min()/bg.background.min()*bg.background) * u.ph/(u.cm**2 * u.s * u.sr) data = data * u.ph / (u.cm**2 * u.s * u.sr) # %% source extraction sources = daofind(data, fwhm=3.0, threshold=5 * std) # %% star identification and quantification XY = column_stack((sources["xcentroid"], sources["ycentroid"])) apertures = CircularAperture(XY, r=4.0) norm = ImageNormalize(stretch=SqrtStretch()) flux = apertures.do_photometry(data, effective_gain=camgain)[0] # %% plots fg.suptitle("{}".format(fnflat.parent), fontsize="x-large") hi = axs[-3].imshow(flatnorm, interpolation="none", origin="lower") fg.colorbar(hi, ax=axs[-3]) axs[-3].set_title("flatfield {}".format(fnflat.name)) hi = axs[-2].imshow(bg.background, interpolation="none", origin="lower") fg.colorbar(hi, ax=axs[-2]) axs[-2].set_title("background {}".format(fnstar.name)) hi = axs[-1].imshow(data.value, cmap="Greys", origin="lower", norm=norm, interpolation="none") fg.colorbar(hi, ax=axs[-1]) for i, xy in enumerate(XY): axs[-1].text(xy[0], xy[1], str(i), ha="center", va="center", fontsize=16, color="w") apertures.plot(ax=axs[-1], color="blue", lw=1.5, alpha=0.5) axs[-1].set_title("star {}".format(fnstar.name)) return flux[istar]
def compute_snr(x, y): positions = (x - 1, y - 1) ap = CircularAperture(positions, r=radius) skyan = CircularAnnulus(positions, r_in=11, r_out=14) ap = CircularAperture(positions, r=radius) skyan = CircularAnnulus(positions, r_in=11, r_out=14) apsum = ap.do_photometry(image)[0] skysum = skyan.do_photometry(image)[0] averagesky = skysum / skyan.area() signal = (apsum - ap.area() * averagesky)[0] n = ap.area() box = image[y + 12:y + 12 + 15, x + 12:x + 12 + 15] noise = np.std(box) noise = noise * np.sqrt(n) snr = signal / noise return snr
def starbright(fnstar,fnflat,istar,axs,fg): #%% load data data = meanstack(fnstar,100)[0] #%% flat field flatnorm = readflat(fnflat,fnstar) data = (data/flatnorm).round().astype(data.dtype) #%% background mean, median, std = sigma_clipped_stats(data, sigma=3.0) rfact=data.shape[0]//40 cfact=data.shape[1]//40 bg = Background(data,(rfact,cfact),interp_order=1, sigclip_sigma=3) # http://docs.astropy.org/en/stable/units/#module-astropy.units #dataphot = (data - bg.background)*u.ph/(1e-4*u.m**2 * u.s * u.sr) # data = (data-0.97*data.min()/bg.background.min()*bg.background) * u.ph/(u.cm**2 * u.s * u.sr) data = data* u.ph/(u.cm**2 * u.s * u.sr) #%% source extraction sources = daofind(data, fwhm=3.0, threshold=5*std) #%% star identification and quantification XY = column_stack((sources['xcentroid'], sources['ycentroid'])) apertures = CircularAperture(XY, r=4.) norm = ImageNormalize(stretch=SqrtStretch()) flux = apertures.do_photometry(data,effective_gain=camgain)[0] #%% plots fg.suptitle('{}'.format(fnflat.parent),fontsize='x-large') hi = axs[-3].imshow(flatnorm,interpolation='none',origin='lower') fg.colorbar(hi,ax=axs[-3]) axs[-3].set_title('flatfield {}'.format(fnflat.name)) hi = axs[-2].imshow(bg.background,interpolation='none',origin='lower') fg.colorbar(hi,ax=axs[-2]) axs[-2].set_title('background {}'.format(fnstar.name)) hi = axs[-1].imshow(data.value, cmap='Greys', origin='lower', norm=norm,interpolation='none') fg.colorbar(hi,ax=axs[-1]) for i,xy in enumerate(XY): axs[-1].text(xy[0],xy[1], str(i),ha='center',va='center',fontsize=16,color='w') apertures.plot(ax=axs[-1], color='blue', lw=1.5, alpha=0.5) axs[-1].set_title('star {}'.format(fnstar.name)) return flux[istar]
def _fractionTotalFLuxCircle(radius: float, image: np.ndarray, centroid: List[float], totalSum: float, fraction: float) -> float: r'''Helper function to help find the radius of a circle that encloses a fraction of the total light in the galaxy of interest. Parameters ---------- radius : float Radius in which to measure galaxy light out to. This is usually Rmax. image : float, 2d np.ndarray Image of galaxy centroid : List[float] Location of the brightest pixel totalSum : float The total amount of light in the galaxy. fraction : float The fraction of the total galaxy light for the circle to enclose. Returns ------- root : float The fraction of light at the current radius minus the fraction, so that a root at 0 can be found. ''' apetureCur = CircularAperture(centroid, radius) currentSum = apetureCur.do_photometry(image, method="exact")[0][0] root = (currentSum / totalSum) - fraction return root
def tso_aperture_photometry(datamodel, xcenter, ycenter, radius, radius_inner, radius_outer): """ Create a photometric catalog for NIRCam TSO imaging observations. Parameters ---------- datamodel : `CubeModel` The input `CubeModel` of a NIRCam TSO imaging observation. xcenter, ycenter : float The ``x`` and ``y`` center of the aperture. radius : float The radius (in pixels) of the circular aperture. radius_inner, radius_outer : float The inner and outer radii (in pixels) of the circular-annulus aperture, used for local background estimation. Returns ------- catalog : `~astropy.table.QTable` An astropy QTable (Quantity Table) containing the source photometry. """ if not isinstance(datamodel, CubeModel): raise ValueError('The input data model must be a CubeModel.') # For the SUB64P subarray with the WLP8 pupil, the circular aperture # extends beyond the image and the circular annulus does not have any # overlap with the image. In that case, we simply sum all values # in the array and skip the background subtraction. sub64p_wlp8 = False if (datamodel.meta.instrument.pupil == 'WLP8' and datamodel.meta.subarray.name == 'SUB64P'): sub64p_wlp8 = True if not sub64p_wlp8: phot_aper = CircularAperture((xcenter, ycenter), r=radius) bkg_aper = CircularAnnulus((xcenter, ycenter), r_in=radius_inner, r_out=radius_outer) # convert the input data and errors from MJy/sr to Jy if datamodel.meta.bunit_data != 'MJy/sr': raise ValueError('data is expected to be in units of MJy/sr') factor = 1.e6 * datamodel.meta.photometry.pixelarea_steradians datamodel.data *= factor datamodel.err *= factor datamodel.meta.bunit_data = 'Jy' datamodel.meta.bunit_err = 'Jy' aperture_sum = [] aperture_sum_err = [] annulus_sum = [] annulus_sum_err = [] nimg = datamodel.data.shape[0] if sub64p_wlp8: info = ('Photometry measured as the sum of all values in the ' 'subarray. No background subtraction was performed.') for i in np.arange(nimg): aperture_sum.append(np.sum(datamodel.data[i, :, :])) aperture_sum_err.append(np.sqrt(np.sum(datamodel.err[i, :, :]**2))) else: info = ('Photometry measured in a circular aperture of r={0} ' 'pixels. Background calculated as the mean in a ' 'circular annulus with r_inner={1} pixels and ' 'r_outer={2} pixels.'.format(radius, radius_inner, radius_outer)) for i in np.arange(nimg): aper_sum, aper_sum_err = phot_aper.do_photometry( datamodel.data[i, :, :], error=datamodel.err[i, :, :]) ann_sum, ann_sum_err = bkg_aper.do_photometry( datamodel.data[i, :, :], error=datamodel.err[i, :, :]) aperture_sum.append(aper_sum[0]) aperture_sum_err.append(aper_sum_err[0]) annulus_sum.append(ann_sum[0]) annulus_sum_err.append(ann_sum_err[0]) aperture_sum = np.array(aperture_sum) aperture_sum_err = np.array(aperture_sum_err) annulus_sum = np.array(annulus_sum) annulus_sum_err = np.array(annulus_sum_err) # construct metadata for output table meta = OrderedDict() meta['instrument'] = datamodel.meta.instrument.name meta['detector'] = datamodel.meta.instrument.detector meta['channel'] = datamodel.meta.instrument.channel meta['subarray'] = datamodel.meta.subarray.name meta['filter'] = datamodel.meta.instrument.filter meta['pupil'] = datamodel.meta.instrument.pupil meta['target_name'] = datamodel.meta.target.catalog_name meta['xcenter'] = xcenter meta['ycenter'] = ycenter ra_icrs, dec_icrs = datamodel.meta.wcs(xcenter, ycenter) meta['ra_icrs'] = ra_icrs meta['dec_icrs'] = dec_icrs meta['apertures'] = info # initialize the output table tbl = QTable(meta=meta) # check for the INT_TIMES table extension if hasattr(datamodel, 'int_times') and datamodel.int_times is not None: nrows = len(datamodel.int_times) else: nrows = 0 log.warning("The INT_TIMES table in the input file is missing or " "empty.") # load the INT_TIMES table data if nrows > 0: shape = datamodel.data.shape if len(shape) == 2: num_integ = 1 else: # len(shape) == 3 num_integ = shape[0] int_start = datamodel.meta.exposure.integration_start if int_start is None: int_start = 1 log.warning(f"INTSTART not found; assuming a value of {int_start}") # Columns of integration numbers & times of integration from the # INT_TIMES table. int_num = datamodel.int_times['integration_number'] mid_utc = datamodel.int_times['int_mid_MJD_UTC'] offset = int_start - int_num[0] # both are one-indexed if offset < 0: log.warning("Range of integration numbers in science data extends " "outside the range in INT_TIMES table.") log.warning("Can't use INT_TIMES table.") del int_num, mid_utc nrows = 0 # flag as bad else: log.debug("Times are from the INT_TIMES table") time_arr = mid_utc[offset:offset + num_integ] int_times = Time(time_arr, format='mjd', scale='utc') # compute integration time stamps on the fly if nrows == 0: log.debug("Times computed from EXPSTART and EFFINTTM") dt = datamodel.meta.exposure.integration_time n_dt = (datamodel.meta.exposure.integration_end - datamodel.meta.exposure.integration_start + 1) dt_arr = (np.arange(1, 1 + n_dt) * dt - (dt / 2.)) int_dt = TimeDelta(dt_arr, format='sec') int_times = (Time(datamodel.meta.exposure.start_time, format='mjd') + int_dt) # populate table columns unit = u.Unit(datamodel.meta.bunit_data) tbl['MJD'] = int_times.mjd tbl['aperture_sum'] = aperture_sum << unit tbl['aperture_sum_err'] = aperture_sum_err << unit if not sub64p_wlp8: tbl['annulus_sum'] = annulus_sum << unit tbl['annulus_sum_err'] = annulus_sum_err << unit if LooseVersion(photutils.__version__) >= '0.7': annulus_mean = annulus_sum / bkg_aper.area annulus_mean_err = annulus_sum_err / bkg_aper.area aperture_bkg = annulus_mean * phot_aper.area aperture_bkg_err = annulus_mean_err * phot_aper.area else: annulus_mean = annulus_sum / bkg_aper.area() annulus_mean_err = annulus_sum_err / bkg_aper.area() aperture_bkg = annulus_mean * phot_aper.area() aperture_bkg_err = annulus_mean_err * phot_aper.area() tbl['annulus_mean'] = annulus_mean << unit tbl['annulus_mean_err'] = annulus_mean_err << unit tbl['aperture_bkg'] = aperture_bkg << unit tbl['aperture_bkg_err'] = aperture_bkg_err << unit net_aperture_sum = aperture_sum - aperture_bkg net_aperture_sum_err = np.sqrt(aperture_sum_err**2 + aperture_bkg_err**2) tbl['net_aperture_sum'] = net_aperture_sum << unit tbl['net_aperture_sum_err'] = net_aperture_sum_err << unit else: colnames = [ 'annulus_sum', 'annulus_sum_err', 'annulus_mean', 'annulus_mean_err', 'aperture_bkg', 'aperture_bkg_err' ] for col in colnames: tbl[col] = np.full(nimg, np.nan) tbl['net_aperture_sum'] = aperture_sum << unit tbl['net_aperture_sum_err'] = aperture_sum_err << unit return tbl
def tso_aperture_photometry(datamodel, xcenter, ycenter, radius, radius_inner, radius_outer): """ Create a photometric catalog for NIRCam TSO imaging observations. Parameters ---------- datamodel : `CubeModel` The input `CubeModel` of a NIRCam TSO imaging observation. xcenter, ycenter : float The ``x`` and ``y`` center of the aperture. radius : float The radius (in pixels) of the circular aperture. radius_inner, radius_outer : float The inner and outer radii (in pixels) of the circular-annulus aperture, used for local background estimation. Returns ------- catalog : `~astropy.table.QTable` An astropy QTable (Quantity Table) containing the source photometry. """ if not isinstance(datamodel, CubeModel): raise ValueError('The input data model must be a CubeModel.') # For the SUB64P subarray with the WLP8 pupil, the circular aperture # extends beyond the image and the circular annulus does not have any # overlap with the image. In that case, we simply sum all values # in the array and skip the background subtraction. sub64p_wlp8 = False if (datamodel.meta.instrument.pupil == 'WLP8' and datamodel.meta.subarray.name == 'SUB64P'): sub64p_wlp8 = True if not sub64p_wlp8: phot_aper = CircularAperture((xcenter, ycenter), r=radius) bkg_aper = CircularAnnulus((xcenter, ycenter), r_in=radius_inner, r_out=radius_outer) aperture_sum = [] aperture_sum_err = [] annulus_sum = [] annulus_sum_err = [] nimg = datamodel.data.shape[0] if sub64p_wlp8: info = ('Photometry measured as the sum of all values in the ' 'subarray. No background subtraction was performed.') for i in np.arange(nimg): aperture_sum.append(np.sum(datamodel.data[i, :, :])) aperture_sum_err.append( np.sqrt(np.sum(datamodel.err[i, :, :]**2))) else: info = ('Photometry measured in a circular aperture of r={0} ' 'pixels. Background calculated as the mean in a ' 'circular annulus with r_inner={1} pixels and ' 'r_outer={2} pixels.'.format(radius, radius_inner, radius_outer)) for i in np.arange(nimg): aper_sum, aper_sum_err = phot_aper.do_photometry( datamodel.data[i, :, :], error=datamodel.err[i, :, :]) ann_sum, ann_sum_err = bkg_aper.do_photometry( datamodel.data[i, :, :], error=datamodel.err[i, :, :]) aperture_sum.append(aper_sum[0]) aperture_sum_err.append(aper_sum_err[0]) annulus_sum.append(ann_sum[0]) annulus_sum_err.append(ann_sum_err[0]) aperture_sum = np.array(aperture_sum) aperture_sum_err = np.array(aperture_sum_err) annulus_sum = np.array(annulus_sum) annulus_sum_err = np.array(annulus_sum_err) # construct metadata for output table meta = OrderedDict() meta['instrument'] = datamodel.meta.instrument.name meta['detector'] = datamodel.meta.instrument.detector meta['channel'] = datamodel.meta.instrument.channel meta['subarray'] = datamodel.meta.subarray.name meta['filter'] = datamodel.meta.instrument.filter meta['pupil'] = datamodel.meta.instrument.pupil meta['target_name'] = datamodel.meta.target.catalog_name meta['xcenter'] = xcenter meta['ycenter'] = ycenter ra_icrs, dec_icrs = datamodel.meta.wcs(xcenter, ycenter) meta['ra_icrs'] = ra_icrs meta['dec_icrs'] = dec_icrs meta['apertures'] = info # initialize the output table tbl = QTable(meta=meta) if hasattr(datamodel, 'int_times') and datamodel.int_times is not None: nrows = len(datamodel.int_times) else: nrows = 0 if nrows == 0: log.warning("There is no INT_TIMES table in the input file.") if nrows > 0: shape = datamodel.data.shape if len(shape) == 2: num_integ = 1 else: # len(shape) == 3 num_integ = shape[0] int_start = datamodel.meta.exposure.integration_start if int_start is None: int_start = 1 log.warning("INTSTART not found; assuming a value of %d", int_start) # Columns of integration numbers & times of integration from the # INT_TIMES table. int_num = datamodel.int_times['integration_number'] mid_utc = datamodel.int_times['int_mid_MJD_UTC'] offset = int_start - int_num[0] # both are one-indexed if offset < 0: log.warning("Range of integration numbers in science data extends " "outside the range in INT_TIMES table.") log.warning("Can't use INT_TIMES table.") del int_num, mid_utc nrows = 0 # flag as bad else: log.debug("Times are from the INT_TIMES table.") time_arr = mid_utc[offset: offset + num_integ] int_times = Time(time_arr, format='mjd', scale='utc') else: log.debug("Times were computed from EXPSTART and TGROUP.") dt = (datamodel.meta.exposure.group_time * (datamodel.meta.exposure.ngroups + 1)) dt_arr = (np.arange(1, 1 + datamodel.meta.exposure.nints) * dt - (dt / 2.)) int_dt = TimeDelta(dt_arr, format='sec') int_times = (Time(datamodel.meta.exposure.start_time, format='mjd') + int_dt) tbl['MJD'] = int_times.mjd tbl['aperture_sum'] = aperture_sum tbl['aperture_sum_err'] = aperture_sum_err if not sub64p_wlp8: tbl['annulus_sum'] = annulus_sum tbl['annulus_sum_err'] = annulus_sum_err annulus_mean = annulus_sum / bkg_aper.area() annulus_mean_err = annulus_sum_err / bkg_aper.area() tbl['annulus_mean'] = annulus_mean tbl['annulus_mean_err'] = annulus_mean_err aperture_bkg = annulus_mean * phot_aper.area() aperture_bkg_err = annulus_mean_err * phot_aper.area() tbl['aperture_bkg'] = aperture_bkg tbl['aperture_bkg_err'] = aperture_bkg_err net_aperture_sum = aperture_sum - aperture_bkg net_aperture_sum_err = np.sqrt(aperture_sum_err ** 2 + aperture_bkg_err ** 2) tbl['net_aperture_sum'] = net_aperture_sum tbl['net_aperture_sum_err'] = net_aperture_sum_err else: colnames = ['annulus_sum', 'annulus_sum_err', 'annulus_mean', 'annulus_mean_err', 'aperture_bkg', 'aperture_bkg_err'] for col in colnames: tbl[col] = np.full(nimg, np.nan) tbl['net_aperture_sum'] = aperture_sum tbl['net_aperture_sum_err'] = aperture_sum_err return tbl
######################################### Compute signal to noise ######################################## import photometry cx, cy = (np.int_(np.mean(xcc)), np.int_(np.mean(ycc))) sx, sy = (np.int_(np.mean(xcs)), np.int_(np.mean(ycs))) radius = 5 r_in, r_out = 11, 14 # Companion: positions = (cx - 1, cy - 1) ap = CircularAperture(positions, r=radius) skyan = CircularAnnulus(positions, r_in=11, r_out=14) ap = CircularAperture(positions, r=radius) skyan = CircularAnnulus(positions, r_in=11, r_out=14) apsum = ap.do_photometry(image)[0] skysum = skyan.do_photometry(image)[0] averagesky = skysum / skyan.area() signal = (apsum - ap.area() * averagesky)[0] n = ap.area() box = image[cy + 12:cy + 12 + 15, cx + 12:cx + 12 + 15] noise = np.std(box) noise = noise * np.sqrt(n) compsnr = signal / noise # Star: positions = (sx - 1, sy - 1) ap = CircularAperture(positions, r=radius) skyan = CircularAnnulus(positions, r_in=11, r_out=14) ap = CircularAperture(positions, r=radius) skyan = CircularAnnulus(positions, r_in=11, r_out=14)
def analyzeImages(X): # create database f = open(starDataBases[X], "wb") # retrieve data hdu = fits.open('./HRData.fits') data814 = hdu[0].data[0, :, :] data275 = hdu[0].data[2, :, :] hdu.close() mean814, median814, std814 = sigma_clipped_stats(data814, sigma=3.0, iters=5) daofind814 = DAOStarFinder(fwhm=3.0, threshold=4. * std814) mean275, median275, std275 = sigma_clipped_stats(data275, sigma=3.0, iters=5) daofind275 = DAOStarFinder(fwhm=3.0, threshold=4. * std275) ## perform photometry analysis # both apertures if (X == 1): print("Find stars from F814W Filter Data") sources814 = daofind814(data814 - median814) print("Finished F814W Search") print("Find stars from F275W Filter Data") sources275 = daofind275(data275 - median275) print("Finished F275 Search") positions814 = (sources814['xcentroid'], sources814['ycentroid']) apertures814 = CircularAperture(positions814, r=4.) photom814 = apertures814.do_photometry(data814 - median814) positions275 = (sources275['xcentroid'], sources275['ycentroid']) apertures275 = CircularAperture(positions275, r=4.) photom275 = apertures275.do_photometry(data275 - median275) # apertures from infrared elif (X == 2): print("Find stars from F814W Filter Data") sources814 = daofind814(data814 - median814) print("Finished F814W Search") positions814 = (sources814['xcentroid'], sources814['ycentroid']) apertures814 = CircularAperture(positions814, r=4.) photom814 = apertures814.do_photometry(data814 - median814) positions275 = positions814 photom275 = apertures814.do_photometry(data275 - median275) # apertures from ultraviolet elif (X == 3): print("Find stars from F275W Filter Data") sources275 = daofind275(data275 - median275) print("Finished F275 Search") positions275 = (sources275['xcentroid'], sources275['ycentroid']) apertures275 = CircularAperture(positions275, r=4.) photom275 = apertures275.do_photometry(data275 - median275) positions814 = positions275 photom814 = apertures275.do_photometry(data814 - median814) else: print("invalid database selection") return # store data data = (positions814, photom814, positions275, photom275) p.dump(data, f) f.close() return data