コード例 #1
0
def create_aperture_from_ds9_region(region_file):
    '''
    Loads a ds9 region ('reg') file saved in physical format and returns an astropy aperture instance.
    '''
    
    # 
    f = open(region_file,'rb')
    for i in range(3):
        f.readline()
    region_text = f.read()

    pdb.set_trace()
    regions = region_text.split('\n')

    src_apertures,bkg_apertures = [],[] 

    for region in regions[:-1]:
        # This is a poor example of string handling, but it works.
        value_text = region.split('(')[1].split(')')[0]
        pos_x,pos_y,r_in,r_out = np.array(value_text.split(','),dtype = float)
        
        src_apertures.append(photutils.CircularAperture((pos_x,pos_y), r=r_in))
        bkg_aperture.append(photutils.CircularAnnulus((pos_x,pos_y), r_in=r_in, r_out=r_out))

    return src_apertures,bkg_apertures
コード例 #2
0
    def _aperture_phot(self, x, y, data, radsize=1,
                       sky_inner=5, skywidth=5, method="subpixel", subpixels=4):
        """Perform sky subtracted aperture photometry, uses photutils functions, photutil must be installed

        Parameters
        ----------
        radsize: int
            Size of the radius

        sky_inner: int
            Inner radius of the sky annulus

        skywidth: int
            Width of the sky annulus

        method: string
            Pixel sampling method to use

        subpixels: int
            How many subpixels to use

        Notes
        -----
           background is taken from sky annulus pixels, check into masking bad pixels

        """
        if not photutils_installed:
            print("Install photutils to enable")
        else:

            apertures = photutils.CircularAperture((x, y), radsize)
            rawflux_table = photutils.aperture_photometry(
                data,
                apertures,
                subpixels=1,
                method="center")

            outer = sky_inner + skywidth
            annulus_apertures = photutils.CircularAnnulus(
                (x, y), r_in=sky_inner, r_out=outer)
            bkgflux_table = photutils.aperture_photometry(
                data,
                annulus_apertures)

            # to calculate the mean local background, divide the circular annulus aperture sums
            # by the area fo the circular annuls. The bkg sum with the circular aperture is then
            # then mean local background tims the circular apreture area.
            aperture_area = apertures.area()
            annulus_area = annulus_apertures.area()

            bkg_sum = (
                bkgflux_table['aperture_sum'] *
                aperture_area /
                annulus_area)[0]
            skysub_flux = rawflux_table['aperture_sum'][0] - bkg_sum

            return (
                float(rawflux_table['aperture_sum'][0]), bkg_sum, skysub_flux)
コード例 #3
0
def perform_aperture_photometry(xcen, ycen, filename, aperture_radii = np.arange(2, 15), bkg_r_in=16., bkg_r_out=20):
    ofile = fits.open(filename)
    apertures = [pu.CircularAperture((xcen, ycen), r=r) for r in aperture_radii]
    annulus_apertures = pu.CircularAnnulus((xcen, ycen), r_in=bkg_r_in, r_out=bkg_r_out)
    apertures.append(annulus_apertures)
    phot_table = pu.aperture_photometry(ofile[1].data, apertures )
    bkg_colname = phot_table.colnames[-1]
    bkg_mean = phot_table[bkg_colname] / annulus_apertures.area()
    for aper, icol in zip(apertures, phot_table.colnames[3:]):
        bkg_sum = bkg_mean*aper.area()
        phot_table.add_column(phot_table[icol]-bkg_sum, name='{}_bkg_sub'.format(icol))
    return phot_table, apertures
コード例 #4
0
    def __init__(self,
                 name='',
                 pos=(0, 0),
                 loupe=None,
                 aperture_radius=5,
                 background_radii=[15, 25],
                 subtract_background=False):
        '''
        Initialize an interactive aperture.

        Parameters
        ----------
        name : str
            A simple name for the aperture
        pos : tuple
            A two-element list of (x,y)? pixel positions for the center
        loupe : a loupe.Loupe object
            A organizing Loupe in which this aperture is embedded
        aperture_radius : float
            A radius for the aperture
        background_radii : list of two floats
            Inner and outer radii for a background-estimation annulus
        subtract_background : bool
            Should we do background subtraction?
        '''

        # initialize the CircularAperture as normal
        photutils.CircularAperture.__init__(self, pos, aperture_radius)

        # create a background annulus
        r_in, r_out = background_radii
        r_out = np.maximum(r_out, r_in + 1)
        self.background_aperture = photutils.CircularAnnulus(pos, r_in, r_out)
        self.subtract_background = subtract_background

        # keep track of this aperture's name
        self.name = name

        # keep track of the loupe this aperture is a part of
        self.loupe = loupe

        # keep track of the flux in this aperture with an undefined flux
        self.flux = np.nan
コード例 #5
0
ファイル: photometry.py プロジェクト: tingard/PSFGAN
def starphot(imdata, position, radius, r_in, r_out):
    """
    sources: http://photutils.readthedocs.io/en/stable/
    photutils/aperture.html
    ARGS:
        imdata:   Numpy array containing the star.
        position: [x,y] coordinates where x corresponds to the second index of
                  imdata
        radius:   Radius of the circular aperture used to compute the flux of
                  the star.
        r_in:     Inner radius of the annulus used to compute the background
                  mean.
        r_out:    Outer radius of the annulus used to compute the background
                  mean.
    Returns [flux, background variance, background mean]
    """
    try:
        statmask = photutils.make_source_mask(imdata,
                                              snr=5,
                                              npixels=5,
                                              dilate_size=10)
    except TypeError:
        return None
    bkg_annulus = photutils.CircularAnnulus(position, r_in, r_out)
    bkg_phot_table = photutils.aperture_photometry(imdata,
                                                   bkg_annulus,
                                                   method='subpixel',
                                                   mask=statmask)
    bkg_mean_per_pixel = bkg_phot_table['aperture_sum'] / bkg_annulus.area()
    src_aperture = photutils.CircularAperture(position, radius)
    src_phot_table = photutils.aperture_photometry(imdata,
                                                   src_aperture,
                                                   method='subpixel')
    signal = src_phot_table['aperture_sum'] - bkg_mean_per_pixel*\
                                              src_aperture.area()
    #noise_squared = signal + bkg_mean_per_pixel*src_aperture.area()
    mean, median, std = sigma_clipped_stats(imdata,
                                            sigma=3.0,
                                            iters=5,
                                            mask=statmask)
    noise_squared = std**2
    return float(str(signal.data[0])), noise_squared,\
           float(str(bkg_mean_per_pixel.data[0]))
コード例 #6
0
ファイル: photometry.py プロジェクト: joshwalawender/IQMon
    def _perform(self):
        """
        Returns an Argument() with the parameters that depend on this
        operation.
        """
        self.log.info(f"Running {self.__class__.__name__} action")

        exptime = self.action.args.meta.get('exptime')
        pixel_scale = self.cfg['Telescope'].getfloat('pixel_scale', 1)
        thresh = self.cfg['Extract'].getint('extract_threshold', 9)
        minarea = self.cfg['Extract'].getint('extract_minarea', 7)
        mina = self.cfg['Extract'].getfloat('fwhm_mina', 1)
        minb = self.cfg['Extract'].getfloat('fwhm_minb', 1)
        faint_limit_pct = self.cfg['Extract'].getfloat(
            'faint_limit_percentile', 0)
        bright_limit_pct = self.cfg['Extract'].getfloat(
            'bright_limit_percentile', 100)
        radius_limit = self.cfg['Extract'].getfloat('radius_limit_pix', 4000)

        bsub = self.action.args.ccddata.data - self.action.args.background.background
        seperr = self.action.args.ccddata.uncertainty.array
        sepmask = self.action.args.ccddata.mask

        # Define quick utility function
        def run_sep(bsub, seperr, sepmask, thresh, minarea):
            try:
                objects = sep.extract(bsub,
                                      err=seperr,
                                      mask=sepmask,
                                      thresh=float(thresh),
                                      minarea=minarea)
                return objects
            except Exception as e:
                if str(e)[:27] == 'internal pixel buffer full:':
                    return None
                else:
                    raise SEPError(str(e))

        objects = None
        while objects is None:
            try:
                self.log.info(f'Invoking SEP with threshold: {thresh}')
                objects = run_sep(bsub, seperr, sepmask, thresh, minarea)
                thresh += 9
            except SEPError as e:
                self.log.error('Source extractor failed:')
                self.log.error(e)
                return self.action.args

        t = Table(objects)
        t['flux'] /= exptime

        # Add radius (of star from center of image) to table
        ny, nx = bsub.shape
        r = np.sqrt((t['x'] - nx / 2.)**2 + (t['y'] - ny / 2.)**2)
        t.add_column(Column(data=r.data, name='r', dtype=np.float))

        # Add FWHM to table
        coef = 2 * np.sqrt(2 * np.log(2))
        fwhm = np.sqrt((coef * t['a'])**2 + (coef * t['b'])**2)
        t.add_column(Column(data=fwhm.data, name='FWHM', dtype=np.float))

        # Add ellipticities to table
        ellipticities = t['a'] / t['b']
        t.add_column(
            Column(data=ellipticities.data, name='ellipticity',
                   dtype=np.float))

        # Filter out stars based on bright and faint limits
        faint_limit = np.percentile(t['flux'], faint_limit_pct)
        bright_limit = np.percentile(t['flux'], bright_limit_pct)
        self.log.info(
            f'  Faintest {faint_limit_pct:.1f}% flux {faint_limit:f}')
        self.log.info(
            f'  Brightest {bright_limit_pct:.1f}% flux {bright_limit:f}')
        filtered = (t['a'] < mina) | (t['b'] < minb) | (t['flag'] > 0) | (
            t['flux'] > bright_limit) | (t['flux'] <
                                         faint_limit) | (t['r'] > radius_limit)
        self.log.debug(f'  Removing {np.sum(filtered):d}/{len(filtered):d}'\
                       f' extractions from FWHM calculation')
        self.log.debug(
            f"    {np.sum( (t['a'] < mina) )} removed for fwhm_mina limit")
        self.log.debug(
            f"    {np.sum( (t['b'] < minb) )} removed for fwhm_minb limit")
        self.log.debug(
            f"    {np.sum( (t['flag'] > 0) )} removed for source extractor flags"
        )
        self.log.debug(
            f"    {np.sum( (t['flux'] < faint_limit) )} removed for faint limit"
        )
        self.log.debug(
            f"    {np.sum( (t['flux'] > bright_limit) )} removed for bright limit"
        )

        self.action.args.meta['n_objects'] = len(t[~filtered])
        self.log.info(
            f'  Found {self.action.args.meta.get("n_objects"):d} stars')

        self.action.args.objects = t[~filtered]
        self.action.args.objects.sort('flux')
        self.action.args.objects.reverse()

        if self.action.args.meta.get("n_objects") == 0:
            self.log.warning('No stars found')
            return self.action.args
        else:
            FWHM_pix = np.median(t['FWHM'][~filtered])
            FWHM_mode_bin = pixel_scale * 0.25
            FWHM_pix_mode = mode(
                t['FWHM'][~filtered] / FWHM_mode_bin) * FWHM_mode_bin
            self.log.info(
                f'  Median FWHM = {FWHM_pix:.1f} pix ({FWHM_pix*pixel_scale:.2f} arcsec)'
            )
            self.log.info(
                f'  Mode FWHM = {FWHM_pix_mode:.1f} pix ({FWHM_pix_mode*pixel_scale:.2f} arcsec)'
            )
            ellipticity = np.median(t['ellipticity'][~filtered])
            ellipticity_mode_bin = 0.05
            ellipticity_mode = mode(
                t['ellipticity'][~filtered] /
                ellipticity_mode_bin) * ellipticity_mode_bin
            self.log.info(f'  Median ellipticity = {ellipticity:.2f}')
            self.log.info(f'  Mode ellipticity = {ellipticity_mode:.2f}')
            self.action.args.meta['fwhm'] = FWHM_pix_mode
            self.action.args.meta['ellipticity'] = ellipticity_mode

        ## Do photutils photometry measurement
        positions = [(det['x'], det['y']) for det in self.action.args.objects]
        ap_radius = self.cfg['Photometry'].getfloat('aperture_radius',
                                                    2) * FWHM_pix
        star_apertures = photutils.CircularAperture(positions, ap_radius)
        sky_apertures = photutils.CircularAnnulus(
            positions,
            r_in=int(np.ceil(1.5 * ap_radius)),
            r_out=int(np.ceil(2.0 * ap_radius)))
        phot_table = photutils.aperture_photometry(
            self.action.args.ccddata, [star_apertures, sky_apertures])
        phot_table['sky'] = phot_table['aperture_sum_1'] / sky_apertures.area()
        med_sky = np.median(phot_table['sky'])
        self.log.info(f'  Median Sky = {med_sky.value:.0f} e-/pix')
        self.action.args.meta['sky_background'] = med_sky.value
        self.action.args.objects.add_column(phot_table['sky'])
        bkg_sum = phot_table['aperture_sum_1'] / sky_apertures.area(
        ) * star_apertures.area()
        final_sum = (phot_table['aperture_sum_0'] - bkg_sum)
        final_uncert = (bkg_sum + final_sum)**0.5 * u.electron**0.5
        phot_table['apflux'] = final_sum / exptime
        self.action.args.objects.add_column(phot_table['apflux'])
        phot_table['apuncert'] = final_uncert / exptime
        self.action.args.objects.add_column(phot_table['apuncert'])
        phot_table['snr'] = final_sum / final_uncert
        self.action.args.objects.add_column(phot_table['snr'])

        where_bad = (final_sum <= 0)
        self.log.info(f'  {np.sum(where_bad)} stars rejected for flux < 0')
        self.action.args.objects = self.action.args.objects[~where_bad]
        self.action.args.meta['n_fluxes'] = len(self.action.args.objects)
        self.log.info(
            f'  Fluxes for {self.action.args.meta["n_fluxes"]:d} stars')

        return self.action.args
コード例 #7
0
def aperture(image, dt_expstart, fcoords):
    """
    The main function for doing aperture photometry on individual FITS files
    app = -1 means the results are for a PSF fit instead of aperture photometry
    
    Arguments:
    image       = Image data as 2D numpy.ndarray
    dt_expstart = UTC timestamp of start of exposure as datetime.datetime object.
    fcoords     = Text file with pixel coordinates for stars in first frame. Format:
     targx targy
     compx compy
     compx compy
    """
    global iap, pguess_old, nstars, svec
    dnorm = 500.
    rann1 = 18.
    dann = 2.
    rann2 = rann1 + dann
    # variable apertures fail for data on 2014-07-01
    # restricting apertures to 4 pix for now
    # STH, 2014-07-01
    # app_min = 1.
    # app_max = 19.
    app_min = 3.
    app_max = 8.
    dapp = 1.
    app_sizes = np.arange(app_min,app_max,dapp)

    # If first time through, read in "guesses" for locations of stars
    # TODO: just read a csv
    if iap == 0:
        var = np.loadtxt(fcoords)
        xvec = var[:,0]
        yvec = var[:,1]
        nstars = len(xvec)
    else:
        xvec = svec[:,0]
        yvec = svec[:,1]

    # Find locations of stars
    # dxx0 is size of bounding box around star location.
    # Box edge is 2*dxx0
    # TODO: make dxx0 = prelim guess of fwhm
    dxx0 = 10.
    for i in range(nstars):
        xx0 = [xvec[i], yvec[i]]
        xbounds = (xx0[0]-dxx0,xx0[0]+dxx0)
        ybounds = (xx0[1]-dxx0,xx0[1]+dxx0)
        # TODO: when next released by photutils, use:
        # centroid = photutils.detection.morphology.centroid_2dg()
        res = sco.minimize(center, xx0, method='L-BFGS-B', bounds=(xbounds,ybounds),jac=der_center)
        xx0=res.x
        xvec[i] = xx0[0]
        yvec[i] = xx0[1]

    # Calculate sky around stars
    anns = [photutils.CircularAnnulus(rann1, rann2)] * len(xvec)
    sky  = photutils.aperture_photometry(image, xvec, yvec, anns, method='exact',subpixels=10)

    # Do psf fits to stars. Results are stored in arrays fwhm, pflux, psky, psf_x, and psf_y
    fwhm  = np.zeros(nstars)

    # Make stacked array of star positions from aperture photometry
    svec = np.dstack((xvec,yvec))[0]

    # Make stacked array of star positions from PSF fitting
    # pvec = np.dstack((psf_x,psf_y))[0]
    pvec = svec

    iap = iap + 1

    starr = []
    apvec = []
    app=-1.0

    # Get time of observation from the header
    #date = hdr['DATE-OBS']   # for Argos files
    #utc  = hdr['UTC']         # for Argos files
    # date = hdr['UTC-DATE']    # for Pro-EM files
    # utc  = hdr['UTC-BEG']     # for Pro-EM files
    # times = date + "  " + utc
    # t = Time(times, format='iso', scale='utc')
    # TODO: astropy 0.3.2 fully supports datetime objects
    # When we can upgrade photutils and thus numpy, use datetime objects.
    try:
        t = Time(dt_expstart, scale='utc')
    # ValueError if we haven't upgraded astropy.
    except ValueError:
        t = Time(dt_expstart.isoformat(), format='isot', scale='utc')
    # Calculate Julian Date of observation
    jd  = t.jd
    # TODO: As of 2014-06-01, photutils allows vectors of apertures. Use them. STH
    for radius in app_sizes:
        app = [photutils.CircularAperture(radius)]
        flux = [photutils.aperture_photometry(image, x, y, app, method='exact',subpixels=10)
                for (x, y) in zip(xvec, yvec)]
        skyc = sky*radius**2/(rann2**2 - rann1**2)
        fluxc = flux  - skyc
        starr.append([fluxc,skyc,fwhm])
        apvec.append(radius)
    starr = np.array(starr)
    apvec = np.array(apvec)
    return jd,svec,pvec,apvec,starr
コード例 #8
0
    def fit_gaussian(self, plot=True, verbose=False, save=None):
        """
        Perform a fit of a 2D gaussian. 
        Input:
            - plot: (optional) bool. If True, makes a plot of the image with 
            the contours of the gaussian
            - verbose: (optional) bool. If True, prints the verbose of mpdfit
            - additional optional keywords can be 'amp', 'centerx', 'centery', 
                'sigmax','sigmay','fwhm' or 'theta' to set the value of the 
                first guess of the fit. theta must be between 0 and 90
            - save: (optional) string with the name to save a pdf of the fit (only
                    valid if plot=True)
                    and a ds9 reg file (still to be implemented)
        Output:
            - fit_result: a dictionary with the parameters of the best fit. 
            The entries are 'AMP' 'X' 'FWHMX' 'Y' 'FWHMY' 'FWHM' 'THETA' 'ell' 
            - fit_error: a dictionary with the parameters of the error on the previous parameters (same entries)
            - chi2: value of the chi square
            - chi2_reduced: value of the reduced chi squared
        """
        for i in self.good_frames:
            if verbose:
                print('Processing image {0:d}'.format(i))
            current_image = self.cube[i, :, :] - self.bck
            current_ma = np.ma.masked_array(current_image - self.bck,
                                            mask=self.mask)

            sky_med = np.median(current_ma)
            sky_rms = np.std(current_ma)
            if sky_med > 5:
                print('Warning, the sky level is high: {0:5.1f} ADU'.format(
                    sky_med))
            if sky_rms > 5:
                print('Warning, the background noise is high: {0:5.1f} ADU'.
                      format(sky_rms))

            # We first set a default guess
            filtered_image = gaussian_filter(current_image, 2)
            argmax = np.argmax(filtered_image)
            ymax, xmax = np.unravel_index(argmax, current_image.shape)
            amp = np.max(current_image)
            guess_dico = {
                'amp': amp,
                'centerx': xmax,
                'centery': ymax,
                'sigx': self.theoretical_sig,
                'sigy': self.theoretical_sig,
                'theta': 0.
            }
            # We also set default boundaries
            parinfo = [
                {
                    'fixed': 0,
                    'limited': [1, 1],
                    'limits': [0., 2 * amp]
                },  # Force the amplitude to be >0
                {
                    'fixed': 0,
                    'limited': [1, 1],
                    'limits': [7, self.nx - 7]
                },  # We restrain the center to be 1px 
                {
                    'fixed': 0,
                    'limited': [1, 1],
                    'limits': [7, self.ny - 7]
                },  # away from the edge
                {
                    'fixed': 0,
                    'limited': [1, 1],
                    'limits':
                    [self.theoretical_sig, 1.4 * self.theoretical_sig]
                },  # sigma_x between 0.5 and 10px
                {
                    'fixed': 0,
                    'limited': [1, 1],
                    'limits':
                    [self.theoretical_sig, 1.4 * self.theoretical_sig]
                },  # sigma_y between 0.5 and 10px
                {
                    'fixed': 0,
                    'limited': [1, 1],
                    'limits': [0, 180.]
                }
            ]  # We limit theta beween 0 and 90 deg

            fa = {
                'x': self.x_array,
                'y': self.y_array,
                'z': current_image,
                'err': np.ones_like(current_image) * sky_rms
            }
            guess = [
                guess_dico['amp'], guess_dico['centerx'],
                guess_dico['centery'], guess_dico['sigx'], guess_dico['sigy'],
                guess_dico['theta']
            ]
            m = mpfit.mpfit(self.gauss2D_fit_erf,
                            guess,
                            functkw=fa,
                            parinfo=parinfo,
                            quiet=1)  # quiet=(not verbose)*1)
            if m.status == 0:
                print(
                    'Fit failed for frame {0:d}. Try to help the minimizer by providing a better first guess'
                    .format(i))
            else:
                residuals = self.gauss2D_fit_erf(
                    m.params,
                    x=self.x_array,
                    y=self.y_array,
                    z=current_image,
                    err=np.ones_like(current_image) * sky_rms)[1].reshape(
                        current_image.shape)
                self.residuals[i, :, :] = residuals  #+self.bck #+sky_med
                self.fit_result['CHI2'][i] = np.sum(residuals**2)
                self.fit_result['CHI2_r'][
                    i] = self.fit_result['CHI2'][i] / m.dof
                self.fit_result['AMP'][i] = m.params[0]
                self.fit_result['X'][i] = m.params[1]
                self.fit_result['Y'][i] = m.params[2]
                sig = np.array([m.params[3], m.params[4]])
                sig_error = np.array([m.perror[3], m.perror[4]])
                error_ell = 4 / (np.sum(sig)**2) * np.sqrt(
                    np.sum((sig * sig_error)**2))
                fwhm = sig2fwhm(sig)
                fwhm_error = sig2fwhm(sig_error)
                self.fit_result['FWHMX'][i] = fwhm[0]
                self.fit_result['FWHMY'][i] = fwhm[1]
                self.fit_result['FWHM'][i] = np.mean(fwhm)
                self.fit_result['THETA'][i] = m.params[5]
                self.fit_result['ell'][i] = (sig[1] - sig[0]) / np.mean(sig)

                self.fit_error['AMP'][i] = m.perror[0]
                self.fit_error['X'][i] = m.perror[1]
                self.fit_error['Y'][i] = m.perror[2]
                self.fit_error['FWHMX'][i] = fwhm_error[0]
                self.fit_error['FWHMY'][i] = fwhm_error[1]
                self.fit_error['FWHM'][i] = np.mean(fwhm_error)
                self.fit_error['THETA'][i] = m.perror[5]
                self.fit_error['ell'][i] = error_ell

                annulus_aperture = photutils.CircularAnnulus((self.fit_result['X'][i],self.fit_result['Y'][i]), \
                                                     r_in=self.theoretical_fwhm,\
                                                     r_out=2*self.theoretical_fwhm)
                phot_table_annulus = photutils.aperture_photometry(residuals**2, \
                                    annulus_aperture,error=np.ones_like(current_image)*sky_rms)
                self.fit_result['annulus_rms'][i] = np.sqrt(
                    phot_table_annulus['aperture_sum']
                    [0]) / phot_table_annulus['aperture_sum_err'][0]

                circular_aperture = photutils.CircularAperture((self.fit_result['X'][i],self.fit_result['Y'][i]), \
                                                     r=2.5*self.theoretical_fwhm)
                phot_table_circle = photutils.aperture_photometry(residuals**2, \
                                    circular_aperture,error=np.ones_like(current_image)*sky_rms)
                self.fit_result['circle_rms'][i] = np.sqrt(
                    phot_table_circle['aperture_sum']
                    [0]) / phot_table_circle['aperture_sum_err'][0]

                mask_aperture = np.zeros_like(current_image, dtype=bool)
                mask_R = np.copy(mask_aperture)  #right
                mask_R[self.x_array > self.fit_result['X'][i]] = True
                mask_L = np.copy(mask_aperture)  #left
                mask_L[self.x_array < self.fit_result['X'][i]] = True
                mask_T = np.copy(mask_aperture)  #top
                mask_T[self.y_array > self.fit_result['Y'][i]] = True
                mask_B = np.copy(mask_aperture)  # bottom
                mask_B[self.y_array < self.fit_result['Y'][i]] = True
                phot_table_T = photutils.aperture_photometry(residuals**2, annulus_aperture,\
                                error=np.ones_like(current_image)*sky_rms,mask=mask_T)
                self.fit_result['T_rms'][i] = np.sqrt(
                    phot_table_T['aperture_sum']
                    [0]) / phot_table_T['aperture_sum_err'][0]
                phot_table_B = photutils.aperture_photometry(residuals**2, annulus_aperture,\
                                error=np.ones_like(current_image)*sky_rms,mask=mask_B)
                self.fit_result['B_rms'][i] = np.sqrt(
                    phot_table_B['aperture_sum']
                    [0]) / phot_table_B['aperture_sum_err'][0]
                phot_table_L = photutils.aperture_photometry(residuals**2, annulus_aperture,\
                                error=np.ones_like(current_image)*sky_rms,mask=mask_L)
                self.fit_result['L_rms'][i] = np.sqrt(
                    phot_table_L['aperture_sum']
                    [0]) / phot_table_L['aperture_sum_err'][0]
                phot_table_R = photutils.aperture_photometry(residuals**2, annulus_aperture,\
                                error=np.ones_like(current_image)*sky_rms,mask=mask_R)
                self.fit_result['R_rms'][i] = np.sqrt(
                    phot_table_R['aperture_sum']
                    [0]) / phot_table_R['aperture_sum_err'][0]
                self.fit_result['asymmetry'][i] = np.max([
                    np.abs(self.fit_result['T_rms'][i] -
                           self.fit_result['B_rms'][i]),
                    np.abs(self.fit_result['L_rms'][i] -
                           self.fit_result['T_rms'][i])
                ])

                if verbose:
                    print('X={0:4.2f}+/-{1:4.2f} Y={2:4.2f}+/-{3:4.2f} FWHM={4:3.2f}+/-{5:4.2f} ell={6:4.2f}+/-{7:4.2f}'.format(self.fit_result['X'][i],\
                          self.fit_error['X'][i],self.fit_result['Y'][i],self.fit_error['Y'][i],self.fit_result['FWHM'][i],self.fit_error['FWHM'][i],self.fit_result['ell'][i],self.fit_error['ell'][i],))
                    print('AMP={0:4.2e}+/-{1:3.2e} theta={2:3.1f}+/-{3:3.1f}deg SKY={4:4.2f}+/-{5:4.2f}'.format(self.fit_result['AMP'][i],\
                          self.fit_error['AMP'][i],self.fit_result['THETA'][i],self.fit_error['THETA'][i],sky_med,sky_rms))
                    print('DOF={0:d} CHI2={1:.1f} CHI2_r={2:.1f}'.format(
                        m.dof, self.fit_result['CHI2'][i],
                        self.fit_result['CHI2_r'][i]))
                if plot:
                    plt.close(1)
                    fig = plt.figure(1, figsize=(7.5, 3))
                    gs = gridspec.GridSpec(1,
                                           3,
                                           height_ratios=[1],
                                           width_ratios=[1, 1, 0.06])
                    gs.update(left=0.1,
                              right=0.9,
                              bottom=0.1,
                              top=0.93,
                              wspace=0.2,
                              hspace=0.03)
                    ax1 = plt.subplot(gs[0, 0])  # Area for the first plot
                    ax2 = plt.subplot(gs[0, 1])  # Area for the second plot
                    ax3 = plt.subplot(gs[0, 2])  # Area for the second plot
                    im = ax1.imshow(current_image,
                                    cmap='CMRmap',
                                    origin='lower',
                                    interpolation='nearest',
                                    extent=[
                                        np.min(self.x_array),
                                        np.max(self.x_array),
                                        np.min(self.y_array),
                                        np.max(self.y_array)
                                    ],
                                    vmin=np.nanmin(current_ma),
                                    vmax=np.nanmax(current_ma))
                    ax1.set_xlabel('X in px')
                    ax1.set_ylabel('Y in px')
                    ax1.contour(
                        self.x_array,
                        self.y_array,
                        sky_med + Gaussian2D(
                            m.params[0], m.params[1], m.params[2], m.params[3],
                            m.params[4], np.radians(m.params[5]))(
                                self.x_array, self.y_array),
                        3,
                        colors='w')
                    ax1.grid(True, c='w')
                    im2 = ax2.imshow(
                        residuals,
                        cmap='CMRmap',
                        origin='lower',
                        interpolation='nearest',
                        extent=[
                            np.min(self.x_array),
                            np.max(self.x_array),
                            np.min(self.y_array),
                            np.max(self.y_array)
                        ],
                        vmin=np.nanmin(current_image),
                        vmax=np.nanmax(current_ma)
                    )  #, extent=[np.min(self.x_array),np.max(self.x_array),np.min(self.y_array),np.max(y_array)])
                    ax2.set_xlabel('X in px')
                    ax2.grid(True, c='w')
                    fig.colorbar(im, cax=ax3)
                    if save is not None:
                        fig.savefig(save + '_{0:d}.pdf'.format(i))
            plt.figure(1)
            plt.clf()
            plt.plot(self.fit_result['CHI2_r'], label='chi2 r')
            plt.plot(self.fit_result['annulus_rms'], label='annulus')
            plt.plot(self.fit_result['asymmetry'], label='asymmetry')
            plt.plot(self.fit_result['circle_rms'], label='circle')
            plt.legend(frameon=False, loc='best')
        return
コード例 #9
0
    def aper_phot(self, x, y, data):
        """Perform aperture photometry, uses photutils functions, photutils must be available

        """
        sigma = 0.  # no centering
        amp = 0.  # no centering
        if not photutils_installed:
            print("Install photutils to enable")
        else:
            if self.aperphot_pars["center"][0]:
                center = True
                delta = 10
                popt = self.gauss_center(x, y, data, delta=delta)
                if 5 > popt.count(0) > 1:  # an error occurred in centering
                    warnings.warn(
                        "Problem fitting center, using original coordinates")
                else:
                    amp, x, y, sigma, offset = popt

            radius = int(self.aperphot_pars["radius"][0])
            width = int(self.aperphot_pars["width"][0])
            inner = int(self.aperphot_pars["skyrad"][0])
            subsky = bool(self.aperphot_pars["subsky"][0])

            outer = inner + width

            apertures = photutils.CircularAperture((x, y), radius)
            rawflux_table = photutils.aperture_photometry(
                data,
                apertures,
                subpixels=1,
                method="center")

            if subsky:
                annulus_apertures = photutils.CircularAnnulus(
                    (x, y), r_in=inner, r_out=outer)
                bkgflux_table = photutils.aperture_photometry(
                    data,
                    annulus_apertures)

                # to calculate the mean local background, divide the circular annulus aperture sums
                # by the area fo teh circular annuls. The bkg sum with the circular aperture is then
                # then mean local background tims the circular apreture area.
                aperture_area = apertures.area()
                annulus_area = annulus_apertures.area()

                bkg_sum = float(
                    (bkgflux_table['aperture_sum'] *
                     aperture_area /
                     annulus_area)[0])
                total_flux = rawflux_table['aperture_sum'][0] - bkg_sum
                sky_per_pix = float(
                    bkgflux_table['aperture_sum'] /
                    annulus_area)

            else:
                total_flux = float(rawflux_table['aperture_sum'][0])

            # compute the magnitude of the sky corrected flux
            magzero = float(self.aperphot_pars["zmag"][0])
            mag = magzero - 2.5 * (np.log10(total_flux))

            pheader = (
                "x\ty\tradius\tflux\tmag(zpt={0:0.2f})\tsky\t".format(magzero)).expandtabs(15)
            if center:
                pheader += ("fwhm")
                pstr = "\n{0:.2f}\t{1:0.2f}\t{2:d}\t{3:0.2f}\t{4:0.2f}\t{5:0.2f}\t{6:0.2f}".format(
                    x + 1, y + 1, radius, total_flux, mag, sky_per_pix, math_helper.gfwhm(sigma)).expandtabs(15)
            else:
                pstr = "\n{0:0.2f}\t{1:0.2f}\t{2:d}\t{3:0.2f}\t{4:0.2f}\t{5:0.2f}".format(
                    x + 1, y + 1, radius, total_flux, mag, sky_per_pix,).expandtabs(15)

            print(pheader + pstr)
            logging.info(pheader + pstr)
コード例 #10
0
    def radial_profile(self, x, y, data=None, form=None, fig=None):
        """Display the radial profile plot (intensity vs radius) for the object.

        Background may be subtracted and centering can be done with a
        2D Gaussian fit
        """
        if not photutils_installed:
            print("Install photutils to enable")
        else:

            if data is None:
                data = self._data

            if not form:
                form = getattr(models, self.radial_profile_pars["fittype"][0])

            getdata = bool(self.radial_profile_pars["getdata"][0])
            subtract_background = bool(
                self.radial_profile_pars["background"][0])

            # cut the data down to size
            datasize = int(self.radial_profile_pars["rplot"][0]) - 1
            delta = 10  # chunk size in pixels to find center

            # center on image using a 2d gaussian
            if self.radial_profile_pars["center"][0]:
                # pull out a small chunk to get the center defined
                amp, centerx, centery, sigma, sigmay = self.gauss_center(
                    x, y, data, delta=delta)
            else:
                centery = y
                centerx = x
            icenterx = int(centerx)
            icentery = int(centery)

            # just grab the data box we want from the image
            data_chunk = data[icentery - datasize:icentery + datasize,
                              icenterx - datasize:icenterx + datasize]

            y, x = np.indices((data_chunk.shape))
            r = np.sqrt((x - datasize)**2 + (y - datasize)**2)
            r = r.astype(np.int)
            # add up the flux in integer bins
            tbin = np.bincount(r.ravel(), data_chunk.ravel())
            nr = np.arange(len(tbin))

            # Get a background measurement
            if subtract_background:
                inner = self.radial_profile_pars["skyrad"][0]
                width = self.radial_profile_pars["width"][0]
                annulus_apertures = photutils.CircularAnnulus(
                    (centerx, centery), r_in=inner, r_out=inner + width)
                bkgflux_table = photutils.aperture_photometry(
                    data, annulus_apertures)

                # to calculate the mean local background, divide the circular
                # annulus aperture sums by the area fo the circular annulus.
                # The bkg sum with the circular aperture is then
                # then mean local background tims the circular apreture area.
                annulus_area = annulus_apertures.area()
                sky_per_pix = float(bkgflux_table['aperture_sum'] /
                                    annulus_area)
                tbin -= np.bincount(r.ravel()) * sky_per_pix
                if getdata:
                    print("Sky per pixel: {0} using\
                         (rad={1}->{2})".format(sky_per_pix, inner,
                                                inner + width))

            if fig is None:
                fig = plt.figure(self._figure_name)
            fig.clf()
            fig.add_subplot(111)
            ax = fig.gca()
            title = self.radial_profile_pars["title"][0]
            ax.set_xlabel(self.radial_profile_pars["xlabel"][0])
            ax.set_ylabel(self.radial_profile_pars["ylabel"][0])

            if getdata:
                info = "\nat (x,y)={0:d},{1:d}\nradii:{2}\nflux:{3}".format(
                    int(centerx + 1), int(centery + 1), nr, tbin)
                print(info)
                logging.info(info)

            #finish the plot
            if bool(self.radial_profile_pars["pointmode"][0]):
                ax.plot(nr, tbin, self.radial_profile_pars["marker"][0])
            else:
                ax.plot(nr, tbin)
            ax.set_title(title)
            ax.set_ylim(0, )

            #over plot a gaussian fit to the data
            if bool(self.radial_profile_pars["fitplot"][0]):
                print("Fit overlay not yet implemented")

            if 'nbagg' in get_backend().lower():
                fig.canvas.draw()
            else:
                plt.draw()
                plt.pause(0.001)
def aperture_photometry_data(star, input_filename, r_stellar, r_inner, r_outer, central_pixel_x, central_pixel_y, wavelength, data, data_unc):

	#Openeing Scuba2 data and error file
	data = observation_file(input_filename, sq_pix_size, wavelength)
	data_unc = observation_file_unc(input_filename, sq_pix_size, wavelength)

	#Getting stellar central postion from fits file header
	fitsFile = fits.open(input_filename)	
	cx = central_pixel_x 
	#print ('cx =', cx)
	cy = central_pixel_y
	#print ('cy =', cy)
	central_positions = (cx-1, cy-1) 

	#Aperture Photometry
	stellar_aperture = photutils.CircularAperture(central_positions, r_stellar) #Stellar Aperture
	sky_annlus = photutils.CircularAnnulus(central_positions, r_inner, r_outer) #Sky Annulus

	error = data_unc
	apertures = [stellar_aperture, sky_annlus]
	aperture_photometry = photutils.aperture_photometry(data, apertures, error=error) #Carrying out Aperture Photometry

	#Adding Object name Aperture Photometry Output Table
	aperture_photometry['Object'] = star

	#x and y centers of the annuli are already automatically in the aperture photometry tables

	#Calculating Final Mean Stellar Flux and Unc. 
	bkg_mean = aperture_photometry['aperture_sum_1'] / sky_annlus.area() #Caclulating BG flux
	bkg_sum = bkg_mean * stellar_aperture.area()

	stellar_flux =  aperture_photometry['aperture_sum_0'] - bkg_sum #Final Mean Flux (Background reduced)
	aperture_photometry['final_stellar_flux_sum'] = stellar_flux 

	#Source Unc
	aperture_photometry_unc = np.sqrt(

					((aperture_photometry['aperture_sum_err_0'])**2) + 
					
						(
                            (((stellar_aperture.area()/sky_annlus.area())*(aperture_photometry['aperture_sum_err_1']))**2)
                             #Rescaling the same as bkg_sum
						)
					) #Add Calibration Error!!!!!!!!


	#np.sqrt((((aperture_photometry['aperture_sum_err_0'])**2) + (((aperture_photometry['aperture_sum_err_1'])*(stellar_aperture.area()/sky_annlus.area()))**2))) #Uncertainty on Final Mean Flux #Add Calibration Error!!!!!!!!

	#Callibration unc of 5% for PACS data
	Cal_unc = 0.05 *  stellar_flux

	
	#Total combined unc
	Tot_unc = ( np.sqrt( ((aperture_photometry_unc/stellar_flux)**2) + ((Cal_unc/stellar_flux)**2) ) ) * stellar_flux 


	aperture_photometry['final_stellar_flux_uncertainty'] = Tot_unc
	
	#print(aperture_photometry)

	return aperture_photometry	
コード例 #12
0
# Approximate positions
xapprx, yapprx = (607,645)

# Centroiding
xc,yc = cntrd(target_i,xapprx,yapprx,fwhm=6)
print xc,yc

# Setting aperture radius and sky annuli
ap_rad = 10.0
sky_in = 13.0
sky_out= 20.0

# Defining aperture radius and sky annulus region
aperture = ph.CircularAperture( (xc,yc), r=ap_rad)    
sky_ann  = ph.CircularAnnulus ( (xc,yc), r_in=sky_in, r_out=sky_out)

# Defining sky per pixel
n_pxls_src = np.pi*ap_rad**2
n_pxls_sky = np.pi*(sky_out**2 - sky_in**2)
sky_per_pixel = sky_raw['aperture_sum'] / n_pxls_sky
bg_flx_in_src = sky_per_pixel * n_pxls_src
print sky_per_pixel

# Defining source flux
src_flux = src_raw['aperture_sum'] - bg_flx_in_src
print src_flux

# Exposure time from FITS header
headerB=pf.getheader('D43.fits')
headerV=pf.getheader('D44.fits')
コード例 #13
0
ファイル: photometry.py プロジェクト: tingard/PSFGAN
def add_hubble_PSF(origpath,
                   original,
                   psf_flux,
                   santinidir=None,
                   median_combine=False,
                   psfdir=None,
                   RA=None,
                   DEC=None,
                   GALFIT_tmpdir=None,
                   save_psf=False,
                   field_path=None):
    """
    Args:
        origpath:      Path to original images.
        psf_flux:      Desired flux of the PSF that is beeing added to the
                       original image.
        obj_line:      Dictionary containing the following SDSS parameters
                       keywords: run, rerun, camcol, field, colc, rowc, dr7ObjID.
        tabledir:      Path to Santini table. This is needed to read the
                       positions of stars if median_combine is True.
        median_combine:Bool specifying wheter a single Hubble PSF is used
                       (median_combine=False) or a position dependent PSF is
                       extracted by median combining stars
                       (median_combine=True).
        psfdir:        Path to Hubble PSF. This is necessary if median_combine
                       is set to False.
        RA/DEC:        Coordinates of the galaxy in degrees. This is used to
                       select stars from the neighbourhood if median_combine is
                       set to True.
        GALFIT_tmpdir: Path to directory where temporary files for GALFIT are
                       saved. GALFIT is only run if median_combine is set to
                       True and all the temporary files will be deleted after
                       they have been used.
        save_psf:      True if PSF should be saved for each image.
        field_path:    Path to field where stars should be extracted from (to
                       create a PSF)
    """
    # If the PSF used for the fake AGN has to be saved (save_psf==True):
    psf_save_path = conf.run_case + '/psf_used/'
    pixel_scale = 0.06
    fwhm = 0.18
    if median_combine:
        #path_to_field = conf.run_case+"/hlsp_candels_hst_wfc3_gs-tot_f160w_v1.0_drz.fits"
        path_to_field = field_path
        if not os.path.isdir(GALFIT_tmpdir):
            os.makedirs(GALFIT_tmpdir)
        table = astrotable.Table.read(santinidir)
        df = table.to_pandas()
        catalog = df[['RAdeg', 'DECdeg', 'Hmag', 'H_SNR', 'Class_star_1']]
        field_hdu = fits.open(path_to_field)[0]
        w = wcs.WCS(field_hdu.header)
        pixel_coordinates = w.wcs_world2pix(RA, DEC, 0, ra_dec_order=True)
        pixel_y = pixel_coordinates[1]
        pixel_x = pixel_coordinates[0]

        # Filter out hihg SNR stars from the neighborhood of the galaxy.
        star_mask = df['Class_star_1'] > 0.9
        df_stars = df[star_mask]
        SNR_mask = df_stars['H_SNR'] > 5.0
        df_bright = df_stars[SNR_mask]
        numpy_ra = np.array(df_bright['RAdeg'])
        numpy_dec = np.array(df_bright['DECdeg'])
        [x_crds, y_crds] = w.wcs_world2pix(numpy_ra,
                                           numpy_dec,
                                           0,
                                           ra_dec_order=True)
        neighbor_mask_size = 4000
        neighbor_mask = np.array(np.ones(len(numpy_ra), dtype=bool))
        for i in range(0, len(numpy_ra)):
            if np.abs(x_crds[i]-pixel_x) > neighbor_mask_size/2 or \
               np.abs(y_crds[i]-pixel_y) > neighbor_mask_size/2:
                neighbor_mask[i] = False
        df_selected = df_bright[neighbor_mask]
        x_coordinates = x_crds[neighbor_mask]
        y_coordinates = y_crds[neighbor_mask]
        h_mags = np.array(df_selected['Hmag'])
        print str(len(x_coordinates)) + ' stars selected.'

        csize = 40
        # get median combined PSF
        psf_unscaled = empirical_PSF(field_hdu.data,
                                     x_coordinates,
                                     y_coordinates,
                                     csize,
                                     fwhm / pixel_scale,
                                     GALFIT_tmpdir,
                                     h_mags,
                                     phot_zeropoint=25.9463,
                                     pixel_scale=pixel_scale)

        files_to_delete = glob.glob(GALFIT_tmpdir + '*')
        for f in files_to_delete:
            os.remove(f)

        if psf_unscaled is None:
            return None

    else:  # else <==> median_combine==False
        psf_unscaled = fits.getdata(psfdir)
        csize = 40

    if median_combine:
        # compute statistics to subtract the background
        psf_centroid = [csize, csize]
        try:
            statmask = photutils.make_source_mask(psf_unscaled,
                                                  snr=5,
                                                  npixels=5,
                                                  dilate_size=10)
        except TypeError:
            return None
        bkg_annulus = photutils.CircularAnnulus(psf_centroid, 25, 40)
        bkg_phot_table = photutils.aperture_photometry(psf_unscaled,
                                                       bkg_annulus,
                                                       method='subpixel',
                                                       mask=statmask)
        bkg_mean_per_pixel = bkg_phot_table['aperture_sum'] / bkg_annulus.area(
        )
        src_aperture = photutils.CircularAperture(psf_centroid, 25)
        src_phot_table = photutils.aperture_photometry(psf_unscaled,
                                                       src_aperture,
                                                       method='subpixel')
        flux_photutils = src_phot_table['aperture_sum'] - bkg_mean_per_pixel * \
        src_aperture.area()

        scale_factor = psf_flux / flux_photutils
        psf = scale_factor * (psf_unscaled - bkg_mean_per_pixel)
        #psf = scale_factor * psf_unscaled
    else:
        scale_factor = psf_flux / psf_unscaled.sum()
        psf = scale_factor * psf_unscaled

    if save_psf:
        hdu = fits.PrimaryHDU(psf_unscaled - bkg_mean_per_pixel)
        hdu.writeto(psf_save_path + os.path.basename(origpath), overwrite=True)

    # add scaled PSF to the center of the galaxy
    center = [original.shape[1] // 2, original.shape[0] // 2]
    centroid_galaxy = find_centroid(original)
    centroid_PSF = find_centroid(psf)

    composite_image = np.copy(original)

    gal_x = int(centroid_galaxy[0])
    gal_y = int(centroid_galaxy[1])
    ps_x = int(centroid_PSF[0])
    ps_y = int(centroid_PSF[1])

    # Put the PS on top of the galaxy at its centroid.
    for x in range(0, psf.shape[1]):
        for y in range(0, psf.shape[0]):
            x_rel = gal_x - ps_x + x
            y_rel = gal_y - ps_y + y
            if x_rel >= 0 and y_rel >= 0 and x_rel < original.shape[1] and \
                                                      y_rel < original.shape[0]:
                composite_image[y_rel, x_rel] += psf[y, x]

    return composite_image
コード例 #14
0
ファイル: photometry.py プロジェクト: tingard/PSFGAN
def add_sdss_PSF(origpath,
                 original,
                 psf_flux,
                 obj_line,
                 SDSStool_path,
                 psFields_path,
                 sexdir=None,
                 median_combine=False,
                 save_psf=False):
    """
    Args:
        origpath:      Path to original images.
        psf_flux:      Desired flux of the PSF that is beeing added to the
                       original image.
        obj_line:      Dictionary containing the following SDSS parameters
                       keywords: run, rerun, camcol, field, colc, rowc, dr7ObjID.
        SDSStool_path:  Path to SDSS tool (stand alone code) executable.
        psFields_path: Path to PSF meda data (psFields).
        sexdir:        Path where temporary SExtractor files should be saved.
                       This directory is emptied after SExtractor has done its
                       job.
    """
    SDSS_psf_dir = '%s/psf/SDSS' % conf.run_case
    GALFIT_psf_dir = '%s/psf/GALFIT' % conf.run_case
    filter_string = conf.filter_
    if not os.path.exists(SDSS_psf_dir):
        os.makedirs(SDSS_psf_dir)
    if not os.path.exists(GALFIT_psf_dir):
        os.makedirs(GALFIT_psf_dir)

    obj_id = obj_line['dr7ObjID'].item()
    SDSS_psf_filename = '%s/%s-%s.fits' % (SDSS_psf_dir, obj_id, filter_string)
    GALFIT_psf_filename = '%s/%s-%s.fits' % (GALFIT_psf_dir, obj_id,
                                             filter_string)
    if not os.path.exists(GALFIT_psf_filename):
        if not os.path.exists(SDSS_psf_filename):
            run_sdss_psftool(obj_line, SDSS_psf_filename, SDSStool_path,
                             psFields_path)
        # Fit the SDSS tool PSF with 3 gaussians to get rid of the noise.
        psf = galfit.fit_PSF_GALFIT(SDSS_psf_filename, GALFIT_psf_dir)
        if psf is None:
            print('Error in Galfit fit')
            return None
    else:
        psf = galfit.open_GALFIT_results(GALFIT_psf_filename, 'model')

    # median combine stars to get the PSF image if median_combine==True
    if median_combine:
        if not os.path.isdir(sexdir):
            os.makedirs(sexdir)
        # Try to get the conversion from nanomaggies to counts. It the
        # information is not available, just use one single value.
        try:
            nmgy_per_count = fits.getheader(origpath)['NMGY']
        except KeyError:
            nmgy_per_count = 0.0238446
        field_data = get_field(obj_line)
        # Get the SDSS field. If the data is not available, return None such
        # that this objid is skipped in roou.py
        if field_data is None:
            return None
        hdu_output = fits.PrimaryHDU(field_data / nmgy_per_count)
        hdulist_output = fits.HDUList([hdu_output])
        hdulist_output.writeto(sexdir + 'field_ADU.fits', overwrite=True)
        # Some SDSS parameters for SExtractor.
        exptime = 53.9
        threshold = 5
        saturation_limit = 4000
        gain = 4.73
        pixel_scale = 0.396
        fwhm = 1.4
        zeropoint = calc_zeropoint(exptime, nmgy_per_count)
        sex_edge = 26
        SExtractor_params = {
            'exptime': exptime,
            'threshold': threshold,
            'saturation_level': saturation_limit,
            'gain': gain,
            'pixel_scale': pixel_scale,
            'fwhm': fwhm,
            'magzero': zeropoint
        }
        x_coordinates, y_coordinates, fluxes, starboolean = \
                                      get_stars_from_field(sexdir,
                                                           'field_ADU.fits',
                                                           SExtractor_params,
                                                           field_data.shape,
                                                           sex_edge,
                                                           mindist=40)
        if not starboolean:
            files_to_delete = glob.glob(sexdir + '*')
            for f in files_to_delete:
                os.remove(f)
            return None

        csize = 20
        fluxes = fluxes * nmgy_per_count
        fluxmask = fluxes > 0
        mag_guesses = []
        for f in fluxes:
            mag_guesses.append(
                mag_from_counts(f / nmgy_per_count, exptime, zeropoint))
        mag_guesses = np.array(mag_guesses)
        # get median combined PSF
        psf_unscaled = empirical_PSF(field_data, x_coordinates[fluxmask],
                                     y_coordinates[fluxmask], csize,
                                     fwhm / pixel_scale, sexdir,
                                     mag_guesses[fluxmask], zeropoint,
                                     pixel_scale)
        if psf_unscaled is None:
            files_to_delete = glob.glob(sexdir + '*')
            for f in files_to_delete:
                os.remove(f)
            return None

        # compute statistics to subtract the background
        psf_centroid = [csize, csize]
        try:
            statmask = photutils.make_source_mask(psf_unscaled,
                                                  snr=5,
                                                  npixels=5,
                                                  dilate_size=10)
        except TypeError:
            files_to_delete = glob.glob(sexdir + '*')
            for f in files_to_delete:
                os.remove(f)
            return None
        bkg_annulus = photutils.CircularAnnulus(psf_centroid,
                                                3 * fwhm / pixel_scale, 20)
        bkg_phot_table = photutils.aperture_photometry(psf_unscaled,
                                                       bkg_annulus,
                                                       method='subpixel',
                                                       mask=statmask)
        bkg_mean_per_pixel = bkg_phot_table['aperture_sum'] / bkg_annulus.area(
        )
        src_aperture = photutils.CircularAperture(psf_centroid, 3*fwhm / \
                                                  pixel_scale)
        src_phot_table = photutils.aperture_photometry(psf_unscaled,
                                                       src_aperture,
                                                       method='subpixel')
        flux_photutils = src_phot_table['aperture_sum'] - bkg_mean_per_pixel * \
                                                          src_aperture.area()
        scale_factor = psf_flux / flux_photutils
        psf = scale_factor * (psf_unscaled - bkg_mean_per_pixel)

        files_to_delete = glob.glob(sexdir + '*')
        for f in files_to_delete:
            os.remove(f)

    # else <==> median_combine==False
    else:
        # Use the 3 gaussian fit of the PSF generated by the SDSS PSF tool.
        psf = psf / psf.sum()
        psf = psf * psf_flux

    center = [original.shape[1] // 2, original.shape[0] // 2]
    centroid_galaxy = find_centroid(original)
    centroid_PSF = find_centroid(psf)

    composite_image = np.copy(original)

    gal_x = int(centroid_galaxy[0])
    gal_y = int(centroid_galaxy[1])
    ps_x = int(centroid_PSF[0])
    ps_y = int(centroid_PSF[1])

    # Put the PS on top of the galaxy at its centroid.
    for x in range(0, psf.shape[1]):
        for y in range(0, psf.shape[0]):
            x_rel = gal_x - ps_x + x
            y_rel = gal_y - ps_y + y
            if x_rel >= 0 and y_rel >= 0 and x_rel < original.shape[1] and \
                                                      y_rel < original.shape[0]:
                composite_image[y_rel, x_rel] += psf[y, x]

    return composite_image
コード例 #15
0
    def _perform(self):
        """
        Returns an Argument() with the parameters that depends on this operation.
        """
        self.log.info(f"Running {self.__class__.__name__} action")

        exptime = float(self.action.args.kd.get('EXPTIME'))

        # Photutils StarFinder
        #         extract_fwhm = self.cfg['Extract'].getfloat('extract_fwhm', 5)
        #         thresh = self.cfg['Extract'].getint('extract_threshold', 9)
        #         pixel_scale = self.cfg['Telescope'].getfloat('pixel_scale', 1)
        #         pd = self.action.args.kd.pixeldata[0]
        #         mean, median, std = stats.sigma_clipped_stats(pd.data, sigma=3.0)
        #         # daofind = photutils.DAOStarFinder(fwhm=extract_fwhm, threshold=thresh*std)
        #         starfind = photutils.IRAFStarFinder(thresh*std, extract_fwhm)
        #         sources = starfind(pd.data)
        #         self.log.info(f'  Found {len(sources):d} stars')
        #         self.log.info(sources.keys())
        #
        #         self.action.args.objects = sources
        #         self.action.args.objects.sort('flux')
        #         self.action.args.objects.reverse()
        #         self.action.args.n_objects = len(sources)
        #         if self.action.args.n_objects == 0:
        #             self.log.warning('No stars found')
        #             self.action.args.fwhm = np.nan
        #             self.action.args.ellipticity = np.nan
        #         else:
        #             FWHM_pix = np.median(sources['fwhm'])
        #             roundness = np.median(sources['roundness'])
        #             self.log.info(f'  Median FWHM = {FWHM_pix:.1f} pix ({FWHM_pix*pixel_scale:.2f} arcsec)')
        #             self.log.info(f'  roundness = {roundness:.2f}')
        #             self.action.args.fwhm = FWHM_pix
        #             self.action.args.ellipticity = np.nan

        # Source Extractor
        pixel_scale = self.cfg['Telescope'].getfloat('pixel_scale', 1)
        thresh = self.cfg['Extract'].getint('extract_threshold', 9)
        minarea = self.cfg['Extract'].getint('extract_minarea', 7)
        mina = self.cfg['Extract'].getfloat('fwhm_mina', 1)
        minb = self.cfg['Extract'].getfloat('fwhm_minb', 1)

        bsub = self.action.args.kd.pixeldata[
            0].data - self.action.args.background[0].background
        try:
            objects = sep.extract(
                bsub,
                err=self.action.args.kd.pixeldata[0].uncertainty.array,
                mask=self.action.args.kd.pixeldata[0].mask,
                thresh=float(thresh),
                minarea=minarea)
        except Exception as e:
            self.log.error('Source extractor failed')
            self.log.error(e)
            return self.action.args

        t = Table(objects)
        t['flux'] /= exptime

        ny, nx = bsub.shape
        r = np.sqrt((t['x'] - nx / 2.)**2 + (t['y'] - ny / 2.)**2)
        t.add_column(Column(data=r.data, name='r', dtype=np.float))

        coef = 2 * np.sqrt(2 * np.log(2))
        fwhm = np.sqrt((coef * t['a'])**2 + (coef * t['b'])**2)
        t.add_column(Column(data=fwhm.data, name='FWHM', dtype=np.float))

        ellipticities = t['a'] / t['b']
        t.add_column(
            Column(data=ellipticities.data, name='ellipticity',
                   dtype=np.float))

        filtered = (t['a'] < mina) | (t['b'] < minb) | (t['flag'] > 0)
        self.log.debug(f'  Removing {np.sum(filtered):d}/{len(filtered):d}'\
                       f' extractions from FWHM calculation')
        self.action.args.n_objects = len(t[~filtered])
        self.log.info(f'  Found {self.action.args.n_objects:d} stars')

        self.action.args.objects = t[~filtered]
        self.action.args.objects.sort('flux')
        self.action.args.objects.reverse()

        if self.action.args.n_objects == 0:
            self.log.warning('No stars found')
        else:
            FWHM_pix = np.median(t['FWHM'][~filtered])
            ellipticity = np.median(t['ellipticity'][~filtered])
            self.log.info(
                f'  Median FWHM = {FWHM_pix:.1f} pix ({FWHM_pix*pixel_scale:.2f} arcsec)'
            )
            self.log.info(f'  ellipticity = {ellipticity:.2f}')
            self.action.args.fwhm = FWHM_pix
            self.action.args.ellipticity = ellipticity

        ## Do photutils photometry measurement
        positions = [(det['x'], det['y']) for det in self.action.args.objects]
        ap_radius = self.cfg['Photometry'].getfloat('aperture_radius',
                                                    2) * FWHM_pix
        star_apertures = photutils.CircularAperture(positions, ap_radius)
        sky_apertures = photutils.CircularAnnulus(
            positions,
            r_in=int(np.ceil(1.5 * ap_radius)),
            r_out=int(np.ceil(2.0 * ap_radius)))
        phot_table = photutils.aperture_photometry(
            self.action.args.kd.pixeldata[0], [star_apertures, sky_apertures])
        phot_table['sky'] = phot_table['aperture_sum_1'] / sky_apertures.area()
        med_sky = np.median(phot_table['sky'])
        self.log.info(f'  Median Sky = {med_sky.value:.0f} e-/pix')
        self.action.args.sky_background = med_sky.value
        self.action.args.objects.add_column(phot_table['sky'])
        bkg_sum = phot_table['aperture_sum_1'] / sky_apertures.area(
        ) * star_apertures.area()
        final_sum = (phot_table['aperture_sum_0'] - bkg_sum)
        final_uncert = (bkg_sum + final_sum)**0.5 * u.electron**0.5
        phot_table['apflux'] = final_sum / exptime
        self.action.args.objects.add_column(phot_table['apflux'])
        phot_table['apuncert'] = final_uncert / exptime
        self.action.args.objects.add_column(phot_table['apuncert'])
        phot_table['snr'] = final_sum / final_uncert
        self.action.args.objects.add_column(phot_table['snr'])

        where_bad = (final_sum <= 0)
        self.log.info(f'  {np.sum(where_bad)} stars rejected for flux < 0')
        self.action.args.objects = self.action.args.objects[~where_bad]

        #         where_low_snr = (self.action.args.objects['snr'] <= 5)
        #         self.log.info(f'  {np.sum(where_low_snr)} stars rejected for SNR < 5')
        #         self.action.args.objects = self.action.args.objects[~where_low_snr]

        self.log.info(f'  Fluxes for {self.action.args.n_objects:d} stars')

        return self.action.args
コード例 #16
0
    def _perform(self):
        """
        Returns an Argument() with the parameters that depends on this operation.
        """
        self.log.info(f"Running {self.__class__.__name__} action")
        nx, ny = self.action.args.kd.pixeldata[0].shape

        ## Do photometry measurement
        self.log.debug(f'  Add pixel positions to catalog')
        x, y = self.action.args.wcs.all_world2pix(self.action.args.calibration_catalog['raMean'],
                                                  self.action.args.calibration_catalog['decMean'], 1)
        self.action.args.calibration_catalog.add_column(Column(data=x, name='x'))
        self.action.args.calibration_catalog.add_column(Column(data=y, name='y'))

        buffer = 10
        in_image = (self.action.args.calibration_catalog['x'] > buffer)\
                   & (self.action.args.calibration_catalog['x'] < nx-buffer)\
                   & (self.action.args.calibration_catalog['y'] > buffer)\
                   & (self.action.args.calibration_catalog['y'] < ny-buffer)
        self.log.debug(f'  Only {np.sum(in_image)} stars are within image pixel boundaries')
        self.action.args.calibration_catalog = self.action.args.calibration_catalog[in_image]

        positions = [p for p in zip(self.action.args.calibration_catalog['x'],
                                    self.action.args.calibration_catalog['y'])]

        self.log.debug(f'  Attemping shape measurement for {len(positions)} stars')
        fwhm = list()
        elliptiticty = list()
        orientation = list()
        xcentroid = list()
        ycentroid = list()
        for i, entry in enumerate(self.action.args.calibration_catalog):
            xi = int(x[i])
            yi = int(y[i])
            if xi > 10 and xi < nx-10 and yi > 10 and yi < ny-10:
                im = self.action.args.kd.pixeldata[0].data[yi-10:yi+10,xi-10:xi+10]
                properties = photutils.data_properties(im)
                fwhm.append(2.355*(properties.semimajor_axis_sigma.value**2\
                            + properties.semiminor_axis_sigma.value**2)**0.5)
                orientation.append(properties.orientation.to(u.deg).value)
                elliptiticty.append(properties.elongation)
                xcentroid.append(properties.xcentroid.value)
                ycentroid.append(properties.ycentroid.value)
            else:
                fwhm.append(np.nan)
                orientation.append(np.nan)
                elliptiticty.append(np.nan)
                xcentroid.append(np.nan)
                ycentroid.append(np.nan)
        wnan = np.isnan(fwhm)
        nmasked = np.sum(wnan)
        self.log.info(f"  Measured {len(fwhm)-nmasked} indivisual FWHM values")
        self.action.args.calibration_catalog.add_column(MaskedColumn(
                data=fwhm, name='FWHM', mask=wnan))
        self.action.args.calibration_catalog.add_column(MaskedColumn(
                data=orientation, name='orientation', mask=wnan))
        self.action.args.calibration_catalog.add_column(MaskedColumn(
                data=elliptiticty, name='elliptiticty', mask=wnan))
        self.action.args.calibration_catalog.add_column(MaskedColumn(
                data=xcentroid, name='xcentroid', mask=wnan))
        self.action.args.calibration_catalog.add_column(MaskedColumn(
                data=ycentroid, name='ycentroid', mask=wnan))


        self.log.debug(f'  Attemping aperture photometry for {len(positions)} stars')
        FWHM_pix = self.action.args.fwhm if self.action.args.fwhm is not None else 8
        ap_radius = int(2.0*FWHM_pix)
        star_apertures = photutils.CircularAperture(positions, ap_radius)
        sky_apertures = photutils.CircularAnnulus(positions,
                                                  r_in=int(np.ceil(1.5*ap_radius)),
                                                  r_out=int(np.ceil(2.0*ap_radius)))
        self.log.debug(f'  Running photutils.aperture_photometry')
        phot_table = photutils.aperture_photometry(
                               self.action.args.kd.pixeldata[0].data,
                               [star_apertures, sky_apertures])

        self.log.debug(f'  Subtracting sky flux')
        phot_table['sky'] = phot_table['aperture_sum_1'] / sky_apertures.area()
        med_sky = np.nanmedian(phot_table['sky'])
        self.log.info(f'  Median Sky = {med_sky:.0f} e-/pix')
        self.action.args.sky_background = med_sky
        self.action.args.calibration_catalog.add_column(phot_table['sky'])
        bkg_sum = phot_table['aperture_sum_1'] / sky_apertures.area() * star_apertures.area()
        final_sum = (phot_table['aperture_sum_0'] - bkg_sum)/self.action.args.kd.exptime()
        phot_table['flux'] = final_sum
        self.action.args.calibration_catalog.add_column(phot_table['flux'])
        wzero = (self.action.args.calibration_catalog['flux'] < 0)
        self.log.debug(f'  Masking {np.sum(wzero)} stars with <0 flux')
        self.action.args.calibration_catalog['flux'].mask = wzero


        # Estimate flux from catalog magnitude
        self.log.debug(f'  Estimate flux from catalog magnitude')
        d_telescope = self.cfg['Telescope'].getfloat('d_primary_mm', 508)
        d_obstruction = self.cfg['Telescope'].getfloat('d_obstruction_mm', 127)
        A = 3.14*(d_telescope/2/1000)**2 - 3.14*(d_obstruction/2/1000)**2 # m^2
        self.action.args.f0 = estimate_f0(A, band=self.action.args.band) # photons / sec
        catflux = self.action.args.f0\
                  * 10**(-self.action.args.calibration_catalog[f'{self.action.args.band}MeanApMag']/2.5)
        self.action.args.calibration_catalog.add_column(Column(data=catflux*u.photon/u.second,
                                                               name='catflux'))

        self.log.debug(f'  Fit, clipping brightest 5% and faintest 5% of stars')
        bad = (self.action.args.calibration_catalog['flux'].mask == True)
        nclip = int(np.floor(0.05*len(self.action.args.calibration_catalog[~bad])))
        fitted_line = sigma_clipping_line_fit(self.action.args.calibration_catalog[~bad]['catflux'][nclip:-nclip].data,
                                              self.action.args.calibration_catalog[~bad]['flux'][nclip:-nclip].data,
                                              intercept_fixed=True)
        self.log.info(f"  Slope (e-/photon) = {fitted_line.slope.value:.3g}")
        self.action.args.zero_point_fit = fitted_line
        deltas = self.action.args.calibration_catalog['flux'].data\
               - fitted_line(self.action.args.calibration_catalog['catflux'].data)
        mean, med, std = stats.sigma_clipped_stats(deltas)
        self.log.info(f"  Fit StdDev = {std:.2g}")

        return self.action.args
コード例 #17
0
ファイル: photometry.py プロジェクト: zkbt/henrietta
def photometry(ax, image, pos, ap_size=10, r_in=20, r_out=30, back_photo=True):
    '''
    Create apertures around specified list of stars

    Parameters:
    -----------
    ax : axis class
        axis of a subplot.
    image : ndarray
        Image for aperture photometry to be performed on.
    pos : 2darray
        A list of positions in x,y pixel coordinates for each star.
        Needs to be as [[0,0],[1,1]...]
    ap_size : int
        The radius of a circular aperture in pixel size
    r_in : int
        The inner radius of background aperture in pixel size
        (Ignore if back_photo=False)
    r_out : int
        The outer radius of background aperture in pixel size
        (Ignore if back_photo=False)
    back_photo : bool
        Set to True if want to return an array of background values, False
        to ignore anything to do with background

    Returns
    -------
    photometry of each star : array
    average background pixel value around each star : array (If back_photo=True)
    plots image with the aperture and centroids located for each star
    '''

    nstars = np.arange(0, np.shape(pos)[0], 1)
    name_stars = []
    for i in nstars:
        name_stars.append('Star {}'.format(i))
    #print name_stars

    aperture = photutils.CircularAperture(pos, r=ap_size)

    if back_photo == True:
        back_aperture = photutils.CircularAnnulus(pos, r_in, r_out)

    pos = np.array(pos)

    #plt.imshow(image,origin='lower')

    for i in range(len(name_stars)):
        circle1 = plt.Circle((pos[i, 0], pos[i, 1]),
                             ap_size,
                             color='black',
                             fill=False,
                             zorder=100)
        ax.add_artist(circle1)
        plt.axhline(pos[i, 1],
                    xmin=pos[i, 0] / 100. - .01,
                    xmax=pos[i, 0] / 100. + .02,
                    color='black')
        plt.axvline(pos[i, 0],
                    ymin=pos[i, 1] / 100. - .01,
                    ymax=pos[i, 1] / 100. + .02,
                    color='black')
        plt.text(pos[i, 0] + ap_size + 1, pos[i, 1], name_stars[i], zorder=11)
        #print pos[i,1]
        #print pos[i,0]

        if back_photo == True:
            circle2 = plt.Circle((pos[i, 0], pos[i, 1]),
                                 r_in,
                                 color='cyan',
                                 fill=False,
                                 zorder=10)
            circle3 = plt.Circle((pos[i, 0], pos[i, 1]),
                                 r_out,
                                 color='cyan',
                                 fill=False,
                                 zorder=10)
            ax.add_artist(circle2)
            ax.add_artist(circle3)
    #aperture.plot(origin=(0,0),indices=None,ax=ax,fill=False)
    #plt.ion()

    phot_table = photutils.aperture_photometry(image, aperture)
    flux_values = phot_table[
        'aperture_sum'].data  #gets a list of the total flux in specified aperture for each star

    if back_photo == True:
        back_table = photutils.aperture_photometry(image, back_aperture)
        area = np.pi * (r_out**2 - r_in**2)
        a = np.ones((np.shape(image)[0], np.shape(image)[1]))
        area = photutils.aperture_photometry(a, back_aperture)
        back_values = back_table['aperture_sum'].data / area[
            'aperture_sum'].data
        return flux_values, back_values * np.pi * ap_size**2
    else:
        return flux_values
コード例 #18
0
def forced_phot(image,
                wcs,
                zp,
                catalog_alt,
                catalog_az,
                catalog_mag,
                catalog_id,
                nside=8,
                phot_params=None,
                do_background=False,
                return_table=False,
                mjd=0.):
    """
    Generate a map of the extinction on the sky

    Parameters
    ----------
    image : array
        The image to find the extinction map from
    wcs : wcs-like object
        WCS describing the image. Note WCS RA,Dec will be interpreted as Az,Alt.
    zp : float
        The zeropoint of the image
    catalog_alt : array
        Altitude of stars expected to be in the image (degrees)
    catalog_az : array
        Azimuth of stars expected in the image (degrees)
    catalog_mag : array
        Magnitudes of stars expected in the image
    nside : int
        Healpixel nside to set resoltion of output map
    phot_params : dict (None)
        Dictionary holding common photometry kwargs. Loads defaults from default_phot_params
        if None.
    do_background : bool (False)
        Do a 2D background model subtraction. Skipped by default because astropy is really slow.
    return_table : bool (False)
        If True, return the astropy table with the photometry, otherwise, return the extinction map.

    Output
    ------
    extinction : array
        A healpixel array (where latitude and longitude are altitude and azimuth). Pixels
        with no stars are filled with the healpixel mask value. Non-masked pixels have the
        measured extinction in magnitudes.
    """

    if phot_params is None:
        phot_params = default_phot_params()

    # Find the healpixel for each catalog star
    lat = np.radians(90. - catalog_alt)
    catalog_hp = hp.ang2pix(nside, lat, np.radians(catalog_az))

    order = np.argsort(catalog_hp)
    catalog_alt = catalog_alt[order]
    catalog_az = catalog_az[order]
    catalog_mag = catalog_mag[order]
    catalog_id = catalog_id[order]
    catalog_hp = catalog_hp[order]
    catalog_x, catalog_y = wcs.all_world2pix(catalog_az, catalog_alt, 0)

    good_transform = ~np.isnan(catalog_x)

    # Find the x,y positions of helpix centers
    lat, lon = hp.pix2ang(nside, np.arange(hp.nside2npix(nside)))
    hp_alt = np.degrees(np.pi / 2. - lat)
    hp_az = np.degrees(lon)
    hp_x, hp_y = wcs.all_world2pix(hp_az, hp_alt, 0)

    # Run the photometry at the expected catalog positions
    if do_background:
        sigma_clip = phu.SigmaClip(sigma=phot_params['bk_clip_sigma'],
                                   iters=phot_params['bk_iter'])
        bkg_estimator = phu.MedianBackground()
        bkg = phu.Background2D(
            image,
            (phot_params['background_size'], phot_params['background_size']),
            filter_size=(phot_params['bk_filter_size'],
                         phot_params['bk_filter_size']),
            sigma_clip=sigma_clip,
            bkg_estimator=bkg_estimator)
        bk_img = image - bkg.background
    else:
        bk_img = image

    positions = list(zip(catalog_x[good_transform], catalog_y[good_transform]))
    apertures = phu.CircularAperture(positions, r=phot_params['apper_r'])
    annulus_apertures = phu.CircularAnnulus(positions,
                                            r_in=phot_params['ann_r_in'],
                                            r_out=phot_params['ann_r_out'])

    apers = [apertures, annulus_apertures]
    phot_table = phu.aperture_photometry(bk_img, apers)

    bkg_mean = phot_table['aperture_sum_1'] / annulus_apertures.area()
    bkg_sum = bkg_mean * apertures.area()
    final_sum = phot_table['aperture_sum_0'] - bkg_sum
    phot_table['residual_aperture_sum'] = final_sum
    phot_table['catalog_id'] = catalog_id[good_transform]

    phot_table['residual_aperture_mag'] = -2.5 * np.log10(final_sum) + zp
    detected = np.where(final_sum > 0)

    mag_difference = phot_table['residual_aperture_mag'][
        detected] - catalog_mag[good_transform][detected]
    phot_table['mag_difference'] = np.zeros(
        phot_table['residual_aperture_mag'].data.size, dtype=float)
    phot_table['mjd'] = np.zeros(phot_table['residual_aperture_mag'].data.size,
                                 dtype=float)
    phot_table['mag_difference'][detected] = mag_difference
    phot_table['mjd'] = mjd

    bins = np.arange(hp.nside2npix(nside) + 1) - 0.5
    result, be, bn = binned_statistic(catalog_hp[good_transform][detected],
                                      mag_difference,
                                      bins=bins)

    if return_table:
        return phot_table, result
    else:
        return result