Example #1
0
 def test_image_auto_conversion_I(self):
     stokes = numpy.array(random.uniform(-1.0, 1.0, [3, 4, 128, 128]))
     ipf = PolarisationFrame('stokesI')
     opf = PolarisationFrame('stokesI')
     cir = convert_pol_frame(stokes, ipf, opf)
     st = convert_pol_frame(cir, opf, ipf)
     assert_array_almost_equal(st.real, stokes, 15)
Example #2
0
 def test_vis_auto_conversion_I(self):
     stokes = numpy.array(random.uniform(-1.0, 1.0, [1000, 3, 1]))
     ipf = PolarisationFrame('stokesI')
     opf = PolarisationFrame('stokesI')
     cir = convert_pol_frame(stokes, ipf, opf, polaxis=2)
     st = convert_pol_frame(cir, opf, ipf, polaxis=2)
     assert_array_almost_equal(st.real, stokes, 15)
    def test_apply_jones(self):
        nsucceeded = 0
        nfailures = 0
        for flux in (numpy.array([100.0, 0.0, 0.0, 0.0]),
                     numpy.array([100.0, 100.0, 0.0, 0.0]),
                     numpy.array([100.0, 0.0, 100.0, 0.0]),
                     numpy.array([100.0, 0.0, 0.0, 100.0]),
                     numpy.array([100.0, 1.0, -10.0, +60.0])):
            vpol = PolarisationFrame("linear")
            cpol = PolarisationFrame("stokesIQUV")
            cflux = convert_pol_frame(flux, cpol, vpol, 0).reshape([2,2])

            diagonal = numpy.array([[1.0 + 0.0j, 0.0 + 0.0j],
                                    [0.0 + 0.0j, 1.0 + 0.0]])
            skew = numpy.array([[0.0 + 0.0j, 1.0 + 0.0j],
                                [1.0 + 0.0j, 0.0 + 0.0]])
            leakage = numpy.array([[1.0 + 0.0j, 0.0 + 0.1j],
                                   [0.0 - 0.1j, 1.0 + 0.0]])
            unbalanced = numpy.array([[100.0 + 0.0j, 0.0 + 0.0j],
                                      [0.0 + 0.0j, 0.03 + 0.0]])

            for ej in (diagonal, skew, leakage, unbalanced):
                try:
                    jflux = apply_jones(ej, cflux, inverse=False)
                    rflux = apply_jones(ej, jflux, inverse=True).reshape([4])
                    rflux = convert_pol_frame(rflux, vpol, cpol, 0)
                    assert_array_almost_equal(flux, numpy.real(rflux), 12)
                    # print("{0} {1} {2} succeeded".format(vpol, str(ej), str(flux)))
                    nsucceeded += 1
                except AssertionError as e:
                    print(e)
                    print("{0} {1} {2} failed".format(vpol, str(ej), str(flux)))
                    nfailures += 1
        assert nfailures == 0, "{0} tests succeeded, {1} failed".format(nsucceeded, nfailures)
Example #4
0
 def test_circular_to_linear(self):
     stokes = numpy.array(random.uniform(-1.0, 1.0, [3, 4, 128, 128]))
     ipf = PolarisationFrame('stokesIQUV')
     opf = PolarisationFrame('circular')
     cir = convert_pol_frame(stokes, ipf, opf)
     wrong_pf = PolarisationFrame('linear')
     with self.assertRaises(ValueError):
         convert_pol_frame(cir, opf, wrong_pf)
Example #5
0
def predict_skycomponent_visibility(
    vis: Union[Visibility, BlockVisibility], sc: Union[Skycomponent,
                                                       List[Skycomponent]]
) -> Union[Visibility, BlockVisibility]:
    """Predict the visibility from a Skycomponent, add to existing visibility, for Visibility or BlockVisibility

    :param vis: Visibility or BlockVisibility
    :param sc: Skycomponent or list of SkyComponents
    :return: Visibility or BlockVisibility
    """
    if sc is None:
        return vis

    if not isinstance(sc, collections.Iterable):
        sc = [sc]

    if isinstance(vis, Visibility):

        _, im_nchan = list(get_frequency_map(vis, None))

        for comp in sc:
            assert isinstance(comp, Skycomponent), comp

            assert_same_chan_pol(vis, comp)

            l, m, n = skycoord_to_lmn(comp.direction, vis.phasecentre)
            phasor = simulate_point(vis.uvw, l, m)

            comp_flux = comp.flux[im_nchan, :]
            vis.data['vis'][...] += comp_flux[:, :] * phasor[:, numpy.newaxis]

    elif isinstance(vis, BlockVisibility):

        ntimes, nant, _, nchan, npol = vis.vis.shape

        k = numpy.array(vis.frequency) / constants.c.to('m s^-1').value

        for comp in sc:
            #            assert isinstance(comp, Skycomponent), comp
            assert_same_chan_pol(vis, comp)

            flux = comp.flux
            if comp.polarisation_frame != vis.polarisation_frame:
                flux = convert_pol_frame(flux, comp.polarisation_frame,
                                         vis.polarisation_frame)

            l, m, n = skycoord_to_lmn(comp.direction, vis.phasecentre)
            uvw = vis.uvw[..., numpy.newaxis] * k
            phasor = numpy.ones([ntimes, nant, nant, nchan, npol],
                                dtype='complex')
            for chan in range(nchan):
                phasor[:, :, :,
                       chan, :] = simulate_point(uvw[..., chan], l,
                                                 m)[..., numpy.newaxis]

            vis.data['vis'][..., :, :] += flux[:, :] * phasor[..., :]

    return vis
Example #6
0
def idft_visibility_skycomponent(vis: Union[Visibility, BlockVisibility],
                                 sc: Union[Skycomponent, List[Skycomponent]]) -> \
        ([Skycomponent, List[Skycomponent]], List[numpy.ndarray]):
    """Inverse DFT a Skycomponent from Visibility or BlockVisibility

    :param vis: Visibility or BlockVisibility
    :param sc: Skycomponent or list of SkyComponents
    :return: Skycomponent or list of SkyComponents, array of weights
    """
    if sc is None:
        return sc

    if not isinstance(sc, collections.abc.Iterable):
        sc = [sc]

    newsc = list()
    weights_list = list()

    for comp in sc:
        assert isinstance(comp, Skycomponent), comp
        assert_same_chan_pol(vis, comp)
        newcomp = copy_skycomponent(comp)

        if isinstance(vis, Visibility):

            flux = numpy.zeros_like(comp.flux, dtype='complex')
            weight = numpy.zeros_like(comp.flux, dtype='float')
            _, im_nchan = list(get_frequency_map(vis, None))
            phasor = numpy.conjugate(
                calculate_visibility_phasor(comp.direction, vis))
            fvwp = vis.flagged_weight * vis.flagged_vis * phasor
            fw = vis.flagged_weight
            for row in range(vis.nvis):
                ic = im_nchan[row]
                flux[ic, :] += fvwp[row, :]
                weight[ic, :] += fw[row, :]

        elif isinstance(vis, BlockVisibility):

            phasor = numpy.conjugate(
                calculate_blockvisibility_phasor(comp.direction, vis))
            flux = numpy.sum(vis.flagged_weight * vis.flagged_vis * phasor,
                             axis=(0, 1, 2))
            weight = numpy.sum(vis.flagged_weight, axis=(0, 1, 2))

        flux[weight > 0.0] = flux[weight > 0.0] / weight[weight > 0.0]
        flux[weight <= 0.0] = 0.0
        if comp.polarisation_frame != vis.polarisation_frame:
            flux = convert_pol_frame(flux, vis.polarisation_frame,
                                     comp.polarisation_frame)

        newcomp.flux = flux

        newsc.append(newcomp)
        weights_list.append(weight)

    return newsc, weights_list
Example #7
0
def dft_skycomponent_visibility(vis: Union[Visibility, BlockVisibility], sc: Union[Skycomponent, List[Skycomponent]]) \
        -> Union[Visibility, BlockVisibility]:
    """DFT to get the visibility from a Skycomponent, for Visibility or BlockVisibility

    :param vis: Visibility or BlockVisibility
    :param sc: Skycomponent or list of SkyComponents
    :return: Visibility or BlockVisibility
    """
    if sc is None:
        return vis

    if not isinstance(sc, collections.abc.Iterable):
        sc = [sc]

    for comp in sc:

        assert_same_chan_pol(vis, comp)
        assert isinstance(comp, Skycomponent), comp
        flux = comp.flux
        if comp.polarisation_frame != vis.polarisation_frame:
            flux = convert_pol_frame(flux, comp.polarisation_frame,
                                     vis.polarisation_frame)

        if isinstance(vis, Visibility):

            _, im_nchan = list(get_frequency_map(vis, None))
            phasor = calculate_visibility_phasor(comp.direction, vis)
            for row in range(vis.nvis):
                ic = im_nchan[row]
                vis.data['vis'][row, :] += flux[ic, :] * phasor[row]

        elif isinstance(vis, BlockVisibility):

            phasor = calculate_blockvisibility_phasor(comp.direction, vis)
            vis.data['vis'] += flux * phasor

    return vis
Example #8
0
    def predict_ng(bvis: BlockVisibility, model: Image,
                   **kwargs) -> BlockVisibility:
        """ Predict using convolutional degridding.
        
        Nifty-gridder version. https://gitlab.mpcdf.mpg.de/ift/nifty_gridder
    
        In the imaging and pipeline workflows, this may be invoked using context='ng'.

        :param bvis: BlockVisibility to be predicted
        :param model: model image
        :return: resulting BlockVisibility (in place works)
        """

        assert isinstance(bvis, BlockVisibility), bvis
        assert image_is_canonical(model)

        if model is None:
            return bvis

        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)

        newbvis = copy_visibility(bvis, zero=True)

        # Extracting data from BlockVisibility
        freq = bvis.frequency  # frequency, Hz
        nrows, nants, _, vnchan, vnpol = bvis.vis.shape

        uvw = newbvis.data['uvw'].reshape([nrows * nants * nants, 3])
        vist = numpy.zeros([vnpol, vnchan, nants * nants * nrows],
                           dtype='complex')

        # Get the image properties
        m_nchan, m_npol, ny, nx = model.data.shape
        # Check if the number of frequency channels matches in bvis and a model
        #        assert (m_nchan == v_nchan)
        assert (m_npol == vnpol)

        fuvw = uvw.copy()
        # We need to flip the u and w axes. The flip in w is equivalent to the conjugation of the
        # convolution function grid_visibility to griddata
        fuvw[:, 0] *= -1.0
        fuvw[:, 2] *= -1.0

        # Find out the image size/resolution
        pixsize = numpy.abs(numpy.radians(model.wcs.wcs.cdelt[0]))

        # Make de-gridding over a frequency range and pol fields
        vis_to_im = numpy.round(model.wcs.sub([4]).wcs_world2pix(
            freq, 0)[0]).astype('int')

        mfs = m_nchan == 1

        if mfs:
            for vpol in range(vnpol):
                vist[vpol, :, :] = ng.dirty2ms(
                    fuvw.astype(numpy.float64),
                    bvis.frequency.astype(numpy.float64),
                    model.data[0, vpol, :, :].T.astype(numpy.float64),
                    pixsize_x=pixsize,
                    pixsize_y=pixsize,
                    epsilon=epsilon,
                    do_wstacking=do_wstacking,
                    nthreads=nthreads,
                    verbosity=verbosity).T

        else:
            for vpol in range(vnpol):
                for vchan in range(vnchan):
                    imchan = vis_to_im[vchan]
                    vist[vpol, vchan, :] = ng.dirty2ms(
                        fuvw.astype(numpy.float64),
                        numpy.array(freq[vchan:vchan + 1]).astype(
                            numpy.float64),
                        model.data[imchan, vpol, :, :].T.astype(numpy.float64),
                        pixsize_x=pixsize,
                        pixsize_y=pixsize,
                        epsilon=epsilon,
                        do_wstacking=do_wstacking,
                        nthreads=nthreads,
                        verbosity=verbosity)[:, 0]

        vis = convert_pol_frame(vist.T,
                                model.polarisation_frame,
                                bvis.polarisation_frame,
                                polaxis=2)

        newbvis.data['vis'] = vis.reshape([nrows, nants, nants, vnchan, vnpol])

        # Now we can shift the visibility from the image frame to the original visibility frame
        return shift_vis_to_image(newbvis, model, tangent=True, inverse=True)
Example #9
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
Example #10
0
File: ng.py Project: Yonhua/rascil
    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
Example #11
0
    def test_apply_voltage_pattern_image_pointsource(self):
        self.createVis(rmax=1e3)
        telescope = 'MID_FEKO_B2'
        vpol = PolarisationFrame("linear")
        self.times = numpy.linspace(-4, +4, 8) * numpy.pi / 12.0
        bvis = create_blockvisibility(self.config,
                                      self.times,
                                      self.frequency,
                                      channel_bandwidth=self.channel_bandwidth,
                                      phasecentre=self.phasecentre,
                                      weight=1.0,
                                      polarisation_frame=vpol,
                                      zerow=True)
        cellsize = advise_wide_field(bvis)['cellsize']

        pbmodel = create_image_from_visibility(
            bvis,
            cellsize=self.cellsize,
            npixel=self.npixel,
            override_cellsize=False,
            polarisation_frame=PolarisationFrame("stokesIQUV"))
        vpbeam = create_vp(pbmodel, telescope=telescope, use_local=False)
        vpbeam.wcs.wcs.ctype[0] = 'RA---SIN'
        vpbeam.wcs.wcs.ctype[1] = 'DEC--SIN'
        vpbeam.wcs.wcs.crval[0] = pbmodel.wcs.wcs.crval[0]
        vpbeam.wcs.wcs.crval[1] = pbmodel.wcs.wcs.crval[1]

        s3_components = create_test_skycomponents_from_s3(
            flux_limit=0.1,
            phasecentre=self.phasecentre,
            frequency=self.frequency,
            polarisation_frame=PolarisationFrame('stokesI'),
            radius=1.5 * numpy.pi / 180.0)

        for comp in s3_components:
            comp.polarisation_frame = PolarisationFrame('stokesIQUV')
            comp.flux = numpy.array([[comp.flux[0, 0], 0.0, 0.0, 0.0]])

        s3_components = filter_skycomponents_by_flux(s3_components, 0.0, 10.0)

        from rascil.processing_components.image import show_image
        import matplotlib.pyplot as plt
        plt.clf()
        show_image(vpbeam, components=s3_components)
        plt.show(block=False)

        vpcomp = apply_voltage_pattern_to_skycomponent(s3_components, vpbeam)
        bvis.data['vis'][...] = 0.0 + 0.0j
        bvis = dft_skycomponent_visibility(bvis, vpcomp)

        rec_comp = idft_visibility_skycomponent(bvis, vpcomp)[0]

        stokes_comp = list()
        for comp in rec_comp:
            stokes_comp.append(
                convert_pol_frame(comp.flux[0], PolarisationFrame("linear"),
                                  PolarisationFrame("stokesIQUV")))

        stokesI = numpy.abs(
            numpy.array([comp_flux[0] for comp_flux in stokes_comp]).real)
        stokesQ = numpy.abs(
            numpy.array([comp_flux[1] for comp_flux in stokes_comp]).real)
        stokesU = numpy.abs(
            numpy.array([comp_flux[2] for comp_flux in stokes_comp]).real)
        stokesV = numpy.abs(
            numpy.array([comp_flux[3] for comp_flux in stokes_comp]).real)
        plt.clf()
        plt.loglog(stokesI, stokesQ, '.', label='Q')
        plt.loglog(stokesI, stokesU, '.', label='U')
        plt.loglog(stokesI, stokesV, '.', label='V')
        plt.xlabel("Stokes Flux I (Jy)")
        plt.ylabel("Flux (Jy)")
        plt.legend()
        plt.savefig('%s/test_primary_beams_pol_rsexecute_stokes_errors.png' %
                    self.dir)
        plt.show(block=False)

        split_times = False
        if split_times:
            bvis_list = list()
            for rows in vis_timeslice_iter(bvis, vis_slices=8):
                bvis_list.append(create_visibility_from_rows(bvis, rows))
        else:
            bvis_list = [bvis]

        bvis_list = rsexecute.scatter(bvis_list)

        model_list = \
            [rsexecute.execute(create_image_from_visibility, nout=1)(bv, cellsize=cellsize, npixel=4096,
                                                                     phasecentre=self.phasecentre,
                                                                     override_cellsize=False,
                                                                     polarisation_frame=PolarisationFrame("stokesIQUV"))
             for bv in bvis_list]

        model_list = rsexecute.persist(model_list)
        bvis_list = weight_list_rsexecute_workflow(bvis_list, model_list)

        continuum_imaging_list = \
            continuum_imaging_list_rsexecute_workflow(bvis_list, model_list,
                                                      context='2d',
                                                      algorithm='hogbom',
                                                      facets=1,
                                                      niter=1000,
                                                      fractional_threshold=0.1,
                                                      threshold=1e-4,
                                                      nmajor=5, gain=0.1,
                                                      deconvolve_facets=4,
                                                      deconvolve_overlap=32,
                                                      deconvolve_taper='tukey',
                                                      psf_support=64,
                                                      restore_facets=4, psfwidth=1.0)
        clean, residual, restored = rsexecute.compute(continuum_imaging_list,
                                                      sync=True)
        centre = 0
        if self.persist:
            export_image_to_fits(
                clean[centre],
                '%s/test_primary_beams_pol_rsexecute_clean.fits' % self.dir)
            export_image_to_fits(
                residual[centre][0],
                '%s/test_primary_beams_pol_rsexecute_residual.fits' % self.dir)
            export_image_to_fits(
                restored[centre],
                '%s/test_primary_beams_pol_rsexecute_restored.fits' % self.dir)

        plt.clf()
        show_image(restored[centre])
        plt.show(block=False)

        qa = qa_image(restored[centre])
        assert numpy.abs(qa.data['max'] - 0.9953017707113947) < 1.0e-7, str(qa)
        assert numpy.abs(qa.data['min'] +
                         0.0036396480874570846) < 1.0e-7, str(qa)
def apply_voltage_pattern_to_skycomponent(sc: Union[Skycomponent, List[Skycomponent]], vp: Image,
                                          inverse=False) \
        -> Union[Skycomponent, List[Skycomponent]]:
    """ Apply a voltage pattern to a Skycomponent

    For inverse==False, input polarisation_frame must be stokesIQUV, and
    output polarisation_frame is same as voltage pattern

    For inverse==True, input polarisation_frame must be same as voltage pattern, and
    output polarisation_frame is "stokesIQUV"

    Requires a complex Image with the correct ordering of polarisation axes:
    e.g. RR, LL, RL, LR or XX, YY, XY, YX

    :param vp: voltage pattern as complex image
    :param sc: SkyComponent or list of SkyComponents
    :return: List of skycomponents
    """
    assert isinstance(vp, Image)
    assert (vp.polarisation_frame == PolarisationFrame("linear")) or \
           (vp.polarisation_frame == PolarisationFrame("circular"))

    assert vp.data.dtype == "complex128"
    single = not isinstance(sc, collections.abc.Iterable)

    if single:
        sc = [sc]

    nchan, npol, ny, nx = vp.shape

    log.debug('apply_vp_to_skycomponent: Processing %d components' % (len(sc)))

    ras = [comp.direction.ra.radian for comp in sc]
    decs = [comp.direction.dec.radian for comp in sc]
    skycoords = SkyCoord(ras * u.rad, decs * u.rad, frame='icrs')
    pixlocs = skycoord_to_pixel(skycoords, vp.wcs, origin=1, mode='wcs')

    newsc = []
    total_flux = numpy.zeros([nchan, npol], dtype="complex")

    for icomp, comp in enumerate(sc):

        assert comp.shape == 'Point', "Cannot handle shape %s" % comp.shape
        assert_same_chan_pol(vp, comp)

        # Convert to linear (xx, xy, yx, yy) or circular (rr, rl, lr, ll)
        nchan, npol = comp.flux.shape
        assert npol == 4
        if not inverse:
            assert comp.polarisation_frame == PolarisationFrame("stokesIQUV")

        comp_flux_cstokes = \
            convert_pol_frame(comp.flux, comp.polarisation_frame, vp.polarisation_frame).reshape([nchan, 2, 2])
        comp_flux = numpy.zeros([nchan, npol], dtype='complex')

        pixloc = (pixlocs[0][icomp], pixlocs[1][icomp])
        if not numpy.isnan(pixloc).any():
            x, y = int(round(float(pixloc[0]))), int(round(float(pixloc[1])))
            if 0 <= x < nx and 0 <= y < ny:
                # Now we want to left and right multiply by the Jones matrices
                # comp_flux = vp.data[:, :, y, x] * comp_flux_cstokes * numpy.vp.data[:, :, y, x]
                for chan in range(nchan):
                    ej = vp.data[chan, :, y, x].reshape([2, 2])
                    cfs = comp_flux_cstokes[chan].reshape([2, 2])
                    comp_flux[chan, :] = apply_jones(ej, cfs,
                                                     inverse).reshape([4])

                total_flux += comp_flux
                if inverse:
                    comp_flux = convert_pol_frame(
                        comp_flux, vp.polarisation_frame,
                        PolarisationFrame("stokesIQUV"))
                    comp.polarisation_frame = PolarisationFrame("stokesIQUV")

                newsc.append(
                    Skycomponent(comp.direction,
                                 comp.frequency,
                                 comp.name,
                                 comp_flux,
                                 shape=comp.shape,
                                 polarisation_frame=vp.polarisation_frame))

    log.debug('apply_vp_to_skycomponent: %d components with total flux %s' %
              (len(newsc), total_flux))
    if single:
        return newsc[0]
    else:
        return newsc