Beispiel #1
0
    def __call__(self, img):

        mylog = mylogger.logging.getLogger("PyBDSM." + img.log + "Shapefit")
        bar = statusbar.StatusBar(
            'Decomposing islands into shapelets ...... : ', 0, img.nisl)
        opts = img.opts
        if img.opts.shapelet_do:
            if opts.quiet == False:
                bar.start()

            # Set up multiproccessing. First create a simple copy of the Image
            # object that contains the minimal data needed.
            opts_dict = opts.to_dict()
            img_simple = Image(opts_dict)
            img_simple.pixel_beamarea = img.pixel_beamarea
            img_simple.pixel_beam = img.pixel_beam
            img_simple.thresh_pix = img.thresh_pix
            img_simple.minpix_isl = img.minpix_isl
            img_simple.clipped_mean = img.clipped_mean
            img_simple.shape = img.ch0_arr.shape

            # Now call the parallel mapping function. Returns a list of
            # [beta, centre, nmax, basis, cf] for each island
            shap_list = mp.parallel_map(
                func.eval_func_tuple,
                itertools.izip(itertools.repeat(self.process_island),
                               img.islands, itertools.repeat(img_simple),
                               itertools.repeat(opts)),
                numcores=opts.ncores,
                bar=bar)

            for id, isl in enumerate(img.islands):
                beta, centre, nmax, basis, cf = shap_list[id]
                isl.shapelet_beta = beta
                isl.shapelet_centre = centre
                isl.shapelet_posn_sky = img.pix2sky(centre)
                isl.shapelet_posn_skyE = [0.0, 0.0, 0.0]
                isl.shapelet_nmax = nmax
                isl.shapelet_basis = basis
                isl.shapelet_cf = cf

            img.completed_Ops.append('shapelets')
Beispiel #2
0
    def __call__(self, img):

        mylog = mylogger.logging.getLogger("PyBDSM."+img.log+"Shapefit")
        bar = statusbar.StatusBar('Decomposing islands into shapelets ...... : ', 0, img.nisl)
        opts = img.opts
        if img.opts.shapelet_do:
            if opts.quiet == False:
                bar.start()

            # Set up multiproccessing. First create a simple copy of the Image
            # object that contains the minimal data needed.
            opts_dict = opts.to_dict()
            img_simple = Image(opts_dict)
            img_simple.pixel_beamarea = img.pixel_beamarea
            img_simple.pixel_beam = img.pixel_beam
            img_simple.thresh_pix = img.thresh_pix
            img_simple.minpix_isl = img.minpix_isl
            img_simple.clipped_mean = img.clipped_mean
            img_simple.shape = img.ch0_arr.shape

            # Now call the parallel mapping function. Returns a list of
            # [beta, centre, nmax, basis, cf] for each island
            shap_list = mp.parallel_map(func.eval_func_tuple,
                        itertools.izip(itertools.repeat(self.process_island),
                        img.islands, itertools.repeat(img_simple),
                        itertools.repeat(opts)), numcores=opts.ncores,
                        bar=bar)

            for id, isl in enumerate(img.islands):
                beta, centre, nmax, basis, cf = shap_list[id]
                isl.shapelet_beta=beta
                isl.shapelet_centre=centre
                isl.shapelet_posn_sky=img.pix2sky(centre)
                isl.shapelet_posn_skyE=[0.0, 0.0, 0.0]
                isl.shapelet_nmax=nmax
                isl.shapelet_basis=basis
                isl.shapelet_cf=cf

            img.completed_Ops.append('shapelets')
Beispiel #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

        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')
Beispiel #4
0
    def __call__(self, img):
        from time import time
        import functions as func
        import itertools

        mylog = mylogger.logging.getLogger("PyBDSM."+img.log+"Gausfit")
        if len(img.islands) == 0:
            img.gaussians = []
            img.ngaus = 0
            img.total_flux_gaus = 0.0
            img.completed_Ops.append('gausfit')
            return img

        bar = statusbar.StatusBar('Fitting islands with Gaussians .......... : ',
                                  0, img.nisl)
        opts = img.opts
        if opts.quiet == False and opts.verbose_fitting == False:
            bar.start()
        iter_ngmax  = 10
        min_maxsize = 50.0
        maxsize = opts.splitisl_maxsize
        min_peak_size = 30.0
        peak_size = opts.peak_maxsize
        if maxsize < min_maxsize:
            maxsize = min_maxsize
            opts.splitisl_maxsize = min_maxsize
        if peak_size < min_peak_size:
            peak_size = min_peak_size
            opts.peak_maxsize = min_peak_size

        # Set up multiproccessing. First create a simple copy of the Image
        # object that contains the minimal data needed.
        opts_dict = opts.to_dict()
        img_simple = Image(opts_dict)
        img_simple.pixel_beamarea = img.pixel_beamarea
        img_simple.pixel_beam = img.pixel_beam
        img_simple.thresh_pix = img.thresh_pix
        img_simple.minpix_isl = img.minpix_isl
        img_simple.clipped_mean = img.clipped_mean
        img_simple.beam2pix = img.beam2pix
        img_simple.beam = img.beam

        # Next, define the weights to use when distributing islands among cores.
        # The weight should scale with the processing time. At the moment
        # we use the island area, but other parameters may be better.
        weights = []
        for isl in img.islands:
            weights.append(isl.size_active)

        # Now call the parallel mapping function. Returns a list of [gaul, fgaul]
        # for each island.
        gaus_list = mp.parallel_map(func.eval_func_tuple,
                    itertools.izip(itertools.repeat(self.process_island),
                    img.islands, itertools.repeat(img_simple),
                    itertools.repeat(opts)), numcores=opts.ncores,
                    bar=bar, weights=weights)

        for isl in img.islands:
            ### now convert gaussians into Gaussian objects and store
            idx = isl.island_id
            gaul = gaus_list[idx][0]
            fgaul = gaus_list[idx][1]
            dgaul = []
            gaul = [Gaussian(img, par, idx, gidx)
                        for (gidx, par) in enumerate(gaul)]

            if len(gaul) == 0:
                # No good Gaussians were fit. In this case, make a dummy
                # Gaussian located at the island center so
                # that the source may still be included in output catalogs.
                # These dummy Gaussians all have an ID of -1. They do not
                # appear in any of the source or island Gaussian lists except
                # the island dgaul list.
                if opts.src_ra_dec != None:
                    # Center the dummy Gaussian on the user-specified source position
                    posn_isl = (isl.shape[0]/2.0, isl.shape[1]/2.0)
                    posn_img = (isl.shape[0]/2.0 + isl.origin[0], isl.shape[1]/2.0 + isl.origin[1])
                    par = [isl.image[posn_isl], posn_img[0], posn_img[1], 0.0, 0.0, 0.0]
                else:
                    # Center the dummy Gaussian on the maximum pixel
                    posn = N.unravel_index(N.argmax(isl.image*~isl.mask_active), isl.shape) + N.array(isl.origin)
                    par = [isl.max_value, posn[0], posn[1], 0.0, 0.0, 0.0]
                dgaul = [Gaussian(img, par, idx, -1)]
                gidx = 0
            fgaul= [Gaussian(img, par, idx, gidx + gidx2 + 1, flag)
                        for (gidx2, (flag, par)) in enumerate(fgaul)]

            isl.gaul = gaul
            isl.fgaul= fgaul
            isl.dgaul = dgaul

        gaussian_list = [g for isl in img.islands for g in isl.gaul]
        img.gaussians = gaussian_list

        ### put in the serial number of the gaussians for the whole image
        n = 0
        nn = 0
        tot_flux = 0.0
        if img.waveletimage:
            # store the wavelet scale for each Gaussian
            # (wavelet img's have a img.j attribute)
            j = img.j
        else:
            j = 0
        for isl in img.islands:
            m = 0
            for g in isl.gaul:
                n += 1; m += 1
                g.gaus_num = n - 1
                tot_flux += g.total_flux
            for dg in isl.dgaul:
                nn -= 1
                dg.gaus_num = nn

            isl.ngaus = m
        img.ngaus = n
        img.total_flux_gaus = tot_flux

        mylogger.userinfo(mylog, "Total number of Gaussians fit to image",
                          str(n))
        if not img._pi and not img.waveletimage:
            mylogger.userinfo(mylog, "Total flux density in model", '%.3f Jy' %
                          tot_flux)

        # Check if model flux is very different from sum of flux in image
        if img.ch0_sum_jy > 0 and not img._pi:
            if img.total_flux_gaus/img.ch0_sum_jy < 0.5 or \
                    img.total_flux_gaus/img.ch0_sum_jy > 2.0:
                mylog.warn('Total flux density in model is %0.2f times sum of pixels '\
                               'in input image. Large residuals may remain.' %
                           (img.total_flux_gaus/img.ch0_sum_jy,))

        # Check if there are many Gaussians with deconvolved size of 0 in one
        # axis but not in the other. Don't bother to do this for wavelet images.
        fraction_1d = self.check_for_1d_gaussians(img)
        if fraction_1d > 0.5 and img.beam != None and img.waveletimage == False:
            mylog.warn('After deconvolution, more than 50% of Gaussians are '\
                           "1-D. Unless you're fitting an extended source, "\
                           "beam may be incorrect.")

        img.completed_Ops.append('gausfit')
        return img
Beispiel #5
0
    def rms_mean_map(self, arr, mask=False, kappa=3, box=None, ncores=None):
        """Calculate map of the mean/rms values

        Parameters:
        arr:  2D array with data
        mask: mask
        kappa: clipping for calculating rms/mean within each box
        box: box parameters (box_size, box_step)

        Returns:
        axes: list of 2 arrays with coordinates of boxes alongside each axis
        mean_map: map of mean values
        rms_map: map of rms values

        Description:
        This function calculates clipped mean and rms maps for the array.
        The algorithm is a moving-window algorithm, where mean&rms are
        calculated within a window of a size (box_size * box_size), and the
        window is stepped withing the image by steps of box_steps.

        Special care is taken for the borders of the image -- outer borders
        (where box doesn't fit properly) are given one extra round with a box
        applied to the border of the image. Additionally outer values are
        extrapolated to cover whole image size, to simplify further processing.

        See also routine 'remap_axes' for 'inverting' axes array

        Example:
        for an input image of 100x100 pixels calling rms_mean_map with default
        box parameters (50, 25) will result in the following:

        axes = [array([  0. ,  24.5,  49.5,  74.5,  99. ]),
                array([  0. ,  24.5,  49.5,  74.5,  99. ])]

        mean_map = <5x5 array>
        rms_map  = <5x5 array>

        rms_map[1,1] is calculated for  arr[0:50, 0:50]
        rms_map[2,1] is calculated for  arr[25:75, 0:50]
        ...etc...
        rms_map[0,0] is extrapolated as .5*(rms_map[0,1] + rms_map[1,0])
        rms_map[0,1] is extrapolated as rms_map[1,1]
        """
        mylog = mylogger.logging.getLogger("PyBDSM.RmsMean")
        if box is None:
            box = (50, 25)
        if box[0] < box[1]:
            raise RuntimeError('Box size is less than step size.')

        # Some math first: boxcount is number of boxes alongsize each axis,
        # bounds is non-zero for axes which have extra pixels beyond last box
        BS, SS = box
        imgshape = N.array(arr.shape)

        # If boxize is less than 10% of image, use simple extrapolation to
        # derive the edges of the mean and rms maps; otherwise, use padded
        # versions of arr and mask to derive the mean and rms maps
        if float(BS)/float(imgshape[0]) < 0.1 and \
                float(BS)/float(imgshape[1]) < 0.1:
            use_extrapolation = True
        else:
            use_extrapolation = False

        if use_extrapolation:
            boxcount = 1 + (imgshape - BS) / SS
            bounds = N.asarray((boxcount - 1) * SS + BS < imgshape, dtype=int)
            mapshape = 2 + boxcount + bounds
        else:
            boxcount = 1 + imgshape / SS
            bounds = N.asarray((boxcount - 1) * SS < imgshape, dtype=int)
            mapshape = boxcount + bounds
            pad_border_size = int(BS / 2.0)
            new_shape = (arr.shape[0] + 2 * pad_border_size,
                         arr.shape[1] + 2 * pad_border_size)
            arr_pad = self.pad_array(arr, new_shape)
            if mask is None:
                mask_pad = None
            else:
                mask_pad = self.pad_array(mask, new_shape)

        # Make arrays for calculated data
        mean_map = N.zeros(mapshape, dtype=N.float32)
        rms_map = N.zeros(mapshape, dtype=N.float32)
        axes = [N.zeros(len, dtype=N.float32) for len in mapshape]

        # Step 1: internal area of the image
        # Make a list of coordinates to send to process_mean_rms_maps()
        coord_list = []
        ind_list = []
        for i in range(boxcount[0]):
            for j in range(boxcount[1]):
                if use_extrapolation:
                    coord_list.append((i + 1, j + 1))
                else:
                    coord_list.append((i, j))
                ind_list.append([i * SS, i * SS + BS, j * SS, j * SS + BS])

        # Now call the parallel mapping function. Returns a list of [mean, rms]
        # for each coordinate.
        if use_extrapolation:
            cm_cr_list = mp.parallel_map(
                func.eval_func_tuple,
                itertools.izip(itertools.repeat(self.process_mean_rms_maps),
                               ind_list, itertools.repeat(mask),
                               itertools.repeat(arr), itertools.repeat(kappa)),
                numcores=ncores)
        else:
            cm_cr_list = mp.parallel_map(
                func.eval_func_tuple,
                itertools.izip(itertools.repeat(self.process_mean_rms_maps),
                               ind_list, itertools.repeat(mask_pad),
                               itertools.repeat(arr_pad),
                               itertools.repeat(kappa)),
                numcores=ncores)

        for i, co in enumerate(coord_list):
            cm, cr = cm_cr_list[i]
            mean_map[co] = cm
            rms_map[co] = cr

        # Check if all regions have too few unmasked pixels
        if mask is not None and N.size(N.where(mean_map != N.inf)) == 0:
            raise RuntimeError("No unmasked regions from which to determine "\
                         "mean and rms maps")

        # Step 2: borders of the image
        if bounds[0]:
            coord_list = []
            ind_list = []
            for j in range(boxcount[1]):
                if use_extrapolation:
                    coord_list.append((-2, j + 1))
                    ind_list.append([-BS, arr.shape[0], j * SS, j * SS + BS])
                else:
                    coord_list.append((-1, j))
                    ind_list.append(
                        [-BS, arr_pad.shape[0], j * SS, j * SS + BS])
            if use_extrapolation:
                cm_cr_list = mp.parallel_map(
                    func.eval_func_tuple,
                    itertools.izip(
                        itertools.repeat(self.process_mean_rms_maps), ind_list,
                        itertools.repeat(mask), itertools.repeat(arr),
                        itertools.repeat(kappa)),
                    numcores=ncores)
            else:
                cm_cr_list = mp.parallel_map(
                    func.eval_func_tuple,
                    itertools.izip(
                        itertools.repeat(self.process_mean_rms_maps), ind_list,
                        itertools.repeat(mask_pad), itertools.repeat(arr_pad),
                        itertools.repeat(kappa)),
                    numcores=ncores)

            for i, co in enumerate(coord_list):
                cm, cr = cm_cr_list[i]
                mean_map[co] = cm
                rms_map[co] = cr

        if bounds[1]:
            coord_list = []
            ind_list = []
            for i in range(boxcount[0]):
                if use_extrapolation:
                    coord_list.append((i + 1, -2))
                    ind_list.append([i * SS, i * SS + BS, -BS, arr.shape[1]])
                else:
                    coord_list.append((i, -1))
                    ind_list.append(
                        [i * SS, i * SS + BS, -BS, arr_pad.shape[1]])
            if use_extrapolation:
                cm_cr_list = mp.parallel_map(
                    func.eval_func_tuple,
                    itertools.izip(
                        itertools.repeat(self.process_mean_rms_maps), ind_list,
                        itertools.repeat(mask), itertools.repeat(arr),
                        itertools.repeat(kappa)),
                    numcores=ncores)
            else:
                cm_cr_list = mp.parallel_map(
                    func.eval_func_tuple,
                    itertools.izip(
                        itertools.repeat(self.process_mean_rms_maps), ind_list,
                        itertools.repeat(mask_pad), itertools.repeat(arr_pad),
                        itertools.repeat(kappa)),
                    numcores=ncores)

            for i, co in enumerate(coord_list):
                cm, cr = cm_cr_list[i]
                mean_map[co] = cm
                rms_map[co] = cr

        if bounds.all():
            if use_extrapolation:
                ind = [-BS, arr.shape[0], -BS, arr.shape[1]]
                self.for_masked(mean_map, rms_map, mask, arr, ind, kappa,
                                [-2, -2])
            else:
                ind = [-BS, arr_pad.shape[0], -BS, arr_pad.shape[1]]
                self.for_masked(mean_map, rms_map, mask_pad, arr_pad, ind,
                                kappa, [-1, -1])

        # Step 3: correct(extrapolate) borders of the image
        def correct_borders(map):
            map[0, :] = map[1, :]
            map[:, 0] = map[:, 1]
            map[-1, :] = map[-2, :]
            map[:, -1] = map[:, -2]

            map[0, 0] = (map[1, 0] + map[0, 1]) / 2.
            map[-1, 0] = (map[-2, 0] + map[-1, 1]) / 2.
            map[0, -1] = (map[0, -2] + map[1, -1]) / 2.
            map[-1, -1] = (map[-2, -1] + map[-1, -2]) / 2.

        if use_extrapolation:
            correct_borders(mean_map)
            correct_borders(rms_map)

        # Step 4: fill in coordinate axes
        for i in range(2):
            if use_extrapolation:
                axes[i][1:boxcount[i] + 1] = (N.arange(boxcount[i]) * SS +
                                              BS / 2. - .5)
                if bounds[i]:
                    axes[i][-2] = imgshape[i] - BS / 2. - .5
            else:
                axes[i][0:boxcount[i]] = N.arange(boxcount[i]) * SS - .5
                if bounds[i]:
                    axes[i][-2] = imgshape[i] - .5
            axes[i][-1] = imgshape[i] - 1

        # Step 5: fill in boxes with < 5 unmasked pixels (set to values of
        # N.inf)
        unmasked_boxes = N.where(mean_map != N.inf)
        if N.size(unmasked_boxes, 1) < mapshape[0] * mapshape[1]:
            mean_map = self.fill_masked_regions(mean_map)
            rms_map = self.fill_masked_regions(rms_map)

        return axes, mean_map, rms_map
Beispiel #6
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')
Beispiel #7
0
    def rms_mean_map(self, arr, mask=False, kappa=3, box=None, ncores=None):
        """Calculate map of the mean/rms values

        Parameters:
        arr:  2D array with data
        mask: mask
        kappa: clipping for calculating rms/mean within each box
        box: box parameters (box_size, box_step)

        Returns:
        axes: list of 2 arrays with coordinates of boxes alongside each axis
        mean_map: map of mean values
        rms_map: map of rms values

        Description:
        This function calculates clipped mean and rms maps for the array.
        The algorithm is a moving-window algorithm, where mean&rms are
        calculated within a window of a size (box_size * box_size), and the
        window is stepped withing the image by steps of box_steps.

        Special care is taken for the borders of the image -- outer borders
        (where box doesn't fit properly) are given one extra round with a box
        applied to the border of the image. Additionally outer values are
        extrapolated to cover whole image size, to simplify further processing.

        See also routine 'remap_axes' for 'inverting' axes array

        Example:
        for an input image of 100x100 pixels calling rms_mean_map with default
        box parameters (50, 25) will result in the following:

        axes = [array([  0. ,  24.5,  49.5,  74.5,  99. ]),
                array([  0. ,  24.5,  49.5,  74.5,  99. ])]

        mean_map = <5x5 array>
        rms_map  = <5x5 array>

        rms_map[1,1] is calculated for  arr[0:50, 0:50]
        rms_map[2,1] is calculated for  arr[25:75, 0:50]
        ...etc...
        rms_map[0,0] is extrapolated as .5*(rms_map[0,1] + rms_map[1,0])
        rms_map[0,1] is extrapolated as rms_map[1,1]
        """
        mylog = mylogger.logging.getLogger("PyBDSM.RmsMean")
        if box is None:
            box = (50, 25)
        if box[0] < box[1]:
            raise RuntimeError('Box size is less than step size.')

        # Some math first: boxcount is number of boxes alongsize each axis,
        # bounds is non-zero for axes which have extra pixels beyond last box
        BS, SS = box
        imgshape = N.array(arr.shape)

        # If boxize is less than 10% of image, use simple extrapolation to
        # derive the edges of the mean and rms maps; otherwise, use padded
        # versions of arr and mask to derive the mean and rms maps
        if float(BS)/float(imgshape[0]) < 0.1 and \
                float(BS)/float(imgshape[1]) < 0.1:
            use_extrapolation = True
        else:
            use_extrapolation = False

        if use_extrapolation:
            boxcount = 1 + (imgshape - BS)/SS
            bounds   = N.asarray((boxcount-1)*SS + BS < imgshape, dtype=int)
            mapshape = 2 + boxcount + bounds
        else:
            boxcount = 1 + imgshape/SS
            bounds   = N.asarray((boxcount-1)*SS < imgshape, dtype=int)
            mapshape = boxcount + bounds
            pad_border_size = int(BS/2.0)
            new_shape = (arr.shape[0] + 2*pad_border_size, arr.shape[1]
                         + 2*pad_border_size)
            arr_pad = self.pad_array(arr, new_shape)
            if mask == None:
                mask_pad = None
            else:
                mask_pad = self.pad_array(mask, new_shape)

        # Make arrays for calculated data
        mean_map = N.zeros(mapshape, dtype=N.float32)
        rms_map  = N.zeros(mapshape, dtype=N.float32)
        axes     = [N.zeros(len, dtype=N.float32) for len in mapshape]

        # Step 1: internal area of the image
        # Make a list of coordinates to send to process_mean_rms_maps()
        coord_list = []
        ind_list = []
        for i in range(boxcount[0]):
            for j in range(boxcount[1]):
                if use_extrapolation:
                    coord_list.append((i+1, j+1))
                else:
                    coord_list.append((i, j))
                ind_list.append([i*SS, i*SS+BS, j*SS, j*SS+BS])

        # Now call the parallel mapping function. Returns a list of [mean, rms]
        # for each coordinate.
        if use_extrapolation:
            cm_cr_list = mp.parallel_map(func.eval_func_tuple,
                    itertools.izip(itertools.repeat(self.process_mean_rms_maps),
                    ind_list, itertools.repeat(mask), itertools.repeat(arr),
                    itertools.repeat(kappa)), numcores=ncores)
        else:
            cm_cr_list = mp.parallel_map(func.eval_func_tuple,
                    itertools.izip(itertools.repeat(self.process_mean_rms_maps),
                    ind_list, itertools.repeat(mask_pad), itertools.repeat(arr_pad),
                    itertools.repeat(kappa)), numcores=ncores)

        for i, co in enumerate(coord_list):
            cm, cr = cm_cr_list[i]
            mean_map[co] = cm
            rms_map[co] = cr

        # Check if all regions have too few unmasked pixels
        if mask != None and N.size(N.where(mean_map != N.inf)) == 0:
            raise RuntimeError("No unmasked regions from which to determine "\
                         "mean and rms maps")

        # Step 2: borders of the image
        if bounds[0]:
            coord_list = []
            ind_list = []
            for j in range(boxcount[1]):
                if use_extrapolation:
                    coord_list.append((-2, j+1))
                    ind_list.append([-BS, arr.shape[0], j*SS,j*SS+BS])
                else:
                    coord_list.append((-1, j))
                    ind_list.append([-BS, arr_pad.shape[0], j*SS,j*SS+BS])
            if use_extrapolation:
                cm_cr_list = mp.parallel_map(func.eval_func_tuple,
                        itertools.izip(itertools.repeat(self.process_mean_rms_maps),
                        ind_list, itertools.repeat(mask), itertools.repeat(arr),
                        itertools.repeat(kappa)), numcores=ncores)
            else:
                cm_cr_list = mp.parallel_map(func.eval_func_tuple,
                        itertools.izip(itertools.repeat(self.process_mean_rms_maps),
                        ind_list, itertools.repeat(mask_pad), itertools.repeat(arr_pad),
                        itertools.repeat(kappa)), numcores=ncores)

            for i, co in enumerate(coord_list):
                cm, cr = cm_cr_list[i]
                mean_map[co] = cm
                rms_map[co] = cr


        if bounds[1]:
            coord_list = []
            ind_list = []
            for i in range(boxcount[0]):
                if use_extrapolation:
                    coord_list.append((i+1, -2))
                    ind_list.append([i*SS,i*SS+BS, -BS,arr.shape[1]])
                else:
                    coord_list.append((i, -1))
                    ind_list.append([i*SS,i*SS+BS, -BS,arr_pad.shape[1]])
            if use_extrapolation:
                cm_cr_list = mp.parallel_map(func.eval_func_tuple,
                        itertools.izip(itertools.repeat(self.process_mean_rms_maps),
                        ind_list, itertools.repeat(mask), itertools.repeat(arr),
                        itertools.repeat(kappa)), numcores=ncores)
            else:
                cm_cr_list = mp.parallel_map(func.eval_func_tuple,
                        itertools.izip(itertools.repeat(self.process_mean_rms_maps),
                        ind_list, itertools.repeat(mask_pad), itertools.repeat(arr_pad),
                        itertools.repeat(kappa)), numcores=ncores)

            for i, co in enumerate(coord_list):
                cm, cr = cm_cr_list[i]
                mean_map[co] = cm
                rms_map[co] = cr

        if bounds.all():
                if use_extrapolation:
                    ind = [-BS,arr.shape[0], -BS,arr.shape[1]]
                    self.for_masked(mean_map, rms_map, mask, arr, ind,
                                    kappa, [-2, -2])
                else:
                    ind = [-BS,arr_pad.shape[0], -BS,arr_pad.shape[1]]
                    self.for_masked(mean_map, rms_map, mask_pad, arr_pad, ind,
                                    kappa, [-1, -1])

        # Step 3: correct(extrapolate) borders of the image
        def correct_borders(map):
            map[0, :] = map[1, :]
            map[:, 0] = map[:, 1]
            map[-1, :] = map[-2, :]
            map[:, -1] = map[:, -2]

            map[0,0] = (map[1,0] + map[0, 1])/2.
            map[-1,0] = (map[-2, 0] + map[-1, 1])/2.
            map[0, -1] = (map[0, -2] + map[1, -1])/2.
            map[-1,-1] = (map[-2, -1] + map[-1, -2])/2.

        if use_extrapolation:
            correct_borders(mean_map)
            correct_borders(rms_map)

        # Step 4: fill in coordinate axes
        for i in range(2):
            if use_extrapolation:
                axes[i][1:boxcount[i]+1] = (N.arange(boxcount[i])*SS
                                            + BS/2. - .5)
                if bounds[i]:
                    axes[i][-2] = imgshape[i] - BS/2. - .5
            else:
                axes[i][0:boxcount[i]] = N.arange(boxcount[i])*SS - .5
                if bounds[i]:
                    axes[i][-2] = imgshape[i] - .5
            axes[i][-1] = imgshape[i] - 1

        # Step 5: fill in boxes with < 5 unmasked pixels (set to values of
        # N.inf)
        unmasked_boxes = N.where(mean_map != N.inf)
        if N.size(unmasked_boxes,1) < mapshape[0]*mapshape[1]:
            mean_map = self.fill_masked_regions(mean_map)
            rms_map = self.fill_masked_regions(rms_map)

        return axes, mean_map, rms_map