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')
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')
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')
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
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
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')
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