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)
Beispiel #3
0
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
Beispiel #4
0
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
Beispiel #5
0
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]
Beispiel #7
0
    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)
Beispiel #10
0
    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
Beispiel #11
0
    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