!
subroutine doself (model,resul,itype,self,weight)
  !---------------------------------------------------------------------
  ! @ public
  !
  ! MAPPING   UV Tools
  !   Compute self calibraton factor
  !---------------------------------------------------------------------
  complex, intent(in) :: model   ! Model visibility
  complex, intent(in) :: resul   ! Actual observation
  integer, intent(in) :: itype   ! Type of self calibration
  complex, intent(out) :: self   ! Self calibration factor
  real, intent(out) :: weight    ! Weight scaling factor
  !
  self = model/resul
  weight = abs(self)
  if (itype.gt.0) then
    ! Phase Only
    self = self/weight
    weight = 1.0
  elseif (itype.lt.0) then
    ! Amplitude Only
    self = weight
    if (weight.gt.1.0) weight = 1.0/weight
  else
    ! Both
    if (weight.gt.1.0) weight = 1.0/weight
  endif
end subroutine doself
!
subroutine doscal (nc,visi,cosi,sinu,sreel,simag,weight)
  !---------------------------------------------------------------------
  ! @ public
  !
  ! MAPPING   UV Tools
  !	  Apply the self-calibration factor to the current visibility
  !	  Set weight to zero if no self-cal factor
  !---------------------------------------------------------------------
  integer, intent(in) :: nc           !  Number of channels
  real, intent(inout) :: visi(*)      !  Visibility
  real, intent(in) :: sreel           !  Real part to subtract
  real, intent(in) :: simag           !  Imaginary part to subtract
  real, intent(in) :: cosi            !  Phase rotation cos
  real, intent(in) :: sinu            !  Phase rotation sin
  real, intent(in) :: weight          !  Scaling factor of weight
  ! Local
  integer :: i,ii,ir,iw
  real :: reel,imag
  !
  do i=3,3*nc,3
    ir = i+5
    ii = i+6
    iw = i+7
    reel = visi(ir)
    imag = visi(ii)
    visi(ir) =  cosi*reel-sinu*imag-sreel
    visi(ii) =  sinu*reel+cosi*imag-simag
    visi(iw) =  visi(iw)*weight
  enddo
end subroutine doscal
!
subroutine dosubt (nc,visi,sreel,simag)
  !---------------------------------------------------------------------
  ! @ public
  !
  ! MAPPING   UV Tools
  !   Subtract a continuum value from a line visibility
  !---------------------------------------------------------------------
  integer, intent(in) :: nc           !  Number of channels
  real, intent(inout) :: visi(*)      !  Visibility
  real, intent(in) :: sreel           !  Real part
  real, intent(in) :: simag           !  Imaginary part
  ! Local
  integer :: i,ii,ir
  !
  do i=3,3*nc,3
    ir = i+5
    ii = i+6
    visi(ir) = visi(ir)-sreel
    visi(ii) = visi(ii)-simag
  enddo
end subroutine dosubt
!
subroutine doflag (nc,visi)
  !---------------------------------------------------------------------
  ! @ public
  !
  ! MAPPING   UV Tools
  !   Flag (by zero) a line visibility
  !---------------------------------------------------------------------
  integer, intent(in) :: nc           !  Number of channels
  real, intent(inout) :: visi(*)      !  Visibility
  ! Local
  integer :: i
  !
  ! Set weight to zero if no self-cal data
  do i=10,7+3*nc,3
    visi(i) = 0.0
  enddo
end subroutine doflag
!
subroutine getiba (visi,stime,time,base,uv)
  !---------------------------------------------------------------------
  ! @ public
  !
  ! MAPPING   UV Tools
  !   Get baseline and time information
  !---------------------------------------------------------------------
  real, intent(in)  :: visi(*)                   ! Visibility
  real(8), intent(in) :: stime                   ! Reference time
  real(8), intent(out) :: time                   ! Time offset
  real, intent(out)  :: base(2)                  ! First and Last antenna
  real, intent(out)  :: uv(2)                    ! U and V
  !
  uv(1) = visi(1)
  uv(2) = visi(2)
  time = nint(dble(visi(4))-stime)
  time = 86400.d0*time+dble(visi(5))
  base(1) = visi(6)
  base(2) = visi(7)
end subroutine getiba
!
subroutine dotime (mv,nv,visi,wtime,it,stime)
  use gkernel_interfaces
  !---------------------------------------------------------------------
  ! @ public
  !
  ! MAPPING   UV Tools
  !	  Compute the observing times of the data, 
  !	  sort it and return sorting index
  !---------------------------------------------------------------------
  integer, intent(in) :: mv           ! Size of visibility
  integer, intent(in) :: nv           ! Number of visibilities
  real, intent(in) :: visi(mv,nv)     ! Visibilities
  real(8), intent(out) :: wtime(nv)   ! Sorted times
  integer, intent(inout) :: it(nv)    ! Sorting index
  real(8), intent(out) :: stime       ! Reference time
  ! Local
  logical :: error
  integer :: i
  real :: tmin,tmax
  !
  tmin = visi(4,1)
  tmax = visi(4,1)
  do i=2,nv
    if (visi(4,i).lt.tmin) then
      tmin = visi(4,i)
    elseif (visi(4,i).gt.tmax) then
      tmax = visi(4,i)
    endif
  enddo
  if (tmin.eq.tmax) then
    do i=1,nv
      wtime(i) = visi(5,i)
    enddo
  else
    do i=1,nv
      wtime(i) = 86400d0*nint(visi(4,i)-tmin)   &
     &        +dble(visi(5,i))
    enddo
  endif
  stime = tmin
  !
  ! Sort
  call gr8_trie(wtime,it,nv,error)
end subroutine dotime
!
subroutine geself (mv,nv,iw,visi,time,ftime,wtime,it,   &
     &    rbase,complx,uv)
  !---------------------------------------------------------------------
  ! @ public
  !
  ! MAPPING   UV Tools
  !	  Compute the Observed Visibility of the "model source"
  !---------------------------------------------------------------------
  integer, intent(in) :: mv           ! Size of visibility
  integer, intent(in) :: nv           ! Number of visibilities
  real, intent(in) :: visi(mv,nv)     ! Visibilities
  real(8), intent(out) :: wtime(nv)   ! Sorted times
  integer, intent(in) :: iw(2)        ! First and Last channel
  real(8), intent(in) :: time         ! Time of observation
  real(8), intent(in) :: ftime        ! Tolerance on time +/-
  integer, intent(in) :: it(nv)       ! Ordering of visibilities
  real, intent(in) :: rbase(2)        ! Antennas
  real, intent(in) :: uv(2)           ! U and V
  complex, intent(out) :: complx      ! Result
  ! Local
  integer :: i,k,l,iv,jv,kv,jr,ji,jw
  real :: reel,imgi,weig
  !
  ! Locate the nearest time range by dichotomic search
  call findr (nv,wtime,time,iv)
  reel = 0.0
  imgi = 0.0
  weig = 0.0
  !
  ! Now find JV and KV corresponding to +/- FTIME
  i = iv
  do 
    if (i.eq.1) exit
    i = i-1
    if (wtime(i).lt.time-ftime) exit
  enddo
  jv  = i
  !
  i = iv
  do 
    if (i.eq.nv) exit
    i = i+1
    if (wtime(i).gt.time+ftime) exit
  enddo
  kv = i
  !
  ! Everything happens between JV and KV. Load the corresponding
  ! baseline data
  do i=jv,kv
    k = it(i)
    if (abs(wtime(i)-time).le.ftime) then
      if ( (visi(6,k).eq.rbase(1) .and.   &
     &        visi(7,k).eq.rbase(2)) .or. (visi(6,k).eq.rbase(2) .and.   &
     &        visi(7,k).eq.rbase(1)) ) then
       if ( (uv(2).gt.0 .and. visi(2,k).gt.0) .or.   &
     &          (uv(2).le.0 .and. visi(2,k).le.0) ) then
          do l = iw(1),iw(2)
            jr = 5+3*l
            ji = jr+1
            jw = ji+1
            reel = reel+visi(jr,k)*visi(jw,k)
            imgi = imgi+visi(ji,k)*visi(jw,k)
            weig = weig + visi(jw,k)
          enddo
        else
          !
          ! Change phase by 180 degree if baseline order is reversed
          do l = iw(1),iw(2)
            jr = 5+3*l
            ji = jr+1
            jw = ji+1
            reel = reel+visi(jr,k)*visi(jw,k)
            imgi = imgi-visi(ji,k)*visi(jw,k)
            weig = weig + visi(jw,k)
          enddo
        endif
      endif
    endif
  enddo
  if (weig.ne.0) then
    reel = reel/weig
    imgi = imgi/weig
    complx = cmplx(reel,imgi)
  else
    complx = 0.0
  endif
end subroutine geself
!
subroutine findr (np,x,xlim,nlim)
  !---------------------------------------------------------------------
  ! @ public
  !
  ! MAPPING   UV Tools
  !	  Find NLIM such as
  !	 	    X(NLIM-1) < XLIM <= X(NLIM)
  !	  for input data ordered.
  !	  Use a dichotomic search for that
  !---------------------------------------------------------------------
  integer, intent(in) :: np          ! Number of data points
  real(8), intent(in) :: x(np)       ! Data values
  real(8), intent(in) :: xlim        ! Value to be localized
  integer, intent(out) :: nlim       ! Found position
  ! Local
  integer :: ninf, nsup, nmid
  !
  ! Check that XLIM is within the range of X
  if (x(1).gt.xlim) then
    nlim = 1
    return
  endif
  ninf = 1
  nsup = np
  !
  do while(nsup.gt.ninf+1)
    nmid = (nsup + ninf)/2
    if (x(nmid).lt.xlim) then
      ninf = nmid
    else
      nsup = nmid
    endif
  enddo
  nlim = nsup
end subroutine findr
