CLEAN algorithm



Aaron Parsons wrote an implementation of the Hogbom clean algorithm in Python, and since it didn't exist yet in IDL (to the best of my knowledge), I translated his code for use in the BGPS pipeline.
;    """This is an implementation of the standard Hoegbom clean deconvolution
;    algorithm, which operates on the assumption that the image is composed of
;    point sources.  This makes it a poor choice for images with distributed
;    flux.  The algorithm works by iteratively constructing a model.  Each
;    iteration, a point is added to this model at the location of the maximum
;    residual, with a fraction (specified by 'gain') of the magnitude.  The
;    convolution of that point is removed from the residual, and the process
;    repeats.  Termination happens after 'maxiter' iterations, or when the
;    clean loops starts increasing the magnitude of the residual.
;    im: The image to be deconvolved.
;    ker: The kernel to deconvolve by (must be same size as im).
;    mdl: An a priori model of what the deconvolved image should look like.
;    gain: The fraction of a residual used in each iteration.  If this is too
;        low, clean takes unnecessarily long.  If it is too high, clean does
;        a poor job of deconvolving.
;    maxiter: The maximum number of iterations performed before terminating.
;    chkiter: The number of iterations between when clean checks if the
;        residual is increasing.
;    verbose: If true, prints some info on how things are progressing."""
;    dim = im.shape[1]
function hogbom_clean,im,ker,mdl=mdl,gain=gain,maxiter=maxiter,$
        chkiter=chkiter,verbose=verbose,model=model
    if ~(keyword_set(gain)) then gain = .2
    if ~(keyword_set(maxiter)) then maxiter = 1000
    if ~(keyword_set(chkiter)) then chkiter = 100
    if ~(keyword_set(verbose)) then verbose = 0
    dim = size(im,/dim)
    ; NEED TO FIX KERNEL SIZE: small kernels are not acceptable
    new_ker = dblarr(dim)
    ker_dim = size(ker,/dim)
    shiftx = floor((dim[0]-ker_dim[0])/2.)
    shifty = floor((dim[1]-ker_dim[1])/2.)
    new_ker[shiftx:shiftx+ker_dim[0]-1,shifty:shifty+ker_dim[1]-1] = ker
    ker = new_ker

    dim = dim[0]
    ker_pwr = total(ker)
    m = max(ker,argm)
    kerx = argm / dim
    kery = argm mod dim
    G = ker_pwr / gain
    if ~keyword_set(mdl) then mdl = fltarr(size(im,/dim))
    dif = im - convolve(mdl,ker)
    score = mean(dif^2,/nan)
    prev_a = 0
    n_mdl = mdl
    n_dif = dif
    mode = 0
;   Begin the clean loop
    for i=0,maxiter do begin
    ; Rather than perform a convolution each loop, we'll just subtract
    ; from the residual a scaled kernel centered on the point just added,
    ; and to avoid recentering the kernel each time (because clean often
    ; chooses the same point over and over), we'll buffer the previous one.
            m = max(n_dif,a,/nan)
            if ~(a eq prev_a) then begin
                prev_a = a
                rec_ker = shift(ker,-(kery - (a mod dim)),-(kerx-a/dim))
            endif
            v = n_dif[a] / G
            n_mdl[a] = n_mdl[a] + v
            n_dif = n_dif - v * rec_ker
            if (i mod chkiter eq 0) then begin
    ;            # Check in on how clean is progressing.  Potenially terminate.
                n_score = mean(abs(n_dif)^2,/nan)
                print,"i: ",i,"   n_score:",n_score,"  score:",score
            endif
            if verbose then print,"v: ",v,"   n_dif[a]: ",n_dif[a],"  G: ",G,$
                " a: ",a," m: ",m,"  score: ",score,"  n_score:",n_score
            if verbose then print,i,n_score,score
            if (n_score gt score and i gt 0 and i mod chkiter eq 0) then begin
                n_mdl = mdl
                n_dif = dif
                print,"In last if, model max: ",max(n_mdl,/nan),$
                    "  n_dif max: ",max(n_dif,/nan)
                print,"Quitting with n_score = ",n_score," > score = ",score
                break
            endif
    ;    If we're still doing fine, buffer this solution as the new best.
            score = n_score
            mdl = n_mdl
            dif = n_dif
    endfor
    model = im - n_dif
    return,n_dif
end