def cImage(image_in, new=False):
    "Convert an Image* into ARL Image structure"
    new_image = Image()
    size = image_in.size
    data_shape = tuple(image_in.data_shape)
    new_image.data = numpy.frombuffer(ff.buffer(image_in.data, size * 8),
                                      dtype='f8',
                                      count=size)

    # frombuffer only does 1D arrays..
    new_image.data = new_image.data.reshape(data_shape)

    # New images don't have pickles yet
    if new:
        new_image.wcs = numpy.frombuffer(ff.buffer(image_in.wcs, 2996),
                                         dtype='b',
                                         count=2996)
        new_image.polarisation_frame = numpy.frombuffer(ff.buffer(
            image_in.polarisation_frame, 117),
                                                        dtype='b',
                                                        count=117)
    else:
        new_image.wcs = pickle.loads(ff.buffer(image_in.wcs, 2996))
        new_image.polarisation_frame = pickle.loads(
            ff.buffer(image_in.polarisation_frame, 117))

    return new_image
def import_image_from_fits(fitsfile: str) -> Image:
    """ Read an Image from fits
    
    :param fitsfile:
    :return: Image
    """
    fim = Image()
    warnings.simplefilter('ignore', FITSFixedWarning)
    hdulist = fits.open(fitsfile)
    fim.data = hdulist[0].data
    fim.wcs = WCS(fitsfile)
    hdulist.close()

    if len(fim.data) == 2:
        fim.polarisation_frame = PolarisationFrame('stokesI')
    else:
        try:
            fim.polarisation_frame = polarisation_frame_from_wcs(
                fim.wcs, fim.data.shape)
        except ValueError:
            fim.polarisation_frame = PolarisationFrame('stokesI')

    log.debug(
        "import_image_from_fits: created %s image of shape %s, size %.3f (GB)"
        % (fim.data.dtype, str(fim.shape), image_sizeof(fim)))
    log.debug("import_image_from_fits: Max, min in %s = %.6f, %.6f" %
              (fitsfile, fim.data.max(), fim.data.min()))

    assert isinstance(fim, Image)
    return fim
def normalize_sumwt(im: Image, sumwt) -> Image:
    """Normalize out the sum of weights

    :param im: Image, im.data has shape [nchan, npol, ny, nx]
    :param sumwt: Sum of weights [nchan, npol]
    """
    nchan, npol, _, _ = im.data.shape
    assert isinstance(im, Image), im
    assert sumwt is not None
    assert nchan == sumwt.shape[0]
    assert npol == sumwt.shape[1]
    for chan in range(nchan):
        for pol in range(npol):
            if sumwt[chan, pol] > 0.0:
                im.data[chan, pol, :, :] = im.data[chan, pol, :, :] / sumwt[chan, pol]
            else:
                im.data[chan, pol, :, :] = 0.0
    return im
Esempio n. 4
0
def create_image_from_array(data: numpy.array, wcs: WCS, polarisation_frame: PolarisationFrame) -> Image:
    """ Create an image from an array and optional wcs
    
    The output image preserves a reference to the input array.

    :param data: Numpy.array
    :param wcs: World coordinate system
    :param polarisation_frame: Polarisation Frame
    :return: Image
    
    """
    fim = Image()
    fim.polarisation_frame = polarisation_frame
    
    fim.data = data
    if wcs is None:
        fim.wcs = None
    else:
        fim.wcs = wcs.deepcopy()
    
    if image_sizeof(fim) >= 1.0:
        log.debug("create_image_from_array: created %s image of shape %s, size %.3f (GB)" %
                  (fim.data.dtype, str(fim.shape), image_sizeof(fim)))
    
    assert isinstance(fim, Image), "Type is %s" % type(fim)
    return fim
Esempio n. 5
0
def copy_image(im: Image):
    """ Create an image from an array
    
    Performs deepcopy of data_models, breaking reference semantics

    :param im:
    :return: Image
    
    """
    
    if im is None:
        return im
    
    assert isinstance(im, Image), im
    fim = Image()
    fim.polarisation_frame = im.polarisation_frame
    fim.data = copy.deepcopy(im.data)
    if im.wcs is None:
        fim.wcs = None
    else:
        fim.wcs = copy.deepcopy(im.wcs)
    if image_sizeof(fim) >= 1.0:
        log.debug("copy_image: copied %s image of shape %s, size %.3f (GB)" %
                  (fim.data.dtype, str(fim.shape), image_sizeof(fim)))
    assert type(fim) == Image
    return fim
Esempio n. 6
0
def replicate_image(im: Image, polarisation_frame=PolarisationFrame('stokesI'), frequency=numpy.array([1e8])) \
        -> Image:
    """ Make a new canonical shape Image, extended along third and fourth axes by replication.

    The order of the data is [chan, pol, dec, ra]


    :param frequency:
    :param im:
    :param polarisation_frame: Polarisation_frame
    :return: Image
    """

    if len(im.data.shape) == 2:
        fim = Image()

        newwcs = WCS(naxis=4)

        newwcs.wcs.crpix = [
            im.wcs.wcs.crpix[0] + 1.0, im.wcs.wcs.crpix[1] + 1.0, 1.0, 1.0
        ]
        newwcs.wcs.cdelt = [im.wcs.wcs.cdelt[0], im.wcs.wcs.cdelt[1], 1.0, 1.0]
        newwcs.wcs.crval = [
            im.wcs.wcs.crval[0], im.wcs.wcs.crval[1], 1.0, frequency[0]
        ]
        newwcs.wcs.ctype = [
            im.wcs.wcs.ctype[0], im.wcs.wcs.ctype[1], 'STOKES', 'FREQ'
        ]

        nchan = len(frequency)
        npol = polarisation_frame.npol
        fim.polarisation_frame = polarisation_frame

        fim.wcs = newwcs
        fshape = [nchan, npol, im.data.shape[1], im.data.shape[0]]
        fim.data = numpy.zeros(fshape)
        log.info("replicate_image: replicating shape %s to %s" %
                 (im.data.shape, fim.data.shape))
        for i3 in range(nchan):
            fim.data[i3, 0, :, :] = im.data[:, :]
        return fim
    else:
        return im
Esempio n. 7
0
def create_empty_image_like(im: Image) -> Image:
    """ Create an empty image like another in shape and wcs

    :param im:
    :return: Image
    
    """
    assert isinstance(im, Image), im
    fim = Image()
    fim.polarisation_frame = im.polarisation_frame
    fim.data = numpy.zeros_like(im.data)
    if im.wcs is None:
        fim.wcs = None
    else:
        fim.wcs = copy.deepcopy(im.wcs)
    if image_sizeof(im) >= 1.0:
        log.debug("create_empty_image_like: created %s image of shape %s, size %.3f (GB)" %
                  (fim.data.dtype, str(fim.shape), image_sizeof(fim)))
    assert isinstance(fim, Image), "Type is %s" % type(fim)
    return fim
Esempio n. 8
0
def image_sizeof(im: Image):
    """ Return size in GB
    """
    return im.size()
def deconvolve_cube(dirty: Image,
                    psf: Image,
                    prefix='',
                    **kwargs) -> (Image, Image):
    """ Clean using a variety of algorithms
    
    Functions that clean a dirty image using a point spread function. The algorithms available are:
    
    hogbom: Hogbom CLEAN See: Hogbom CLEAN A&A Suppl, 15, 417, (1974)
    
    msclean: MultiScale CLEAN See: Cornwell, T.J., Multiscale CLEAN (IEEE Journal of Selected Topics in Sig Proc,
    2008 vol. 2 pp. 793-801)

    mfsmsclean, msmfsclean, mmclean: MultiScale Multi-Frequency See: U. Rau and T. J. Cornwell,
    “A multi-scale multi-frequency deconvolution algorithm for synthesis imaging in radio interferometry,” A&A 532,
    A71 (2011).
    
    For example::
    
        comp, residual = deconvolve_cube(dirty, psf, niter=1000, gain=0.7, algorithm='msclean',
                                         scales=[0, 3, 10, 30], threshold=0.01)
                                         
    For the MFS clean, the psf must have number of channels >= 2 * nmoment
    
    :param dirty: Image dirty image
    :param psf: Image Point Spread Function
    :param window_shape: Window image (Bool) - clean where True
    :param mask: Window in the form of an image, overrides woindow_shape
    :param algorithm: Cleaning algorithm: 'msclean'|'hogbom'|'mfsmsclean'
    :param gain: loop gain (float) 0.7
    :param threshold: Clean threshold (0.0)
    :param fractional_threshold: Fractional threshold (0.01)
    :param scales: Scales (in pixels) for multiscale ([0, 3, 10, 30])
    :param nmoment: Number of frequency moments (default 3)
    :param findpeak: Method of finding peak in mfsclean: 'Algorithm1'|'ASKAPSoft'|'CASA'|'ARL', Default is ARL.
    :return: componentimage, residual
    
    """

    assert isinstance(dirty, Image), dirty
    assert isinstance(psf, Image), psf

    window_shape = get_parameter(kwargs, 'window_shape', None)
    if window_shape == 'quarter':
        log.info("deconvolve_cube %s: window is inner quarter" % prefix)
        qx = dirty.shape[3] // 4
        qy = dirty.shape[2] // 4
        window = numpy.zeros_like(dirty.data)
        window[..., (qy + 1):3 * qy, (qx + 1):3 * qx] = 1.0
        log.info(
            'deconvolve_cube %s: Cleaning inner quarter of each sky plane' %
            prefix)
    elif window_shape == 'no_edge':
        edge = get_parameter(kwargs, 'window_edge', 16)
        nx = dirty.shape[3]
        ny = dirty.shape[2]
        window = numpy.zeros_like(dirty.data)
        window[..., (edge + 1):(ny - edge), (edge + 1):(nx - edge)] = 1.0
        log.info(
            'deconvolve_cube %s: Window omits %d-pixel edge of each sky plane'
            % (prefix, edge))
    elif window_shape is None:
        log.info("deconvolve_cube %s: Cleaning entire image" % prefix)
        window = None
    else:
        raise ValueError("Window shape %s is not recognized" % window_shape)

    mask = get_parameter(kwargs, 'mask', None)
    if isinstance(mask, Image):
        if window is not None:
            log.warning(
                'deconvolve_cube %s: Overriding window_shape with mask image' %
                (prefix))
        window = mask.data

    psf_support = get_parameter(kwargs, 'psf_support',
                                max(dirty.shape[2] // 2, dirty.shape[3] // 2))
    if (psf_support <= psf.shape[2] // 2) and (
        (psf_support <= psf.shape[3] // 2)):
        centre = [psf.shape[2] // 2, psf.shape[3] // 2]
        psf.data = psf.data[..., (centre[0] - psf_support):(centre[0] +
                                                            psf_support),
                            (centre[1] - psf_support):(centre[1] +
                                                       psf_support)]
        log.info('deconvolve_cube %s: PSF support = +/- %d pixels' %
                 (prefix, psf_support))
        log.info('deconvolve_cube %s: PSF shape %s' %
                 (prefix, str(psf.data.shape)))

    algorithm = get_parameter(kwargs, 'algorithm', 'msclean')

    if algorithm == 'msclean':
        log.info(
            "deconvolve_cube %s: Multi-scale clean of each polarisation and channel separately"
            % prefix)
        gain = get_parameter(kwargs, 'gain', 0.7)
        assert 0.0 < gain < 2.0, "Loop gain must be between 0 and 2"
        thresh = get_parameter(kwargs, 'threshold', 0.0)
        assert thresh >= 0.0
        niter = get_parameter(kwargs, 'niter', 100)
        assert niter > 0
        scales = get_parameter(kwargs, 'scales', [0, 3, 10, 30])
        fracthresh = get_parameter(kwargs, 'fractional_threshold', 0.01)
        assert 0.0 < fracthresh < 1.0

        comp_array = numpy.zeros_like(dirty.data)
        residual_array = numpy.zeros_like(dirty.data)
        for channel in range(dirty.data.shape[0]):
            for pol in range(dirty.data.shape[1]):
                if psf.data[channel, pol, :, :].max():
                    log.info(
                        "deconvolve_cube %s: Processing pol %d, channel %d" %
                        (prefix, pol, channel))
                    if window is None:
                        comp_array[channel, pol, :, :], residual_array[channel, pol, :, :] = \
                            msclean(dirty.data[channel, pol, :, :], psf.data[channel, pol, :, :],
                                    None, gain, thresh, niter, scales, fracthresh, prefix)
                    else:
                        comp_array[channel, pol, :, :], residual_array[channel, pol, :, :] = \
                            msclean(dirty.data[channel, pol, :, :], psf.data[channel, pol, :, :],
                                    window[channel, pol, :, :], gain, thresh, niter, scales, fracthresh,
                                    prefix)
                else:
                    log.info(
                        "deconvolve_cube %s: Skipping pol %d, channel %d" %
                        (prefix, pol, channel))

        comp_image = create_image_from_array(comp_array, dirty.wcs,
                                             dirty.polarisation_frame)
        residual_image = create_image_from_array(residual_array, dirty.wcs,
                                                 dirty.polarisation_frame)

    elif algorithm == 'msmfsclean' or algorithm == 'mfsmsclean' or algorithm == 'mmclean':
        findpeak = get_parameter(kwargs, "findpeak", 'ARL')

        log.info(
            "deconvolve_cube %s: Multi-scale multi-frequency clean of each polarisation separately"
            % prefix)
        nmoment = get_parameter(kwargs, "nmoment", 3)
        assert nmoment >= 1, "Number of frequency moments must be greater than or equal to one"
        nchan = dirty.shape[0]
        assert nchan > 2 * (nmoment -
                            1), "Require nchan %d > 2 * (nmoment %d - 1)" % (
                                nchan, 2 * (nmoment - 1))
        dirty_taylor = calculate_image_frequency_moments(dirty,
                                                         nmoment=nmoment)
        if nmoment > 1:
            psf_taylor = calculate_image_frequency_moments(psf,
                                                           nmoment=2 * nmoment)
        else:
            psf_taylor = calculate_image_frequency_moments(psf, nmoment=1)
        psf_peak = numpy.max(psf_taylor.data)
        dirty_taylor.data /= psf_peak
        psf_taylor.data /= psf_peak
        log.info("deconvolve_cube %s: Shape of Dirty moments image %s" %
                 (prefix, str(dirty_taylor.shape)))
        log.info("deconvolve_cube %s: Shape of PSF moments image %s" %
                 (prefix, str(psf_taylor.shape)))
        gain = get_parameter(kwargs, 'gain', 0.7)
        assert 0.0 < gain < 2.0, "Loop gain must be between 0 and 2"
        thresh = get_parameter(kwargs, 'threshold', 0.0)
        assert thresh >= 0.0
        niter = get_parameter(kwargs, 'niter', 100)
        assert niter > 0
        scales = get_parameter(kwargs, 'scales', [0, 3, 10, 30])
        fracthresh = get_parameter(kwargs, 'fractional_threshold', 0.1)
        assert 0.0 < fracthresh < 1.0

        comp_array = numpy.zeros(dirty_taylor.data.shape)
        residual_array = numpy.zeros(dirty_taylor.data.shape)
        for pol in range(dirty_taylor.data.shape[1]):
            if psf_taylor.data[0, pol, :, :].max():
                log.info("deconvolve_cube %s: Processing pol %d" %
                         (prefix, pol))
                if window is None:
                    comp_array[:, pol, :, :], residual_array[:, pol, :, :] = \
                        msmfsclean(dirty_taylor.data[:, pol, :, :], psf_taylor.data[:, pol, :, :],
                                   None, gain, thresh, niter, scales, fracthresh, findpeak, prefix)
                else:
                    log.info(
                        'deconvolve_cube %s: Clean window has %d valid pixels'
                        % (prefix, int(numpy.sum(window[0, pol]))))
                    comp_array[:, pol, :, :], residual_array[:, pol, :, :] = \
                        msmfsclean(dirty_taylor.data[:, pol, :, :], psf_taylor.data[:, pol, :, :],
                                   window[0, pol, :, :], gain, thresh, niter, scales, fracthresh,
                                   findpeak, prefix)
            else:
                log.info("deconvolve_cube %s: Skipping pol %d" % (prefix, pol))

        comp_image = create_image_from_array(comp_array, dirty_taylor.wcs,
                                             dirty.polarisation_frame)
        residual_image = create_image_from_array(residual_array,
                                                 dirty_taylor.wcs,
                                                 dirty.polarisation_frame)

        return_moments = get_parameter(kwargs, "return_moments", False)
        if not return_moments:
            log.info("deconvolve_cube %s: calculating spectral cubes" % prefix)
            comp_image = calculate_image_from_frequency_moments(
                dirty, comp_image)
            residual_image = calculate_image_from_frequency_moments(
                dirty, residual_image)
        else:
            log.info("deconvolve_cube %s: constructed moment cubes" % prefix)

    elif algorithm == 'hogbom':
        log.info(
            "deconvolve_cube %s: Hogbom clean of each polarisation and channel separately"
            % prefix)
        gain = get_parameter(kwargs, 'gain', 0.7)
        assert 0.0 < gain < 2.0, "Loop gain must be between 0 and 2"
        thresh = get_parameter(kwargs, 'threshold', 0.0)
        assert thresh >= 0.0
        niter = get_parameter(kwargs, 'niter', 100)
        assert niter > 0
        fracthresh = get_parameter(kwargs, 'fractional_threshold', 0.1)
        assert 0.0 < fracthresh < 1.0

        comp_array = numpy.zeros(dirty.data.shape)
        residual_array = numpy.zeros(dirty.data.shape)
        for channel in range(dirty.data.shape[0]):
            for pol in range(dirty.data.shape[1]):
                if psf.data[channel, pol, :, :].max():
                    log.info(
                        "deconvolve_cube %s: Processing pol %d, channel %d" %
                        (prefix, pol, channel))
                    if window is None:
                        comp_array[channel, pol, :, :], residual_array[channel, pol, :, :] = \
                            hogbom(dirty.data[channel, pol, :, :], psf.data[channel, pol, :, :],
                                   None, gain, thresh, niter, fracthresh, prefix)
                    else:
                        comp_array[channel, pol, :, :], residual_array[channel, pol, :, :] = \
                            hogbom(dirty.data[channel, pol, :, :], psf.data[channel, pol, :, :],
                                   window[channel, pol, :, :], gain, thresh, niter, fracthresh, prefix)
                else:
                    log.info(
                        "deconvolve_cube %s: Skipping pol %d, channel %d" %
                        (prefix, pol, channel))

        comp_image = create_image_from_array(comp_array, dirty.wcs,
                                             dirty.polarisation_frame)
        residual_image = create_image_from_array(residual_array, dirty.wcs,
                                                 dirty.polarisation_frame)
    elif algorithm == 'hogbom-complex':
        log.info(
            "deconvolve_cube_complex: Hogbom-complex clean of each polarisation and channel separately"
        )
        gain = get_parameter(kwargs, 'gain', 0.7)
        assert 0.0 < gain < 2.0, "Loop gain must be between 0 and 2"
        thresh = get_parameter(kwargs, 'threshold', 0.0)
        assert thresh >= 0.0
        niter = get_parameter(kwargs, 'niter', 100)
        assert niter > 0
        fracthresh = get_parameter(kwargs, 'fractional_threshold', 0.1)
        assert 0.0 <= fracthresh < 1.0

        comp_array = numpy.zeros(dirty.data.shape)
        residual_array = numpy.zeros(dirty.data.shape)
        for channel in range(dirty.data.shape[0]):
            for pol in range(dirty.data.shape[1]):
                if pol == 0 or pol == 3:
                    if psf.data[channel, pol, :, :].max():
                        log.info(
                            "deconvolve_cube_complex: Processing pol %d, channel %d"
                            % (pol, channel))
                        if window is None:
                            comp_array[channel, pol, :, :], residual_array[channel, pol, :, :] = \
                                hogbom(dirty.data[channel, pol, :, :], psf.data[channel, pol, :, :],
                                       None, gain, thresh, niter, fracthresh)
                        else:
                            comp_array[channel, pol, :, :], residual_array[channel, pol, :, :] = \
                                hogbom(dirty.data[channel, pol, :, :], psf.data[channel, pol, :, :],
                                       window[channel, pol, :, :], gain, thresh, niter, fracthresh)
                    else:
                        log.info(
                            "deconvolve_cube_complex: Skipping pol %d, channel %d"
                            % (pol, channel))
                if pol == 1:
                    if psf.data[channel, 1:2, :, :].max():
                        log.info(
                            "deconvolve_cube_complex: Processing pol 1 and 2, channel %d"
                            % (channel))
                        if window is None:
                            comp_array[channel, 1, :, :], comp_array[
                                channel, 2, :, :], residual_array[
                                    channel, 1, :, :], residual_array[
                                        channel, 2, :, :] = hogbom_complex(
                                            dirty.data[channel, 1, :, :],
                                            dirty.data[channel, 2, :, :],
                                            psf.data[channel, 1, :, :],
                                            psf.data[channel, 2, :, :], None,
                                            gain, thresh, niter, fracthresh)
                        else:
                            comp_array[channel, 1, :, :], comp_array[
                                channel, 2, :, :], residual_array[
                                    channel, 1, :, :], residual_array[
                                        channel, 2, :, :] = hogbom_complex(
                                            dirty.data[channel, 1, :, :],
                                            dirty.data[channel, 2, :, :],
                                            psf.data[channel, 1, :, :],
                                            psf.data[channel, 2, :, :],
                                            window[channel, pol, :, :], gain,
                                            thresh, niter, fracthresh)
                    else:
                        log.info(
                            "deconvolve_cube_complex: Skipping pol 1 and 2, channel %d"
                            % (channel))
                if pol == 2:
                    continue

        comp_image = create_image_from_array(
            comp_array,
            dirty.wcs,
            polarisation_frame=PolarisationFrame('stokesIQUV'))
        residual_image = create_image_from_array(
            residual_array,
            dirty.wcs,
            polarisation_frame=PolarisationFrame('stokesIQUV'))

    else:
        raise ValueError('deconvolve_cube %s: Unknown algorithm %s' %
                         (prefix, algorithm))

    return comp_image, residual_image
def deconvolve_cube_complex(dirty: Image, psf: Image,
                            **kwargs) -> (Image, Image):
    """ Clean using the complex Hogbom algorithm for polarised data (2016MNRAS.462.3483P)
        
    The algorithm available is:
    hogbom-complex: See: Pratley L. & Johnston-Hollitt M., (2016), MNRAS, 462, 3483.
    
    This code is based upon the deconvolve_cube code for standard Hogbom clean available in ARL.
    
    Args:
    dirty (numpy array): The dirty image, i.e., the image to be deconvolved.
    psf (numpy array): The point spread-function.
    window (float): Regions where clean components are allowed. If True, entire dirty Image is allowed.
    algorithm (str): Cleaning algorithm: 'hogbom-complex' only.
    gain (float): The "loop gain", i.e., the fraction of the brightest pixel that is removed in each iteration.
    threshold (float): Cleaning stops when the maximum of the absolute deviation of the residual is less than this value.
    niter (int): Maximum number of components to make if the threshold `thresh` is not hit.
    fractional_threshold (float): The predefined fractional threshold at which to stop cleaning.

    Returns:
    comp_image: clean component image.
    residual_image: residual image.
    """
    assert isinstance(dirty, Image), "Type is %s" % (type(dirty))
    assert isinstance(psf, Image), "Type is %s" % (type(psf))

    window_shape = get_parameter(kwargs, 'window_shape', None)
    if window_shape == 'quarter':
        qx = dirty.shape[3] // 4
        qy = dirty.shape[2] // 4
        window = np.zeros_like(dirty.data)
        window[..., (qy + 1):3 * qy, (qx + 1):3 * qx] = 1.0
        log.info(
            'deconvolve_cube_complex: Cleaning inner quarter of each sky plane'
        )
    else:
        window = None

    psf_support = get_parameter(kwargs, 'psf_support', None)
    if isinstance(psf_support, int):
        if (psf_support < psf.shape[2] // 2) and (
            (psf_support < psf.shape[3] // 2)):
            centre = [psf.shape[2] // 2, psf.shape[3] // 2]
            psf.data = psf.data[..., (centre[0] - psf_support):(centre[0] +
                                                                psf_support),
                                (centre[1] - psf_support):(centre[1] +
                                                           psf_support)]
            log.info('deconvolve_cube_complex: PSF support = +/- %d pixels' %
                     (psf_support))

    algorithm = get_parameter(kwargs, 'algorithm', 'msclean')

    if algorithm == 'hogbom-complex':
        log.info(
            "deconvolve_cube_complex: Hogbom-complex clean of each polarisation and channel separately"
        )
        gain = get_parameter(kwargs, 'gain', 0.7)
        assert 0.0 < gain < 2.0, "Loop gain must be between 0 and 2"
        thresh = get_parameter(kwargs, 'threshold', 0.0)
        assert thresh >= 0.0
        niter = get_parameter(kwargs, 'niter', 100)
        assert niter > 0
        fracthresh = get_parameter(kwargs, 'fractional_threshold', 0.1)
        assert 0.0 <= fracthresh < 1.0

        comp_array = np.zeros(dirty.data.shape)
        residual_array = np.zeros(dirty.data.shape)
        for channel in range(dirty.data.shape[0]):
            for pol in range(dirty.data.shape[1]):
                if pol == 0 or pol == 3:
                    if psf.data[channel, pol, :, :].max():
                        log.info(
                            "deconvolve_cube_complex: Processing pol %d, channel %d"
                            % (pol, channel))
                        if window is None:
                            comp_array[channel, pol, :, :], residual_array[channel, pol, :, :] = \
                                hogbom(dirty.data[channel, pol, :, :], psf.data[channel, pol, :, :],
                                       None, gain, thresh, niter, fracthresh)
                        else:
                            comp_array[channel, pol, :, :], residual_array[channel, pol, :, :] = \
                                hogbom(dirty.data[channel, pol, :, :], psf.data[channel, pol, :, :],
                                       window[channel, pol, :, :], gain, thresh, niter, fracthresh)
                    else:
                        log.info(
                            "deconvolve_cube_complex: Skipping pol %d, channel %d"
                            % (pol, channel))
                if pol == 1:
                    if psf.data[channel, 1:2, :, :].max():
                        log.info(
                            "deconvolve_cube_complex: Processing pol 1 and 2, channel %d"
                            % (channel))
                        if window is None:
                            comp_array[channel, 1, :, :], comp_array[
                                channel, 2, :, :], residual_array[
                                    channel, 1, :, :], residual_array[
                                        channel, 2, :, :] = hogbom_complex(
                                            dirty.data[channel, 1, :, :],
                                            dirty.data[channel, 2, :, :],
                                            psf.data[channel, 1, :, :],
                                            psf.data[channel, 2, :, :], None,
                                            gain, thresh, niter, fracthresh)
                        else:
                            comp_array[channel, 1, :, :], comp_array[
                                channel, 2, :, :], residual_array[
                                    channel, 1, :, :], residual_array[
                                        channel, 2, :, :] = hogbom_complex(
                                            dirty.data[channel, 1, :, :],
                                            dirty.data[channel, 2, :, :],
                                            psf.data[channel, 1, :, :],
                                            psf.data[channel, 2, :, :],
                                            window[channel, pol, :, :], gain,
                                            thresh, niter, fracthresh)
                    else:
                        log.info(
                            "deconvolve_cube_complex: Skipping pol 1 and 2, channel %d"
                            % (channel))
                if pol == 2:
                    continue

        comp_image = create_image_from_array(
            comp_array,
            dirty.wcs,
            polarisation_frame=PolarisationFrame('stokesIQUV'))
        residual_image = create_image_from_array(
            residual_array,
            dirty.wcs,
            polarisation_frame=PolarisationFrame('stokesIQUV'))

    else:
        raise ValueError('deconvolve_cube_complex: Unknown algorithm %s' %
                         algorithm)

    return comp_image, residual_image