program p_uvcorrel
  use gkernel_interfaces
  use image_def
  use gbl_message
  !$ use omp_lib
  !
  ! Compute Frequency Cross-Correlation spectrum
  ! of two UV tables
  !
  character(len=256) cmod,cuv,cspec 
  logical error
  type (gildas) :: hmod,huv,hspec
  character(len=*), parameter :: rname='UV_CORRELATE'
  real, allocatable :: accum(:), accums(:,:), current(:)
  logical :: equal
  integer :: it, iv, nchan, i, ier, nker, nthread, ithread, nsize
  !
  call gildas_open
  call gildas_char('MODEL$',cmod)
  call gildas_char('UVDATA$',cuv)
  call gildas_char('SPECTRUM$',cspec)
  call gildas_close
  !
  call gildas_null(hmod,type='UVT')
  call gildas_null(huv,type='UVT')
  !
  call sic_parse_file(cmod,' ','.uvt',hmod%file)
  call sic_parse_file(cuv,' ','.uvt',huv%file)
  !
  call gdf_read_header(hmod,error)
  call gdf_read_header(huv,error)
  !
  nchan = hmod%gil%nchan
  nsize = hmod%gil%dim(1)
  !
  hmod%gil%dim(1) = huv%gil%dim(1) ! For tests so far
  hmod%gil%nchan  = huv%gil%nchan
  call gdf_compare_shape(huv,hmod,equal)  !
  if (.not.equal) then
    call gag_message(seve%e,rname,'MODEL and UVDATA UV tables do not match')
    call sysexi(fatale)
  endif
  hmod%gil%dim(1) = nsize ! restore values 
  hmod%gil%nchan  = nchan ! 
  !
  ! Will be done by Blocks later
  call gdf_allocate(hmod,error)
  call gdf_allocate(huv,error)
  call gdf_read_data(hmod,hmod%r2d,error)
  call gdf_read_data(huv,huv%r2d,error)
  !
  call gildas_null(hspec,type='TABLE')
  call sic_parse_file(cspec,' ','.tab',hspec%file)
  !
  ! This will be a Spectrum
  nker = min(huv%gil%nchan/4,hmod%gil%nchan)
  hspec%gil%ndim = 2
  hspec%gil%dim(1:2) = [huv%gil%nchan-nker,3]
  hspec%gil%nchan = hspec%gil%dim(1)
  call gdf_allocate(hspec,error)
  !
  do i=1,hspec%gil%dim(1)
    hspec%r2d(i,1) = (i-huv%gil%ref(1)+nker/2)*huv%gil%vres + huv%gil%voff
    hspec%r2d(i,2) = (i-huv%gil%ref(1)+nker/2)*huv%gil%fres + huv%gil%freq
  enddo
  !
  !!Print *,'SPEC Dim ',hspec%gil%dim,' Kernel size ',nker,' Channels ',huv%gil%nchan
  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 gag_message(seve%e,rname,'Allocation error')
    call sysexi(fatale)
  endif
  !
  accums = 0.0
  !$OMP PARALLEL DEFAULT(NONE) &
  !$OMP &  SHARED(huv,hmod,nker,accums) &
  !$OMP &  PRIVATE(iv,current,ithread)
  !
  !$ ithread = omp_get_thread_num()+1
  !$OMP DO
  do iv = 1, huv%gil%nvisi
    current = 0.0
    call uvcorrel(huv%r2d(:,iv),huv%gil%nchan, & 
      & hmod%r2d(:,iv),hmod%gil%nchan,nker,current)
    accums(:,ithread) = accums(:,ithread) + current
  enddo
  !$OMP END DO
  !$OMP END PARALLEL
  !
  hspec%r2d(:,3) = 0.0
  do it =1,nthread
    hspec%r2d(:,3) = hspec%r2d(:,3) + accums(:,it)
  enddo
  call gdf_write_image(hspec,hspec%r2d,error)
  !
  contains
!
subroutine uvcorrel(uvdata,nc,kernel,mk,nk,current)
  use image_def
  use gkernel_interfaces
  !
  real, intent(in) :: uvdata(:)
  real, intent(in) :: kernel(:)
  integer, intent(in) :: nc, nk, mk
  real, intent(out) :: current(:)
  !
  ! Small automatic arrays
  real :: rdata(nc),idata(nc),wdata(nc),weight
  real :: rkernel(nk),ikernel(nk)
  complex :: cdata,ckernel(nk)
  integer :: ishift, ik, jc, icount, jk, hk
  real(8) :: r2, rp
  !
  weight = kernel(7+3*(mk/2))
  if (weight.le.0) return  ! Flagged visibility
  !
  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 NK/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
!
end program p_uvcorrel

        
