subroutine uv_check_comm(line,error)
  use gkernel_interfaces
  use gbl_message
  use imager_interfaces, except_this => uv_check_comm
  use clean_types
  use clean_arrays
  use clean_beams
  !----------------------------------------------------------------------
  ! @ private
  !
  ! IMAGER support routine for command
  !     UV_CHECK [Beams|Nulls|Integration] [/FILE File]
  !----------------------------------------------------------------------
  logical, intent(out) :: error ! Logical error flag
  character(len=*), intent(in) :: line
  !
  character(len=*), parameter :: rname='UV_CHECK'
  integer, parameter :: o_file=1
  !
  integer(kind=index_length) :: dim(4)
  integer :: nu,nv,nc,na,ncase, jcase, ier, i, iv, kv, ni
  integer, allocatable :: cases(:), bad(:)
  real, allocatable :: weights(:)
  real(4) :: dtol, dmax, inte(1000)
  character(len=12) :: argum,cmode
  integer, parameter :: mmode=3
  character(len=12) :: smode(mmode)
  real :: tole=3E-3 ! Precision to check beam conformance
  data smode /'BEAMS','INTEGRATION','NULLS'/
  !
  character(len=filename_length) :: file
  type (gildas) :: uvin
  logical :: dofile, err
  integer :: ib, nblock, nf, nvisi
  character(len=128) :: mess
  !
  argum = 'BEAMS'
  call sic_ke(line,0,1,argum,na,.false.,error)
  call sic_ambigs (rname,argum,cmode,na,smode,mmode,error)
  if (error) return
  !
  dofile = sic_present(o_file,0)
  if (.not.dofile) then
    !
    !  Memory mode
    if (huv%loca%size.eq.0) then
      call map_message(seve%e,rname,'No UV data loaded')
      error = .true.
      return
    endif
    nu = huv%gil%dim(1)
    nv = huv%gil%nvisi ! not %dim(2)
    nc = huv%gil%nchan
    !
    !
    select case (cmode)
    case('BEAMS')
      nbeam_ranges = -1
      call check_beams_mem(error)
    case ('NULLS')
      call map_message(seve%i,rname,'Checking for unflagged null visibilities')
      allocate (bad(0:nv),stat=ier)
      bad(0) = 0
      kv = 0
      call sub_get_nulls(duv,nv,nc,bad,kv)
      if (kv.ne.0) then
        write(6,*) 'Flagged ',kv,' null visibilities'
        write(6,*) (bad(iv),iv=1,kv)
      else
        call map_message(seve%i,rname,'No null visibilities left unflagged')
      endif
      deallocate (bad,stat=ier)
      !
    case ('INTEGRATION')
      dmax = 300  ! Seconds
      call sic_r4(line,0,2,dmax,.false.,error)
      dtol = 0.05
      call sic_r4(line,0,3,dtol,.false.,error)
      if (error) return
      !
      ni = 0
      call sub_get_inte(huv,duv,nv,dmax,dtol,inte,ni,error)
      !
      write(6,'(A)') 'Possible integration times (seconds) '
      write(6,'((8(1X,F10.2)))') inte(1:ni)
    end select
  else
    call gildas_null (uvin, type = 'UVT')     ! Define a UVTable gildas header
    !
    call sic_ch(line,o_file,1,file,nf,.true.,error)
    if (error)  return
    call gdf_read_gildas (uvin, file, '.uvt', error, data=.false.)
    if (error) return
    !
    ! Define blocking factor, on largest data file, usually the input one
    ! but not always...
    !
    ! Set the Blocking Factor
    nblock = space_nitems('SPACE_IMAGER',uvin,1)
    ! Allocate respective space for each file
    allocate (uvin%r2d(uvin%gil%dim(1),nblock),stat=ier)
    if (failed_allocate(rname,'UV input data',ier,error)) then
      call gdf_close_image(uvin,err)
      return
    endif
    !
    nu = uvin%gil%dim(1)
    nv = uvin%gil%nvisi ! not %dim(2)
    nc = uvin%gil%nchan
    !
    ! Loop over line table
    uvin%blc = 0
    uvin%trc = 0
    !
    select case (cmode)
    case ('INTEGRATION')
      dmax = 300  ! Seconds
      call sic_r4(line,0,2,dmax,.false.,error)
      dtol = 0.05
      call sic_r4(line,0,3,dtol,.false.,error)
      if (error) return
      !
      ni = 0
      !
      do ib = 1,uvin%gil%dim(2),nblock
        write(mess,*) ib,' / ',uvin%gil%dim(2),nblock
        call map_message(seve%i,rname,mess)
        uvin%blc(2) = ib
        uvin%trc(2) = min(uvin%gil%dim(2),ib-1+nblock)
        call gdf_read_data(uvin,uvin%r2d,error)
        if (error) exit
        !
        nvisi = uvin%trc(2)-uvin%blc(2)+1
        !
        call sub_get_inte(uvin,uvin%r2d,nvisi,dmax,dtol,inte,ni,error)
      enddo
      !
      write(6,'(A)') 'Possible integration times (seconds) '
      write(6,'((8(1X,F10.2)))') inte(1:ni)
    case ('NULLS')
      call map_message(seve%i,rname,'Checking for null visibilities')
      allocate (bad(0:uvin%gil%nvisi),stat=ier)
      bad(0) = 0
      kv = 0
      !
      do ib = 1,uvin%gil%dim(2),nblock
        write(mess,*) ib,' / ',uvin%gil%dim(2),nblock
        call map_message(seve%i,rname,mess)
        uvin%blc(2) = ib
        uvin%trc(2) = min(uvin%gil%nvisi,ib-1+nblock)
        call gdf_read_data(uvin,uvin%r2d,error)
        if (error) exit
        !
        nvisi = uvin%trc(2)-uvin%blc(2)+1
        !
        call sub_get_nulls(uvin%r2d,nvisi,nc,bad,kv)
      enddo
      if (kv.ne.0) then
        write(6,*) 'Flagged ',kv,' null visibilities'
        write(6,*) (bad(iv),iv=1,kv)
      else
        call map_message(seve%i,rname,'No null visibilities left unflagged')
      endif
      deallocate (bad,stat=ier)
    case ('BEAMS')
      call sic_delvariable ('BEAM_RANGES',.false.,error)
      allocate (cases(nc),weights(nc),stat=ier)
      if (ier.ne.0) then
        call map_message(seve%e,rname,'Memory allocation error')
        error = .true.
        return
      endif
      !
      weights = 0.
      do ib = 1,uvin%gil%dim(2),nblock
        write(mess,*) ib,' / ',uvin%gil%dim(2),nblock
        call map_message(seve%i,rname,mess)
        uvin%blc(2) = ib
        uvin%trc(2) = min(uvin%gil%nvisi,ib-1+nblock)
        call gdf_read_data(uvin,uvin%r2d,error)
        if (error) exit
        !
        nvisi = uvin%trc(2)-uvin%blc(2)+1
        !
        call sub_get_nbeams(uvin, uvin%r2d, nvisi, nc, weights)
      enddo
      call howmany_beams(weights, nc, cases, ncase, tole) 
      !
      ! Write the result
      if (ncase.eq.1) then
        call map_message(seve%i,rname,'Only one beam needed')
      else
        if (ncase.eq.nc) then
          call map_message(seve%w,rname,'Need one beam per channel')
        else
          call map_message(seve%w,rname,'Beams needed for the following channel ranges:')
          if (allocated(beam_ranges)) deallocate(beam_ranges)
          allocate(beam_ranges(3,ncase),stat=ier)
          cases(ncase+1) = nc+1
          jcase = 0
          do i=1, ncase
            write(6,'(a,i6,a,i6,a,1pg10.3)') '[',cases(i),'-',cases(i+1)-1,'] ', weights(cases(i))
            if (weights(cases(i)).ne.0) then
              jcase = jcase+1
              beam_ranges(1,jcase) = cases(i)
              beam_ranges(2,jcase) = cases(i+1)-1
              beam_ranges(3,jcase) = weights(cases(i))
            endif
          enddo
          dim = [3,jcase,0,0]
          call sic_def_real('BEAM_RANGES',beam_ranges,2,dim,.false.,error)
        endif
      endif
    case default
      call map_message(seve%e,rname,'/FILE option not yet implemented for '//cmode)
      error = .true.
    end select
    !
    deallocate(uvin%r2d,stat=ier)
    call gdf_close_image(uvin,err)
    error = err.or.error
  endif
end subroutine uv_check_comm
!
subroutine sub_get_inte(huv,duv,nv,dmax,dtol,inte,kv,error)
  use image_def
  use gkernel_interfaces, only : gr8_trie
  !----------------------------------------------------------------------
  ! @ private
  !
  ! IMAGER support routine for command
  !     UV_CHECK Integration [/FILE File]
  ! Attempt to derive integration times, by differencing time stamps
  ! of consecutive visibvilities.
  !----------------------------------------------------------------------
  type(gildas), intent(in) :: huv   ! UV data header
  real, intent(in) :: duv(:,:)      ! UV data
  integer, intent(in) :: nv         ! Number of visibilities
  real, intent(inout) :: dmax       ! Longest allowed time step
  real, intent(in) :: dtol          ! Time stamp tolerance
  real, intent(inout) :: inte(:)    ! Possible integration times
  integer, intent(inout) :: kv      ! Number of possible times
  logical, intent(out) :: error
  !
  integer, allocatable :: idx(:)
  real(8), allocatable :: times(:)
  real(4) :: dt
  logical :: found
  !
  integer :: iv
  integer :: jv,ier
  !
  allocate(times(nv),idx(nv),stat=ier)
  !
  do iv=1,nv
    times(iv) = duv(4,iv)*86400d0 + duv(5,iv)
  enddo
  call gr8_trie(times,idx,nv,error)
  if (error) return
  !
  do iv=2,nv
    if (times(iv).ne.times(iv-1)) then
      dt = real(times(iv)-times(iv-1))
      if (dt.lt.dmax) then
        found = .false.
        do jv=1,kv
          if (abs(dt-inte(jv)).lt.dtol*dt) then
            found = .true.
            exit
          endif
        enddo
        if (.not.found) then
          kv = kv+1
          inte(kv) = dt 
        endif
      endif
    endif
  enddo
  !
end subroutine sub_get_inte
!
subroutine sub_get_nulls(duv,nv,nc,bad,kv)
  !----------------------------------------------------------------------
  ! @ private
  !
  ! IMAGER support routine for command
  !     UV_CHECK Nulls [/FILE File]
  !  Find out Null visibilities with non zero weights
  ! (occasionally happens with CASA data)
  !----------------------------------------------------------------------
  real, intent(inout) :: duv(:,:)
  integer, intent(in) :: nv, nc
  integer, intent(inout) :: bad(0:nv)
  integer, intent(inout) :: kv
  !
  integer :: iv,ic
  !
  do iv=1,nv
    do ic=1,nc
      if (duv(7+3*ic,iv).gt.0) then
        if (duv(5+3*ic,iv).eq.0 .and. duv(6+3*ic,iv).eq.0) then
          if (bad(kv).ne.iv) then
            kv = kv+1
            bad(kv) = iv
          endif
          duv(7+3*ic,iv) = 0
        endif
      endif
    enddo
  enddo
end subroutine sub_get_nulls
!
subroutine sub_get_nbeams(uvin, din, nvisi, nchan, weights)
  use image_def
  !----------------------------------------------------------------------
  ! @ public
  !
  ! IMAGER support routine for command
  !     UV_CHECK BEAM
  ! Get the sum of weights for each channel
  !----------------------------------------------------------------------
  type(gildas), intent(in) :: uvin                  ! UV table header
  integer, intent(in) :: nvisi                      ! Number of visibilities
  integer, intent(in) :: nchan                      ! Number of channels 
  real, intent(in) :: din(uvin%gil%dim(1),nvisi)    ! UV data
  real, intent(inout) :: weights(uvin%gil%nchan)    ! Cumulative weights
  !
  integer :: iv,ic
  real :: dw
  !
  do iv=1,nvisi
    do ic=1,nchan
      dw = din(uvin%gil%fcol-1+3*ic,iv)
      if (dw.gt.0) then
        weights(ic) = weights(ic)+dw      
      endif
    enddo
  enddo
end subroutine sub_get_nbeams
!
subroutine howmany_beams(weights, nc, cases, ncase, tole) 
  use image_def
  !----------------------------------------------------------------------
  ! @ public
  !
  ! IMAGER support routine for command
  !     UV_CHECK BEAM
  ! Find out how many different sum of weights
  !----------------------------------------------------------------------
  integer, intent(in) :: nc                         ! Number of channels
  real, intent(in) :: weights(nc)                   ! Weight array
  integer, intent(inout) :: cases(nc)               ! Possible cases for beams
  integer, intent(inout) :: ncase                   ! Number of cases
  real, intent(in) :: tole                          ! Tolerance
  !
  real :: wlast, wtole, wnext
  integer :: ic
  !
  wlast = 0
  ncase = 0
  !
  do ic = 1,nc
    wnext = weights(ic)
    wtole = tole*max(wlast,wnext)
    !
    if (abs(wnext-wlast).gt.wtole) then
      ncase = ncase+1
      cases(ncase) = ic ! Which channel
      wlast = weights(ic)
    endif
  enddo
end subroutine howmany_beams
!
subroutine check_beams_mem(error)
  use clean_beams
  use clean_arrays
  use gbl_message
  use gkernel_interfaces
  use imager_interfaces, only : map_message
  ! @ private
  logical, intent(inout) :: error  
  !
  character(len=*), parameter :: rname='UV_CHECK'
  real :: tole=3E-3 ! Precision to check beam conformance
  !
  real, allocatable :: weights(:)
  integer :: nu
  integer :: nv
  integer :: nc
  integer :: ncase, jcase, i, ier
  integer(kind=index_length) :: dim(4)
  integer, allocatable :: cases(:)
  
  ! Return if already done
  if (nbeam_ranges.ne.-1) return
  !  
  nv = huv%gil%nvisi 
  nc = huv%gil%nchan
  !
  call sic_delvariable ('BEAM_RANGES',.false.,error)
  error = .false.
  allocate (cases(nc),weights(nc),stat=ier)
  if (ier.ne.0) then
    call map_message(seve%e,rname,'Memory allocation error')
    error = .true.
    return
  endif
  !
  weights = 0.
  call sub_get_nbeams(huv, duv, nv, nc, weights)
  call howmany_beams(weights, nc, cases, ncase, tole) 
  !
  ! Write the result
  if (ncase.eq.1) then
    call map_message(seve%i,rname,'Only one beam needed')
    nbeam_ranges = 0
  else
    if (ncase.eq.nc) then
      call map_message(seve%w,rname,'Need one beam per channel',3)
      nbeam_ranges = 0
    else
      call map_message(seve%w,rname,'Beams needed for the following channel ranges:',3)
      if (allocated(beam_ranges)) deallocate(beam_ranges)
      allocate(beam_ranges(3,ncase),stat=ier)
      cases(ncase+1) = nc+1
      jcase = 0
      do i=1, ncase
        if (weights(cases(i)).ne.0) then
          write(6,'(a,i6,a,i6,a,1pg10.3)') '[',cases(i),'-',cases(i+1)-1,']    Weight;', weights(cases(i))
          jcase = jcase+1
          beam_ranges(1,jcase) = cases(i)
          beam_ranges(2,jcase) = cases(i+1)-1
          beam_ranges(3,jcase) = weights(cases(i))
        endif
      enddo
      nbeam_ranges = jcase
      dim = [3,jcase,0,0]
      call sic_def_real('BEAM_RANGES',beam_ranges,2,dim,.false.,error)
    endif
  endif
end subroutine check_beams_mem
