def sum_invert_results_local(image_list): """ Sum a set of invert results with appropriate weighting without normalize_sumwt at the end :param image_list: List of [image, sum weights] pairs :return: image, sum of weights """ first = True sumwt = 0.0 im = None for i, arg in enumerate(image_list): if arg is not None: if isinstance(arg[1], numpy.ndarray): scale = arg[1][..., numpy.newaxis, numpy.newaxis] else: scale = arg[1] if first: im = copy_image(arg[0]) im.data *= scale sumwt = arg[1].copy() first = False else: im.data += scale * arg[0].data sumwt += arg[1] assert not first, "No invert results" return im, sumwt
def deconvolve(dirty, psf, model, facet, gthreshold, msk=None): if prefix == '': lprefix = "subimage %d" % facet else: lprefix = "%s, subimage %d" % (prefix, facet) if nmoment > 0: moment0 = calculate_image_frequency_moments(dirty) this_peak = numpy.max(numpy.abs( moment0.data[0, ...])) / dirty.data.shape[0] else: ref_chan = dirty.data.shape[0] // 2 this_peak = numpy.max(numpy.abs(dirty.data[ref_chan, ...])) if this_peak > 1.1 * gthreshold: kwargs['threshold'] = gthreshold result, _ = deconvolve_cube(dirty, psf, prefix=lprefix, mask=msk, **kwargs) if result.data.shape[0] == model.data.shape[0]: result.data += model.data return result else: return copy_image(model)
def calculate_sf_from_screen(screen): """ Calculate structure function image from screen Screen axes are ['XX', 'YY', 'TIME', 'FREQ'] :param screen: :return: """ from scipy.signal import fftconvolve nchan, ntimes, ny, nx = screen.data.shape sf = numpy.zeros([nchan, 1, 2 * ny - 1, 2 * nx - 1]) for chan in range(nchan): sf[chan, 0, ...] = fftconvolve(screen.data[chan, 0, ...], screen.data[chan, 0, ::-1, ::-1]) for itime in range(ntimes): sf += fftconvolve(screen.data[chan, itime, ...], screen.data[chan, itime, ::-1, ::-1]) sf[chan, 0, ...] /= numpy.max(sf[chan, 0, ...]) sf[chan, 0, ...] = 1.0 - sf[chan, 0, ...] sf_image = copy_image(screen) sf_image.data = sf[:, :, (ny - ny // 4):(ny + ny // 4), (nx - nx // 4):(nx + nx // 4)] sf_image.wcs.wcs.crpix[0] = ny // 4 + 1 sf_image.wcs.wcs.crpix[1] = ny // 4 + 1 sf_image.wcs.wcs.crpix[2] = 1 return sf_image
def restore_cube(model: Image, psf: Image, residual=None, **kwargs) -> Image: """ Restore the model image to the residuals :params psf: Input PSF :return: restored image """ assert isinstance(model, Image), model assert image_is_canonical(model) assert isinstance(psf, Image), psf assert image_is_canonical(psf) assert residual is None or isinstance(residual, Image), residual assert image_is_canonical(residual) restored = copy_image(model) npixel = psf.data.shape[3] sl = slice(npixel // 2 - 7, npixel // 2 + 8) size = get_parameter(kwargs, "psfwidth", None) if size is None: # isotropic at the moment! from scipy.optimize import minpack try: fit = fit_2dgaussian(psf.data[0, 0, sl, sl]) if fit.x_stddev <= 0.0 or fit.y_stddev <= 0.0: log.debug( 'restore_cube: error in fitting to psf, using 1 pixel stddev' ) size = 1.0 else: size = max(fit.x_stddev, fit.y_stddev) log.debug('restore_cube: psfwidth = %s' % (size)) except minpack.error as err: log.debug('restore_cube: minpack error, using 1 pixel stddev') size = 1.0 except ValueError as err: log.debug( 'restore_cube: warning in fit to psf, using 1 pixel stddev') size = 1.0 else: log.debug('restore_cube: Using specified psfwidth = %s' % (size)) # By convention, we normalise the peak not the integral so this is the volume of the Gaussian norm = 2.0 * numpy.pi * size**2 gk = Gaussian2DKernel(size) for chan in range(model.shape[0]): for pol in range(model.shape[1]): restored.data[chan, pol, :, :] = norm * convolve_fft( model.data[chan, pol, :, :], gk, normalize_kernel=False, allow_huge=True) if residual is not None: restored.data += residual.data return restored
def predict_wstack_single(vis, model, remove=True, gcfcf=None, **kwargs) -> Visibility: """ Predict using a single w slices. This processes a single w plane, rotating out the w beam for the average w The w-stacking or w-slicing approach is to partition the visibility data by slices in w. The measurement equation is approximated as: .. math:: V(u,v,w) =\\sum_i \\int \\frac{ I(l,m) e^{-2 \\pi j (w_i(\\sqrt{1-l^2-m^2}-1))})}{\\sqrt{1-l^2-m^2}} e^{-2 \\pi j (ul+vm)} dl dm If images constructed from slices in w are added after applying a w-dependent image plane correction, the w term will be corrected. :param vis: Visibility to be predicted :param model: model image :return: resulting visibility (in place works) """ assert isinstance(vis, Visibility), vis assert image_is_canonical(model) vis.data['vis'][...] = 0.0 log.debug("predict_wstack_single: predicting using single w slice") # We might want to do wprojection so we remove the average w w_average = numpy.average(vis.w) if remove: vis.data['uvw'][..., 2] -= w_average tempvis = copy_visibility(vis) # Calculate w beam and apply to the model. The imaginary part is not needed workimage = copy_image(model) w_beam = create_w_term_like(model, w_average, vis.phasecentre) # Do the real part workimage.data = w_beam.data.real * model.data vis = predict_2d(vis, workimage, gcfcf=gcfcf, **kwargs) # and now the imaginary part workimage.data = w_beam.data.imag * model.data tempvis = predict_2d(tempvis, workimage, gcfcf=gcfcf, **kwargs) vis.data['vis'] -= 1j * tempvis.data['vis'] if remove: vis.data['uvw'][..., 2] += w_average return vis
marker='.', label='Original') plt.semilogy(numpy.arange(len(ical_fluxes)), ical_fluxes, marker='.', label='ICAL') plt.semilogy(numpy.arange(len(mpccal_fluxes)), mpccal_fluxes, marker='.', label='MPCCAL') plt.title('All component fluxes') plt.ylabel('Flux (Jy)') plt.legend() plt.show(block=block_plots) difference_image = copy_image(mpccal_restored) difference_image.data -= ical_restored.data print(qa_image(difference_image, context='MPCCAL - ICAL image')) show_image(difference_image, title='MPCCAL - ICAL image', components=ical_components) plt.show(block=block_plots) export_image_to_fits( difference_image, rascil_path( 'test_results/low-sims-mpc-mpccal-ical-restored_%.1frmax.fits' % rmax)) newscreen = create_empty_image_like(screen) gaintables = [sm.gaintable for sm in mpccal_skymodel]
def invert_ng(bvis: BlockVisibility, model: Image, dopsf: bool = False, normalize: bool = True, **kwargs) -> (Image, numpy.ndarray): """ Invert using nifty-gridder module https://gitlab.mpcdf.mpg.de/ift/nifty_gridder Use the image im as a template. Do PSF in a separate call. In the imaging and pipeline workflows, this may be invoked using context='ng'. :param dopsf: Make the PSF instead of the dirty image :param bvis: BlockVisibility to be inverted :param im: image template (not changed) :param normalize: Normalize by the sum of weights (True) :return: (resulting image, sum of the weights for each frequency and polarization) """ assert image_is_canonical(model) assert isinstance(bvis, BlockVisibility), bvis im = copy_image(model) nthreads = get_parameter(kwargs, "threads", 4) epsilon = get_parameter(kwargs, "epsilon", 1e-12) do_wstacking = get_parameter(kwargs, "do_wstacking", True) verbosity = get_parameter(kwargs, "verbosity", 0) sbvis = copy_visibility(bvis) sbvis = shift_vis_to_image(sbvis, im, tangent=True, inverse=False) freq = sbvis.frequency # frequency, Hz nrows, nants, _, vnchan, vnpol = sbvis.vis.shape # if dopsf: # sbvis = fill_vis_for_psf(sbvis) ms = sbvis.vis.reshape([nrows * nants * nants, vnchan, vnpol]) ms = convert_pol_frame(ms, bvis.polarisation_frame, im.polarisation_frame, polaxis=2) uvw = sbvis.uvw.reshape([nrows * nants * nants, 3]) wgt = sbvis.flagged_imaging_weight.reshape( [nrows * nants * nants, vnchan, vnpol]) if epsilon > 5.0e-6: ms = ms.astype("c8") wgt = wgt.astype("f4") # Find out the image size/resolution npixdirty = im.nwidth pixsize = numpy.abs(numpy.radians(im.wcs.wcs.cdelt[0])) fuvw = uvw.copy() # We need to flip the u and w axes. fuvw[:, 0] *= -1.0 fuvw[:, 2] *= -1.0 nchan, npol, ny, nx = im.shape im.data[...] = 0.0 sumwt = numpy.zeros([nchan, npol]) # There's a latent problem here with the weights. # wgt = numpy.real(convert_pol_frame(wgt, bvis.polarisation_frame, im.polarisation_frame, polaxis=2)) # Set up the conversion from visibility channels to image channels vis_to_im = numpy.round(model.wcs.sub([4]).wcs_world2pix( freq, 0)[0]).astype('int') # Nifty gridder likes to receive contiguous arrays so we transpose # at the beginning mfs = nchan == 1 if dopsf: mst = ms.T mst[...] = 0.0 mst[0, ...] = 1.0 wgtt = wgt.T if mfs: dirty = ng.ms2dirty(fuvw.astype(numpy.float64), bvis.frequency.astype(numpy.float64), numpy.ascontiguousarray(mst[0, :, :].T), numpy.ascontiguousarray(wgtt[0, :, :].T), npixdirty, npixdirty, pixsize, pixsize, epsilon, do_wstacking=do_wstacking, nthreads=nthreads, verbosity=verbosity) sumwt[0, :] += numpy.sum(wgtt[0, 0, :].T, axis=0) im.data[0, :] += dirty.T else: for vchan in range(vnchan): ichan = vis_to_im[vchan] frequency = numpy.array(freq[vchan:vchan + 1]).astype( numpy.float64) dirty = ng.ms2dirty( fuvw.astype(numpy.float64), frequency.astype(numpy.float64), numpy.ascontiguousarray(mst[0, vchan, :][..., numpy.newaxis]), numpy.ascontiguousarray(wgtt[0, vchan, :][..., numpy.newaxis]), npixdirty, npixdirty, pixsize, pixsize, epsilon, do_wstacking=do_wstacking, nthreads=nthreads, verbosity=verbosity) sumwt[ichan, :] += numpy.sum(wgtt[0, ichan, :].T, axis=0) im.data[ichan, :] += dirty.T else: mst = ms.T wgtt = wgt.T for pol in range(npol): if mfs: dirty = ng.ms2dirty( fuvw.astype(numpy.float64), bvis.frequency.astype(numpy.float64), numpy.ascontiguousarray(mst[pol, :, :].T), numpy.ascontiguousarray(wgtt[pol, :, :].T), npixdirty, npixdirty, pixsize, pixsize, epsilon, do_wstacking=do_wstacking, nthreads=nthreads, verbosity=verbosity) sumwt[0, pol] += numpy.sum(wgtt[pol, 0, :].T, axis=0) im.data[0, pol] += dirty.T else: for vchan in range(vnchan): ichan = vis_to_im[vchan] frequency = numpy.array(freq[vchan:vchan + 1]).astype( numpy.float64) dirty = ng.ms2dirty(fuvw.astype(numpy.float64), frequency.astype(numpy.float64), numpy.ascontiguousarray( mst[pol, vchan, :][..., numpy.newaxis]), numpy.ascontiguousarray( wgtt[pol, vchan, :][..., numpy.newaxis]), npixdirty, npixdirty, pixsize, pixsize, epsilon, do_wstacking=do_wstacking, nthreads=nthreads, verbosity=verbosity) sumwt[ichan, pol] += numpy.sum(wgtt[pol, ichan, :].T, axis=0) im.data[ichan, pol] += dirty.T if normalize: im = normalize_sumwt(im, sumwt) return im, sumwt
def subtract(im1, im2): im = copy_image(im1[0]) im.data -= im2[0].data return im, im1[1]
default=None, help='Second image') parser.add_argument('--outimage', type=str, default=None, help='Second image') parser.add_argument('--mode', type=str, default='pipeline', help='Imaging mode') args = parser.parse_args() pp.pprint(vars(args)) im1 = import_image_from_fits(args.image1) im2 = import_image_from_fits(args.image2) print(qa_image(im1, context='Image 1')) print(qa_image(im2, context='Image 2')) outim = copy_image(im1) outim.data -= im2.data print(qa_image(outim, context='Difference image')) export_image_to_fits(outim, args.outimage) plt.clf() show_image(outim) plt.savefig(args.outimage.replace('.fits', '.jpg')) plt.show(block=False)
def ingest_visibility(self, freq=None, chan_width=None, times=None, add_errors=False, block=True, bandpass=False): if freq is None: freq = [1e8] if chan_width is None: chan_width = [1e6] if times is None: times = (numpy.pi / 12.0) * numpy.linspace(-3.0, 3.0, 5) lowcore = create_named_configuration('LOWBD2', rmax=750.0) frequency = numpy.array(freq) channel_bandwidth = numpy.array(chan_width) phasecentre = SkyCoord(ra=+180.0 * u.deg, dec=-60.0 * u.deg, frame='icrs', equinox='J2000') if block: vt = create_blockvisibility( lowcore, times, frequency, channel_bandwidth=channel_bandwidth, weight=1.0, phasecentre=phasecentre, polarisation_frame=PolarisationFrame("stokesI")) else: vt = create_visibility( lowcore, times, frequency, channel_bandwidth=channel_bandwidth, weight=1.0, phasecentre=phasecentre, polarisation_frame=PolarisationFrame("stokesI")) cellsize = 0.001 model = create_image_from_visibility( vt, npixel=self.npixel, cellsize=cellsize, npol=1, frequency=frequency, phasecentre=phasecentre, polarisation_frame=PolarisationFrame("stokesI")) nchan = len(self.frequency) flux = numpy.array(nchan * [[100.0]]) facets = 4 rpix = model.wcs.wcs.crpix - 1.0 spacing_pixels = self.npixel // facets centers = [-1.5, -0.5, 0.5, 1.5] comps = list() for iy in centers: for ix in centers: p = int(round(rpix[0] + ix * spacing_pixels * numpy.sign(model.wcs.wcs.cdelt[0]))), \ int(round(rpix[1] + iy * spacing_pixels * numpy.sign(model.wcs.wcs.cdelt[1]))) sc = pixel_to_skycoord(p[0], p[1], model.wcs, origin=1) comp = create_skycomponent( direction=sc, flux=flux, frequency=frequency, polarisation_frame=PolarisationFrame("stokesI")) comps.append(comp) if block: dft_skycomponent_visibility(vt, comps) else: dft_skycomponent_visibility(vt, comps) insert_skycomponent(model, comps) self.comps = comps self.model = copy_image(model) self.empty_model = create_empty_image_like(model) export_image_to_fits( model, '%s/test_pipeline_functions_model.fits' % (self.dir)) if add_errors: # These will be the same for all calls numpy.random.seed(180555) gt = create_gaintable_from_blockvisibility(vt) gt = simulate_gaintable(gt, phase_error=1.0, amplitude_error=0.0) vt = apply_gaintable(vt, gt) if bandpass: bgt = create_gaintable_from_blockvisibility(vt, timeslice=1e5) bgt = simulate_gaintable(bgt, phase_error=0.01, amplitude_error=0.01, smooth_channels=4) vt = apply_gaintable(vt, bgt) return vt
def invert_ng(bvis: BlockVisibility, model: Image, dopsf: bool = False, normalize: bool = True, **kwargs) -> (Image, numpy.ndarray): """ Invert using nifty-gridder module https://gitlab.mpcdf.mpg.de/ift/nifty_gridder Use the image im as a template. Do PSF in a separate call. This is at the bottom of the layering i.e. all transforms are eventually expressed in terms of this function. . Any shifting needed is performed here. :param bvis: BlockVisibility to be inverted :param im: image template (not changed) :param normalize: Normalize by the sum of weights (True) :return: (resulting image, sum of the weights for each frequency and polarization) """ assert image_is_canonical(model) assert isinstance(bvis, BlockVisibility), bvis im = copy_image(model) nthreads = get_parameter(kwargs, "threads", 4) epsilon = get_parameter(kwargs, "epsilon", 1e-12) do_wstacking = get_parameter(kwargs, "do_wstacking", True) verbosity = get_parameter(kwargs, "verbosity", 0) sbvis = copy_visibility(bvis) sbvis = shift_vis_to_image(sbvis, im, tangent=True, inverse=False) vis = bvis.vis freq = sbvis.frequency # frequency, Hz nrows, nants, _, vnchan, vnpol = vis.shape uvw = sbvis.uvw.reshape([nrows * nants * nants, 3]) ms = vis.reshape([nrows * nants * nants, vnchan, vnpol]) wgt = sbvis.imaging_weight.reshape( [nrows * nants * nants, vnchan, vnpol]) if dopsf: ms[...] = 1.0 + 0.0j if epsilon > 5.0e-6: ms = ms.astype("c8") wgt = wgt.astype("f4") # Find out the image size/resolution npixdirty = im.nwidth pixsize = numpy.abs(numpy.radians(im.wcs.wcs.cdelt[0])) fuvw = uvw.copy() # We need to flip the u and w axes. fuvw[:, 0] *= -1.0 fuvw[:, 2] *= -1.0 nchan, npol, ny, nx = im.shape im.data[...] = 0.0 sumwt = numpy.zeros([nchan, npol]) ms = convert_pol_frame(ms, bvis.polarisation_frame, im.polarisation_frame, polaxis=2) # There's a latent problem here with the weights. # wgt = numpy.real(convert_pol_frame(wgt, bvis.polarisation_frame, im.polarisation_frame, polaxis=2)) # Set up the conversion from visibility channels to image channels vis_to_im = numpy.round(model.wcs.sub([4]).wcs_world2pix( freq, 0)[0]).astype('int') for vchan in range(vnchan): ichan = vis_to_im[vchan] for pol in range(npol): # Nifty gridder likes to receive contiguous arrays ms_1d = numpy.array([ ms[row, vchan:vchan + 1, pol] for row in range(nrows * nants * nants) ], dtype='complex') ms_1d.reshape([ms_1d.shape[0], 1]) wgt_1d = numpy.array([ wgt[row, vchan:vchan + 1, pol] for row in range(nrows * nants * nants) ]) wgt_1d.reshape([wgt_1d.shape[0], 1]) dirty = ng.ms2dirty(fuvw, freq[vchan:vchan + 1], ms_1d, wgt_1d, npixdirty, npixdirty, pixsize, pixsize, epsilon, do_wstacking=do_wstacking, nthreads=nthreads, verbosity=verbosity) sumwt[ichan, pol] += numpy.sum(wgt[:, vchan, pol]) im.data[ichan, pol] += dirty.T if normalize: im = normalize_sumwt(im, sumwt) return im, sumwt
def create_vpterm_convolutionfunction(im, make_vp=None, oversampling=8, support=6, use_aaf=False, maxsupport=512, pa=None, normalise=True): """ Fill voltage pattern kernel projection kernel into a GridData. The makes the convolution function for gridding polarised data with a voltage pattern. :param im: Image template :param make_vp: Function to make the voltage pattern model image (hint: use a partial) :param oversampling: Oversampling of the convolution function in uv space :return: griddata correction Image, griddata kernel as GridData """ if oversampling % 2 == 0: log.info("Setting oversampling to next greatest odd number {}".format( oversampling)) oversampling += 1 d2r = numpy.pi / 180.0 # We only need the griddata correction function for the PSWF so we make # it for the shape of the image nchan, npol, ony, onx = im.data.shape assert isinstance(im, Image) # Calculate the template convolution kernel. cf = create_convolutionfunction_from_image(im, oversampling=oversampling, support=support) cf_shape = list(cf.data.shape) cf.data = numpy.zeros(cf_shape).astype('complex') assert isinstance(oversampling, int) assert oversampling > 0 nx = max(maxsupport, 2 * oversampling * support) ny = max(maxsupport, 2 * oversampling * support) qnx = nx // oversampling qny = ny // oversampling cf.data[...] = 0.0 subim = copy_image(im) ccell = onx * numpy.abs(d2r * subim.wcs.wcs.cdelt[0]) / qnx subim.data = numpy.zeros([nchan, npol, qny, qnx]) subim.wcs.wcs.cdelt[0] = -ccell / d2r subim.wcs.wcs.cdelt[1] = +ccell / d2r subim.wcs.wcs.crpix[0] = qnx // 2 + 1.0 subim.wcs.wcs.crpix[1] = qny // 2 + 1.0 vp = make_vp(subim) if pa is not None: rvp = convert_azelvp_to_radec(vp, subim, pa) else: rvp = convert_azelvp_to_radec(vp, subim, 0.0) if use_aaf: this_pswf_gcf, _ = create_pswf_convolutionfunction(subim, oversampling=1, support=6) rvp.data /= this_pswf_gcf.data # We might need to work with a larger image padded_shape = [nchan, npol, ny, nx] paddedplane = pad_image(rvp, padded_shape) paddedplane = fft_image(paddedplane) ycen, xcen = ny // 2, nx // 2 for y in range(oversampling): ybeg = y + ycen + (support * oversampling) // 2 - oversampling // 2 yend = y + ycen - (support * oversampling) // 2 - oversampling // 2 # vv = range(ybeg, yend, -oversampling) for x in range(oversampling): xbeg = x + xcen + (support * oversampling) // 2 - oversampling // 2 xend = x + xcen - (support * oversampling) // 2 - oversampling // 2 # uu = range(xbeg, xend, -oversampling) cf.data[..., 0, y, x, :, :] = \ paddedplane.data[..., ybeg:yend:-oversampling, xbeg:xend:-oversampling] if normalise: cf.data /= numpy.sum( numpy.real(cf.data[0, 0, 0, oversampling // 2, oversampling // 2, :, :])) cf.data = numpy.conjugate(cf.data) if use_aaf: pswf_gcf, _ = create_pswf_convolutionfunction(im, oversampling=1, support=6) else: pswf_gcf = create_empty_image_like(im) pswf_gcf.data[...] = 1.0 return pswf_gcf, cf
def create_awterm_convolutionfunction(im, make_pb=None, nw=1, wstep=1e15, oversampling=9, support=8, use_aaf=True, maxsupport=512, pa=None, normalise=True): """ Fill AW projection kernel into a GridData. :param im: Image template :param make_pb: Function to make the primary beam model image (hint: use a partial) :param nw: Number of w planes :param wstep: Step in w (wavelengths) :param oversampling: Oversampling of the convolution function in uv space :return: griddata correction Image, griddata kernel as GridData """ if oversampling % 2 == 0: oversampling += 1 log.info("Setting oversampling to next greatest odd number {}".format( oversampling)) d2r = numpy.pi / 180.0 # We only need the griddata correction function for the PSWF so we make # it for the shape of the image nchan, npol, ony, onx = im.data.shape assert isinstance(im, Image) # Calculate the template convolution kernel. cf = create_convolutionfunction_from_image(im, oversampling=oversampling, support=support) cf_shape = list(cf.data.shape) assert nw > 0, "Number of w planes must be greater than zero" cf_shape[2] = nw cf.data = numpy.zeros(cf_shape).astype('complex') cf.grid_wcs.wcs.crpix[4] = nw // 2 + 1.0 cf.grid_wcs.wcs.cdelt[4] = wstep cf.grid_wcs.wcs.ctype[4] = 'WW' if numpy.abs(wstep) > 0.0: w_list = cf.grid_wcs.sub([5]).wcs_pix2world(range(nw), 0)[0] else: w_list = [0.0] assert isinstance(oversampling, int) assert oversampling > 0 nx = max(maxsupport, 2 * oversampling * support) ny = max(maxsupport, 2 * oversampling * support) qnx = nx // oversampling qny = ny // oversampling cf.data[...] = 0.0 subim = copy_image(im) ccell = onx * numpy.abs(d2r * subim.wcs.wcs.cdelt[0]) / qnx subim.data = numpy.zeros([nchan, npol, qny, qnx]) subim.wcs.wcs.cdelt[0] = -ccell / d2r subim.wcs.wcs.cdelt[1] = +ccell / d2r subim.wcs.wcs.crpix[0] = qnx // 2 + 1.0 subim.wcs.wcs.crpix[1] = qny // 2 + 1.0 if use_aaf: this_pswf_gcf, _ = create_pswf_convolutionfunction(subim, oversampling=1, support=6) norm = 1.0 / this_pswf_gcf.data else: norm = 1.0 if make_pb is not None: pb = make_pb(subim) if pa is not None: rpb = convert_azelvp_to_radec(pb, subim, pa) else: rpb = convert_azelvp_to_radec(pb, subim, 0.0) norm *= rpb.data # We might need to work with a larger image padded_shape = [nchan, npol, ny, nx] thisplane = copy_image(subim) thisplane.data = numpy.zeros(thisplane.shape, dtype='complex') for z, w in enumerate(w_list): thisplane.data[...] = 0.0 + 0.0j thisplane = create_w_term_like(thisplane, w, dopol=True) thisplane.data *= norm paddedplane = pad_image(thisplane, padded_shape) paddedplane = fft_image(paddedplane) ycen, xcen = ny // 2, nx // 2 for y in range(oversampling): ybeg = y + ycen + (support * oversampling) // 2 - oversampling // 2 yend = y + ycen - (support * oversampling) // 2 - oversampling // 2 # vv = range(ybeg, yend, -oversampling) for x in range(oversampling): xbeg = x + xcen + (support * oversampling) // 2 - oversampling // 2 xend = x + xcen - (support * oversampling) // 2 - oversampling // 2 # uu = range(xbeg, xend, -oversampling) cf.data[..., z, y, x, :, :] = paddedplane.data[..., ybeg:yend:-oversampling, xbeg:xend:-oversampling] # for chan in range(nchan): # for pol in range(npol): # cf.data[chan, pol, z, y, x, :, :] = paddedplane.data[chan, pol, :, :][vv, :][:, uu] if normalise: norm = numpy.zeros([nchan, npol, oversampling, oversampling]) for y in range(oversampling): for x in range(oversampling): # uu = range(xbeg, xend, -oversampling) norm[..., y, x] = numpy.sum(numpy.real(cf.data[:, :, 0, y, x, :, :]), axis=(-2, -1)) for z, _ in enumerate(w_list): for y in range(oversampling): for x in range(oversampling): cf.data[:, :, z, y, x] /= norm[..., y, x][..., numpy.newaxis, numpy.newaxis] cf.data = numpy.conjugate(cf.data) if use_aaf: pswf_gcf, _ = create_pswf_convolutionfunction(im, oversampling=1, support=6) else: pswf_gcf = create_empty_image_like(im) pswf_gcf.data[...] = 1.0 return pswf_gcf, cf