!>
!   This File contains all CLEAN command related dispatching
! sub-routines
!!
subroutine clean_comm(line,error)
  use gbl_message
  use gkernel_interfaces
  use imager_interfaces, except_this=>clean_comm
  use clean_arrays
  use clean_default
  !----------------------------------------------------------------------
  ! @ public
  !*  IMAGER --  Support for command CLEAN & GCLEAN  
  !   Call appropriate subroutine according to METHOD%METHOD
  !!
  !----------------------------------------------------------------------
  character(len=*), intent(inout) :: line    !! Command line
  logical,          intent(out)   :: error   !! Logical error flag
  !
  integer, parameter :: opt_start=6
  character(len=1), parameter :: question_mark='?'
  character(len=12) :: cmethod
  character(len=24) :: topic
  character(len=80) :: chain
  integer :: nm, narg, ier, nt
  !
  narg = sic_narg(0) 
  if (narg.gt.0) then
    call sic_ch(line,0,1,cmethod,nm,.false.,error)
    if (cmethod(1:1).eq.question_mark) then
      if (sic_present(0,2)) then
        call sic_ch(line,0,2,topic,nt,.true.,error)
        chain = 'HELP CLEAN '//topic
      else
        chain = "@ i_clean "//cmethod
      endif
      call exec_program(chain)
      return
    else if (narg.eq.2) then
      call sic_ch(line,0,2,cmethod,nm,.false.,error)
      if (cmethod(1:1).eq.question_mark) then
        call sic_ch(line,0,1,topic,nt,.true.,error)
        chain = 'HELP CLEAN '//topic
        call exec_program(chain)
        return 
      endif    
    endif
    !
    if (sic_present(opt_start,0)) then
      call map_message(seve%w,'CLEAN','First and Last argument not tested with /RESTART option',seve%e)
    endif
  endif
  !
  call sic_get_char('METHOD',cmethod,nm,error)
  call sic_upper(cmethod)
  !
  select case (cmethod)
  case ('CLARK')
    call clark_comm(line,error)
  case ('HOGBOM')
    call hogbom_comm(line,error)
  case ('MRC')
    call mrc_comm(line,error)
  case ('MULTI')
    call multi_comm(line,error)
  case ('SDI')
    call sdi_comm(line,error)
  case ('GAUSS')
    call gauss_comm(line,error)
  case default
    call map_message(seve%e,'CLEAN','Unsupported method '//cmethod)
    error = .true.
    return
  end select
  ! 
  ! Reset the per-plane stopping criterium
  ares_listsize = 0
  niter_listsize = 0
  !
  if (error) return 
  !
  ! Re-define continuum image if needed
  if (do_continuum) then
    call sic_delvariable('CONTINUUM',.false.,error)
    if (allocated(dcont)) deallocate(dcont)
    call gildas_null(hcont)
    if (user_method%mosaic) then
      call gdf_copy_header(hsky,hcont,error)
    else
      call gdf_copy_header(hclean,hcont,error)
    endif
    hcont%gil%ndim = 2
    allocate(dcont(hcont%gil%dim(1),hcont%gil%dim(2)),stat=ier)
    if (ier.ne.0) then
      call map_message(seve%e,'CLEAN','Memory allocation error')
      error = .true.
      return
    endif
    !
    if (user_method%mosaic) then
      dcont(:,:) = dsky(:,:,1)
    else
      dcont(:,:) = dclean(:,:,1)
    endif
    hcont%loca%size = hcont%gil%dim(1) * hcont%gil%dim(2)
    hcont%r2d => dcont
    !
    call sic_mapgildas('CONTINUUM',hcont,error,dcont)
  endif    
  !
end subroutine clean_comm
!
subroutine mrc_comm (line,error)
  use gkernel_interfaces
  use imager_interfaces, except_this=>mrc_comm
  use clean_def
  use clean_default
  use clean_arrays
  use gbl_message
  !----------------------------------------------------------------------
  ! @ private
  !
  !*  IMAGER --  CLEAN Internal routine for MRC  
  !   Implementation of Multi Resolution Clean according to Wakker & Schwartz
  !!
  !----------------------------------------------------------------------
  character(len=*), intent(inout) :: line    !! Command line
  logical, intent(out) :: error              !! Logical error flag
  !
  character(len=3) :: rname = 'MRC'
  !
  ! Local ---
  integer ratio,nx,ny
  !
  ! Code ----
  if (user_method%mosaic) then
    call map_message(seve%e,rname,'Not valid for mosaic')
    error = .true.
    return
  endif
  !
  ! Data checkup
  user_method%method = 'MRC'
  call clean_data (error)
  if (error) return
  !
  ! Parameter Definitions
  call beam_unit_conversion(user_method)
  call copy_method(user_method,the_method)
  !
  ! Smoothing ratio : given by user or 2, 4 or 8 according to image size
  if (the_method%ratio.ne.0) then
    ratio = the_method%ratio
    if (power_of_two(ratio).eq.-1) then
      call map_message(seve%e,rname,'Smoothing ratio has to be a power of 2')
      error = .true.
      return
    endif
  else
    nx = hdirty%gil%dim(1)
    ny = hdirty%gil%dim(2)
    if (nx*ny.gt.512*512) then
      ratio = 8
    elseif (nx*ny.gt.128*128) then
      ratio = 4
    else
      ratio = 2
    endif
  endif
  the_method%ratio = ratio
  the_method%pflux = sic_present(1,0)
  the_method%pcycle = sic_present(2,0)
  if (sic_present(6,0)) then
    the_method%restart = 6
  else
    the_method%restart = 0
  endif
  the_method%qcycle = .false.
  !
  call sub_clean(the_method,line,error)
  user_method%do_mask = .true. ! important sinon CLARK ne marche plus
end subroutine mrc_comm
!
subroutine multi_comm (line,error)
  use gkernel_interfaces
  use imager_interfaces, except_this=>multi_comm
  use clean_def
  use clean_default
  use clean_arrays
  use gbl_message
  !----------------------------------------------------------------------
  ! @ private
  !
  !*
  !   IMAGER -- CLEAN  Internal routine for MULTISCALE
  !
  !   Implementation of Multi Scale Clean, using a pixel-based 
  !   user-define kernel with limited support.
  !     Slow, but precise in convergence (deprecated)
  !!
  !----------------------------------------------------------------------
  character(len=*), intent(inout) :: line  !! Command line
  logical, intent(out) :: error            !! Logical error flag
  !
  ! Code ----
  if (user_method%mosaic) then
    call map_message(seve%w,'MULTI','MultiScale method still experimental for mosaic')
  endif
  !
  ! Data checkup
  user_method%method = 'MULTI'
  call clean_data (error)
  if (error) return
  !
  ! Parameter Definitions
  call beam_unit_conversion(user_method)
  call copy_method(user_method,the_method)
  the_method%pflux = sic_present(1,0)
  the_method%pcycle = .false.
  the_method%qcycle = .false.
  if (sic_present(6,0)) then
    the_method%restart = 6
  else
    the_method%restart = 0
  endif
!
  the_method%gains = the_method%gain
  call sic_get_real('CLEAN_GAINS[1]',the_method%gains(1),error)
  call sic_get_real('CLEAN_GAINS[2]',the_method%gains(2),error)
  call sic_get_real('CLEAN_GAINS[3]',the_method%gains(3),error)
  !
  call sub_clean(the_method,line,error)
end subroutine multi_comm
!
subroutine sdi_comm (line,error)
  use gkernel_interfaces
  use imager_interfaces, except_this=>sdi_comm
  use clean_def
  use clean_default
  use clean_arrays
  !----------------------------------------------------------------------
  ! @ private
  !
  !*
  !   IMAGER -- CLEAN Internal routine for SDI  
  !   Implementation of Steer Dewdney Ito Clean
  !
  !     Very sensitive to chosen support.
  !!
  !----------------------------------------------------------------------
  character(len=*), intent(inout) :: line  !! Command line
  logical, intent(out) :: error            !! Logical error flag
  !
  character(len=8) :: voc1(2)
  data voc1/'CLEAN','RESIDUAL'/
  !
  ! Local ---
  integer iv,na,m_iter
  character(len=8) :: name,argum
  !
  ! Code ----
  ! Save default number of components
  m_iter = user_method%m_iter
  user_method%m_iter = hdirty%gil%dim(1) * hdirty%gil%dim(2)
  !
  ! Data checkup: method must be defined first ?
  user_method%method = 'SDI'
  call clean_data (error)
  if (error) return
  !
  ! Parameter Definitions
  call beam_unit_conversion(user_method)
  call copy_method(user_method,the_method)
  the_method%pflux = .false.
  if (sic_present(6,0)) then
    the_method%restart = 6
  else
    the_method%restart = 0
  endif
  the_method%pcycle = sic_present(2,0)
  the_method%qcycle = sic_present(3,0)
  if (the_method%pcycle) then
    argum = 'RESIDUAL'
    call sic_ke (line,2,1,argum,na,.false.,error)
    if (error) return
    call sic_ambigs ('PLOT',argum,name,iv,voc1,2,error)
    if (error) return
    the_method%pclean = iv.eq.1
  else
    the_method%pclean = .false.
  endif
  call sub_clean(the_method,line,error)
  ! Restore default number of components
  user_method%m_iter = m_iter
end subroutine sdi_comm
!
subroutine hogbom_comm (line,error)
  use gkernel_interfaces
  use imager_interfaces, except_this=>hogbom_comm
  use clean_def
  use clean_default
  use clean_arrays
  !----------------------------------------------------------------------
  ! @ private
  !
  !*
  !   IMAGER - CLEAN Internal routine for HOGBOM  
  !   Implementation of classical Hogbom Clean
  !
  !     Slow, but extremely robust, and with a minimum of parameters
  !!
  !----------------------------------------------------------------------
  character(len=*), intent(inout) :: line  !! Command line
  logical, intent(out) :: error            !! Logical error flag
  !
  ! Code ----
  ! Data checkup
  user_method%method = 'HOGBOM'
  call clean_data (error)
  if (error) return
  !
  ! Parameter Definitions
  call beam_unit_conversion(user_method)
  call copy_method(user_method,the_method)
  the_method%pflux = sic_present(1,0)
  if (sic_present(6,0)) then
    the_method%restart = 6
  else
    the_method%restart = 0
  endif
  the_method%pcycle = .false.
  the_method%qcycle = .false.
  call sub_clean(the_method,line,error)
end subroutine hogbom_comm
!
subroutine clark_comm (line,error)
  use gkernel_interfaces
  use imager_interfaces, except_this=>clark_comm
  use clean_def
  use clean_default
  use clean_arrays
  !----------------------------------------------------------------------
  ! @ private
  !
  !*
  !   IMAGER -- CLEAN Internal routine for CLARK  
  !   Implementation of Barry Clark Clean
  !
  !     Faster than HOGBOM, requiring more limited map sizes, but 
  !   convergence is difficult to control in some cases
  !!
  !----------------------------------------------------------------------
  character(len=*), intent(inout) :: line  !! Command line
  logical, intent(out) :: error            !! Logical error flag
  !
  ! Constants
  character(len=8) :: voc1(2)
  data voc1/'CLEAN','RESIDUAL'/
  ! Local ---
  character(len=8) :: name,argum
  integer iv,na
  !
  ! Data checkup
  user_method%method = 'CLARK'
  call clean_data (error)
  if (error) return
  !
  ! Parameter Definitions
  call beam_unit_conversion(user_method)
  call copy_method(user_method,the_method)
  the_method%pflux = sic_present(1,0)
  if (sic_present(6,0)) then
    the_method%restart = 6
  else
    the_method%restart = 0
  endif
  the_method%pcycle = sic_present(2,0)
  the_method%qcycle = sic_present(3,0)
  if (the_method%pcycle) then
    argum = 'RESIDUAL'
    call sic_ke (line,2,1,argum,na,.false.,error)
    if (error) return
    call sic_ambigs ('PLOT',argum,name,iv,voc1,2,error)
    if (error) return
    the_method%pclean = iv.eq.1
  else
    the_method%pclean = .false.
  endif
  call sub_clean(the_method,line,error)
end subroutine clark_comm
!
subroutine gauss_comm (line,error)
  use gkernel_interfaces
  use imager_interfaces, except_this=>gauss_comm
  use clean_def
  use clean_default
  use clean_arrays
  use gbl_message
  !----------------------------------------------------------------------
  ! @ private
  !
  !* 
  !   IMAGER -- CLEAN Internal routine for GAUSS method  
  !   Implementation of Gaussian Multi Scale.
  !
  !     Faster than pixel-based Multi Scale.  A spheroidal kernel should be
  !   provided also instead of the Gaussian kernel. Support limitations
  !   could be implemented as well.
  !!
  !----------------------------------------------------------------------
  character(len=*), intent(inout) :: line  !! Command line
  logical, intent(out) :: error            !! Logical error flag
  !
  ! Constants
  real, parameter :: rad_to_sec=180.*3600./acos(-1.0)
  !
  ! Local ---
  integer :: i,j,narg,nchan,nfield
  real :: bsize
  logical :: sticky
  !
  ! Code ----
  if (user_method%mosaic) then
    call map_message(seve%w,'GAUSS', &
      & 'MultiScale Gauss method still experimental for mosaic')
  endif
  !
  ! Data checkup
  user_method%method = 'GAUSS'
  call clean_data (error)
  if (error) return
  !
  ! Parameter Definitions
  call beam_unit_conversion(user_method)
  call copy_method(user_method,the_method)
  !
  the_method%pflux = sic_present(1,0)
  if (sic_present(2,0)) then
    the_method%restart = 2
  else
    the_method%restart = 0
  endif
  the_method%pcycle = .false.
  the_method%qcycle = .false.
  !
  the_method%gsize = 0.
  narg = min(sic_narg(0),clean_mscale-1)
  sticky = .false.
  if (narg.ne.0) then
    ! User defined scale factors
    do i=1,narg
      call sic_r4(line,0,i,the_method%gsize(i+1),.true.,error)
      if (error) return
    enddo
    sticky = .true.
  else if (any(user_method%gsize.ne.0)) then
    ! No assumption on order in entry
    ! Size 0 (Point Sources) is always first on exit
    the_method%gsize(1) = 0.
    j = 1
    do i=1,size(user_method%gsize)
      if (user_method%gsize(i).ne.0) then
        j = j+1
        if (j.gt.size(the_method%gsize)) exit
        the_method%gsize(j) = user_method%gsize(i)
      endif
    enddo
  else
    ! Automatic scale factors
    bsize = sqrt(hbeam%gil%majo*hbeam%gil%mino)
    if (bsize.eq.0) then
      nchan = max(hbeam%gil%dim(3),1)
      nfield = max(1,abs(themap%nfields))
      call sub_fit_beam(nfield,nchan,1,nfield,1,nchan, &
      & .false., .false., .false., error)
    endif
    bsize = sqrt(hbeam%gil%majo*hbeam%gil%mino)*rad_to_sec
    the_method%gsize(2) = bsize
    the_method%gsize(3) = 2*bsize
  endif
  !
  ! This is only valid for 3 scales...
  the_method%gains = the_method%gain
  call sic_get_real('CLEAN_GAINS[1]',the_method%gains(1),error)
  call sic_get_real('CLEAN_GAINS[2]',the_method%gains(2),error)
  call sic_get_real('CLEAN_GAINS[3]',the_method%gains(3),error)
  error = .false.
  !
  call sub_clean(the_method,line,error)
  if (error) return
  if (sticky) user_method%gsize = the_method%gsize
end subroutine gauss_comm
!
subroutine sub_clean (method,line,error)
  use gkernel_interfaces
  use imager_interfaces, except_this=>sub_clean
  use clean_def
  use clean_default
  use clean_arrays
  use clean_types
  use gbl_message
  !$  use omp_lib
  !----------------------------------------------------------------------
  ! @ private
  !
  !*
  !   IMAGER -- CLEAN Internal routine.  
  !     Implementation of all standard CLEAN deconvolution algorithms,
  ! Parsing has been done before, for all methods. 
  !
  !   To be done: some additional parsing is still done here, about
  !   First and Last channels, flux limits, and also in CCT_PREPARE.
  !   It should be moved to a separate routine.
  !!
  !----------------------------------------------------------------------
  type(clean_par), intent(inout) :: method  !! Clean control parameters
  character(len=*), intent(inout) :: line   !! Command line
  logical, intent(out) :: error             !! Logical error flag
  !
  real(8), parameter :: pi=3.14159265358979323846d0
  character(len=*), parameter :: rname='CLEAN'
  character(len=6) :: clist(3)=['CLEAN ','CCT   ','SKY   ']
  character(len=80) :: chain
  !
  integer :: i, ipen, nx, ny, np, nsizes(3)
  logical limits
  real ylimn,ylimp
  logical :: clean_extrema=.true.
  integer :: mthread, plot_case, save_converge
  logical :: err
  !
  call map_message(seve%d,rname,'Calling SUB_CLEAN in all_clean.f90')
  call sic_get_logi('CLEAN_EXTREMA',clean_extrema,error)
  !
  if (user_method%mosaic) then
    where (method%blc.eq.0) method%blc = 17
    where (method%trc.eq.0) method%trc = hdirty%gil%dim(1:2)-16
    write(chain,'(A,4(1X,I0))') 'Set default search box to ',method%blc, method%trc
    call map_message(seve%i,rname,chain)
  endif    
  !
  ! General First Last channel selection (Obsolescent)...
  call sic_get_inte('FIRST',method%first,error)
  call sic_get_inte('LAST',method%last,error)
  !
  if (method%method.eq.'GAUSS') then
    method%nscale = clean_mscale
    do i=2,clean_mscale
      if (method%gsize(i).eq.0) then
        method%nscale = i-1
        exit
      endif
    enddo
    if (method%nscale.eq.0) then
      call map_message(seve%e,rname,'Smoothing Gaussians  are all Zero')
      error = .true.
      return
    endif
    write(chain,'(A,5(F9.2))') 'Gaussian sizes ',method%gsize(1:method%nscale)
    call map_message(seve%i,rname,chain)
  else  if (sic_present(0,1)) then
    ! Optional FIRST and LAST
    call sic_i4(line,0,1,method%first,.false.,error)
    if (error) return
    method%last = method%first
    call sic_i4(line,0,2,method%last,.false.,error)
    if (error) return
  endif
  !
  ! Usefull variables
  nx = hdirty%gil%dim(1)
  ny = hdirty%gil%dim(2)
  np = max(1,hprim%gil%dim(1))
  !
  ! Update the Channel range
  if (method%first.eq.0) method%first = 1
  if (method%last.eq.0) method%last = hdirty%gil%dim(3)
  method%first = max(1,min(method%first,hdirty%gil%dim(3)))
  method%last = max(method%first,min(method%last,hdirty%gil%dim(3)))
  !
  call check_area(method,hdirty,.false.)
  call check_mask(method,hdirty)
  user_method%do_mask = method%do_mask
  !
  ! Allocate the CCT Table
  nsizes(1:3) = hdirty%gil%dim(1:3)
  call cct_prepare(line,nsizes,method,rname,error)
  if (error) return
  !
  ! Set the pointers for use in subroutines
  hdirty%r3d => ddirty
  if (user_method%mosaic) then
    hclean%r3d => dsky 
  else
    hclean%r3d => dclean    
  endif  
  hbeam%r4d  => dbeam
  hresid%r3d => dresid
  hprim%r4d  => dprim
  hmask%r3d => dmask
  !
  ! Flux limits
  limits = sic_present(1,0)
  if (sic_present(1,1)) then
    call sic_r4 (line,1,1,ylimn,.true.,error)
    if (error) return
    call sic_r4 (line,1,2,ylimp,.true.,error)
    if (error) return
  else
    ylimp = sqrt (float(method%m_iter+200) *   &
     &      log(float(method%m_iter+1)) ) * method%gain
    if (ylimp.eq.0.) ylimp = 1.0
    if (-hdirty%gil%rmin.gt.1.3*hdirty%gil%rmax) then
      ! Probably negative
      ylimn = ylimp*hdirty%gil%rmin
      ylimp = 0.0
    elseif (-1.3*hdirty%gil%rmin.gt.hdirty%gil%rmax) then
      ! Probably positive
      ylimn = 0.0
      ylimp = ylimp*hdirty%gil%rmax
    else
      ! Do not know...,
      ylimn = ylimp*hdirty%gil%rmin
      ylimp = ylimp*hdirty%gil%rmax
    endif
    if (sic_present(1,0)) then
      ! Start with a small range - This will be increased later
      ylimn = 0.001*ylimn
      ylimp = 0.001*ylimp
      call sic_r4 (line,1,1,ylimn,.false.,error)
      if (error) return
      call sic_r4 (line,1,2,ylimp,.false.,error)
      if (error) return
    endif
  endif
  !
  ! Beam patch according to Method and adjust the convergence criterium also
  save_converge = method%converge 
  if (method%method.eq.'CLARK'.or.   &
     &    method%method.eq.'MRC') then
    if (user_method%patch(1).ne.0) then
      method%patch(1) = min(user_method%patch(1),nx)
    else
      method%patch(1) = min(nx,max(32,nx/4))
    endif
    if (user_method%patch(2).ne.0) then
      method%patch(2) = min(user_method%patch(2),ny)
    else
      method%patch(2) = min(ny,max(32,ny/4))
    endif
    !
    if (method%converge.gt.0) then
     ! Make sure the convergence length is short enough 
     ! as CLARK method is easily unstable
     method%converge = min(method%converge,20)
    else
     ! Negative values are for tests only
     method%converge = -method%converge
    endif
  elseif (method%method.eq.'SDI') then
    if (user_method%patch(1).ne.0) then
      method%patch(1) = min(user_method%patch(1),nx/4)
    else
      method%patch(1) = min(nx/2,max(16,nx/8))
    endif
    if (user_method%patch(2).ne.0) then
      method%patch(2) = min(user_method%patch(2),ny/4)
    else
      method%patch(2) = min(ny,max(16,ny/8))
    endif
    method%converge = abs(method%converge)
  else
    method%converge = abs(method%converge)
  endif
  !
  ! Disable Plotting in Parallel mode
  mthread = 1
  !$  mthread = omp_get_max_threads()
  if (mthread.gt.1 .and. method%last.ne.method%first) then
    if (method%pcycle .or. method%pflux) then
      call map_message(seve%w,rname,'Ignoring /PLOT and /FLUX option in Parallel mode')
      method%pcycle = .false.
      method%pflux = .false.
    endif
    plot_case = 1
  else
    plot_case = 0
  endif
  !
  if (method%pflux) call init_flux90(method,hdirty,ylimn,ylimp,ipen)
  !
  ! Delete CCT variable
  call sic_delvariable('CCT',.false.,error)
  !
  ! Avoid array constructors (too touchy about Kind)
  method%bzone(1:2) = 1
  method%bzone(3:4) = hdirty%gil%dim(1:2)
  if (method%method.eq.'MRC') then
    call sub_mrc('MRC',method,hdirty,hresid,hclean,hbeam,hprim,d_mask, &
      &   error, plot_mrc)
  else
    if (plot_case.eq.1) then
      call sub_major(method,hdirty,hresid,hclean,hbeam,hprim,hmask, &
        &   dcclist,dcct,d_mask,d_list,error, no_major_plot, no_next_flux)
    else
      call sub_major(method,hdirty,hresid,hclean,hbeam,hprim,hmask, &
        &   dcclist,dcct,d_mask,d_list,error, major_plot90, next_flux90)
    endif
  endif
  !
  ! Close display in all cases
  method%converge = save_converge
  if (method%pflux .and. method%method.ne.'MRC') then
    err = .false.
    call close_flux90(ipen,err)
  else
    call gr_execl('CHANGE DIRECTORY <GREG')
  endif
  !
  ! Abort in case of Errors
  if (error) return 
  !
  ! Reset extrema
  if (user_method%mosaic) then
    hsky%gil%blan_words = 2
    hsky%gil%eval = 0.0 
  endif
  if (clean_extrema) then
    hresid%loca%addr = locwrd(dresid)
    call gdf_get_extrema (hresid,error)
    hresid%gil%extr_words = def_extr_words
    !
    if (user_method%mosaic) then
      call map_message(seve%i,rname,'Computing extrema of SKY and DIRTY')
      hsky%gil%blan_words = 2
      hsky%gil%eval = 0.0 
      hsky%loca%addr = locwrd(dsky)   
      call gdf_get_extrema (hsky,error)
      hsky%gil%extr_words = def_extr_words
    else
      call map_message(seve%i,rname,'Computing extrema of CLEAN and DIRTY')
      hclean%loca%addr = locwrd(dclean) 
      call gdf_get_extrema (hclean,error)
      hclean%gil%extr_words = def_extr_words
    endif    
  else
    hresid%gil%extr_words = 0
    hclean%gil%extr_words = 0
    hsky%gil%extr_words = 0
  endif
  !
  if (method%method.ne.'MRC') save_data(code_save_cct) = .true.
  !
  ! Save general parameters...
  user_method%ibeam = method%ibeam
  user_method%nlist = method%nlist
  !
  if (user_method%mosaic) then
    ! Specify clean beam parameters
    hsky%gil%reso_words = 3
    hsky%gil%majo = method%major
    hsky%gil%mino = method%minor
    hsky%gil%posa = pi*method%angle/180.0
    hclean%loca%size = 0  ! No Clean data
    last_shown = 'SKY'    ! For SHOW NOISE
    save_data(code_save_sky) = .true.
    !
    hatten%gil%bval = 0.
    where (datten.ne.0.0) datten = 1.0/datten
    if (hatten%gil%dim(3).le.1) then
      hatten%gil%ndim = 2
      hatten%gil%dim(3) = 1
    endif
    hatten%r3d => datten
    call cube_minmax('WEIGHT',hatten,error)
    if (error) return
    !
  else
    ! Specify clean beam parameters
    hclean%gil%reso_words = 3
    hclean%gil%majo = method%major
    hclean%gil%mino = method%minor
    hclean%gil%posa = pi*method%angle/180.0
    hsky%loca%size = 0    ! Reset the Sky (primary beam corrected) image
    ! and in beam too
    hbeam%gil%reso_words = 3
    hbeam%gil%majo = method%major
    hbeam%gil%mino = method%minor
    hbeam%gil%posa = pi*method%angle/180.0
    !
    hsky%loca%size = 0    ! Reset the Sky (primary beam corrected) image
    last_shown = 'CLEAN'  ! For SHOW NOISE
    save_data(code_save_clean) = .true.
  endif
  !
  call cct_truncate(hcct,dcct)
  call sic_mapgildas ('CCT',hcct,error,dcct)
  last_resid = 'CCT'    ! For UV_RESIDUAL
  !
  ! Signal that these display have been updated
  call set_buffer_modified('CCT')
  clist = ['CLEAN ','CCT   ','SKY   ']
  call check_view(3,clist)   ! Force VIEW re-computation for these
  !
end subroutine sub_clean
!
subroutine cct_truncate(hcct,dcct)
  use image_def
  use clean_def
  !----------------------------------------------------------------------
  ! @ private-mandatory
  !
  !*
  !   IMAGER -- CCT handling support routine  
  !     Truncate the CCT variable to its actual non-zero size
  !!
  !----------------------------------------------------------------------
  type(gildas), intent(inout) :: hcct 
  !! CCT Header
  real, intent(in) :: dcct(:,:,:)     
  !! CCT data
  !
  integer :: j
  integer(kind=index_length) :: mclean,i
  integer(kind=index_length), allocatable :: nclean(:) 
  !
  allocate(nclean(hcct%gil%dim(2)))
  nclean(:) = -1 ! No clean component by default
  do i=1,size(dcct,3) !! hcct%gil%dim(3)
    do j=1,hcct%gil%dim(2)
      if (nclean(j).eq.-1) then
        if (dcct(3,j,i).eq.0) nclean(j) = i-1
      endif
    enddo
    ! Exit when all set
    if (.not.(any(nclean(:).eq.-1) )) exit
  enddo
  do j=1,hcct%gil%dim(2)
    if (nclean(j).eq.-1) nclean(j) = size(dcct,3) !! hcct%gil%dim(3)
  enddo
  mclean = maxval(nclean)
  hcct%gil%dim(3) = max(mclean,1) ! No empty size...
  hcct%loca%size = product(hcct%gil%dim(1:3))
  deallocate(nclean)
end subroutine cct_truncate
!
subroutine clean_data(error)
  use gkernel_interfaces
  use imager_interfaces, except_this=>clean_data
  use clean_def
  use clean_default
  use clean_arrays
  use gbl_message
  !--------------------------------------------------------
  ! @ private
  !
  !*
  ! IMAGER -- CLEAN Support routine  
  !   Prepare Clean parameters.  
  !   Prepare Clean arrays: CLEAN or SKY, RESIDUAL  
  !!
  !--------------------------------------------------------
  logical, intent(out) :: error  !! Logical error flag
  !
  character(len=5), parameter :: rname = 'CLEAN'
  !
  ! Local ---
  integer nx,ny,nc,nb,ier
  logical equal
  !
  ! Code ----
  error = .false.
  if (hdirty%loca%size.eq.0) then
    call map_message(seve%e,rname,'No dirty image')
    error = .true.
  endif
  if (hbeam%loca%size.eq.0) then
    call map_message(seve%e,rname,'No dirty beam')
    error = .true.
  endif
  if (user_method%mosaic) then
    if (hprim%loca%size.eq.0) then
      call map_message(seve%e,rname,'No primary beam')
      error = .true.
    endif
  endif
  if (error) return
  !
  ! Create clean image if needed
  nx = hdirty%gil%dim(1)
  ny = hdirty%gil%dim(2)
  nc = hdirty%gil%dim(3)
  !
  call gdf_compare_shape(hdirty,hclean,equal)
  if (.not.equal) then
    if (allocated(dclean)) deallocate(dclean,stat=ier)
    call sic_delvariable ('CLEAN',.false.,error)
    if (allocated(dsky)) deallocate(dsky,stat=ier)
    call sic_delvariable ('SKY',.false.,error)
    if (allocated(dresid)) deallocate(dresid,stat=ier)
    call sic_delvariable ('RESIDUAL',.false.,error)
    if (allocated(datten)) deallocate(datten,stat=ier)
    if (allocated(d_mask)) deallocate(d_mask,stat=ier)
    if (allocated(d_list)) deallocate(d_list,stat=ier)
    call sic_delvariable ('THEMASK',.false.,error)
  endif
  !
  call gildas_null(hclean)
  call gdf_copy_header(hdirty,hclean,error)       ! Define header in all cases...
  !
  ! Clean image is either CLEAN or SKY
  if (user_method%mosaic) then
    call gdf_copy_header(hdirty,hsky,error)       ! Define header ?
    if (.not.allocated(dsky)) then
      allocate(dsky(nx,ny,nc),stat=ier)
      if (ier.ne.0) then
        call map_message(seve%e,rname,'Sky Memory allocation failure')
        error = .true.
        return
      endif
      call sic_mapgildas ('SKY',hsky,error,dsky)
    endif  
  else
    if (.not.allocated(dclean)) then
      allocate(dclean(nx,ny,nc),stat=ier)
      if (ier.ne.0) then
        call map_message(seve%e,rname,'Clean Memory allocation failure')
        error = .true.
        return
      endif
      call sic_mapgildas ('CLEAN',hclean,error,dclean)
    endif
  endif
  !
  if (.not.allocated(dresid)) then
    hresid = hdirty
    allocate(dresid(nx,ny,nc),stat=ier)
    if (ier.ne.0) then
      call map_message(seve%e,rname,'Residual Memory allocation failure')
      error = .true.
      return
    endif
    call sic_mapgildas('RESIDUAL',hresid,error,dresid)
  endif
  !
  if (.not.allocated(d_mask)) then
    allocate(d_mask(nx,ny),d_list(nx*ny),stat=ier)
    if (ier.ne.0) then
      call map_message(seve%e,rname,'Mask & List memory allocation failure')
      error = .true.
      return
    endif
    call sic_def_inte_addr ('THEMASK',d_mask,2,hdirty%gil%dim,   &
     &      .true.,error)
    user_method%do_mask = .true.
  endif
  !
  if (user_method%do_mask) then
    user_method%nlist = 0
  endif
  !
  ! Clean Component Table
  !
  ! Must define M_ITER before allocating space
!  m_iter = user_method%m_iter
  if (user_method%m_iter.eq.0) then
     call beam_unit_conversion(user_method)
     call copy_method(user_method,the_method)
     call check_area(the_method,hdirty,.true.)
!     m_iter = method%m_iter
  else
     call copy_method(user_method,the_method)
  endif
  !
  ! Allocate weight and check beam/image compatibility
  ! Weights are only defined if a Mosaic is treated.
  call gildas_null(hatten)
  call sic_delvariable ('WEIGHT',.false.,error)
  !
  if (user_method%mosaic) then
    !  Mosaic mode check...
    if (hbeam%gil%dim(3).ne.hprim%gil%dim(1)) then
      call map_message(seve%e,rname, &
      & 'MOSAIC mode: Beam and Primary have different number of pointings')
      error = .true.
    endif
    !
    if (hbeam%gil%dim(hbeam%gil%faxi).ne.hprim%gil%dim(4)) then
      call map_message(seve%e,rname, &
      & 'MOSAIC mode: Beam and Primary have different number of Frequencies')
      error = .true.
    endif
    if (error) return
    nb = hbeam%gil%dim(4)
    !
    call gdf_copy_header(hdirty,hatten,error)        ! Define header in all cases...
    hatten%gil%dim(3) = hbeam%gil%dim(4)            ! Number of frequency beams
    hatten%gil%convert(:,3) = hbeam%gil%convert(:,4)
    hatten%char%code(3) = hbeam%char%code(4)
    hatten%gil%ndim = 3          ! No spectral channels, but frequency beams
    hatten%loca%size = nx*ny*nb  ! It differs from that of hdirty !...
    !
    if (.not.allocated(datten)) then
      allocate(datten(nx,ny,nb),stat=ier)
      if (ier.ne.0) then
        call map_message(seve%e,rname,'Memory allocation failure')
        error = .true.
        return
      endif
      user_method%atten => datten
    endif
    ! Define the WEIGHT variable
    call sic_mapgildas('WEIGHT',hatten,error,datten)
    !
  elseif (hbeam%gil%dim(3).ne.1) then
    if (hbeam%gil%ndim.eq.3) then
      ! In Single-Field images, 3rd axis is Frequency
      if (hbeam%gil%dim(3).ne.hdirty%gil%dim(3)) then
        call map_message(seve%w,rname,'Different beam and image spectral resolution, '// &
        'not fully tested yet')
        !! error = .true.
        ! Single field verification
      endif
    else
      ! 4-D beam means a Mosaic for sure.
      ! In Single-Field images, 3rd axis is Frequency
      if (hbeam%char%code(3).ne.'VELOCITY') then
        !!
        call map_message(seve%e,rname,'More than 1 pointing, and Mosaic mode OFF')
        error = .true.
      endif
    endif
  endif
  !
  ! Frequency matching case - The ordering is LMVF - 
  if (hbeam%gil%dim(4).le.1) then
    continue
  elseif (hbeam%gil%dim(3).ne.hdirty%gil%dim(3)) then
    call map_message(seve%w,rname,'Different beam and image spectral resolution, '// &
    'not fully tested yet')
    !! error = .true.
  endif
  !
end subroutine clean_data
