Пример #1
0
    def __init__(self, data):
        """

        Initialize the object by loading the portion of the image to be
        analyzed.

        """
        
        """ Put the input data into the class """
        self.data = data.copy()

        """ Set some default parameters """
        self.rms_clip = None
        self.mean_clip = None

        """
        It may be that the astropy model fitters don't work when the input
        data has NaN's in it.  Therefore replace any NaN's or infinities with
        Gaussian noise
        """
        goodmask = np.isfinite(data)
        if goodmask.sum() < data.size:
            self.mean_clip, self.rms_clip = df.sigclip(data)
            noise = np.random.normal(self.mean_clip, self.rms_clip, data.shape)
            badmask = np.logical_not(goodmask)
            self.data[badmask] = noise[badmask]
            del badmask

        
        """ Define the coordinate arrays """
        self.y, self.x = np.indices(data.shape)

        """ Clean up """
        del goodmask
Пример #2
0
    def sigma_clip(self, nsig=3., statsec=None, mask=None, verbose=False):
        """
        Runs a sigma-clipping on image data.  After doing outlier rejection
        the code returns the mean and rms of the clipped data.

        This method is just a minimal wrapper for the sigclip method in the
         cdfutils.datafuncs library.

        NOTE: The region used for determining these image statistics is set
        by the following decision path:
         - if statsec is not None, use statsec
         - else, use the entire image
        for the second option, an optional mask can be used to
        exclude known bad pixels from the calculation.

        Optional inputs:
          nsig     - Number of sigma from the mean beyond which points are
                      rejected.  Default=3.
          statsec  - Region of the input image to be used to determine the
                      image statistics, defined by the coordinates of its
                      corners (x1, y1, x2, y2).
                      If this variable is is None (the default value)
                      then the image statistics will be determined from:
                        - the subimage, if it has been set
                        - else, the entire image.
                      The format for statsec can be any of the following:
                        1. A 4-element numpy array
                        2. A 4-element list:  [x1, y1, x2, y2]
                        3. A 4-element tuple: (x1, y1, x2, y2)
                        4. statsec=None.  In this case, the region used for
                           determining the pixel statistics defaults to either
                           the subimage (if defined) or the full image (if no
                           subimage has been defined)
          mask     - If some of the input data are known to be bad, they can
                       be flagged before the inputs are computed by including
                       a mask.  This mask must be set such that True
                       indicates good data and False indicates bad data
          verbose  - If False (the default) no information is printed
        """
        """ Determine what the input data set is """
        scdata = self.data.copy()
        if statsec is not None:
            x1, y1, x2, y2 = statsec
            scdata = scdata[y1:y2, x1:x2]
        """ Find the clipped mean and rms """
        mu, sig = df.sigclip(scdata, nsig=nsig, mask=mask, verbose=verbose)
        """ Store the results and clean up """
        del scdata
        self.found_rms = True
        self.mean_clip = mu
        self.rms_clip = sig
        return
Пример #3
0
    def get_ap_oldham(self, slit, apcent, nsig, ordinfo, doplot=True):
        """
        Defines a uniform aperture as in the example ESI extraction scripts
        from Lindsay
        """

        B = ordinfo['pixmin']
        R = ordinfo['pixmax']
        xproj = np.median(slit[:, B:R], 1)
        m, s = df.sigclip(xproj)

        smooth = ndimage.gaussian_filter(xproj, 1)
        if ordinfo['name'] == 'Order 3':
            smooth = ndimage.gaussian_filter(xproj[:-30], 1)
        x = np.arange(xproj.size) * 1.
        """
        The four parameters immediately below are the initial guesses
        bkgd, amplitude, mean location, and sigma for a Gaussian fit
        """
        fit = np.array([0., smooth.max(), smooth.argmax(), 1.])
        fit = sf.ngaussfit(xproj, fit)[0]

        cent = fit[2] + apcent / ordinfo['pixscale']
        apymax = 0.1 * xproj.max()
        ap = np.where(abs(x - cent) < nsig / ordinfo['pixscale'], 1., 0.)
        # slit.apmin = cent - nsig
        # slit.apmax = cent + nsig

        if doplot:
            plt.subplot(2, 5, (ordinfo['order']))
            plt.plot(x, apymax * ap)  # Scale the aperture to easily see it
            plt.plot(x, xproj)
            plt.ylim(-apymax, 1.1 * xproj.max())
            plt.axvline(cent, color='k', ls='dotted')

        ap = ap.repeat(slit.shape[1]).reshape(slit.shape)
        return ap, fit
Пример #4
0
    def moments(self, x0, y0, rmax=10., detect_thresh=3., skytype='global',
                verbose=False):
        """


        flux-weighted first and second moments within a square centered
        on the initial guess point and with side length of 2*rmax + 1.
        The moments will be estimates of the centroid and sigma of the
        light distribution within the square.

        Inputs:
          x0      - initial guess for x centroid
          y0      - initial guess for y centroid
          rmax    - used to set size of image region probed, which will be a
                     square with side = 2*rmax + 1. Default=10
          skytype - set how the sky/background level is set.  The options are:
                     'global' - Use the clipped mean as determined by the
                                sigma_clip method.  This is the default.
                     None     - Don't do any sky/background subtraction
        """

        """
        Select the data within the square of interest
        """
        x1, x2 = x0-rmax-1, x0+rmax+1
        y1, y2 = y0-rmax-1, y0+rmax+1
        pixmask = (self.x > x1) & (self.x < x2) & (self.y > y1) & \
            (self.y < y2)

        """ Subtract the sky level if requested """
        if skytype is None:
            f = self.data[pixmask]
        else:
            if self.rms_clip is None:
                self.mean_clip, self.rms_clip = df.sigclip(self.data)
            if verbose:
                print(self.mean_clip, self.rms_clip)
            f = self.data[pixmask] - self.mean_clip

        """ Get the x and y coordinates associated with the region """
        x = self.x[pixmask]
        y = self.y[pixmask]

        """
        Select pixels that are significantly above background for the
        calculation
        """
        objmask = f > self.mean_clip + detect_thresh * self.rms_clip
        fgood = f[objmask]
        
        """
        Calculate the flux-weighted moments
         NOTE: Do the moment calculations relative to (x1, y1) -- and then add
          x1 and y1 back at the end -- in order to avoid rounding errors (see
          SExtractor user manual)
        """
        xgood = x[objmask] - x1
        ygood = y[objmask] - y1
        fsum = fgood.sum()
        mux = (fgood * xgood).sum() / fsum
        muy = (fgood * ygood).sum() / fsum
        sigxx = (fgood * xgood**2).sum() / fsum - mux**2
        sigyy = (fgood * ygood**2).sum() / fsum - muy**2
        sigxy = (fgood * xgood * ygood).sum() / fsum - mux * muy
        mux += x1
        muy += y1
        if verbose:
            print(mux, muy)
            print(sqrt(sigxx), sqrt(sigyy), sigxy)

        """ Package the results in a dictionary, clean up, and return  """
        del x, y, xgood, ygood, fgood, pixmask, objmask
        outdict = {'mux': mux, 'muy': muy, 'sigxx': sigxx, 'sigxy': sigxy,
                   'sigyy': sigyy}
        return outdict
Пример #5
0
    def slice_stats(self,
                    imslice,
                    dmode='input',
                    nsig=3.,
                    verbose=False,
                    debug=False):
        """

        Calculates a mean and variance associated with the selected slice.
        The statistics are calculated within the good region of the slice,
         which is set by the mask if the mask has been loaded into the
         OsCube object.
        The returned values are the clipped mean and the square of the
         clipped rms, where "clipped" means that the statistics are
         calculated after a sigma-clipping routine that rejects obvious
         outliers has been run.

        Required inputs:
         imslice - the image slice for which the statistics are calculated

        Optional inputs:
         verbose - Report the image statistics?

        """
        """
        Get the 2-dimensional mask that is appropriate for this slice.
        NOTE: Ordinarily, if we were getting the mask as a 2d slice from a
         3d mask, we would have to transpose the mask to match the
         image slice, since the slices are generally set up to have RA
         along the x axis.  Here, however, since we just care about image
         statistics and not the WCS orientation, we don't transpose the
         image slices.  This does, however, mean that a 2d mask does
         need to be transposed, since it is assuming the standard WCS
         orientation.
        """
        if self.mask.ndim == 3:
            mask2d = self.mask[:, :, imslice]
        else:
            mask2d = np.transpose(self.mask)
        """
        Select the requested slice from the science data cube and calculate
         its statistics
        """
        # self.set_imslice(imslice, display=False)
        # self['slice'].sigma_clip(mask=mask2d, verbose=False)
        # mean = self['slice'].mean_clip
        # r = self['slice'].rms_clip
        data = self[dmode].data[:, :, imslice]
        mean, r = df.sigclip(data, nsig=nsig, mask=mask2d, verbose=False)
        var = r**2
        if debug:
            print('Total pixels in slice: %d' % self['slice'].data.size)
            print('Number of good pixels: %d' % mask2d.sum())
            self['slice'].sigma_clip(verbose=False)
            print('Unmasked rms: %f' % self['slice'].rms_clip)
            print('Masked rms:   %f' % r)
            print('')
        """
        Report statistics, if requested, and return the mean and variance
        """
        if verbose:
            print(imslice, mean, r)
        return mean, var