Ejemplo n.º 1
0
    def make_varcube(self, maskfile=None, **kwargs):
        """

        Takes the 1-dimensional variance spectrum and converts it into a
         3-dimensional data cube, where each slice is created by multiplying
         an integer version of the mask (where 1 is good and 0 and bad) by
         the variance that has been computed for that slice.
        This method requires that the make_varspec method has been run
         first.

        """
        """ Make the variance spectrum if it has not already been done """
        if self.varspec is None:
            self.make_varspec(maskfile, **kwargs)
        """ Create the container for the variance cube """
        self['var'] = WcsHDU(self.data, self.header)
        self['var'].data *= 0.
        """ Step through the slices, making each one a 2d variance slice """
        for imslice, var in enumerate(self.varspec['flux']):
            """
            Get the 2-dimensional mask that is appropriate for this slice
            """
            if self.mask.ndim == 3:
                mask2d = self.mask[:, :, imslice]
            else:
                mask2d = np.transpose(self.mask)
            """ Set the good pixels to the variance value for the slice """
            self['var'].data[:, :, imslice][mask2d] = var
Ejemplo n.º 2
0
    def make_snrcube(self, maskfile=None):
        """

        Use the information in the variance spectrum to make a SNR cube

        """
        """ Make sure that the variance spectrum exists """
        if self.varspec is None:
            print('')
            print('In order to run the make_snrcube algorithm, you first have '
                  'to run make_varspec')
            print('')
            return
        """
        Make a copy of the data cube and step through the slices, dividing
        each by the associated rms value
        """
        cube = self.data.copy()
        rms = np.sqrt(self.varspec['flux'])
        mask = (np.transpose(self.mask)).astype(float)
        for i, r in enumerate(rms):
            cube[:, :, i] *= (mask / r)
        """ Save the result """
        self['snr'] = WcsHDU(cube, self.header)
        del (cube)
Ejemplo n.º 3
0
    def read_maskfile(self, maskfile, maskdir='../Clean', debug=False):
        """

        Reads an external file that will be used as a mask for the
        spatial data.  The data in the file should be set up so that
        values > 0 indicate good data, while 0 indicates bad data.
        The information gets saved as the 'mask' attribute of the class,
        which is a boolean array.

        """
        """ Set up the mask filename if 'default' was chosen """
        if maskfile == 'default':
            mfile = 'mask_%s_%s.fits' % (self.filt, self.lenslet)
            if maskdir is not None:
                maskfile = os.path.join(maskdir, mfile)
            else:
                maskfile = mfile
            if debug:
                print(maskfile)
        """
        Load the information from the file and convert the data into
        a boolean format
        """
        mhdu = WcsHDU(maskfile, wcsverb=False)
        self.mask = mhdu.data > 0.
Ejemplo n.º 4
0
    def slice_cube(self,
                   wlim=None,
                   dmode='input',
                   outroot='slice',
                   debug=False):
        """

        Splits the cube into all of its individual slices and saves them
        to disk

        """
        """
        Get the range of wavelength slices to extract from the cube.
        The default is to use the full wavelength range.
        """
        if wlim is not None:
            wmin = wlim[0]
            wmax = wlim[1]
        else:
            wmin = 0
            wmax = self.wsize
        """
        Make a wcs header for the slice, i.e., a set of 2d wcs information
        without the spectral information.
        """
        w2dhdr = self.make_wcs2dhdr()
        """ Flip the data cube if it hasn't already been done """
        if 'xyz' not in self:
            data = self[dmode].data.swapaxes(0, 2)
            wcsinfo = self.wcsinfo.swapaxes(0, 2)
            hdr = wcsinfo.to_header()
            self['xyz'] = WcsHDU(data, hdr, wcsverb=False)
        else:
            data = self['xyz'].data
        """ Extract the slices """
        for w in range(wmin, wmax):
            outname = '%s_%03d.fits' % (outroot, w)
            dat = data[w, :, :]
            pf.PrimaryHDU(dat, w2dhdr).writeto(outname, overwrite=True)
Ejemplo n.º 5
0
 def smooth_xy(self, kwidth, smtype='median', outfile=None):
     """
     Smooths the cube over the two spatial dimensions.
     The type of smoothing set by the smtype parameter.  This could be one
      of the following:
        'gauss':   a circular gaussian with sigma=kwidth
        'median':  a median filter with side length=kwidth
        (more to come)
      kwidth is given in pixels
     """
     """ Smooth the data """
     data = self.data
     sm = smtype.lower()
     if sm == 'gauss' or sm == 'guass' or sm == 'gaussian':
         cube = filters.gaussian_filter(data, sigma=[kwidth, kwidth, 0])
         smotype = 'Gaussian'
     elif sm == 'median' or sm == 'medfilt':
         cube = filters.median_filter(data, size=[kwidth, kwidth, 1])
         smotype = 'Median filter'
     else:
         print('')
         print('Smoothing type %s has not been implemented' % smtype)
         print('')
         raise NameError
     """ Put the smoothed data into a new WcsHDU """
     hdr = self.header.copy()
     hdr['history'] = 'Data have been spatially smoothed'
     hdr['smotype'] = smotype
     hdr['smoothw'] = ('%5.1f' % kwidth, 'Smoothing kernel width')
     self['smooth'] = WcsHDU(cube, hdr)
     """ Save the smoothed cube in an output file if desired """
     if outfile:
         print('')
         print('Wrote smoothed data cube to %s' % outfile)
         self['smooth'].writeto(outfile, overwrite=True)
         print('')
Ejemplo n.º 6
0
    def clean(self,
              nsig1=5.,
              nsig2=5.,
              smtype='median',
              smsize=3,
              skysub=True,
              verbose=False):
        """

        Does a bad-pixel cleaning, slice by slice.  The basic algorithm
        is the following:
           1. Create a smoothed (on the slices but not in wavelength) version
              of the data using the smooth_xy method
           2. Use the pixel-to-pixel variance for each plane (obtained
              previously by running the make_varspec method) to flag pixels
              that satisfy both of the following conditions:
              A. Deviate from the clipped mean by more than nsig1 sigma
              B. Deviate from the smoothed version of the data by more than
                 nsig2 sigma
              This should flag bad pixels without incorrectly flagging
              pixels that are high due to the presence of a real astronomical
              object
           3. Replace the flagged pixels with the corresponding value in
              the smooth data

        """
        """ Make sure that the variance spectrum exists """
        if self.varspec is None:
            print('')
            print('In order to run the clean algorithm, you first have to '
                  'run make_varspec')
            print('')
            return
        """
        Create a smoothed version of the data and subtract it from the
        input data
        """
        data = self.data.copy()
        self.smooth_xy(smsize, smtype)
        diff = np.fabs(data - self['smooth'].data)
        """
        Step through the slices, flagging the pixels that differ too much
        from both the clipped mean value and the smoothed data
        """
        if verbose:
            print('')
            print('Slice N_flag')
            print('----- ------')
        rms = np.sqrt(self.varspec['flux'])
        for i, r in enumerate(rms):
            """ Subtract the sky if requested """
            if skysub:
                slmean = self.meanspec[i]
            else:
                slmean = 0.
            smdat = self['smooth'].data[:, :, i] - slmean
            mdiff = np.fabs(data[:, :, i] - slmean)
            data[:, :, i] -= slmean
            mask = (mdiff > nsig1 * r) & (diff[:, :, i] > nsig2 * r)
            data[:, :, i][mask] = smdat[mask]
            if verbose:
                print(' %3d  %5d' % (i, mask.sum()))
            """
            Make sure that the regions outside the illuminated part of the
            chip are set to zero, since they may have been set to a non-zero
            value in the sky subtraction
            """
            data[np.transpose(np.logical_not(self.mask))] = 0.
        """ Save the cleaned cube """
        self['clean'] = WcsHDU(data, self.header)
Ejemplo n.º 7
0
    def compress_spec(self,
                      wlim=None,
                      xlim=None,
                      ylim=None,
                      wmode='slice',
                      dmode='input',
                      combmode='sum',
                      display=True,
                      verbose=True,
                      **kwargs):
        """

        Compresses the data cube along the spectral dimension, but only
        for image slices between some minimum and maximum wavelengths.
        These wavelength limits (wlim) can be set either by the slice
        number or the actual wavelength in Angstrom [wavelength mode is NOT
        yet implemented].
        Setting wlim=None (the default) will use the full wavelength range

        The compression can be done either as a sum or as a median.

        The result is a 2-dimensional spatial image, which is stored in the
        data container and, thus, can be easily displayed.
        """
        """ First select the image slices to use """
        if wmode == 'wavelength':
            print('NOTE: wavelength mode has not yet been implemented')
            return
        else:
            if wlim is None:
                wlim = (0, self.wsize - 1)
            minslice = wlim[0]
            maxslice = wlim[1]
            wavmin = self.wav[minslice]
            wavmax = self.wav[maxslice]

        if verbose:
            print('')
            print('Data cube will be compressed along the spectral direction')
            print('  Image slice range: %d - %d' % (minslice, maxslice))
            print('  Corresponding wavelength range: %8.2f - %8.2f' %
                  (wavmin, wavmax))
        """ Create a temporary cube container """
        cube, cubehdr = self.select_cube(wlim,
                                         xlim,
                                         ylim,
                                         dmode=dmode,
                                         verbose=verbose)
        """
        Make a wcs header for the slice that will be the output of the
        compression, i.e., a set of 2d wcs information without the spectral
        information.
        """
        w2dhdr = self.make_wcs2dhdr(hdr=cubehdr)
        """ Compress the temporary cube along the spectral axis """
        if combmode == 'median':
            self['slice'] = WcsHDU(np.transpose(np.median(cube, axis=2)),
                                   w2dhdr)
        else:
            self['slice'] = WcsHDU(np.transpose(cube.sum(axis=2)), w2dhdr)
        """ Display the result if requested """
        if display:
            self.display(dmode='slice', **kwargs)
        """ Clean up """
        del (cube)
Ejemplo n.º 8
0
    def set_imslice(self,
                    imslice,
                    dmode='input',
                    display=True,
                    mode='xy',
                    **kwargs):
        """
        Sets the 2-dimension slice to use for the display functions.

        Inputs:
          imslice - which image slice to use.
        """
        """ Get the number of dimensions in the input image """
        hdr = self.header
        if 'NAXIS' in hdr.keys():
            ndim = hdr['naxis']
        else:
            raise KeyError('No NAXIS keyword in fits header')
        """
        The OSIRIS data-reduction pipeline produces a 3-dimensional data cube.
        Check this
        """
        if ndim != 3:
            print('')
            print('ERROR: Expected a 3-dimensional data cube but found '
                  '%d dimensions' % ndim)
            print('')
            raise ValueError
        """
        Select the image slice to use.  Right now this assumes the standard
        axis order produced by the pipeline, namely that CTYPE1 is WAVE,
        CTYPE2 is RA, and CTYPE3 is DEC.  This means that the data array
        structure is hard-wired to this assumption
        """

        if imslice >= self.wsize:
            print('')
            print('ERROR: Requested an image slice outside the available '
                  'range')
            print('Maximum available slice value is %d' % (self.wsize - 1))
            print('')
            raise IndexError
        """
        Make a wcs header for the slice, i.e., a set of 2d wcs information
        without the spectral information.
        """
        w2dhdr = self.make_wcs2dhdr()
        """
        Actually make the slice.
        The transpose is to get RA and Dec into the order that the WcsHDU
         container expects them to be
        The header information.
        """
        # self['slice'] = WcsHDU(np.transpose(self.data[:, :, imslice]))
        self['slice'] = WcsHDU(np.transpose(self[dmode].data[:, :, imslice]),
                               w2dhdr,
                               wcsverb=False)
        """ Display the image slice if requested """
        self.found_rms = False
        if display:
            self.display(dmode='slice',
                         mode=mode,
                         title='Image Slice %d (zero-indexed)' % imslice,
                         **kwargs)