!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
module clean_types
  ! Types
  public :: clean_par
  ! Variables
  public :: clean_converge
  public :: major_sec,minor_sec
  ! Methods
  public :: beam_unit_conversion
  private
  !
  real :: major_sec
  real :: minor_sec
  integer :: clean_converge = 10 ! Cleaning convergence criterium
  !
  type clean_par
!     sequence !***JP: Why?
     integer(kind=4) :: first           ! First plane
     integer(kind=4) :: last            ! Last plane
     integer(kind=4) :: nlist           ! List size
     integer(kind=4) :: iplane          ! Current image plane
     integer(kind=4) :: ibeam           ! Current beam plane
     integer(kind=4) :: imask           ! Current mask plane 
     !
     real(kind=4) :: thresh             ! Threshold for beam fit
     real(kind=4) :: gain = 0.2         ! Loop gain
     real(kind=4) :: fres = 0.0         ! Fractional residual
     real(kind=4) :: ares = 0.0         ! Absolute residual
     real(kind=4) :: phat               ! Prussian hat
     real(kind=4) :: flux               ! Cleaned Flux
     !
     ! Mosaic
     real(kind=4) :: search = 0.2       ! Threshold for searching
     real(kind=4) :: restor = 0.2       ! Threshold for restoration
     real(kind=4) :: trunca             ! Beam truncation value
     !
     ! Clark
     real(kind=4) :: spexp = 1.0        ! Speed up factor
     !
     ! MRC
     real(kind=4) :: ratio = 0.0        ! Smoothing ratio
     !
     ! Multi-scale
     real(kind=4) :: smooth = sqrt(3.0)    ! Smoothing factor
     real(kind=4) :: worry                 ! Worry factor
     integer(kind=4) :: nker(3) = [1,7,11] ! Kernel
     real(kind=4) :: gains(3)              ! Clean gains
     integer(kind=4) :: ninflate = 20      ! Component "inflation" factor
                                           ! 20 is a decent value, sometimes too short
     !
     integer(kind=4) :: ngoal = 10000   ! Maximum number of minor cycle components
     logical :: keep = .true.           ! Convergence criterium 
     integer(kind=4) :: m_iter = 500    ! Maximum number of iterations
     integer(kind=4) :: n_iter = 0      ! Current number of iterations
     integer(kind=4) :: p_iter = 0      ! Positive number of iterations
     integer(kind=4) :: n_major = 50    ! Maximum number of major cycle
     !
     real(kind=4) :: major = 0.0        ! Major axis
     real(kind=4) :: minor = 0.0        ! Minor axis
     real(kind=4) :: angle = 0.0        ! Clean beam angle
     real(kind=4) :: beam_min           ! Beam minimum
     real(kind=4) :: beam_max           ! Beam maximum
     real(kind=4) :: bgain              ! Outer sidelobe
     !
     integer(kind=4) :: blc(2) = 0      ! Bottom Left Corner
     integer(kind=4) :: trc(2) = 0      ! Top Right Corner
     integer(kind=4) :: box(4)          ! Cleaning Box
     integer(kind=4) :: beam0(2)        ! Beam center X,Y
     integer(kind=4) :: patch(2) = 0    ! Beam patch sizes
     integer(kind=4) :: bzone(4)        ! Beam patch
     integer(kind=4) :: bshift(3)       ! Beam shift
     !
     logical :: mosaic = .false.        ! Mosaic flag
     logical :: pflux = .false.         ! Flux display
     logical :: pcycle = .false.        ! Residual display in cycle
     logical :: pmrc                    ! MRC display in cycle
     logical :: qcycle                  ! Query mode
     logical :: pclean                  ! Clean display in cycle
     logical :: do_mask = .true.        ! Re-compute the mask ?
     logical :: verbose = .false.       ! Lots of printout ?
     !
     character(len=12) :: method = 'HOGBOM' ! METHOD
     real(kind=4), pointer :: weight(:,:,:) ! Mosaic weights (as function of freq)
     !
     ! integer, pointer :: list(:)    ! List of selected pixels
     ! logical, pointer :: mask(:,:)  ! Selection mask
   contains
     procedure, public :: init     => clean_par_init
     procedure, public :: copyto   => clean_par_copyto
     procedure, public :: sicdef   => clean_par_sicdef
     procedure, public :: list     => clean_par_list
     procedure, public :: fit_beam => clean_par_fit_beam
  end type clean_par
  !
contains
  !
  subroutine clean_par_init(prog,error)
    !-----------------------------------------------------------------------
    ! Initialize by setting the intent to out
    !-----------------------------------------------------------------------
    class(clean_par), intent(out)   :: prog
    logical,          intent(inout) :: error
    !
    if (error) return
  end subroutine clean_par_init
  !
  subroutine clean_par_copyto(in,out)
    !----------------------------------------------------------------------
    ! Copy method
    !----------------------------------------------------------------------
    class(clean_par), intent(in)    ::  in
    type(clean_par),  intent(inout) ::  out
    !
    out%method = in%method
    out%verbose = in%verbose
    !
    out%gain = in%gain
    out%fres = in%fres
    out%ares = in%ares
    out%major = in%major
    out%minor = in%minor
    out%angle = in%angle
    out%ratio = in%ratio
    out%spexp = in%spexp
    out%phat = in%phat
    out%smooth = in%smooth
    out%keep = in%keep
    out%mosaic = in%mosaic
    out%search = in%search
    out%restor = in%restor
    out%trunca = in%trunca
    out%m_iter = in%m_iter
    out%p_iter = in%p_iter
    out%ngoal = in%ngoal
    out%n_major = in%n_major
    out%nker = in%nker
    out%ninflate = in%ninflate
    out%blc = in%blc
    out%trc = in%trc
    out%patch = in%patch
    out%do_mask = in%do_mask
    ! 
    ! Pointer issue
    out%weight => in%weight
    ! Consequences
    !     box, beam0, bzone, n_iter, bshift, beam_min, beam_max, bgain, flux
    ! Variables
    !     Major, Minor, Angle
    ! Temporary
    !     Pflux, Pcycle, Qcycle, Pmrc, Pclean,
    ! Return
    !     Do_beam, Do_mask
  end subroutine clean_par_copyto
  !
  subroutine clean_par_sicdef(prog,error)
    use gkernel_interfaces
    !-----------------------------------------------------------------------
    ! 
    !-----------------------------------------------------------------------
    class(clean_par), intent(out)   :: prog
    logical,          intent(inout) :: error
    !
    logical :: warning ! To avoid raising errors when deleting GREG variables
    integer(kind=index_length) :: dim(4) = 0
    !
    call sic_def_inte('NITER',prog%m_iter,0,0,.false.,error)
    if (error) return
    dim(1) = 2
    call sic_def_inte('BEAM_PATCH',prog%patch,1,dim,.false.,error)
    if (error) return
    dim(1) = 2
    call sic_def_inte('BLC',prog%blc,1,dim,.false.,error)
    if (error) return
    call sic_def_inte('TRC',prog%trc,1,dim,.false.,error)
    if (error) return
    call sic_def_inte('POSITIVE',prog%p_iter,0,0,.false.,error)
    if (error) return
    call sic_def_inte('NMAJOR',prog%n_major,0,0,.false.,error)
    if (error) return
    call sic_def_real('GAIN',prog%gain,0,0,.false.,error)
    if (error) return
    call sic_def_real('FRES',prog%fres,0,0,.false.,error)
    if (error) return
    call sic_def_real('ARES',prog%ares,0,0,.false.,error)
    if (error) return
    !
    call sic_def_real('MAJOR',major_sec,0,0,.false.,error)
    if (error) return
    call sic_def_real('MINOR',minor_sec,0,0,.false.,error)
    if (error) return
    ! Delete the ANGLE variable defined by define.greg and recreate it
    ! such as it maps 'prog%angle'
    call sic_delvariable('ANGLE',.true.,warning)
    call sic_def_real('ANGLE',prog%angle,0,0,.false.,error)
    if (error) return
    call sic_def_logi('KEEP',prog%keep,.false.,error)
    if (error) return
    call sic_def_real('SPEED',prog%spexp,0,0,.false.,error)
    if (error) return
    call sic_def_inte('NGOAL',prog%ngoal,0,0,.false.,error)
    if (error) return
    !
    ! MultiScale
    dim(1) = 3
    call sic_def_inte('KERNEL',prog%nker,1,dim,.false.,error)
    if (error) return
    call sic_def_inte('INFLATE',prog%ninflate,0,0,.false.,error)
    if (error) return
    call sic_def_real('SMOOTH',prog%smooth,0,0,.false.,error)
    if (error) return
    !
    ! MRC
    call sic_def_real('RATIO',prog%ratio,0,0,.false.,error)
    if (error) return
    !
    ! Mosaic mode
    ! Delete the MOSAIC variable defined by define.greg and recreate it
    ! such as it maps 'prog%mosaic'
    call sic_delvariable('MOSAIC',.true.,warning)
    if (error) return
    call sic_def_logi('MOSAIC',prog%mosaic,.false.,error)
    if (error) return
    call sic_def_real('SEARCH_W',prog%search,0,0,.false.,error)
    if (error) return
    call sic_def_real('RESTORE_W',prog%restor,0,0,.false.,error)
    if (error) return
    !
    call sic_def_logi('METHOD_DOMASK',prog%do_mask,.false.,error)
    if (error) return
    call sic_def_logi('VERBOSE',prog%verbose,.false.,error)
    if (error) return
    !
    call sic_def_inte('CLEAN_CONVERGE',clean_converge,0,0,.false.,error)
    if (error) return
  end subroutine clean_par_sicdef
  !
  subroutine clean_par_list(clean)
    !--------------------------------------------------------------------
    !
    !--------------------------------------------------------------------
    class(clean_par) :: clean
    !
    write(6,*) clean%gain,clean%fres,clean%ares,' Loop gain,Fres,Ares'
    write(6,*) clean%major,clean%minor,clean%angle,' Major/Minor/Angle axis'
    write(6,*) clean%beam_min,clean%beam_max,clean%bgain,' Beam Min/Max Sidelobe'
    write(6,*) clean%ratio,clean%spexp,clean%phat,clean%smooth,' MRC ratio,Speed,Phat,Multi ratio'
    write(6,*) clean%flux,clean%keep,' Cleaned Flux,Keep'
    write(6,*) clean%search,clean%restor,clean%trunca,' Threshold Search/Restore/Truncate'
    write(6,*) clean%blc,clean%trc,' BLC,TRC '
    write(6,*) clean%box,' Cleaning Box'
    write(6,*) clean%beam0,clean%patch,' Beam center X,Y,Patch size'
    write(6,*) clean%bzone,' Beam patch Zone'
    write(6,*) clean%m_iter,clean%p_iter,clean%n_iter,' Iterations Max/Pos/Actual'
    write(6,*) clean%ngoal,clean%n_major,' Max select,Max cycle'
    write(6,*) clean%bshift,' Beam shift'
    write(6,*) clean%nker,' Kernel for Multi-Scale clean'
    write(6,*) 'Mos. Flux,Cycle,Query,Mrc,Clean,Beam/Mask'
    write(6,*) clean%mosaic,clean%pflux,clean%pcycle ,clean%qcycle,clean%pmrc,clean%pclean,clean%do_mask
    write(6,*) clean%first,clean%last,clean%iplane,clean%ibeam,clean%nlist,' First/Last/Current  Beam List'
    write(6,*) clean%method,' METHOD'
  end subroutine clean_par_list
  !
  subroutine clean_par_fit_beam(method,hbeam,dbeam,error)
    use image_def
    use fit_beam_tool
    !----------------------------------------------------------------------
    ! Fit clean beam parameters
    !----------------------------------------------------------------------
    class(clean_par), intent(inout) :: method
    type(gildas),     intent(in)    :: hbeam
    real,             intent(in)    :: dbeam(hbeam%gil%dim(1),hbeam%gil%dim(2))
    logical,          intent(inout) :: error
    !
    integer :: nx,ny
    !
    ! Use beam patch to search for maximum
    error = .false.
    nx =  hbeam%gil%dim(1)
    ny =  hbeam%gil%dim(2)
    call fibeam('CLEAN',dbeam,nx,ny,&
         method%patch(1),method%patch(2),method%thresh,&
         method%major,method%minor,method%angle,&
         hbeam%gil%convert,error)
  end subroutine clean_par_fit_beam
  !
  subroutine beam_unit_conversion(prog)
    use phys_const
    !----------------------------------------------------------------------
    ! Major and minor SIC variables are in seconds but the method structure
    ! assumes that its major and minor fields are in radian. So we need
    ! a conversion...
    !----------------------------------------------------------------------
    type(clean_par) :: prog
    !
    prog%major = major_sec*rad_per_sec
    prog%minor = minor_sec*rad_per_sec
  end subroutine beam_unit_conversion
end module clean_types
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
