subroutine correlate_comm(line,comm,error)
  use gkernel_interfaces
  use image_def
  use clean_arrays
  use gbl_message
  use imager_interfaces, only : uvcorrel, map_message
  !$ use omp_lib
  !---------------------------------------------------------------------
  ! @ private
  !   IMAGER
  ! Support for command
  !   UV_CORRELATE [/FILE Data Model]
  ! Compute Frequency Cross-Correlation spectrum of two UV data sets
  !---------------------------------------------------------------------
  character(len=*), intent(in) :: line
  character(len=*), intent(in) :: comm
  logical, intent(inout) :: error
  !
  integer, parameter :: o_file=1
  character(len=256) cmod,cuv,cspec 
  character(len=128) :: mess
  type (gildas) :: hmod,hdata,hspec
  character(len=*), parameter :: rname='UV_CORRELATE'
  !
  real, allocatable :: accum(:), accums(:,:), current(:)
  logical :: equal, byfile, err
  integer :: it, iv, nchan, i, nker, nthread, ithread, nsize, n
  integer :: ier, nblock, ib, nvisi
  real :: weight
  !
  error = .false.
  call gildas_null(hmod,type='UVT')
  call gildas_null(hdata,type='UVT')
  call gildas_null(hspec)
  !
  byfile = sic_present(o_file,0)
  if (.not.byfile) then
    if (huv%loca%size.eq.0) then
      call map_message(seve%e,rname,'No UV data')
      error = .true.
    endif
    if (huvm%loca%size.eq.0) then
      call map_message(seve%e,rname,'No UV model')
      error = .true.
    endif
    if (error) return
    call gdf_copy_header(huv,hdata,error)
    call gdf_copy_header(huvm,hmod,error)
    hmod%r2d => duvm
    hdata%r2d => duv
  else
    call sic_ch(line,o_file,2,cmod,n,.true.,error)
    if (error) return
    call sic_ch(line,o_file,1,cuv,n,.true.,error)
    if (error) return
    !
    call sic_parse_file(cmod,' ','.uvt',hmod%file)
    call sic_parse_file(cuv,' ','.uvt',hdata%file)
    !
    call gdf_read_header(hmod,error)
    if (error) return
    call gdf_read_header(hdata,error)
    if (error) return
  endif
  !
  call sic_ch(line,0,1,cuv,n,.true.,error)
  if (error) return
  call sic_parse_file(cmod,' ','.tab',hspec%file)
  !
  nchan = hmod%gil%nchan
  nsize = hmod%gil%dim(1)
  !
  hmod%gil%dim(1) = huv%gil%dim(1) ! For the tests below 
  hmod%gil%nchan  = huv%gil%nchan
  call gdf_compare_shape(huv,hmod,equal)  !
  if (.not.equal) then
    call map_message(seve%e,rname,'MODEL and UVDATA UV tables do not match')
    error = .true.
    return
  endif
  hmod%gil%dim(1) = nsize ! restore values 
  hmod%gil%nchan  = nchan ! 
  Print *,'Ready to proceed ',nsize,nchan
  !
  ! This will be a Spectrum with Velocity,Frequency,Value
  nker = min(hdata%gil%nchan/4,hmod%gil%nchan)
  hspec%gil%ndim = 2
  hspec%gil%dim(1:2) = [hdata%gil%nchan-nker,3]
  hspec%gil%nchan = hspec%gil%dim(1)
  Print *,'Ready for kernel ',nker,' byfile ',byfile,' Dims ',hspec%gil%dim(1:2)
  !
  !
  call gdf_allocate(hspec,error)
  if (error) return
  do i=1,hspec%gil%dim(1)
    hspec%r2d(i,1) = (i-hdata%gil%ref(1)+nker/2)*hdata%gil%vres + hdata%gil%voff
    hspec%r2d(i,2) = (i-hdata%gil%ref(1)+nker/2)*hdata%gil%fres + hdata%gil%freq
  enddo
  !
  nchan = hspec%gil%dim(1)
  nthread = 1
  !$ nthread = omp_get_max_threads()
  allocate(accum(nchan),accums(nchan,nthread),current(nchan),stat=ier)
  if (ier.ne.0) then
    call map_message(seve%e,rname,'Allocation error')
    error =.true.
    return
  endif
  !
  accums = 0.0
  !
  if (.not.byfile) then
    hdata%r2d => duv
    hmod%r2d => duvm
    !
    Print *,'SPEC Dim ',hspec%gil%dim(1:2),' Kernel size ',nker,' Channels ',hdata%gil%nchan
    !$OMP PARALLEL DEFAULT(NONE) &
    !$OMP &  SHARED(hdata,hmod,nker,accums) &
    !$OMP &  PRIVATE(iv,current,ithread,weight)
    !
    !$ ithread = omp_get_thread_num()+1
    !$OMP DO
    do iv = 1, hdata%gil%nvisi
      current = 0.0
      ! We use the weight of the Model, should we use that of the data ?
      weight = hmod%r2d(7+3*(hmod%gil%nchan/2),iv) ! Kernel
      weight = hdata%r2d(7+3*(hdata%gil%nchan/3),iv)  ! Data 
      if (weight.le.0) cycle  ! Flagged visibility
    !
      call uvcorrel(hdata%r2d(:,iv),hdata%gil%nchan, & 
        & hmod%r2d(:,iv),hmod%gil%nchan,nker,weight,current)
      accums(:,ithread) = accums(:,ithread) + current
    enddo
    !$OMP END DO
    !$OMP END PARALLEL
    !
  else
    !
    ! Define blocking factor, on largest data file usually.
    call gdf_nitems('SPACE_GILDAS',nblock,hdata%gil%dim(1)) ! Visibilities at once
    nblock = min(nblock,hdata%gil%dim(2))
    ! Allocate respective space for each file
    allocate (hdata%r2d(hdata%gil%dim(1),nblock), hmod%r2d(hmod%gil%dim(1),nblock), stat=ier)
    if (ier.ne.0) then
      write(mess,*) 'Memory allocation error ',hdata%gil%dim(1), nblock
      call map_message(seve%e,rname,mess)
      error = .true.
      return
    endif
    !
    ! Loop over line table - The example assumes the same
    ! number of visibilities in Input and Output, which may not
    ! be true...
    hdata%blc = 0
    hdata%trc = 0
    hmod%blc = 0
    hmod%trc = 0
    do ib = 1,hdata%gil%dim(2),nblock
      write(mess,*) ib,' / ',hdata%gil%dim(2),nblock
      call map_message(seve%i,rname,mess)
      hdata%blc(2) = ib
      hdata%trc(2) = min(hdata%gil%dim(2),ib-1+nblock)
      hmod%blc(2) = ib
      hmod%trc(2) = hdata%trc(2)
      call gdf_read_data(hdata,hdata%r2d,error)
      if (error) exit
      call gdf_read_data(hmod,hmod%r2d,error)
      if (error) exit
      !
      ! Here do the job
      nvisi = hmod%trc(2)-hmod%blc(2)+1
      !
      !$OMP PARALLEL DEFAULT(NONE) &
      !$OMP &  SHARED(hdata,hmod,nker,accums,nvisi) &
      !$OMP &  PRIVATE(iv,current,ithread,weight)
      !
      !$ ithread = omp_get_thread_num()+1
      !$OMP DO
      do iv = 1, nvisi
        current = 0.0
        ! We use the weight of the Model, should we use that of the data ?
        weight = hmod%r2d(7+3*(hmod%gil%nchan/2),iv) ! Kernel
        weight = hdata%r2d(7+3*(hdata%gil%nchan/3),iv)  ! Data 
        if (weight.le.0) cycle  ! Flagged visibility
      !
        call uvcorrel(hdata%r2d(:,iv),hdata%gil%nchan, & 
          & hmod%r2d(:,iv),hmod%gil%nchan,nker,weight,current)
        accums(:,ithread) = accums(:,ithread) + current
      enddo
      !$OMP END DO
      !$OMP END PARALLEL
    enddo
    !
    ! Finalize the image
    call gdf_close_image(hdata,err)
    call gdf_close_image(hmod,err)
    if (error) return
  endif
  !
  ! Accumulate the Thread results
  hspec%r2d(:,3) = 0.0
  do it =1,nthread
    hspec%r2d(:,3) = hspec%r2d(:,3) + accums(:,it)
  enddo
  !
  ! Define the result as a SPECTRUM
  open(unit=2,file='toto.dat',status='unknown')
  rewind(2)
  do i=1,nchan
    write(2,*) hspec%r2d(i,1), hspec%r2d(i,2), hspec%r2d(i,3)
  enddo
  close(unit=2)
!!  call gdf_write_image(hspec,hspec%r2d,error)
  !
end subroutine correlate_comm
!
subroutine uvcorrel(uvdata,nc,kernel,mk,nk,weight,current)
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------  
  real, intent(in) :: uvdata(:) ! UV data to be matched
  real, intent(in) :: kernel(:) ! Kernel against witch matching is to be made
  integer, intent(in) :: nc ! Number of channels of uvdata
  integer, intent(in) :: nk ! Useable size of the Kernel
  integer, intent(in) :: mk ! Number of channels of the Kernel
  real, intent(in) :: weight ! Weight of this data set
  real, intent(out) :: current(:) ! Correlation spectrum
  !
  ! Small automatic arrays
  real :: rdata(nc),idata(nc),wdata(nc)
  real :: rkernel(nk),ikernel(nk)
  complex :: cdata,ckernel(nk)
  integer :: ishift, ik, jc, icount, jk, hk
  real(8) :: r2, rp
  !
  rdata(:) = uvdata(8:5+3*nc:3)
  idata(:) = uvdata(9:6+3*nc:3)
  wdata(:) = uvdata(10:7+3*nc:3)
  !
  ! For the Kernel, we take NK channels out of MK
  ! So we start from MK/2-NK/2 
  jk = (mk/2)-nk/2 + 1
  hk = jk + nk - 1
  rkernel(:) = kernel(5+3*jk:5+3*hk:3)
  ikernel(:) = kernel(6+3*jk:6+3*hk:3)
  ckernel = cmplx(rkernel,ikernel)
!!
!! xc += np.correlate(data.VV[v], np.matmul(data.wgts[v]*R_inv, kernel[v]))
!!        # normalize the output such that real and imag noise powers are both 1 (hence factor of sqrt(2))
!!                kernel_noise_power += np.dot(kernel[v],np.matmul(data.wgts[v]*R_inv, kernel[v].conj()))
!!        xc = xc/np.sqrt(kernel_noise_power)*np.sqrt(2)  
!!
  ! Assume no correlation between channels
  do ik = 1,nc-nk
    r2 = 0.
    rp = 0. ! Noise power
    do jc=ik,ik+nk-1
      jk = jc-ik+1
      icount = icount+1
      if (wdata(jc).gt.0) then
        cdata = cmplx(rdata(jc),idata(jc))
        cdata = cdata*ckernel(jk)*weight
        r2 = r2 + real(cdata)
        rp = rp + ckernel(jk)*weight*conjg(ckernel(jk))
      endif
    enddo
    current(ik) = sqrt(2.)*r2/sqrt(rp)
  enddo
end subroutine uvcorrel
!

        
