Beispiel #1
0
 def read(self, filename, hdu=None):
     self.filename = filename
     self.name = self.name or os.path.basename(filename)
     # read FITS file
     if not hdu:
         dprint(3, "opening", filename)
         hdu = pyfits.open(filename)[0]
         hdu.verify('silentfix')
     hdr = self.fits_header = hdu.header
     dprint(3, "reading data")
     data = hdu.data
     # NB: all-data operations (such as getting global min/max or computing of histograms) are much faster
     # (almost x2) when data is iterated
     # over in the proper order. After a transpose(), data is in fortran order. Tell this to setData().
     data = numpy.transpose(data)
     # .copy()
     dprint(3, "setting data")
     self.setData(data, fortran_order=True)
     dprint(3, "reading header")
     ndim = hdr['NAXIS']
     if ndim < 2:
         raise ValueError, "Cannot load a one-dimensional FITS file"
     # setup projection
     # (strip out history from header, as big histories really slow down FITSWCS)
     hdr1 = pyfits.Header(
         filter(lambda x: not str(x).startswith('HISTORY'), hdr.cards))
     proj = Projection.FITSWCS(hdr1)
     nx = ny = None
     # find X and Y axes
     for iaxis in range(ndim):
         axs = str(iaxis + 1)
         npix = hdr['NAXIS' + axs]
         name = hdr.get('CTYPE' + axs, axs).strip().upper()
         # have we found the coordinate axes?
         if FITSHeaders.isAxisTypeX(name):
             nx = npix
             iaxis_ra = iaxis
         elif FITSHeaders.isAxisTypeY(name):
             ny = npix
             iaxis_dec = iaxis
     # check that we have them
     if nx is None or ny is None:
         iaxis_ra, iaxis_dec = 0, 1
         nx, ny = hdr.get('NAXIS1'), hdr.get('NAXIS2')
     for iaxis in range(ndim):
         axs = str(iaxis + 1)
         # get axis description
         npix = hdr['NAXIS' + axs]
         crval = hdr.get('CRVAL' + axs, 0)
         cdelt = hdr.get('CDELT' + axs, 1)
         crpix = hdr.get('CRPIX' + axs, 1) - 1
         name = hdr.get('CTYPE' + axs, axs).strip().upper()
         unit = hdr.get('CUNIT' + axs)
         # if this is not an X/Y axis, add it to the slicers
         if iaxis not in (iaxis_ra, iaxis_dec):
             # values becomes a list of axis values
             values = list(crval + (numpy.arange(npix) - crpix) * cdelt)
             unit = unit and unit.lower().capitalize()
             # FITS knows of two enumerable axes: STOKES and COMPLEX. For these two, replace values with proper names
             if name == "STOKES":
                 labels = [(self.StokesNames[int(i)] if i > 0
                            and i < len(self.StokesNames) else "%d" % i)
                           for i in values]
             elif name == "COMPLEX":
                 labels = [(self.ComplexNames[int(i)] if i > 0
                            and i < len(self.ComplexNames) else "%d" % i)
                           for i in values]
             else:
                 name = name.split("-")[0]
                 # if values are a simple sequence startying at 0 or 1, make simple labels
                 if cdelt == 1 and values[0] in (0., 1.):
                     labels = ["%d%s" % (val, unit) for val in values]
                 # else set labels to None: setExtraAxis() will figure it out
                 else:
                     labels = None
             self.setExtraAxis(iaxis, name or ("axis " + axs), labels,
                               values, unit)
     # check for beam parameters
     psf = [hdr.get(x, None) for x in 'BMAJ', 'BMIN', 'BPA']
     if all([x is not None for x in psf]):
         self.setPsfSize(*[p / 180 * math.pi for p in psf])
     self.setSkyAxis(0, iaxis_ra, nx, proj.ra0, -proj.xscale, proj.xpix0)
     self.setSkyAxis(1, iaxis_dec, ny, proj.dec0, proj.yscale, proj.ypix0)
     self.setDefaultProjection(proj)
     dprint(3, "setting initial slice")
     self._setupSlice()
Beispiel #2
0
def fitPsf(filename, cropsize=None):
    """Fits a Gaussian PSF to the FITS file given by 'filename'.
    If cropsize is specified, crops the central cropsize X cropsize pixels before fitting.
    Else determines cropsize by looking for the first negative sidelobe from the centre outwards.
    Returns maj_sigma,min_sigma,pa_NE (in radians)
    """
    # read PSF from file
    psf = pyfits.open(filename)[0]
    hdr = psf.header
    psf = psf.data
    dprintf(2, "Read PSF of shape %s from file %s\n", psf.shape, filename)
    # remove stokes and freq axes
    if len(psf.shape) == 4:
        psf = psf[0, 0, :, :]
    elif len(psf.shape) == 3:
        psf = psf[0, :, :]
    else:
        raise RuntimeError("illegal PSF shape %s" + psf.shape)
    nx, ny = psf.shape
    # crop the central region
    if cropsize:
        size = cropsize
        psf = psf[(nx - size) // 2:(nx + size) // 2,
                  (ny - size) // 2:(ny + size) // 2]
    # if size not specified, then auto-crop by looking for the first negative value starting from the center
    # this will break on very extended diagonal PSFs, but that's a pathological case
    else:
        ix = numpy.where(psf[:, ny // 2] < 0)[0]
        ix0 = max(ix[ix < nx // 2])
        ix1 = min(ix[ix > nx // 2])
        iy = numpy.where(psf[nx // 2, :] < 0)[0]
        iy0 = max(iy[iy < ny // 2])
        iy1 = min(iy[iy > ny // 2])
        print(ix0, ix1, iy0, iy1)
        psf = psf[ix0:ix1, iy0:iy1]
    psf[psf < 0] = 0

    # estimate gaussian parameters, then fit
    from . import gaussfitter2
    parms0 = gaussfitter2.moments(psf, circle=0, rotate=1, vheight=0)
    print(parms0)
    dprint(2, "Estimated parameters are", parms0)
    parms = gaussfitter2.gaussfit(psf,
                                  None,
                                  parms0,
                                  autoderiv=1,
                                  return_all=0,
                                  circle=0,
                                  rotate=1,
                                  vheight=0)
    dprint(0, "Fitted parameters are", parms)

    # now swap x and y around, since our axes are in reverse order
    ampl, y0, x0, sy, sx, rot = parms

    # get pixel sizes in radians (by constructing a projection object)
    proj = Projection.FITSWCS(hdr)
    xscale, yscale = proj.xscale, proj.yscale

    sx_rad = abs(sx * proj.xscale)
    sy_rad = abs(sy * proj.yscale)
    rot -= 90
    # convert West through North PA into the conventional North through East
    if sx_rad < sy_rad:
        sx_rad, sy_rad = sy_rad, sx_rad
        rot -= 90
    rot %= 180

    dprintf(
        1,
        "Fitted gaussian PSF FWHM of %f x %f pixels (%f x %f arcsec), PA %f deg\n",
        sx * FWHM, sy * FWHM, sx_rad * FWHM * ARCSEC, sy_rad * FWHM * ARCSEC,
        rot)

    return sx_rad, sy_rad, rot / DEG