예제 #1
0
    def __call__(self, img):

      if img.opts.psf_vary_do:
        mylog = mylogger.logging.getLogger("PyBDSM."+img.log+"Psf_Vary")
        mylogger.userinfo(mylog, '\nEstimating PSF variations')
        opts = img.opts
        dir = img.basedir + '/misc/'
        plot = False # debug figures
        image = img.ch0_arr

        try:
            from astropy.io import fits as pyfits
            old_pyfits = False
        except ImportError, err:
            from distutils.version import StrictVersion
            import pyfits
            if StrictVersion(pyfits.__version__) < StrictVersion('2.2'):
                old_pyfits = True
            else:
                old_pyfits = False

        if old_pyfits:
            mylog.warning('PyFITS version is too old: psf_vary module skipped')
            return

        over = 2
        generators = opts.psf_generators; nsig = opts.psf_nsig; kappa2 = opts.psf_kappa2
        snrtop = opts.psf_snrtop; snrbot = opts.psf_snrbot; snrcutstack = opts.psf_snrcutstack
        gencode = opts.psf_gencode; primarygen = opts.psf_primarygen; itess_method = opts.psf_itess_method
        tess_sc = opts.psf_tess_sc; tess_fuzzy= opts.psf_tess_fuzzy
        bright_snr_cut = opts.psf_high_snr
        s_only = opts.psf_stype_only
        if opts.psf_snrcut < 5.0:
            mylogger.userinfo(mylog, "Value of psf_snrcut too low; increasing to 5")
            snrcut = 5.0
        else:
            snrcut = opts.psf_snrcut
        img.psf_snrcut = snrcut
        if opts.psf_high_snr != None:
            if opts.psf_high_snr < 10.0:
                mylogger.userinfo(mylog, "Value of psf_high_snr too low; increasing to 10")
                high_snrcut = 10.0
            else:
                high_snrcut = opts.psf_high_snr
        else:
            high_snrcut = opts.psf_high_snr
        img.psf_high_snr = high_snrcut

        wtfns=['unity', 'roundness', 'log10', 'sqrtlog10']
        if 0 <= itess_method < 4: tess_method=wtfns[itess_method]
        else: tess_method='unity'

        ### now put all relevant gaussian parameters into a list
        ngaus = img.ngaus
        nsrc = img.nsrc
        num = N.zeros(nsrc, dtype=N.int32)
        peak = N.zeros(nsrc)
        xc = N.zeros(nsrc)
        yc = N.zeros(nsrc)
        bmaj = N.zeros(nsrc)
        bmin = N.zeros(nsrc)
        bpa = N.zeros(nsrc)
        code = N.array(['']*nsrc);
        rms = N.zeros(nsrc)
        src_id_list = []
        for i, src in enumerate(img.sources):
            src_max = 0.0
            for gmax in src.gaussians:
                # Take only brightest Gaussian per source
                if gmax.peak_flux > src_max:
                    src_max = gmax.peak_flux
                    g = gmax
            num[i] = i
            peak[i] = g.peak_flux
            xc[i] = g.centre_pix[0]
            yc[i] = g.centre_pix[1]
            bmaj[i] = g.size_pix[0]
            bmin[i] = g.size_pix[1]
            bpa[i] = g.size_pix[2]
            code[i] = img.sources[g.source_id].code
            rms[i] = img.islands[g.island_id].rms
        gauls = (num, peak, xc, yc, bmaj, bmin, bpa, code, rms)
        tr_gauls = self.trans_gaul(gauls)

        # takes gaussians with code=S and snr > snrcut.
        if s_only:
            tr = [n for n in tr_gauls if n[1]/n[8]>snrcut and n[7] == 'S']
        else:
            tr = [n for n in tr_gauls if n[1]/n[8]>snrcut]
        g_gauls = self.trans_gaul(tr)

        # computes statistics of fitted sizes. Same as psfvary_fullstat.f in fBDSM.
        bmaj_a, bmaj_r, bmaj_ca, bmaj_cr, ni = _cbdsm.bstat(bmaj, None, nsig)
        bmin_a, bmin_r, bmin_ca, bmin_cr, ni = _cbdsm.bstat(bmin, None, nsig)
        bpa_a, bpa_r, bpa_ca, bpa_cr, ni = _cbdsm.bstat(bpa, None, nsig)

        # get subset of sources deemed to be unresolved. Same as size_ksclip_wenss.f in fBDSM.
        flag_unresolved = self.get_unresolved(g_gauls, img.beam, nsig, kappa2, over, img.psf_high_snr, plot)

        # see how much the SNR-weighted sizes of unresolved sources differ from the synthesized beam.
        wtsize_beam_snr = self.av_psf(g_gauls, img.beam, flag_unresolved)

        # filter out resolved sources
        tr_gaul = self.trans_gaul(g_gauls)
        tr = [n for i, n in enumerate(tr_gaul) if flag_unresolved[i]]
        g_gauls = self.trans_gaul(tr)
        mylogger.userinfo(mylog, 'Number of unresolved sources', str(len(g_gauls[0])))

        # get a list of voronoi generators. vorogenS has values (and not None) if generators='field'.
        vorogenP, vorogenS = self.get_voronoi_generators(g_gauls, generators, gencode, snrcut, snrtop, snrbot, snrcutstack)
        mylogger.userinfo(mylog, 'Number of generators for PSF variation', str(len(vorogenP[0])))
        if len(vorogenP[0]) < 3:
            mylog.warning('Insufficient number of generators')
            return

        mylogger.userinfo(mylog, 'Tesselating image')
        # group generators into tiles
        tile_prop = self.edit_vorogenlist(vorogenP, frac=0.9)

        # tesselate the image
        volrank, vorowts = self.tesselate(vorogenP, vorogenS, tile_prop, tess_method, tess_sc, tess_fuzzy, \
                  generators, gencode, image.shape)
        if opts.output_all:
            func.write_image_to_file(img.use_io, img.imagename + '.volrank.fits', volrank, img, dir)

        tile_list, tile_coord, tile_snr = tile_prop
        ntile = len(tile_list)
        bar = statusbar.StatusBar('Determining PSF variation ............... : ', 0, ntile)
        mylogger.userinfo(mylog, 'Number of tiles for PSF variation', str(ntile))

        # For each tile, calculate the weighted averaged psf image. Also for all the sources in the image.
        cdelt = list(img.wcs_obj.acdelt[0:2])
        factor=3.
        psfimages, psfcoords, totpsfimage, psfratio, psfratio_aper = self.psf_in_tile(image, img.beam, g_gauls, \
                   cdelt, factor, snrcutstack, volrank, tile_prop, plot, img)
        npsf = len(psfimages)

        if opts.psf_use_shap:
            # use totpsfimage to get beta, centre and nmax for shapelet decomposition. Use nmax=5 or 6
            mask=N.zeros(totpsfimage.shape, dtype=bool)
            (m1, m2, m3)=func.moment(totpsfimage, mask)
            betainit=sqrt(m3[0]*m3[1])*2.0  * 1.4
            tshape = totpsfimage.shape
            cen = N.array(N.unravel_index(N.argmax(totpsfimage), tshape))+[1,1]
            cen = tuple(cen)
            nmax = 12
            basis = 'cartesian'
            betarange = [0.5,sqrt(betainit*max(tshape))]
            beta, error  = sh.shape_varybeta(totpsfimage, mask, basis, betainit, cen, nmax, betarange, plot)
            if error == 1: print '  Unable to find minimum in beta'

            # decompose all the psf images using the beta from above
            nmax=12; psf_cf=[]
            for i in range(npsf):
                psfim = psfimages[i]
                cf = sh.decompose_shapelets(psfim, mask, basis, beta, cen, nmax, mode='')
                psf_cf.append(cf)
                if img.opts.quiet == False:
                    bar.increment()
            bar.stop()

            # transpose the psf image list
            xt, yt = N.transpose(tile_coord)
            tr_psf_cf = N.transpose(N.array(psf_cf))

            # interpolate the coefficients across the image. Ok, interpolate in scipy for
            # irregular grids is crap. doesnt even pass through some of the points.
            # for now, fit polynomial.
            compress = 100.0
            x, y = N.transpose(psfcoords)
            if len(x) < 3:
                mylog.warning('Insufficient number of tiles to do interpolation of PSF variation')
                return

            psf_coeff_interp, xgrid, ygrid = self.interp_shapcoefs(nmax, tr_psf_cf, psfcoords, image.shape, \
                     compress, plot)

            psfshape = psfimages[0].shape
            skip = 5
            aa = self.create_psf_grid(psf_coeff_interp, image.shape, xgrid, ygrid, skip, nmax, psfshape, \
                 basis, beta, cen, totpsfimage, plot)
            img.psf_images = aa
        else:
            if ntile < 4:
                mylog.warning('Insufficient number of tiles to do interpolation of PSF variation')
                return
            else:
                # Fit stacked PSFs with Gaussians and measure aperture fluxes
                bm_pix = N.array([img.pixel_beam()[0]*fwsig, img.pixel_beam()[1]*fwsig, img.pixel_beam()[2]])
                psf_maj = N.zeros(npsf)
                psf_min = N.zeros(npsf)
                psf_pa = N.zeros(npsf)
                if img.opts.quiet == False:
                    bar.start()
                for i in range(ntile):
                    psfim = psfimages[i]
                    mask = N.zeros(psfim.shape, dtype=bool)
                    x_ax, y_ax = N.indices(psfim.shape)
                    maxv = N.max(psfim)
                    p_ini = [maxv, (psfim.shape[0]-1)/2.0*1.1, (psfim.shape[1]-1)/2.0*1.1, bm_pix[0]/fwsig*1.3,
                             bm_pix[1]/fwsig*1.1, bm_pix[2]*2]
                    para, ierr = func.fit_gaus2d(psfim, p_ini, x_ax, y_ax, mask)
                    ### first extent is major
                    if para[3] < para[4]:
                        para[3:5] = para[4:2:-1]
                        para[5] += 90
                    ### clip position angle
                    para[5] = divmod(para[5], 180)[1]

                    psf_maj[i] = para[3]
                    psf_min[i] = para[4]
                    posang = para[5]
                    while posang >= 180.0:
                        posang -= 180.0
                    psf_pa[i] = posang

                    if img.opts.quiet == False:
                        bar.increment()
                bar.stop()

                # Interpolate Gaussian parameters
                if img.aperture == None:
                    psf_maps = [psf_maj, psf_min, psf_pa, psfratio]
                else:
                    psf_maps = [psf_maj, psf_min, psf_pa, psfratio, psfratio_aper]
                nimgs = len(psf_maps)
                bar = statusbar.StatusBar('Interpolating PSF images ................ : ', 0, nimgs)
                if img.opts.quiet == False:
                    bar.start()
                map_list = mp.parallel_map(func.eval_func_tuple,
                    itertools.izip(itertools.repeat(self.interp_prop),
                    psf_maps, itertools.repeat(psfcoords),
                    itertools.repeat(image.shape)), numcores=opts.ncores,
                    bar=bar)
                if img.aperture == None:
                    psf_maj_int, psf_min_int, psf_pa_int, psf_ratio_int = map_list
                else:
                    psf_maj_int, psf_min_int, psf_pa_int, psf_ratio_int, psf_ratio_aper_int = map_list

                # Smooth if desired
                if img.opts.psf_smooth != None:
                    sm_scale = img.opts.psf_smooth / img.pix2beam([1.0, 1.0, 0.0])[0] / 3600.0 # pixels
                    if img.opts.aperture == None:
                        psf_maps = [psf_maj_int, psf_min_int, psf_pa_int, psf_ratio_int]
                    else:
                        psf_maps = [psf_maj_int, psf_min_int, psf_pa_int, psf_ratio_int, psf_ratio_aper_int]
                    nimgs = len(psf_maps)
                    bar = statusbar.StatusBar('Smoothing PSF images .................... : ', 0, nimgs)
                    if img.opts.quiet == False:
                        bar.start()
                    map_list = mp.parallel_map(func.eval_func_tuple,
                        itertools.izip(itertools.repeat(self.blur_image),
                        psf_maps, itertools.repeat(sm_scale)), numcores=opts.ncores,
                        bar=bar)
                    if img.aperture == None:
                        psf_maj_int, psf_min_int, psf_pa_int, psf_ratio_int = map_list
                    else:
                        psf_maj_int, psf_min_int, psf_pa_int, psf_ratio_int, psf_ratio_aper_int = map_list

                # Make sure all smoothed, interpolated images are ndarrays
                psf_maj_int = N.array(psf_maj_int)
                psf_min_int = N.array(psf_min_int)
                psf_pa_int = N.array(psf_pa_int)
                psf_ratio_int = N.array(psf_ratio_int)
                if img.aperture == None:
                    psf_ratio_aper_int = N.zeros(psf_maj_int.shape, dtype=N.float32)
                else:
                    psf_ratio_aper_int = N.array(psf_ratio_aper_int, dtype=N.float32)

                # Blank with NaNs if needed
                mask = img.mask_arr
                if isinstance(mask, N.ndarray):
                    pix_masked = N.where(mask == True)
                    psf_maj_int[pix_masked] = N.nan
                    psf_min_int[pix_masked] = N.nan
                    psf_pa_int[pix_masked] = N.nan
                    psf_ratio_int[pix_masked] = N.nan
                    psf_ratio_aper_int[pix_masked] = N.nan

                # Store interpolated images. The major and minor axis images are
                # the sigma in units of arcsec, the PA image in units of degrees east of
                # north, the ratio images in units of 1/beam.
                img.psf_vary_maj_arr = psf_maj_int * img.pix2beam([1.0, 1.0, 0.0])[0] * 3600.0 # sigma in arcsec
                img.psf_vary_min_arr = psf_min_int * img.pix2beam([1.0, 1.0, 0.0])[0] * 3600.0 # sigma in arcsec
                img.psf_vary_pa_arr = psf_pa_int
                img.psf_vary_ratio_arr = psf_ratio_int # in 1/beam
                img.psf_vary_ratio_aper_arr = psf_ratio_aper_int # in 1/beam

                if opts.output_all:
                    func.write_image_to_file(img.use_io, img.imagename + '.psf_vary_maj.fits', img.psf_vary_maj_arr*fwsig, img, dir)
                    func.write_image_to_file(img.use_io, img.imagename + '.psf_vary_min.fits', img.psf_vary_min_arr*fwsig, img, dir)
                    func.write_image_to_file(img.use_io, img.imagename + '.psf_vary_pa.fits', img.psf_vary_pa_arr, img, dir)
                    func.write_image_to_file(img.use_io, img.imagename + '.psf_vary_ratio.fits', img.psf_vary_ratio_arr, img, dir)
                    func.write_image_to_file(img.use_io, img.imagename + '.psf_vary_ratio_aper.fits', img.psf_vary_ratio_aper_arr, img, dir)

                # Loop through source and Gaussian lists and deconvolve the sizes using appropriate beam
                bar2 = statusbar.StatusBar('Correcting deconvolved source sizes ..... : ', 0, img.nsrc)
                if img.opts.quiet == False:
                    bar2.start()
                for src in img.sources:
                    src_pos = img.sky2pix(src.posn_sky_centroid)
                    src_pos_int = (int(src_pos[0]), int(src_pos[1]))
                    gaus_c = img.gaus2pix(src.size_sky, src.posn_sky_centroid)
                    gaus_bm = [psf_maj_int[src_pos_int]*fwsig, psf_min_int[src_pos_int]*fwsig, psf_pa_int[src_pos_int]*fwsig]
                    gaus_dc, err = func.deconv2(gaus_bm, gaus_c)
                    src.deconv_size_sky = img.pix2gaus(gaus_dc, src_pos)
                    src.deconv_size_skyE = [0.0, 0.0, 0.0]
                    for g in src.gaussians:
                        gaus_c = img.gaus2pix(g.size_sky, src.posn_sky_centroid)
                        gaus_dc, err = func.deconv2(gaus_bm, gaus_c)
                        g.deconv_size_sky = img.pix2gaus(gaus_dc, g.centre_pix)
                        g.deconv_size_skyE = [0.0, 0.0, 0.0]
                        if img.opts.quiet == False:
                            bar2.spin()
                    if img.opts.quiet == False:
                        bar2.increment()
                bar2.stop()
        img.completed_Ops.append('psf_vary')
예제 #2
0
    def inigaus_nobeam(self, isl, thr, beam, img):
        """ To get initial guesses when the source sizes are very different
        from the beam, and can also be elongated. Mainly in the context of
        a-trous transform images. Need to arrive at a good guess of the sizes
        and hence need to partition the image around the maxima first. Tried the
        IFT watershed algo but with markers, it segments the island only around
        the minima and not the whole island. Cant find a good weighting scheme
        for tesselation either. Hence will try this :

        Calculate number of maxima. If one, then take moment as initial
        guess. If more than one, then moment of whole island is one of the
        guesses if mom1 is within n pixels of one of the maxima. Else dont take
        whole island moment. Instead, find minima on lines connecting all maxima
        and use geometric mean of all minima of a peak as the size of that peak.
        """
        from math import sqrt
        from const import fwsig
        import scipy.ndimage as nd
        import functions as func

        im = isl.image-isl.islmean
        if img.opts.ini_method == 'curvature':
            im_pos = -1.0 * func.make_curvature_map(isl.image-isl.islmean)
            thr_pos = 0.0
        else:
            im_pos = im
            thr_pos = -1e9
        mask = isl.mask_active
        av = img.clipped_mean
        inipeak, iniposn, im1 = func.get_maxima(im, mask, thr_pos, isl.shape, beam, im_pos=im_pos)
        npeak = len(iniposn)
        gaul = []

        av, stdnew, maxv, maxp, minv, minp = func.arrstatmask(im, mask)
        mom = func.momanalmask_gaus(isl.image-isl.islmean, isl.mask_active, 0, 1.0, True)
        if npeak <= 1:
          g = (float(maxv), int(round(mom[1])), int(round(mom[2])), mom[3]/fwsig, \
                                  mom[4]/fwsig, mom[5])
          gaul.append(g)

        if npeak > 1:                   # markers start from 1=background, watershed starts from 1=background
          watershed, markers = func.watershed(im, mask=isl.mask_active)
          nshed = N.max(markers)-1      # excluding background
          xm, ym = N.transpose([N.where(markers==i) for i in range(1,nshed+2)])[0]
          coords = [c for c in N.transpose([xm,ym])[1:]]
          alldists = [func.dist_2pt(c1, c2) for c1 in coords for c2 in coords if N.any(c1!=c2)]  # has double
          meandist = N.mean(alldists)    # mean dist between all pairs of markers
          compact = []; invmask = []
          for ished in range(nshed):
            shedmask = N.where(watershed==ished+2, False, True) + isl.mask_active # good unmasked pixels = 0
            imm = nd.binary_dilation(~shedmask, N.ones((3,3), int))
            xbad, ybad = N.where((imm==1)*(im>im[xm[ished+1], ym[ished+1]]))
            imm[xbad, ybad] = 0
            invmask.append(imm); x, y = N.where(imm); xcen, ycen = N.mean(x), N.mean(y) # good pixels are now = 1
            dist = func.dist_2pt([xcen, ycen], [xm[ished+1], ym[ished+1]])
            if dist < max(3.0, meandist/4.0):
              compact.append(True)  # if not compact, break source + diffuse
            else:
              compact.append(False)
          if not N.all(compact):
           avsize = []
           ind = N.where(compact)[0]
           for i in ind: avsize.append(N.sum(invmask[i]))
           avsize = sqrt(N.mean(N.array(avsize)))
           for i in range(len(compact)):
             if not compact[i]:                         # make them all compact
               newmask = N.zeros(imm.shape, bool)
               newmask[max(0,xm[i+1]-avsize/2):min(im.shape[0],xm[i+1]+avsize/2), \
                       max(0,ym[i+1]-avsize/2):min(im.shape[1],ym[i+1]+avsize/2)] = True
               invmask[i] = invmask[i]*newmask
          resid = N.zeros(im.shape, dtype=N.float32)                    # approx fit all compact ones
          for i in range(nshed):
            mask1 = ~invmask[i]
            size = sqrt(N.sum(invmask))/fwsig
            xf, yf = coords[i][0], coords[i][1]
            p_ini = [im[xf, yf], xf, yf, size, size, 0.0]
            x, y = N.indices(im.shape)
            p, success = func.fit_gaus2d(im*invmask[i], p_ini, x, y)
            resid = resid + func.gaus_2d(p, x, y)
            gaul.append(p)
          resid = im - resid
          if not N.all(compact):                        # just add one gaussian to fit whole unmasked island
            maxv = N.max(resid)                         # assuming resid has only diffuse emission. can be false
            x, y = N.where(~isl.mask_active); xcen = N.mean(x); ycen = N.mean(y)
            invm = ~isl.mask_active
            #bound = invm - nd.grey_erosion(invm, footprint = N.ones((3,3), int)) # better to use bound for ellipse fitting
            mom = func.momanalmask_gaus(invm, N.zeros(invm.shape, dtype=N.int16), 0, 1.0, True)
            g = (maxv, xcen, ycen, mom[3]/fwsig, mom[4]/fwsig, mom[5]-90.)
            gaul.append(g)
            coords.append([xcen, ycen])

        return gaul
예제 #3
0
    def __call__(self, img):

      if img.opts.psf_vary_do:
        mylog = mylogger.logging.getLogger("PyBDSM."+img.log+"Psf_Vary")
        mylogger.userinfo(mylog, '\nEstimating PSF variations')
        opts = img.opts
        dir = img.basedir + '/misc/'
        plot = False # debug figures
        image = img.ch0_arr

        try:
            from astropy.io import fits as pyfits
            old_pyfits = False
        except ImportError, err:
            from distutils.version import StrictVersion
            import pyfits
            if StrictVersion(pyfits.__version__) < StrictVersion('2.2'):
                old_pyfits = True
            else:
                old_pyfits = False

        if old_pyfits:
            mylog.warning('PyFITS version is too old: psf_vary module skipped')
            return

        if opts.psf_fwhm is not None:
            # User has specified a constant PSF to use, so skip PSF fitting/etc.
            psf_maj = opts.psf_fwhm[0] # FWHM in deg
            psf_min = opts.psf_fwhm[1] # FWHM in deg
            psf_pa = opts.psf_fwhm[2] # PA in deg
            mylogger.userinfo(mylog, 'Using constant PSF (major, minor, pos angle)',
                  '(%.5e, %.5e, %s) degrees' % (psf_maj, psf_maj,
                                            round(psf_pa, 1)))
        else:
            # Use did not specify a constant PSF to use, so estimate it
            over = 2
            generators = opts.psf_generators; nsig = opts.psf_nsig; kappa2 = opts.psf_kappa2
            snrtop = opts.psf_snrtop; snrbot = opts.psf_snrbot; snrcutstack = opts.psf_snrcutstack
            gencode = opts.psf_gencode; primarygen = opts.psf_primarygen; itess_method = opts.psf_itess_method
            tess_sc = opts.psf_tess_sc; tess_fuzzy= opts.psf_tess_fuzzy
            bright_snr_cut = opts.psf_high_snr
            s_only = opts.psf_stype_only
            if opts.psf_snrcut < 5.0:
                mylogger.userinfo(mylog, "Value of psf_snrcut too low; increasing to 5")
                snrcut = 5.0
            else:
                snrcut = opts.psf_snrcut
            img.psf_snrcut = snrcut
            if opts.psf_high_snr is not None:
                if opts.psf_high_snr < 10.0:
                    mylogger.userinfo(mylog, "Value of psf_high_snr too low; increasing to 10")
                    high_snrcut = 10.0
                else:
                    high_snrcut = opts.psf_high_snr
            else:
                high_snrcut = opts.psf_high_snr
            img.psf_high_snr = high_snrcut

            wtfns=['unity', 'roundness', 'log10', 'sqrtlog10']
            if 0 <= itess_method < 4: tess_method=wtfns[itess_method]
            else: tess_method='unity'

            ### now put all relevant gaussian parameters into a list
            ngaus = img.ngaus
            nsrc = img.nsrc
            num = N.zeros(nsrc, dtype=N.int32)
            peak = N.zeros(nsrc)
            xc = N.zeros(nsrc)
            yc = N.zeros(nsrc)
            bmaj = N.zeros(nsrc)
            bmin = N.zeros(nsrc)
            bpa = N.zeros(nsrc)
            code = N.array(['']*nsrc);
            rms = N.zeros(nsrc)
            src_id_list = []
            for i, src in enumerate(img.sources):
                src_max = 0.0
                for gmax in src.gaussians:
                    # Take only brightest Gaussian per source
                    if gmax.peak_flux > src_max:
                        src_max = gmax.peak_flux
                        g = gmax
                num[i] = i
                peak[i] = g.peak_flux
                xc[i] = g.centre_pix[0]
                yc[i] = g.centre_pix[1]
                bmaj[i] = g.size_pix[0]
                bmin[i] = g.size_pix[1]
                bpa[i] = g.size_pix[2]
                code[i] = img.sources[g.source_id].code
                rms[i] = img.islands[g.island_id].rms
            gauls = (num, peak, xc, yc, bmaj, bmin, bpa, code, rms)
            tr_gauls = self.trans_gaul(gauls)

            # takes gaussians with code=S and snr > snrcut.
            if s_only:
                tr = [n for n in tr_gauls if n[1]/n[8]>snrcut and n[7] == 'S']
            else:
                tr = [n for n in tr_gauls if n[1]/n[8]>snrcut]
            g_gauls = self.trans_gaul(tr)

            # computes statistics of fitted sizes. Same as psfvary_fullstat.f in fBDSM.
            bmaj_a, bmaj_r, bmaj_ca, bmaj_cr, ni = _cbdsm.bstat(bmaj, None, nsig)
            bmin_a, bmin_r, bmin_ca, bmin_cr, ni = _cbdsm.bstat(bmin, None, nsig)
            bpa_a, bpa_r, bpa_ca, bpa_cr, ni = _cbdsm.bstat(bpa, None, nsig)

            # get subset of sources deemed to be unresolved. Same as size_ksclip_wenss.f in fBDSM.
            flag_unresolved = self.get_unresolved(g_gauls, img.beam, nsig, kappa2, over, img.psf_high_snr, plot)
            if len(flag_unresolved) == 0:
                mylog.warning('Insufficient number of sources to determine PSF variation.\nTry changing the PSF options or specify a (constant) PSF with the "psf_fwhm" option')
                return

            # see how much the SNR-weighted sizes of unresolved sources differ from the synthesized beam.
            wtsize_beam_snr = self.av_psf(g_gauls, img.beam, flag_unresolved)

            # filter out resolved sources
            tr_gaul = self.trans_gaul(g_gauls)
            tr = [n for i, n in enumerate(tr_gaul) if flag_unresolved[i]]
            g_gauls = self.trans_gaul(tr)
            mylogger.userinfo(mylog, 'Number of unresolved sources', str(len(g_gauls[0])))

            # get a list of voronoi generators. vorogenS has values (and not None) if generators='field'.
            vorogenP, vorogenS = self.get_voronoi_generators(g_gauls, generators, gencode, snrcut, snrtop, snrbot, snrcutstack)
            mylogger.userinfo(mylog, 'Number of generators for PSF variation', str(len(vorogenP[0])))
            if len(vorogenP[0]) < 3:
                mylog.warning('Insufficient number of generators')
                return

            mylogger.userinfo(mylog, 'Tesselating image')
            # group generators into tiles
            tile_prop = self.edit_vorogenlist(vorogenP, frac=0.9)

            # tesselate the image
            volrank, vorowts = self.tesselate(vorogenP, vorogenS, tile_prop, tess_method, tess_sc, tess_fuzzy, \
                      generators, gencode, image.shape)
            if opts.output_all:
                func.write_image_to_file(img.use_io, img.imagename + '.volrank.fits', volrank, img, dir)

            tile_list, tile_coord, tile_snr = tile_prop
            ntile = len(tile_list)
            bar = statusbar.StatusBar('Determining PSF variation ............... : ', 0, ntile)
            mylogger.userinfo(mylog, 'Number of tiles for PSF variation', str(ntile))

            # For each tile, calculate the weighted averaged psf image. Also for all the sources in the image.
            cdelt = list(img.wcs_obj.acdelt[0:2])
            factor=3.
            psfimages, psfcoords, totpsfimage, psfratio, psfratio_aper = self.psf_in_tile(image, img.beam, g_gauls, \
                       cdelt, factor, snrcutstack, volrank, tile_prop, plot, img)
            npsf = len(psfimages)

        if opts.psf_use_shap:
            if opts.psf_fwhm is None:
                # use totpsfimage to get beta, centre and nmax for shapelet decomposition. Use nmax=5 or 6
                mask=N.zeros(totpsfimage.shape, dtype=bool)
                (m1, m2, m3)=func.moment(totpsfimage, mask)
                betainit=sqrt(m3[0]*m3[1])*2.0  * 1.4
                tshape = totpsfimage.shape
                cen = N.array(N.unravel_index(N.argmax(totpsfimage), tshape))+[1,1]
                cen = tuple(cen)
                nmax = 12
                basis = 'cartesian'
                betarange = [0.5,sqrt(betainit*max(tshape))]
                beta, error  = sh.shape_varybeta(totpsfimage, mask, basis, betainit, cen, nmax, betarange, plot)
                if error == 1: print '  Unable to find minimum in beta'

                # decompose all the psf images using the beta from above
                nmax=12; psf_cf=[]
                for i in range(npsf):
                    psfim = psfimages[i]
                    cf = sh.decompose_shapelets(psfim, mask, basis, beta, cen, nmax, mode='')
                    psf_cf.append(cf)
                    if img.opts.quiet == False:
                        bar.increment()
                bar.stop()

                # transpose the psf image list
                xt, yt = N.transpose(tile_coord)
                tr_psf_cf = N.transpose(N.array(psf_cf))

                # interpolate the coefficients across the image. Ok, interpolate in scipy for
                # irregular grids is crap. doesnt even pass through some of the points.
                # for now, fit polynomial.
                compress = 100.0
                x, y = N.transpose(psfcoords)
                if len(x) < 3:
                    mylog.warning('Insufficient number of tiles to do interpolation of PSF variation')
                    return

                psf_coeff_interp, xgrid, ygrid = self.interp_shapcoefs(nmax, tr_psf_cf, psfcoords, image.shape, \
                         compress, plot)

                psfshape = psfimages[0].shape
                skip = 5
                aa = self.create_psf_grid(psf_coeff_interp, image.shape, xgrid, ygrid, skip, nmax, psfshape, \
                     basis, beta, cen, totpsfimage, plot)
                img.psf_images = aa
        else:
            if opts.psf_fwhm is None:
                if ntile < 4:
                    mylog.warning('Insufficient number of tiles to do interpolation of PSF variation')
                    return
                else:
                    # Fit stacked PSFs with Gaussians and measure aperture fluxes
                    bm_pix = N.array([img.pixel_beam()[0]*fwsig, img.pixel_beam()[1]*fwsig, img.pixel_beam()[2]])
                    psf_maj = N.zeros(npsf)
                    psf_min = N.zeros(npsf)
                    psf_pa = N.zeros(npsf)
                    if img.opts.quiet == False:
                        bar.start()
                    for i in range(ntile):
                        psfim = psfimages[i]
                        mask = N.zeros(psfim.shape, dtype=bool)
                        x_ax, y_ax = N.indices(psfim.shape)
                        maxv = N.max(psfim)
                        p_ini = [maxv, (psfim.shape[0]-1)/2.0*1.1, (psfim.shape[1]-1)/2.0*1.1, bm_pix[0]/fwsig*1.3,
                                 bm_pix[1]/fwsig*1.1, bm_pix[2]*2]
                        para, ierr = func.fit_gaus2d(psfim, p_ini, x_ax, y_ax, mask)
                        ### first extent is major
                        if para[3] < para[4]:
                            para[3:5] = para[4:2:-1]
                            para[5] += 90
                        ### clip position angle
                        para[5] = divmod(para[5], 180)[1]

                        psf_maj[i] = para[3]
                        psf_min[i] = para[4]
                        posang = para[5]
                        while posang >= 180.0:
                            posang -= 180.0
                        psf_pa[i] = posang

                        if img.opts.quiet == False:
                            bar.increment()
                    bar.stop()

                    # Interpolate Gaussian parameters
                    if img.aperture is None:
                        psf_maps = [psf_maj, psf_min, psf_pa, psfratio]
                    else:
                        psf_maps = [psf_maj, psf_min, psf_pa, psfratio, psfratio_aper]
                    nimgs = len(psf_maps)
                    bar = statusbar.StatusBar('Interpolating PSF images ................ : ', 0, nimgs)
                    if img.opts.quiet == False:
                        bar.start()
                    map_list = mp.parallel_map(func.eval_func_tuple,
                        itertools.izip(itertools.repeat(self.interp_prop),
                        psf_maps, itertools.repeat(psfcoords),
                        itertools.repeat(image.shape)), numcores=opts.ncores,
                        bar=bar)
                    if img.aperture is None:
                        psf_maj_int, psf_min_int, psf_pa_int, psf_ratio_int = map_list
                    else:
                        psf_maj_int, psf_min_int, psf_pa_int, psf_ratio_int, psf_ratio_aper_int = map_list

                    # Smooth if desired
                    if img.opts.psf_smooth is not None:
                        sm_scale = img.opts.psf_smooth / img.pix2beam([1.0, 1.0, 0.0])[0] / 3600.0 # pixels
                        if img.opts.aperture is None:
                            psf_maps = [psf_maj_int, psf_min_int, psf_pa_int, psf_ratio_int]
                        else:
                            psf_maps = [psf_maj_int, psf_min_int, psf_pa_int, psf_ratio_int, psf_ratio_aper_int]
                        nimgs = len(psf_maps)
                        bar = statusbar.StatusBar('Smoothing PSF images .................... : ', 0, nimgs)
                        if img.opts.quiet == False:
                            bar.start()
                        map_list = mp.parallel_map(func.eval_func_tuple,
                            itertools.izip(itertools.repeat(self.blur_image),
                            psf_maps, itertools.repeat(sm_scale)), numcores=opts.ncores,
                            bar=bar)
                        if img.aperture is None:
                            psf_maj_int, psf_min_int, psf_pa_int, psf_ratio_int = map_list
                        else:
                            psf_maj_int, psf_min_int, psf_pa_int, psf_ratio_int, psf_ratio_aper_int = map_list

                    # Make sure all smoothed, interpolated images are ndarrays
                    psf_maj_int = N.array(psf_maj_int)
                    psf_min_int = N.array(psf_min_int)
                    psf_pa_int = N.array(psf_pa_int)
                    psf_ratio_int = N.array(psf_ratio_int)
                    if img.aperture is None:
                        psf_ratio_aper_int = N.zeros(psf_maj_int.shape, dtype=N.float32)
                    else:
                        psf_ratio_aper_int = N.array(psf_ratio_aper_int, dtype=N.float32)

                    # Blank with NaNs if needed
                    mask = img.mask_arr
                    if isinstance(mask, N.ndarray):
                        pix_masked = N.where(mask == True)
                        psf_maj_int[pix_masked] = N.nan
                        psf_min_int[pix_masked] = N.nan
                        psf_pa_int[pix_masked] = N.nan
                        psf_ratio_int[pix_masked] = N.nan
                        psf_ratio_aper_int[pix_masked] = N.nan

                    # Store interpolated images. The major and minor axis images are
                    # the sigma in units of arcsec, the PA image in units of degrees east of
                    # north, the ratio images in units of 1/beam.
                    img.psf_vary_maj_arr = psf_maj_int * img.pix2beam([1.0, 1.0, 0.0])[0] * 3600.0 # sigma in arcsec
                    img.psf_vary_min_arr = psf_min_int * img.pix2beam([1.0, 1.0, 0.0])[0] * 3600.0 # sigma in arcsec
                    img.psf_vary_pa_arr = psf_pa_int
                    img.psf_vary_ratio_arr = psf_ratio_int # in 1/beam
                    img.psf_vary_ratio_aper_arr = psf_ratio_aper_int # in 1/beam

                    if opts.output_all:
                        func.write_image_to_file(img.use_io, img.imagename + '.psf_vary_maj.fits', img.psf_vary_maj_arr*fwsig, img, dir)
                        func.write_image_to_file(img.use_io, img.imagename + '.psf_vary_min.fits', img.psf_vary_min_arr*fwsig, img, dir)
                        func.write_image_to_file(img.use_io, img.imagename + '.psf_vary_pa.fits', img.psf_vary_pa_arr, img, dir)
                        func.write_image_to_file(img.use_io, img.imagename + '.psf_vary_ratio.fits', img.psf_vary_ratio_arr, img, dir)
                        func.write_image_to_file(img.use_io, img.imagename + '.psf_vary_ratio_aper.fits', img.psf_vary_ratio_aper_arr, img, dir)

            # Loop through source and Gaussian lists and deconvolve the sizes using appropriate beam
            bar2 = statusbar.StatusBar('Correcting deconvolved source sizes ..... : ', 0, img.nsrc)
            if img.opts.quiet == False:
                bar2.start()
            for src in img.sources:
                src_pos = img.sky2pix(src.posn_sky_centroid)
                src_pos_int = (int(src_pos[0]), int(src_pos[1]))
                gaus_c = img.gaus2pix(src.size_sky, src.posn_sky_centroid)
                if opts.psf_fwhm is None:
                    gaus_bm = [psf_maj_int[src_pos_int]*fwsig, psf_min_int[src_pos_int]*fwsig, psf_pa_int[src_pos_int]]
                else:
                    # Use user-specified constant PSF instead
                    gaus_bm = img.beam2pix(opts.psf_fwhm)
                gaus_dc, err = func.deconv2(gaus_bm, gaus_c)
                src.deconv_size_sky = img.pix2gaus(gaus_dc, src_pos)
                src.deconv_size_skyE = [0.0, 0.0, 0.0]
                for g in src.gaussians:
                    gaus_c = img.gaus2pix(g.size_sky, src.posn_sky_centroid)
                    gaus_dc, err = func.deconv2(gaus_bm, gaus_c)
                    g.deconv_size_sky = img.pix2gaus(gaus_dc, g.centre_pix)
                    g.deconv_size_skyE = [0.0, 0.0, 0.0]
                    if img.opts.quiet == False:
                        bar2.spin()
                if img.opts.quiet == False:
                    bar2.increment()
            bar2.stop()
        img.completed_Ops.append('psf_vary')
예제 #4
0
    def process_Multiple(self, img, g_sublist, mask, src_index, isrc, subim,
                         isl, delc, subn, subm):
        """ Same as gaul_to_source.f. isrc is same as k in the fortran version. """
        from math import pi, sqrt
        from const import fwsig
        from scipy import ndimage
        import functions as func

        mylog = mylogger.logging.getLogger("PyBDSM." + img.log + "Gaul2Srl  ")
        dum = img.beam[0] * img.beam[1]
        cdeltsq = img.wcs_obj.acdelt[0] * img.wcs_obj.acdelt[1]
        bmar_p = 2.0 * pi * dum / (cdeltsq * fwsig * fwsig)

        # try
        subim_src = self.make_subim(subn, subm, g_sublist, delc)
        mompara = func.momanalmask_gaus(subim_src, mask, isrc, bmar_p, True)
        # initial peak posn and value
        maxv = N.max(subim_src)
        maxx, maxy = N.unravel_index(N.argmax(subim_src), subim_src.shape)
        # fit gaussian around this posn
        blc = N.zeros(2)
        trc = N.zeros(2)
        n, m = subim_src.shape[0:2]
        bm_pix = N.array([
            img.pixel_beam()[0] * fwsig,
            img.pixel_beam()[1] * fwsig,
            img.pixel_beam()[2]
        ])
        ssubimsize = max(N.int(N.round(N.max(bm_pix[0:2]) * 2)) + 1, 5)
        blc[0] = max(0, maxx - (ssubimsize - 1) / 2)
        blc[1] = max(0, maxy - (ssubimsize - 1) / 2)
        trc[0] = min(n, maxx + (ssubimsize - 1) / 2)
        trc[1] = min(m, maxy + (ssubimsize - 1) / 2)
        s_imsize = trc - blc + 1

        p_ini = [maxv, (s_imsize[0]-1)/2.0*1.1, (s_imsize[1]-1)/2.0*1.1, bm_pix[0]/fwsig*1.3, \
                 bm_pix[1]/fwsig*1.1, bm_pix[2]*2]
        data = subim_src[blc[0]:blc[0] + s_imsize[0],
                         blc[1]:blc[1] + s_imsize[1]]
        smask = mask[blc[0]:blc[0] + s_imsize[0], blc[1]:blc[1] + s_imsize[1]]
        rmask = N.where(smask == isrc, False, True)
        x_ax, y_ax = N.indices(data.shape)

        if N.sum(~rmask) >= 6:
            para, ierr = func.fit_gaus2d(data, p_ini, x_ax, y_ax, rmask)
            if (0.0<para[1]<s_imsize[0]) and (0.0<para[2]<s_imsize[1]) and \
              para[3]<s_imsize[0] and para[4]<s_imsize[1]:
                maxpeak = para[0]
            else:
                maxpeak = maxv
            posn = para[1:3] - (0.5 * N.sum(s_imsize) - 1) / 2.0 + N.array(
                [maxx, maxy]) - 1 + delc
        else:
            maxpeak = maxv
            posn = N.unravel_index(N.argmax(data * ~rmask),
                                   data.shape) + N.array(delc) + blc

        # calculate peak by bilinear interpolation around centroid
        # First check that moment analysis gave a valid position. If not, use
        # posn from gaussian fit instead.
        if N.isnan(mompara[1]):
            mompara[1] = posn[0] - delc[0]
        x1 = N.int(N.floor(mompara[1]))
        if N.isnan(mompara[2]):
            mompara[2] = posn[1] - delc[1]
        y1 = N.int(N.floor(mompara[2]))
        xind = slice(x1, x1 + 2, 1)
        yind = slice(y1, y1 + 2, 1)
        if img.opts.flag_smallsrc and (
                N.sum(mask[xind, yind] == N.ones((2, 2)) * isrc) != 4):
            mylog.debug('Island = ' + str(isl.island_id))
            mylog.debug('Mask = ' + repr(mask[xind, yind]) +
                        'xind, yind, x1, y1 = ' + repr(xind) + ' ' +
                        repr(yind) + ' ' + repr(x1) + ' ' + repr(y1))
        t = (mompara[1] - x1) / (x1 + 1 - x1)  # in case u change it later
        u = (mompara[2] - y1) / (y1 + 1 - y1)
        s_peak=(1.0-t)*(1.0-u)*subim_src[x1,y1]+t*(1.0-u)*subim_src[x1+1,y1]+ \
               t*u*subim_src[x1+1,y1+1]+(1.0-t)*u*subim_src[x1,y1+1]
        if (not img.opts.flag_smallsrc) and (
                N.sum(mask[xind, yind] == N.ones((2, 2)) * isrc) != 4):
            mylog.debug('Speak ' + repr(s_peak) + 'Mompara = ' + repr(mompara))
            mylog.debug('x1, y1 : ' + repr(x1) + ', ' + repr(y1))
            # import pylab as pl
            # pl.imshow(N.transpose(subim_src), origin='lower', interpolation='nearest')
            # pl.suptitle('Image of bad M source '+str(isl.island_id))
            # convert pixels to coords
        try:
            sra, sdec = img.pix2sky(
                [mompara[1] + delc[0], mompara[2] + delc[1]])
            mra, mdec = img.pix2sky(posn)
        except RuntimeError, err:
            # Invalid pixel wcs coordinate
            sra, sdec = 0.0, 0.0
            mra, mdec = 0.0, 0.0
예제 #5
0
파일: gaul2srl.py 프로젝트: jjdmol/LOFAR
    def process_Multiple(self, img, g_sublist, mask, src_index, isrc, subim, isl, delc, subn, subm):
        """ Same as gaul_to_source.f. isrc is same as k in the fortran version. """
        from math import pi, sqrt
        from const import fwsig
        from scipy import ndimage
        import functions as func

        mylog = mylogger.logging.getLogger("PyBDSM."+img.log+"Gaul2Srl  ")
        dum = img.beam[0]*img.beam[1]
        cdeltsq = img.wcs_obj.acdelt[0]*img.wcs_obj.acdelt[1]
        bmar_p = 2.0*pi*dum/(cdeltsq*fwsig*fwsig)

                                        # try
        subim_src = self.make_subim(subn, subm, g_sublist, delc)
        mompara = func.momanalmask_gaus(subim_src, mask, isrc, bmar_p, True)
                                        # initial peak posn and value
        maxv = N.max(subim_src)
        maxx, maxy = N.unravel_index(N.argmax(subim_src), subim_src.shape)
                                        # fit gaussian around this posn
        blc = N.zeros(2); trc = N.zeros(2)
        n, m = subim_src.shape[0:2]
        bm_pix = N.array([img.pixel_beam()[0]*fwsig, img.pixel_beam()[1]*fwsig, img.pixel_beam()[2]])
        ssubimsize = max(N.int(N.round(N.max(bm_pix[0:2])*2))+1, 5)
        blc[0] = max(0, maxx-(ssubimsize-1)/2); blc[1] = max(0, maxy-(ssubimsize-1)/2)
        trc[0] = min(n, maxx+(ssubimsize-1)/2); trc[1] = min(m, maxy+(ssubimsize-1)/2)
        s_imsize = trc - blc + 1

        p_ini = [maxv, (s_imsize[0]-1)/2.0*1.1, (s_imsize[1]-1)/2.0*1.1, bm_pix[0]/fwsig*1.3, \
                 bm_pix[1]/fwsig*1.1, bm_pix[2]*2]
        data = subim_src[blc[0]:blc[0]+s_imsize[0], blc[1]:blc[1]+s_imsize[1]]
        smask = mask[blc[0]:blc[0]+s_imsize[0], blc[1]:blc[1]+s_imsize[1]]
        rmask = N.where(smask==isrc, False, True)
        x_ax, y_ax = N.indices(data.shape)

        if N.sum(~rmask) >=6:
          para, ierr = func.fit_gaus2d(data, p_ini, x_ax, y_ax, rmask)
          if (0.0<para[1]<s_imsize[0]) and (0.0<para[2]<s_imsize[1]) and \
            para[3]<s_imsize[0] and para[4]<s_imsize[1]:
            maxpeak = para[0]
          else:
            maxpeak = maxv
          posn = para[1:3]-(0.5*N.sum(s_imsize)-1)/2.0+N.array([maxx, maxy])-1+delc
        else:
          maxpeak = maxv
          posn = N.unravel_index(N.argmax(data*~rmask), data.shape)+N.array(delc) +blc

        # calculate peak by bilinear interpolation around centroid
        # First check that moment analysis gave a valid position. If not, use
        # posn from gaussian fit instead.
        if N.isnan(mompara[1]):
            mompara[1] = posn[0] - delc[0]
        x1 = N.int(N.floor(mompara[1]))
        if N.isnan(mompara[2]):
            mompara[2] = posn[1] - delc[1]
        y1 = N.int(N.floor(mompara[2]))
        xind = slice(x1, x1+2, 1); yind = slice(y1, y1+2, 1)
        if img.opts.flag_smallsrc and (N.sum(mask[xind, yind]==N.ones((2,2))*isrc) != 4):
            mylog.debug('Island = '+str(isl.island_id))
            mylog.debug('Mask = '+repr(mask[xind, yind])+'xind, yind, x1, y1 = '+repr(xind)+' '+repr(yind)+' '+repr(x1)+' '+repr(y1))
        t=(mompara[1]-x1)/(x1+1-x1)  # in case u change it later
        u=(mompara[2]-y1)/(y1+1-y1)
        s_peak=(1.0-t)*(1.0-u)*subim_src[x1,y1]+t*(1.0-u)*subim_src[x1+1,y1]+ \
               t*u*subim_src[x1+1,y1+1]+(1.0-t)*u*subim_src[x1,y1+1]
        if (not img.opts.flag_smallsrc) and (N.sum(mask[xind, yind]==N.ones((2,2))*isrc) != 4):
            mylog.debug('Speak '+repr(s_peak)+'Mompara = '+repr(mompara))
            mylog.debug('x1, y1 : '+repr(x1)+', '+repr(y1))
            # import pylab as pl
            # pl.imshow(N.transpose(subim_src), origin='lower', interpolation='nearest')
            # pl.suptitle('Image of bad M source '+str(isl.island_id))
                                        # convert pixels to coords
        try:
            sra, sdec = img.pix2sky([mompara[1]+delc[0], mompara[2]+delc[1]])
            mra, mdec = img.pix2sky(posn)
        except RuntimeError, err:
            # Invalid pixel wcs coordinate
            sra, sdec = 0.0, 0.0
            mra, mdec = 0.0, 0.0