!
subroutine uv_calibrate(line,error)
  use gildas_def
  use gkernel_interfaces
  use imager_interfaces, except_this => uv_calibrate
  use gbl_message
  use clean_arrays
  !---------------------------------------------------------------------
  ! @ private
  !
  ! IMAGER
  !   Support routine for 
  !     CALIBRATE\APPLY [Mode [Gain]] [/FLAG]
  ! 
  ! Apply gains from the GAIN data set to the UV data set.
  ! If no available solution, keep the data as it was.
  !---------------------------------------------------------------------
  character(len=*), intent(in) :: line
  logical, intent(inout) :: error
  !
  ! Global
  character(len=*), parameter :: rname='CALIBRATE'
  real(8), parameter :: pi=3.141592653589793d0
  integer, parameter :: o_flag=1
  ! Local
  character(len=80) :: mess
  real, pointer :: duv_previous(:,:), duv_next(:,:)
  real(8), allocatable :: itimg(:), it(:)
  integer, allocatable :: flagged(:)
  integer, allocatable :: idxg(:), idx(:)
  integer(4) ::  n, nvis, ncol, nvg, ndc, ier
  real(8) :: phase_gain, ampli_gain
  real(8) :: fdata, fgain ! Reference frequencies for Gain and UV
  real(4) :: gain
  logical :: do_flag
  integer, parameter :: mmode=3
  character(len=12) :: smode(mmode), mode, argum
  character(len=32) :: chain
  data smode /'AMPLITUDE','DELAY','PHASE'/
  !
  error = .false.
  !
  if (hbgain%loca%size.eq.0) then
    call map_message(seve%e,rname,'Gain table is not defined')
    error = .true.
    return
  endif
  !
  do_flag = sic_present(o_flag,0)
  !
  gain = 1.0
  if (sic_present(0,1)) then
    call sic_ke(line,0,1,argum,n,.true.,error)
    call sic_r4(line,0,2,gain,.false.,error)
    if (error) return
  else
    call sic_get_char('SELF_MODE',argum,n,error)
  endif    
  call sic_ambigs (rname,argum,mode,n,smode,mmode,error)
  if (error) return
  !
  if (gain.le.0. .or. gain.gt.1.0) then
    call map_message(seve%e,rname,trim(mode)//' gain out of range [0,1]')
    error = .true.
    return
  endif
  write(chain,*) gain
  call map_message(seve%i,rname,'Applying '//trim(mode)// &
    & ' calibration with gain '//trim(chain))
  !
  select case(mode)
  case ('AMPLITUDE') 
    ampli_gain = gain
    phase_gain = 0.0
  case ('PHASE')
    phase_gain = gain
    ampli_gain = 0.0
  case ('DELAY')
    fgain = gdf_uv_frequency(hbgain)
    fdata = gdf_uv_frequency(huv)
    write(mess,'(A,F10.1,A,F10.1,A)') 'Frequencies : Data ',fdata,',  Gain table ',fgain,' MHz'
    call map_message(seve%i,rname,mess)  
    phase_gain = gain * fdata/fgain
    write(mess,'(A,F6.3)',iostat=ier) 'Phase gain is ',phase_gain
    call map_message(seve%i,rname,mess)  
    ampli_gain = 0.0
  end select
  !
  ! Now do the job
  nvis = huv%gil%nvisi ! not %dim(2)
  ncol = huv%gil%dim(1)
  ndc =  huv%gil%nchan
  !
  nullify (duv_previous, duv_next)  
  call uv_find_buffers (rname,ncol,nvis,duv_previous, duv_next,error)
  if (error) return
  !
  nvg = hbgain%gil%dim(2)
  !
  ! Get a bunch of memory ...
  allocate (it(nvis), idx(nvis), flagged(nvis), stat=ier)
  if (ier.ne.0) then
    error = .true.
    call map_message(seve%e,rname,'Visibility work array allocation error')
    return
  endif
  allocate (itimg(nvg), idxg(nvg), stat=ier)
  if (ier.ne.0) then
    error = .true.
    call map_message(seve%e,rname,'Gain work array allocation error')
    return
  endif
  !
  call sub_uvcal(ncol,nvis, duv_previous, ndc, duv_next, &
     &    idx, it, do_flag, flagged, nvg, duvbg, idxg, itimg,  &
     &    ampli_gain,phase_gain,error)
    !Print *,'Done do_cal ',self%blc(2),self%trc(2),self%gil%dim(2),error
  if (error) return
  !
  call uv_clean_buffers (duv_previous, duv_next,error)
  !
  ! Self Calibration affects Weights
  call uv_new_data (.true.)
  !! do_weig = .true.
end subroutine uv_calibrate
!
subroutine sub_uvcal(ncol,nvis,data,ndc,cal, &
     &    index,times,do_flag,flagged,nvg,gain,indg,timesg,   &
     &    ampli_gain,phase_gain,error)
  use imager_interfaces, only : map_message
  use gbl_message
  !---------------------------------------------------------------------
  ! @ public
  !
  ! IMAGER
  !      Support routine for command APPLY
  !
  !   Apply phase and/or amplitude calibration to
  !   the "raw" UV data.   Phase and Amplitudes are stored in
  !   the "gain" UV table, and usually come from a previous
  !   use of Task uv_gain.    This subroutine allows to apply the
  !   corrections to a spectral line table, whatever the way the gains
  !   were computed before.
  !---------------------------------------------------------------------
  integer, intent(in) :: ncol            ! Visibility size
  integer, intent(in) :: nvis            ! Number of visibilities
  real, intent(in) :: data(ncol,nvis)    ! Visibility array
  integer, intent(in) :: ndc             ! Number of channels
  real, intent(out) :: cal(ncol,nvis)    ! Calibrated visibilities
  integer, intent(in) :: index(nvis)     ! Visibility Index
  real(8), intent(inout) :: times(nvis)  ! Visibility Time stamp
  logical, intent(in) :: do_flag           ! Flag data with no solution
  integer, intent(inout) :: flagged(nvis)  ! Flag work array
  integer, intent(in) :: nvg             ! Number of gains
  real, intent(in) :: gain(10,nvg)       ! Gain array
  integer, intent(out) :: indg(nvg)      ! Index in gains
  real(8), intent(out) :: timesg(nvg)    ! Gain time stamp
  real(8), intent(in) :: ampli_gain      ! Amplitude gain
  real(8), intent(in) :: phase_gain      ! Phase gain
  logical, intent(out) :: error          ! Error flag
  !
  character(len=*), parameter :: rname='CALIBRATE'
  integer, parameter :: mant=256  ! ALMA maximum, after renumbering
  ! Local
  integer :: iv, jv, k, ivg, jvg, ia, ja, kv, isev
  complex :: zdata, zgain(mant,mant), zcal, zg
  real :: wg
  real(8) :: t, tg, tgold
  real(8) :: ampli, phase
  real(8) :: time_step = 1.0d0
  character(len=80) :: mess
  !
  !---------------------------------------------------------------------
  !
  ! Get the chronological order, for both input tables:
  do iv=1, nvis
    times(iv) = data(4,iv)*86400.d0+data(5,iv)
  enddo
  call gr8_trie (times,index,nvis,error)
  if (error) then
    call map_message(seve%e,rname,'Error sorting UV Table')
    return
  endif
  !
  do ivg=1, nvg
    timesg(ivg) = gain(4,ivg)*86400.d0+gain(5,ivg)
  enddo
  call gr8_trie (timesg,indg,nvg,error)
  if (error) then
    call map_message(seve%e,rname,'Error sorting Gain Table')
    return
  endif
  !
  iv = 1
  jv = index(iv)
  ivg = 1
  tgold = timesg(ivg)
  zgain = 0.0
  !
  ! The loop is done on calibration times, so
  ! there is no guarantee that a given data visibility is treated.
  !
  ! To handle this, we set a counter for each visibility, to
  ! check whether it has indeed been affected...
  !
  flagged(1:nvis) = 1
  jvg = indg(1) ! To suppress compiler warning
  !
  do ivg = 1, nvg+1
    if (ivg.le.nvg) then
      jvg = indg(ivg)
      tg = timesg(ivg)
    else
      ! Last one, force a dummy time change
      tg = tgold+1e20
    endif
    !         type *, 'ivg, jvg, tg, tgold'
    !         type *, ivg, jvg, tg, tgold
    if (tg.ne.tgold) then
      !
      ! Time change, apply calibration
      t = times(iv)
      jv = index(iv)
      do while (t-tgold.le.time_step)
        !               type *, 'iv,jv,t'
        !               type *, iv,jv,t
        cal(:,jv) = data(:,jv)    ! Copy visibility
        if (t.ge.tgold-time_step) then
          ia = nint(cal(6,jv))
          ja = nint(cal(7,jv))
          !                  type *, ia, ja, zgain(ia,ja)
          if (zgain(ia,ja).ne.0) then
            flagged(jv) = 0 
            zg = zgain(ia,ja)
            wg = abs(zg)**2
            do k=8, 3*ndc+7, 3
              zdata = cmplx(data(k,jv),data(k+1,jv))
              zcal = zdata/zg
              cal(k,jv) = real(zcal)
              cal(k+1,jv) = aimag(zcal)
              cal(k+2,jv) = data(k+2,jv)*wg
            enddo
          endif
        endif
        iv = iv+1
        if (iv.gt.nvis) exit
        t = times(iv)
        jv = index(iv)
        ! print *, iv, jv, t-tgold
      enddo
      if (iv.gt.nvis) exit
      tgold = tg
      zgain = 0.0
    endif
    !
    ! Always fill the baseline gain array (even if new time !)
    ia = nint(gain(6,jvg))
    ja = nint(gain(7,jvg))
    zgain(ia,ja) = 0.0       ! Although already done just above
    !
    ! Sign of weight gain(10,jvg) indicates if there is a solution
    if (gain(10,ivg).gt.0) then
      ampli = sqrt(gain(8,jvg)**2+gain(9,jvg)**2)
      phase = atan2(gain(9,jvg),gain(8,jvg))
      if (ampli.ne.0) then
        !
        ! Correct (a fraction of) the phase
        phase = phase_gain*phase
        zg = cmplx(cos(phase),sin(phase))
        !
        ampli = 1d0-ampli_gain+ampli*ampli_gain
        zg = ampli*zg
        !
        ! Fill both baseline directions...
        zgain(ia,ja) = zg
        zgain(ja,ia) = conjg(zg)
      endif
    endif
    !            type *, ia, ja, zGAIN(IA,JA)
  enddo
  !
  kv = sum(flagged)
  if (do_flag) then
    do iv = 1,nvis
      if (flagged(iv).ne.0) then
        !! Print *,'Visi ',iv,' not calibrated'
        cal(8:3*ndc+7,iv) = 0.0
      endif
    enddo
  endif
  !
  if (kv.eq.0) then
    write(mess,'(A,I0,A)') 'Calibrated all ',nvis-kv,' visibilities'
    isev = seve%i
  else if (do_flag) then
    write(mess,'(A,I0,A,I0,A)') 'Calibrated ',nvis-kv,', flagged ',kv, &
      & ' visibilities'
    isev = seve%w
  else
    write(mess,'(A,I0,A,I0,A)') 'Calibrated ',nvis-kv,', kept ',kv, &
      & ' visibilities'
    isev = seve%w
  endif
  call map_message(isev,rname,mess)
end subroutine sub_uvcal
