Esempio n. 1
0
def invert_kernel(ixs, function, dopsf, normalize, context, **kwargs):
    iix, (data_image, data_visibility) = ixs
    facet_id = data_image.facet_id
    ix = None
    if context == "facets_slice" or context == "facets_wstack":
        ix = (iix[0], iix[1], iix[2], iix[3], facet_id, iix[5])
    elif context in ["facets_timeslice"]:
        ix = (iix[0], iix[1], iix[2], iix[3], data_visibility.iter_id, iix[5])
    else:
        ix = iix
    if data_visibility is not None:
        result = function(data_visibility,
                          data_image,
                          dopsf=dopsf,
                          normalize=normalize,
                          **kwargs)
        if context == "2d" or context == "facets":
            result = (ix, sum_invert_results([result]))
        else:
            result = (ix, result)
        result[1][0].facet_id = facet_id
    else:
        result = (create_empty_image_like(data_image), 0.0)
        if context == "2d" or context == "facets":
            result = (ix, sum_invert_results([result]))
        else:
            result = (ix, result)
        result[1][0].facet_id = facet_id
    label = "Invert Kernel "
    print(label + str(result))
    return result
Esempio n. 2
0
 def test_continuum_imaging(self):
     model = create_empty_image_like(self.image)
     visres, comp, residual = continuum_imaging(self.vis,
                                                model,
                                                algorithm='msmfsclean')
     export_image_to_fits(
         comp, "%s/test_pipelines-continuum-imaging-comp.fits" % (self.dir))
    def test_psf_location_2d(self):

        self.actualSetUp()
        self.componentvis = create_visibility(
            self.lowcore,
            self.times,
            self.frequency,
            channel_bandwidth=self.channel_bandwidth,
            phasecentre=self.phasecentre,
            weight=1.0,
            polarisation_frame=self.vis_pol)
        self.componentvis.data['uvw'][:, 2] = 0.0
        self.componentvis.data['vis'] *= 0.0

        psf2d = create_empty_image_like(self.model)
        psf2d, sumwt = invert_2d(self.componentvis,
                                 psf2d,
                                 dopsf=True,
                                 **self.params)

        export_image_to_fits(
            psf2d,
            '%s/test_imaging_functions_invert_psf_location.fits' % self.dir)

        nchan, npol, ny, nx = psf2d.shape

        assert numpy.abs(psf2d.data[0, 0, ny // 2, nx // 2] - 1.0) < 2e-3
        imagecentre = pixel_to_skycoord(nx // 2 + 1.0,
                                        ny // 2 + 1.0,
                                        wcs=psf2d.wcs,
                                        origin=1)
        assert imagecentre.separation(self.phasecentre).value < 1e-15, \
            "Image phase centre %s not as expected %s" % (imagecentre, self.phasecentre)
    def test_invert_2d(self):
        # Test if the 2D invert works with w set to zero
        # Set w=0 so that the two-dimensional transform should agree exactly with the model.
        # Good check on the grid correction in the vis->image direction

        self.actualSetUp()
        self.componentvis = create_visibility(
            self.lowcore,
            self.times,
            self.frequency,
            channel_bandwidth=self.channel_bandwidth,
            phasecentre=self.phasecentre,
            weight=1.0,
            polarisation_frame=self.vis_pol)
        self.componentvis.data['uvw'][:, 2] = 0.0
        self.componentvis.data['vis'] *= 0.0
        # Predict the visibility using direct evaluation
        for comp in self.components:
            predict_skycomponent_visibility(self.componentvis, comp)

        dirty2d = create_empty_image_like(self.model)
        dirty2d, sumwt = invert_2d(self.componentvis, dirty2d, **self.params)

        export_image_to_fits(
            dirty2d,
            '%s/test_imaging_functions_invert_2d_dirty.fits' % self.dir)

        self._checkcomponents(dirty2d)
Esempio n. 5
0
 def ingest_visibility(self, freq=None, chan_width=None, times=None, reffrequency=None, add_errors=False,
                       block=True):
     if freq is None:
         freq = [1e8]
     if times is None:
         ntimes = 5
         times = numpy.linspace(-numpy.pi / 3.0, numpy.pi / 3.0, ntimes)
     if chan_width is None:
         chan_width = [1e6]
     
     if reffrequency is None:
         reffrequency = [1e8]
     lowcore = create_named_configuration('LOWBD2-CORE')
     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=reffrequency, phasecentre=phasecentre,
                                          polarisation_frame=PolarisationFrame("stokesI"))
     flux = numpy.array([[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(flux=flux, frequency=frequency, direction=sc,
                                        polarisation_frame=PolarisationFrame("stokesI"))
             comps.append(comp)
     if block:
         predict_skycomponent_blockvisibility(vt, comps)
     else:
         predict_skycomponent_visibility(vt, comps)
     insert_skycomponent(model, comps)
     self.model = copy_image(model)
     self.empty_model = create_empty_image_like(model)
     export_image_to_fits(model, '%s/test_pipeline_bags_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)
     return vt
Esempio n. 6
0
def create_illum_vla(model):
    def disk(a, xx, yy, radius):
        disk = numpy.zeros_like(a)
        nx, ny = a.shape
        rr = numpy.sqrt(xx ** 2 + yy ** 2)
        for y in range(ny):
            for x in range(nx):
                if rr[x, y] < radius / 2:
                    disk[x, y] = 1.0
        return disk
    
    nchan, npol, ny, nx = model.shape
    
    # The beam is assumed to just scale with frequency.
    
    beam = create_empty_image_like(model)
    illum = fft_image(beam)
    
    for chan in range(nchan):
        
        # The frequency axis is the second to last in the beam
        frequency = model.wcs.sub(['spectral']).wcs_pix2world([chan], 0)[0]
        wavelength = const.c.to('m/s').value / frequency
        scaleuv = numpy.abs(illum.wcs.sub(2).wcs.cdelt[0]) * wavelength
        
        xx, yy = numpy.meshgrid(scaleuv * (range(nx) - illum.wcs.sub(2).wcs.crpix[0]),
                                scaleuv * (range(ny) - illum.wcs.sub(2).wcs.crpix[1]))
        
        for pol in range(npol):
            reflector = disk(illum.data[chan, pol, ...], xx, yy, 25.0)
            blockage = disk(illum.data[chan, pol, ...], xx, yy, 1.67)
            illum.data[chan, pol, ...] = reflector - blockage
    
    return illum
Esempio n. 7
0
 def test_ICAL_bandpass(self):
     self.setupVis(add_errors=True, block=True, freqwin=32, bandpass=True)
     model = create_empty_image_like(self.model)
     comp, residual, restored = ical(self.vis,
                                     model,
                                     algorithm='msclean',
                                     context='wstack',
                                     vis_slices=51,
                                     scales=[0, 3, 10, 30],
                                     threshold=0.01,
                                     findpeak='ARL',
                                     fractional_threshold=0.01,
                                     T_first_selfcal=2,
                                     G_first_selfcal=3,
                                     B_first_selfcal=4,
                                     nmajor=5)
     export_image_to_fits(
         comp,
         "%s/test_pipelines-ical-deconvolved-bandpass.fits" % (self.dir))
     export_image_to_fits(
         residual,
         "%s/test_pipelines-ical-residual-bandpass.fits" % (self.dir))
     export_image_to_fits(
         restored,
         "%s/test_pipelines-ical-restored-bandpass.fits" % (self.dir))
 def _invert_base(self, invert, fluxthreshold=20.0, positionthreshold=1.0):
     dirtyFacet = create_empty_image_like(self.model)
     dirtyFacet, sumwt = invert(self.componentvis, dirtyFacet,
                                **self.params)
     assert sumwt.all() > 0.0
     export_image_to_fits(
         dirtyFacet, '%s/test_%s_dirty.fits' % (self.dir, invert.__name__))
     self._checkcomponents(dirtyFacet, fluxthreshold, positionthreshold)
Esempio n. 9
0
 def test_spectral_line_imaging_no_deconvolution(self):
     model = create_empty_image_like(self.image)
     visres, comp, residual = spectral_line_imaging(
         self.vis, model, continuum_model=model, deconvolve_spectral=False)
     export_image_to_fits(
         comp,
         "%s/test_pipelines-spectral-no-deconvolution-imaging-comp.fits" %
         (self.dir))
 def gather_image_iteration_results(results, template_model):
     result = create_empty_image_like(template_model)
     i = 0
     for dpatch in image_iter(result, facets=facets, **kwargs):
         if results[i] is not None:
             dpatch.data[...] = results[i][0].data[...]
             i += 1
     return result, results[0][1]
Esempio n. 11
0
 def gather_invert_results(results, template_model, facets, **kwargs):
     # Results contains the images for each facet, after adding across vis_graphs
     image_results = create_empty_image_like(template_model)
     image_results = image_gather([result[0] for result in results], image_results,
                                  facets=facets)
     # For the gather, assume all are the same weight
     sumwt = results[0][1]
     
     return image_results, sumwt
 def invert_ignore_none(vis, model):
     if vis is not None:
         return invert(vis,
                       model,
                       context=context,
                       dopsf=dopsf,
                       normalize=normalize,
                       **kwargs)
     else:
         return create_empty_image_like(model), 0.0
Esempio n. 13
0
def create_low_test_beam(model: Image) -> Image:
    """Create a test power beam for LOW using an image from OSKAR

    :param model: Template image
    :return: Image
    """

    beam = import_image_from_fits(arl_path('data/models/SKA1_LOW_beam.fits'))

    # Scale the image cellsize to account for the different in frequencies. Eventually we will want to
    # use a frequency cube
    log.info("create_low_test_beam: primary beam is defined at %.3f MHz" %
             (beam.wcs.wcs.crval[2] * 1e-6))

    nchan, npol, ny, nx = model.shape

    # We need to interpolate each frequency channel separately. The beam is assumed to just scale with
    # frequency.

    reprojected_beam = create_empty_image_like(model)

    for chan in range(nchan):

        model2dwcs = model.wcs.sub(2).deepcopy()
        model2dshape = [model.shape[2], model.shape[3]]
        beam2dwcs = beam.wcs.sub(2).deepcopy()

        # The frequency axis is the second to last in the beam
        frequency = model.wcs.sub(['spectral']).wcs_pix2world([chan], 0)[0]
        fscale = beam.wcs.wcs.crval[2] / frequency

        beam2dwcs.wcs.cdelt = fscale * beam.wcs.sub(2).wcs.cdelt
        beam2dwcs.wcs.crpix = beam.wcs.sub(2).wcs.crpix
        beam2dwcs.wcs.crval = model.wcs.sub(2).wcs.crval
        beam2dwcs.wcs.ctype = model.wcs.sub(2).wcs.ctype
        model2dwcs.wcs.crpix = [
            model.shape[2] // 2 + 1, model.shape[3] // 2 + 1
        ]

        beam2d = create_image_from_array(beam.data[0, 0, :, :], beam2dwcs,
                                         model.polarisation_frame)
        reprojected_beam2d, footprint = reproject_image(beam2d,
                                                        model2dwcs,
                                                        shape=model2dshape)
        assert numpy.max(
            footprint.data) > 0.0, "No overlap between beam and model"

        reprojected_beam2d.data *= reprojected_beam2d.data
        reprojected_beam2d.data[footprint.data <= 0.0] = 0.0
        for pol in range(npol):
            reprojected_beam.data[chan,
                                  pol, :, :] = reprojected_beam2d.data[:, :]

    return reprojected_beam
Esempio n. 14
0
 def test_spectral_line_imaging_with_deconvolution(self):
     model = create_empty_image_like(self.image)
     visres, comp, residual = spectral_line_imaging(
         self.vis,
         model,
         continuum_model=self.image,
         algorithm='hogbom',
         deconvolve_spectral=True)
     export_image_to_fits(
         comp,
         "%s/test_pipelines-spectral-with-deconvolution-imaging-comp.fits" %
         (self.dir))
Esempio n. 15
0
 def test_continuum_imaging(self):
     model = create_empty_image_like(self.image)
     visres, comp, residual = continuum_imaging(self.vis,
                                                model,
                                                algorithm='msmfsclean',
                                                scales=[0, 3, 10],
                                                threshold=0.01,
                                                nmoments=2,
                                                findpeak='ARL',
                                                fractional_threshold=0.01)
     export_image_to_fits(
         comp, "%s/test_pipelines-continuum-imaging-comp.fits" % (self.dir))
 def gather_image_iteration_results(results, template_model):
     result = create_empty_image_like(template_model)
     i = 0
     sumwt = numpy.zeros([template_model.nchan, template_model.npol])
     for dpatch in image_iter(result, facets=facets, **kwargs):
         assert i < len(
             results), "Too few results in gather_image_iteration_results"
         if results[i] is not None:
             assert len(results[i]) == 2, results[i]
             dpatch.data[...] = results[i][0].data[...]
             sumwt += results[i][1]
             i += 1
     return result, sumwt
Esempio n. 17
0
 def _checkdirty(self, vis, name='test_invert_2d_dirty', fluxthreshold=1.0):
     # Make the dirty image
     self.params['imaginary'] = False
     dirty = create_empty_image_like(self.model)
     dirty, sumwt = invert_2d(vis=vis,
                              im=dirty,
                              dopsf=False,
                              normalize=True,
                              **self.params)
     export_image_to_fits(dirty, '%s/%s_dirty.fits' % (self.dir, name))
     maxabs = numpy.max(numpy.abs(dirty.data))
     assert maxabs < fluxthreshold, "%s, abs max %f exceeds flux threshold" % (
         name, maxabs)
Esempio n. 18
0
def invert_timeslice_single(vis: Visibility,
                            im: Image,
                            dopsf,
                            normalize=True,
                            **kwargs) -> (Image, numpy.ndarray):
    """Process single time slice
    
    Extracted for re-use in parallel version
    :param vis: Visibility to be inverted
    :param im: image template (not changed)
    :param dopsf: Make the psf instead of the dirty image
    :param normalize: Normalize by the sum of weights (True)
    """
    inchan, inpol, ny, nx = im.shape

    if not isinstance(vis, Visibility):
        avis = coalesce_visibility(vis, **kwargs)
    else:
        avis = vis

    log.debug("invert_timeslice: inverting using time slices")

    avis, p, q = fit_uvwplane(avis, remove=True)

    workimage, sumwt = invert_2d_base(avis,
                                      im,
                                      dopsf,
                                      normalize=normalize,
                                      **kwargs)

    finalimage = create_empty_image_like(im)

    # Use griddata to do the conversion. This could be improved. Only cubic is possible in griddata.
    # The interpolation is ok for invert since the image is smooth.

    # Calculate nominal and distorted coordinates. The image is in distorted coordinates so we
    # need to convert back to nominal
    lnominal, mnominal, ldistorted, mdistorted = lm_distortion(
        workimage, -p, -q)

    for chan in range(inchan):
        for pol in range(inpol):
            finalimage.data[chan, pol, ...] = \
                griddata((mdistorted.flatten(), ldistorted.flatten()),
                         values=workimage.data[chan, pol, ...].flatten(),
                         method='cubic',
                         xi=(mnominal.flatten(), lnominal.flatten()),
                         fill_value=0.0,
                         rescale=True).reshape(finalimage.data[chan, pol, ...].shape)

    return finalimage, sumwt
 def _invert_base(self,
                  context,
                  extra='',
                  fluxthreshold=1.0,
                  positionthreshold=1.0,
                  check_components=True):
     dirty = create_empty_image_like(self.model)
     dirty, sumwt = invert_context(self.componentvis,
                                   dirty,
                                   dopsf=False,
                                   context=context,
                                   **self.params)
     export_image_to_fits(
         dirty, '%s/test_imaging_functions_invert_%s%s_dirty.fits' %
         (self.dir, context, extra))
     if check_components:
         self._checkcomponents(dirty, fluxthreshold, positionthreshold)
Esempio n. 20
0
 def test_ICAL(self):
     self.setupVis(add_errors=True, block=True, freqwin=5)
     model = create_empty_image_like(self.model)
     visres, comp, residual = ical(self.vis,
                                   model,
                                   algorithm='msclean',
                                   context='wstack',
                                   vis_slices=51,
                                   scales=[0, 3, 10, 30],
                                   threshold=0.01,
                                   findpeak='ARL',
                                   fractional_threshold=0.01,
                                   first_selfcal=2,
                                   nmajor=5)
     export_image_to_fits(comp,
                          "%s/test_pipelines-ical-comp.fits" % (self.dir))
     export_image_to_fits(
         residual, "%s/test_pipelines-ical-residual.fits" % (self.dir))
    def _checkdirty(self, vis, context, fluxthreshold=0.3):
        # Make the dirty image
        self.params['imaginary'] = False
        self.params['timeslice'] = 'auto'

        dirty = create_empty_image_like(self.model)
        dirty, sumwt = invert_context(vis=vis,
                                      im=dirty,
                                      dopsf=False,
                                      normalize=True,
                                      context='2d',
                                      **self.params)
        export_image_to_fits(
            dirty,
            '%s/test_imaging_functions_%s_dirty.fits' % (self.dir, context))
        maxabs = numpy.max(numpy.abs(dirty.data))
        assert maxabs < fluxthreshold, "%s, abs max %f exceeds flux threshold" % (
            context, maxabs)
Esempio n. 22
0
 def test_continuum_imaging(self):
     self.setupVis(add_errors=False, block=True, freqwin=7)
     model = create_empty_image_like(self.model)
     comp, residual, restored = continuum_imaging(self.vis,
                                                  model,
                                                  algorithm='msmfsclean',
                                                  context='wstack',
                                                  vis_slices=51,
                                                  scales=[0, 3, 10],
                                                  threshold=0.01,
                                                  nmoments=2,
                                                  findpeak='ARL',
                                                  fractional_threshold=0.01)
     export_image_to_fits(
         comp, "%s/test_pipelines-continuum-imaging-comp.fits" % (self.dir))
     export_image_to_fits(
         residual,
         "%s/test_pipelines-continuum-imaging-residual.fits" % (self.dir))
Esempio n. 23
0
    def test_invert_2d(self):
        # Test if the 2D invert works with w set to zero
        # Set w=0 so that the two-dimensional transform should agree exactly with the model.
        # Good check on the grid correction in the vis->image direction

        self.actualSetUp()
        self.componentvis.data['uvw'][:, 2] = 0.0
        self.componentvis.data['vis'] *= 0.0
        # Predict the visibility using direct evaluation
        for comp in self.components:
            predict_skycomponent_visibility(self.componentvis, comp)

        dirty2d = create_empty_image_like(self.model)
        dirty2d, sumwt = invert_2d(self.componentvis, dirty2d, **self.params)

        export_image_to_fits(
            dirty2d,
            '%s/test_imaging_functions_invert_2d_dirty.fits' % self.dir)

        self._checkcomponents(dirty2d)
def invert_with_vis_iterator(vis,
                             im,
                             dopsf=False,
                             normalize=True,
                             vis_iter=vis_slice_iter,
                             invert=invert_2d,
                             **kwargs):
    """ Invert using a specified iterator and invert
    
    This knows about the structure of invert in different execution frameworks but not
    anything about the actual processing.

    :param vis:
    :param im:
    :param dopsf: Make the psf instead of the dirty image
    :param normalize: Normalize by the sum of weights (True)
    :param kwargs:
    :return:
    """
    resultimage = create_empty_image_like(im)

    i = 0
    for rows in vis_iter(vis, **kwargs):
        if rows is not None:
            visslice = create_visibility_from_rows(vis, rows)
            workimage, sumwt = invert(visslice,
                                      im,
                                      dopsf,
                                      normalize=False,
                                      **kwargs)
            resultimage.data += workimage.data
            if i == 0:
                totalwt = sumwt
            else:
                totalwt += sumwt
            i += 1

    if normalize:
        resultimage = normalize_sumwt(resultimage, totalwt)

    return resultimage, totalwt
Esempio n. 25
0
def create_pb_vla(model, pointingcentre=None):
    """
    Make an image like model and fill it with an analytical model of the primary beam
    :param model:
    :return:
    """
    beam = create_empty_image_like(model)

    nchan, npol, ny, nx = model.shape

    if pointingcentre is not None:
        cx, cy = skycoord_to_pixel(pointingcentre, model.wcs, 0, 'wcs')
    else:
        with warnings.catch_warnings():
            warnings.simplefilter('ignore')
            cx, cy = beam.wcs.sub(2).wcs.crpix[0] - 1, beam.wcs.sub(
                2).wcs.crpix[1] - 1

    for chan in range(nchan):

        # The frequency axis is the second to last in the beam
        with warnings.catch_warnings():
            warnings.simplefilter('ignore')
            frequency = model.wcs.sub(['spectral']).wcs_pix2world([chan], 0)[0]
        wavelength = const.c.to('m/s').value / frequency

        d2r = numpy.pi / 180.0
        scale = d2r * numpy.abs(beam.wcs.sub(2).wcs.cdelt[0])
        xx, yy = numpy.meshgrid(scale * (range(nx) - cx),
                                scale * (range(ny) - cy))
        # Radius of each cell in radians
        rr = numpy.sqrt(xx**2 + yy**2)

        for pol in range(npol):
            reflector = ft_disk(rr * numpy.pi * 25.0 / wavelength)
            # blockage = ft_disk(rr * numpy.pi * 1.67 / wavelength)
            beam.data[chan, pol, ...] = reflector  # - blockage

    beam.data *= beam.data
    return beam
Esempio n. 26
0
    def test_psf_location_2d(self):

        self.actualSetUp()

        psf2d = create_empty_image_like(self.model)
        psf2d, sumwt = invert_2d(self.componentvis,
                                 psf2d,
                                 dopsf=True,
                                 **self.params)

        export_image_to_fits(
            psf2d,
            '%s/test_imaging_functions_invert_psf_location.fits' % self.dir)

        nchan, npol, ny, nx = psf2d.shape

        assert numpy.abs(psf2d.data[0, 0, ny // 2, nx // 2] - 1.0) < 2e-3
        imagecentre = pixel_to_skycoord(nx // 2 + 1.0,
                                        ny // 2 + 1.0,
                                        wcs=psf2d.wcs,
                                        origin=1)
        assert imagecentre.separation(self.phasecentre).value < 1e-15, \
            "Image phase centre %s not as expected %s" % (imagecentre, self.phasecentre)
 def invert_ignore_none(vis, model):
     if vis is not None:
         return invert_context(vis, model, context=context, dopsf=dopsf, normalize=normalize,
                               **kwargs)
     else:
         return create_empty_image_like(model), numpy.zeros([model.nchan, model.npol])
Esempio n. 28
0
 def invert_ignore_None(vis, model, *args, **kwargs):
     if vis is not None:
         return invert(vis, model, *args, **kwargs)
     else:
         return create_empty_image_like(model), 0.0
Esempio n. 29
0
 def test_create_empty_image_like(self):
     emptyimage = create_empty_image_like(self.m31image)
     assert emptyimage.shape == self.m31image.shape
     assert numpy.max(numpy.abs(emptyimage.data)) == 0.0
def invert_function(vis,
                    im: Image,
                    dopsf=False,
                    normalize=True,
                    context='2d',
                    inner=None,
                    **kwargs):
    """ Invert using algorithm specified by context:

     * 2d: Two-dimensional transform
     * wstack: wstacking with either vis_slices or wstack (spacing between w planes) set
     * wprojection: w projection with wstep (spacing between w places) set, also kernel='wprojection'
     * timeslice: snapshot imaging with either vis_slices or timeslice set. timeslice='auto' does every time
     * facets: Faceted imaging with facets facets on each axis
     * facets_wprojection: facets AND wprojection
     * facets_wstack: facets AND wstacking
     * wprojection_wstack: wprojection and wstacking


    :param vis:
    :param im:
    :param dopsf: Make the psf instead of the dirty image (False)
    :param normalize: Normalize by the sum of weights (True)
    :param context: Imaging context e.g. '2d', 'timeslice', etc.
    :param inner: Inner loop 'vis'|'image'
    :param kwargs:
    :return: Image, sum of weights
    """
    c = imaging_context(context)
    vis_iter = c['vis_iterator']
    image_iter = c['image_iterator']
    invert = c['invert']
    if inner is None:
        inner = c['inner']

    if not isinstance(vis, Visibility):
        svis = coalesce_visibility(vis, **kwargs)
    else:
        svis = vis

    resultimage = create_empty_image_like(im)

    if inner == 'image':
        totalwt = None
        for rows in vis_iter(svis, **kwargs):
            if numpy.sum(rows):
                visslice = create_visibility_from_rows(svis, rows)
                sumwt = 0.0
                workimage = create_empty_image_like(im)
                for dpatch in image_iter(workimage, **kwargs):
                    result, sumwt = invert(visslice,
                                           dpatch,
                                           dopsf,
                                           normalize=False,
                                           **kwargs)
                    # Ensure that we fill in the elements of dpatch instead of creating a new numpy arrray
                    dpatch.data[...] = result.data[...]
                # Assume that sumwt is the same for all patches
                if totalwt is None:
                    totalwt = sumwt
                else:
                    totalwt += sumwt
                resultimage.data += workimage.data
    else:
        # We assume that the weight is the same for all image iterations
        totalwt = None
        workimage = create_empty_image_like(im)
        for dpatch in image_iter(workimage, **kwargs):
            totalwt = None
            for rows in vis_iter(svis, **kwargs):
                if numpy.sum(rows):
                    visslice = create_visibility_from_rows(svis, rows)
                    result, sumwt = invert(visslice,
                                           dpatch,
                                           dopsf,
                                           normalize=False,
                                           **kwargs)
                    # Ensure that we fill in the elements of dpatch instead of creating a new numpy arrray
                    dpatch.data[...] += result.data[...]
                    if totalwt is None:
                        totalwt = sumwt
                    else:
                        totalwt += sumwt
            resultimage.data += workimage.data
            workimage.data[...] = 0.0

    assert totalwt is not None, "No valid data found for imaging"
    if normalize:
        resultimage = normalize_sumwt(resultimage, totalwt)

    return resultimage, totalwt