subroutine dispatch_clean(line,error)
  use gbl_message
  use gkernel_interfaces
  use imager_interfaces, except_this=>dispatch_clean
  use clean_arrays
  !----------------------------------------------------------------------
  ! @ public
  !
  ! IMAGER   Main CLEAN routine
  !   Call appropriate subroutine according to METHOD%METHOD
  !----------------------------------------------------------------------
  character(len=*), intent(inout) :: line  ! Command line
  logical,          intent(out)   :: error ! Logical error flag
  !
  character(len=1), parameter :: question_mark='?'
  character(len=12) :: cmethod
  integer :: nm, narg
  !
  narg = sic_narg(0) 
  if (narg.eq.1) then
    call sic_ch(line,0,1,cmethod,nm,.false.,error)
    if (cmethod(1:1).eq.question_mark) then
      call exec_program("@ i_clean "//cmethod)
      return
    endif
  endif
  call sic_get_char('METHOD',cmethod,nm,error)
  call sic_upper(cmethod)
  !
  select case (cmethod)
  case ('CLARK')
    call clark_clean(line,error)
  case ('HOGBOM')
    call hogbom_clean(line,error)
  case ('MRC')
    call mrc_clean(line,error)
  case ('MULTI')
    call multi_clean(line,error)
  case ('SDI')
    call sdi_clean(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
  !
end subroutine dispatch_clean
!
subroutine mrc_clean (line,error)
  use gkernel_interfaces
  use imager_interfaces, except_this=>mrc_clean
  use clean_def
  use clean_arrays
  use gbl_message
  !----------------------------------------------------------------------
  ! @ private
  !
  ! IMAGER Internal routine
  !   Implementation of Multi Resolution Clean
  !----------------------------------------------------------------------
  character(len=*), intent(inout) :: line
  logical, intent(out) :: error
  !
  integer ratio,nx,ny
  character(len=3) :: rname = 'MRC'
  !
  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,method)
  !
  ! Smoothing ratio : given by user or 2, 4 or 8 according to image size
  if (method%ratio.ne.0) then
    ratio = 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
  method%ratio = ratio
  method%pflux = sic_present(1,0)
  method%pcycle = sic_present(2,0)
  method%qcycle = .false.
  !
  call sub_clean(line,error)
  user_method%do_mask = .true. ! important sinon CLARK ne marche plus
end subroutine mrc_clean
!
subroutine multi_clean (line,error)
  use gkernel_interfaces
  use imager_interfaces, except_this=>multi_clean
  use clean_def
  use clean_arrays
  use gbl_message
  !----------------------------------------------------------------------
  ! @ private
  !
  ! IMAGER Internal routine
  !   Implementation of Multi Scale Clean
  !----------------------------------------------------------------------
  character(len=*), intent(inout) :: line
  logical, intent(out) :: error
  !
  if (user_method%mosaic) then
    call map_message(seve%e,'MULTI','Not yet implemented for mosaic')
    error = .true.
    return
  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,method)
  method%pflux = sic_present(1,0)
  method%pcycle = .false.
  method%qcycle = .false.
  !
  method%gains = method%gain
  call sic_get_real('CLEAN_GAINS[1]',method%gains(1),error)
  call sic_get_real('CLEAN_GAINS[2]',method%gains(2),error)
  call sic_get_real('CLEAN_GAINS[3]',method%gains(3),error)
  !
  call sub_clean(line,error)
end subroutine multi_clean
!
subroutine sdi_clean (line,error)
  use gkernel_interfaces
  use imager_interfaces, except_this=>sdi_clean
  use clean_def
  use clean_arrays
  !----------------------------------------------------------------------
  ! @ private
  !
  ! IMAGER Internal routine
  !   Implementation of Steer Dewdney Ito Clean
  !----------------------------------------------------------------------
  character(len=*), intent(inout) :: line
  logical, intent(out) :: error
  !
  integer iv,na,m_iter
  character(len=8) :: name,argum,voc1(2)
  data voc1/'CLEAN','RESIDUAL'/
  !
  ! 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,method)
  method%pflux = .false.
  method%pcycle = sic_present(2,0)
  method%qcycle = sic_present(3,0)
  if (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
    method%pclean = iv.eq.1
  else
    method%pclean = .false.
  endif
  call sub_clean(line,error)
  ! Restore default number of components
  user_method%m_iter = m_iter
end subroutine sdi_clean
!
subroutine hogbom_clean (line,error)
  use gkernel_interfaces
  use imager_interfaces, except_this=>hogbom_clean
  use clean_def
  use clean_arrays
  !----------------------------------------------------------------------
  ! @ private
  !
  ! IMAGER Internal routine
  !   Implementation of Hogbom Clean
  !----------------------------------------------------------------------
  character(len=*), intent(inout) :: line
  logical, intent(out) :: error
  !
  ! 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,method)
  method%pflux = sic_present(1,0)
  method%pcycle = .false.
  method%qcycle = .false.
  call sub_clean(line,error)
end subroutine hogbom_clean
!
subroutine clark_clean (line,error)
  use gkernel_interfaces
  use imager_interfaces, except_this=>clark_clean
  use clean_def
  use clean_arrays
  !----------------------------------------------------------------------
  ! @ private
  !
  ! IMAGER Internal routine
  !   Implementation of Barry Clark Clean
  !----------------------------------------------------------------------
  character(len=*), intent(inout) :: line
  logical, intent(out) :: error
  !
  integer iv,na
  character(len=8) :: name,argum,voc1(2)
  data voc1/'CLEAN','RESIDUAL'/
  !
  ! 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,method)
  method%pflux = sic_present(1,0)
  method%pcycle = sic_present(2,0)
  method%qcycle = sic_present(3,0)
  if (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
    method%pclean = iv.eq.1
  else
    method%pclean = .false.
  endif
  call sub_clean(line,error)
end subroutine clark_clean
!
subroutine sub_clean (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 Internal routine
  !     Implementation of all standard CLEAN deconvolution algorithms,
  !----------------------------------------------------------------------
  character(len=*), intent(inout) :: line
  logical, intent(out) :: error
  !
  real(8), parameter :: pi=3.14159265358979323846d0
  character(len=*), parameter :: rname='CLEAN'
  character(len=6) :: clist(3)=['CLEAN ','CCT   ','SKY   ']
  character(len=80) :: chain
  !
  integer ipen, nx, ny, np
  logical limits
  real ylimn,ylimp
  logical :: clean_extrema=.true.
  integer :: mthread, plot_case, nc
  !
  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
  call sic_get_inte('FIRST',method%first,error)
  call sic_get_inte('LAST',method%last,error)
  if (sic_present(0,1)) then
    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
  !
  method%thresh = 0.30
  call sic_get_real('THRESHOLD',method%thresh,error)
  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
  !
  nc = hdirty%gil%dim(3)
  call cct_prepare(line,nc,method,rname,error)
  !
  !
  ! 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
  !
  limits = sic_present(1,0)
  if (limits) 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 (-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
  endif
  ! Usefull variables
  nx = hdirty%gil%dim(1)
  ny = hdirty%gil%dim(2)
  np = max(1,hprim%gil%dim(1))
  !
  !
  !
  ! Beam patch according to Method
  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
  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
  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, &
        &   dcct,d_mask,d_list,error, no_major_plot, no_next_flux)
    else
      call sub_major(method,hdirty,hresid,hclean,hbeam,hprim,hmask, &
        &   dcct,d_mask,d_list,error, major_plot90, next_flux90)
    endif
  endif
  !
  if (method%pflux .and. method%method.ne.'MRC') then
    call close_flux90(ipen,error)
  else
    call gr_execl('CHANGE DIRECTORY <GREG')
  endif
  !
  ! 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
    last_shown = 'CLEAN'  ! For SHOW NOISE
    save_data(code_save_clean) = .true.
  endif
  !
  call sic_mapgildas ('CCT',hcct,error,dcct)
  last_resid = 'CCT'    ! For UV_RESIDUAL
  !
  ! Signal that these display have been updated
  clist = ['CLEAN ','CCT   ','SKY   ']
  call check_view(3,clist)   ! Force VIEW re-computation for these
  !
end subroutine sub_clean
!
subroutine clean_data(error)
  use gkernel_interfaces
  use imager_interfaces, except_this=>clean_data
  use clean_def
  use clean_arrays
  use gbl_message
  !--------------------------------------------------------
  ! @ private
  !
  ! IMAGER
  !   Prepare Clean parameters
  !   Prepare Clean arrays: CLEAN or SKY, RESIDUAL  
  !--------------------------------------------------------
  logical, intent(out) :: error
  !
  integer nx,ny,nc,nb,m_iter,ier
  logical equal
  character(len=5) :: rname = 'CLEAN'
  !
  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 (m_iter.eq.0) then
     call beam_unit_conversion(user_method)
     call copy_method(user_method,method)
     call check_area(method,hdirty,.true.)
     m_iter = method%m_iter
  else
     call copy_method(user_method,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 pointings')
      error = .true.
    endif
    !
    if (hbeam%gil%dim(4).ne.hprim%gil%dim(4)) then
      call map_message(seve%e,rname, &
      & 'MOSAIC mode: Beam and Primary have different 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
!! Currently, ordering is unclear...
    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
    !!
    call map_message(seve%e,rname,'More than 1 pointing, and Mosaic mode OFF')
    error = .true.
  endif
  !
  ! Frequency matching case
  if (hbeam%gil%dim(4).le.1) then
    continue
  elseif (hbeam%gil%dim(4).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
