subroutine solve_gain(line,error)
  use gildas_def
  use gkernel_interfaces
  use image_def
  use gbl_format
  use gbl_message
  use imager_interfaces, except_this => solve_gain
  use clean_def
  use clean_arrays
  !---------------------------------------------------------------------
  ! @ private
  !
  ! IMAGER
  !     S.Guilloteau & V.Pietu, from R.Lucas CLIC code
  !
  ! Support for command
  !   SOLVE Time SNR [Reference] 
  !       /MODE [Phase|Amplitude] [Antenna|Baseline] [Flag|Keep]
  !
  ! Compute Gains by comparing the UV data and the UV model.
  ! Input : a UV data (observed)
  !         a UV model
  ! Output: a UV table, with the gains.
  !         a UV self-calibrated table
  !---------------------------------------------------------------------
  character(len=*), intent(in) :: line
  logical, intent(inout) :: error
  !
  ! Local
  integer, parameter :: mant=256  ! Valid for ALMA, VLA and most others.
  integer, parameter :: mbas=mant*(mant-1)/2
  character(len=*), parameter :: rname='UV_GAIN'
  integer(4) ::  i, n, narg, ichan, nvis, ncol, ier
  !
  character(len=filename_length) :: uvdata, uvmodel, uvgain, uvcal, &
    & uvsol, name   ! File names
  real :: tinteg    ! Integration time
  real :: snr       ! Minimum SNR for a solution
  real :: snr_min   ! Minimum SNR for correction of Amplitude gains
  real :: snr_scale ! Noise scaling factor - 
  integer :: refant ! Reference antenna (0 = automatic)
  logical :: flag   ! Flag data with no solution
  logical :: do_amp ! Self calibrate amplitude
  logical :: do_pha ! Self calibrate phase
  logical :: antenna_based ! Antenna based self calibration
  !
  integer, allocatable :: index(:)  ! Sorting index (by time)
  real(8), allocatable :: itime(:)  ! Times of observations
  real, pointer :: basegain(:,:), antegain(:,:) ! Gain arrays
  integer :: ntimes   ! Number of different times in data
  integer :: nantes   ! Maximum number of antennas in data
  !
  real :: scale_gain, scale_ante
  integer :: iv
  !
  integer, parameter :: mmode=6
  integer :: nmode, conflict(mmode)
  logical :: has_mode(mmode)
  character(len=12) :: smode(mmode), mode, argum
  data smode /'AMPLITUDE','ANTENNA','BASELINE','FLAG','KEEP','PHASE'/
  data conflict/6,3,2,5,4,1/
  !
  ! Code
  uvsol = 'test.tab'  ! To be modified SG
  !
  snr_min = 1.5
  snr_scale = sqrt(2.0) ! should be 1.0, but ALMA seem to require something different
  call sic_get_real('SELF_SNOISE',snr_scale,error)
  !
  call sic_r4(line,0,1,tinteg,.true.,error)
  if (error) return
  !
  snr = 6.0
  call sic_r4(line,0,2,snr,.false.,error)
  if (error) return
  !
  refant = 0
  ichan = 0
  !
  ! Set defaults: PHASE ANTENNA KEEP 
  do_pha = .true.
  antenna_based = .true.
  flag = .false.
  !
  narg = sic_narg(1)
  has_mode(:) = .false.
  do i=1,narg
    call sic_ke(line,1,i,argum,n,.true.,error)
    call sic_ambigs (rname,argum,mode,n,smode,mmode,error)
    if (error) return
    !
    if (has_mode(conflict(n))) then
      call map_message(seve%e,rname,'Conflicting keywords '//mode// &
      & ' and '//smode(conflict(n)))
      error = .true.
      return
    endif
    has_mode(n) = .true.
    select case (mode)
    case ('AMPLITUDE')
      do_pha = .false.
    case ('BASELINE')
      antenna_based = .false.
    case ('FLAG') 
      flag = .true.
    end select
  end do
  !
  ! For the time being, do not allow Phase and Amplitude at once.
  do_amp = .not.do_pha
  !
  if (hraw%loca%size.eq.0) then
    call map_message(seve%e,rname,'HRAW not initialized, Use UV_MAP /SELF once')
    error = .true.
    return
  endif
  nvis = hraw%gil%dim(2)
  ncol = hraw%gil%dim(1)
  ichan = 1         ! We use the only channel
  !
  ! Check size of MODEL in "huvm"
  !
  if (.not.allocated(duvm)) then
    call map_message(seve%e,rname,'MODEL is not allocated')
    error = .true.
    return
  endif
  !
  ! Prepare output gain table : in "cgains" and "agains"
  call sic_delvariable ('CGAINS',.false.,error)
  if (allocated(duvbg)) deallocate(duvbg,stat=ier)
  call gildas_null(hbgain, type = 'UVT')
  call gdf_copy_header (hraw, hbgain, error)
  !
  call sic_delvariable ('AGAINS',.false.,error)
  call gildas_null(hagain) 
  !
  if (antenna_based) then
    allocate (index(nvis), itime(nvis), &
      & duvbg(10,nvis),basegain(10,nvis), stat=ier)
      antegain => duvbg
  else
    allocate (index(nvis), itime(nvis), &
      & duvbg(10,nvis),stat=ier)
      basegain => duvbg
  endif
  if (ier.ne.0) then
    call map_message(seve%e,rname,'Cannot allocate gain arrays')
    error = .true.
    return
  endif
  !
  ! Get baseline-based gains ...
  call do_base_gain(do_amp,do_pha,nvis,ncol,ichan,itime,   &
     &    index,duvraw,duvm,basegain)
  !
  if (antenna_based) then
    !
    ! Compute antenna-based gains ...
    call do_ante_gain(do_amp,do_pha,nvis,itime,tinteg,snr,   &
     &      basegain, antegain, refant, ntimes, nantes,      &
     &      snr_min, snr_scale, flag, error)
    if (error) then
      call map_message(seve%e,rname,'No self calibration solution')
      return
    endif
    ! 
    ! Prepare the plot
    call gdf_copy_header (hraw, hagain, error)
    call do_get_cgain(ntimes,nantes,hagain,dagain,refant,scale_ante,error)
    hagain%char%unit = '(none)'
    hagain%char%code(1) = 'TIME'
    hagain%gil%xaxi = 0
    hagain%gil%yaxi = 0
    hagain%gil%faxi = 0
    !
    ! Re-normalize the gains if amplitude
    if (do_amp) then
      call do_normalize_v(10,nvis,duvbg,scale_gain)
      write(name,'(A,F8.3,A,F8.3,A)') 'Re-scaled by ',scale_gain,' (or by antennas: ',scale_ante,')'
      call map_message(seve%i,rname,name)
      scale_ante = scale_gain**2     ! Weight factor
      scale_gain = 1.0/scale_gain    ! Baseline gain factor
      do iv=1, nvis
        duvbg(8:9,iv) = duvbg(8:9,iv) * scale_gain
        duvbg(10,iv) = scale_ante * duvbg(10,iv)
      enddo
      scale_ante = sqrt(scale_gain)  ! Antenna gain factor
      do iv=1,nantes
        dagain(:,2+3*iv) = dagain(:,2+3*iv)*scale_ante 
      enddo
    else
      scale_gain = 1.0
    endif
    !
    hagain%loca%size = hagain%gil%dim(1)*hagain%gil%dim(2)
    call sic_mapgildas ('AGAINS',hagain,error,dagain)
  endif
  !
  ! Fill in calibrated table
  call do_apply_cal(ncol,1,nvis,duvraw,duvself,duvbg,flag,index)
  !
  ! Define CGAINS variable - Remember to remove trailing columns
  ! if any...
  hbgain%gil%dim(1) = 10
  if (hbgain%gil%ntrail.gt.0) then
    do i=1,code_uvt_last
      if (hbgain%gil%column_pointer(i).gt.hbgain%gil%dim(1)) then
        call map_message(seve%i,rname,'Found column '//uv_column_name(i))
        hbgain%gil%column_size(i) = 0
        hbgain%gil%column_pointer(i) = 0
      endif
    enddo
    hbgain%gil%ntrail = 0
  endif
  hbgain%loca%size = hbgain%gil%dim(1)*hbgain%gil%dim(2)
  hbgain%gil%nchan = 1
  hbgain%gil%nvisi = nvis
  hbgain%gil%nstokes = 1
  call gdf_setuv(hbgain,error)
  !
  call sic_mapgildas ('CGAINS',hbgain,error,duvbg)
  call message_colour(2)
  call map_message(seve%i,rname,'Successful completion')
  call message_colour(-1)
end subroutine solve_gain
!
subroutine do_apply_cal(ncol,nch,nvis,data,cal,gain,flag,index)
  !---------------------------------------------------------------------
  ! @ public
  !
  ! IMAGER command SOLVE
  ! Task UV_GAIN
  !
  !     Apply Gain Table to input UV data set
  !
  ! Index is the ordering of the gain. Gain(i) applies to Visi(Index(i))
  !---------------------------------------------------------------------
  integer, intent(in) :: ncol                   ! Number of column in visi
  integer, intent(in) :: nvis                   ! Number of visibilities
  integer, intent(in) :: nch                    ! Number of channels
  real, intent(in) :: data(ncol,nvis)           ! Raw data
  real, intent(out) :: cal(ncol,nvis)           ! Calibrated data
  real, intent(in) :: gain(10,nvis)             ! Gain array
  logical, intent(in) :: flag                   ! Flag data with no solution
  integer, intent(in) :: index(nvis)            ! Visibility order
  ! Local
  integer :: iv   ! Gain index
  integer :: jv   ! Visibility index
  integer :: k    ! position in visibility 
  complex :: zdata, zgain, zcal
  !-----------------------------------------------------------------------
  do iv=1, nvis
    jv = index(iv)
    do k=1, 7
      cal(k,jv) = data(k,jv)
    enddo
    zgain = cmplx(gain(8,iv),gain(9,iv))
    if (gain(10,iv).lt.0) then
      zgain = 0
    endif
    do k=8, 5+3*nch, 3
      if (zgain.ne.0) then
        zdata = cmplx(data(k,jv),data(k+1,jv))
        zcal = zdata / zgain
        cal(k,jv) = real(zcal)
        cal(k+1,jv) = aimag(zcal)
        cal(k+2,jv) = data(k+2,jv)*abs(zgain)**2
      else
        cal(k,jv) = data(k,jv)
        cal(k+1,jv) = data(k+1,jv)
        cal(k+2,jv) = data(k+2,jv)
        if (flag) cal(k+2,jv) = -abs(cal(k+2,jv))
      endif
    enddo
    if (8+3*nch.le.ncol) then
      cal(8+3*nch:ncol,jv) = data(8+3*nch:ncol,jv)
    endif
  enddo
end subroutine do_apply_cal
!
subroutine do_ante_gain(do_amp,do_pha,nvis,times,tinteg,snr, &
  & basegain,antegain,refant,ntimes,nantes,smin,scal,flag,error)
  use gildas_def
  use gbl_message
  !---------------------------------------------------------------------
  ! @ public
  !
  ! IMAGER command SOLVE
  ! Task UV_GAIN
  !
  !     S.Guilloteau & V.Pietu, derived from R.Lucas CLIC code
  !
  !   Compute complex gains (antenna-based solution) from a set
  !   of initial Antenna gains, smoothing in time as needed.
  !
  !   The initial Antenna gains must be sorted by increasing time
  !---------------------------------------------------------------------
  logical, intent(in)  :: do_amp                 ! Calibrate amplitude ?
  logical, intent(in)  :: do_pha                 ! Compute phase ?
  integer, intent(in)  :: nvis                   ! Number of visibilities
  real(8), intent(in)  :: times(nvis)            ! Times of visibilities
  real, intent(in)  :: tinteg                    ! Integration time
  real, intent(in)  :: snr                       ! requested Signal to Noise 
  real, intent(in)  :: basegain(10,nvis)         ! Input baseline gain array
  real, intent(inout)  :: antegain(10,nvis)      ! Output antenna gain array
  integer, intent(in) :: refant                  ! Reference antenna
  integer, intent(out) :: ntimes                 ! Number of time steps
  integer, intent(out) :: nantes                 ! Number of antennas
  real, intent(in) :: smin  ! Min SNR for de-biasing
  real, intent(in) :: scal  ! Scale factor for SNR de-biasing 
  logical, intent(in) :: flag                    ! Flag wrong solutions ?
  logical, intent(out) :: error                  ! In case nothing left ...
  ! Global
  character(len=*), parameter :: rname='UV_GAIN'
  real(8), parameter :: pi=3.14159265358979323846d0
  ! Maximum Size of problem
  ! ALMA uses stations rather than antennas
  integer, parameter :: mant=256  
  integer, parameter :: mbas=mant*(mant-1)/2
  ! Local
  character(len=256) :: mess
  real(8) ::  t, told
  real :: ampli, phase, ug, vg, d2, dmin, maxsnr,minsnr
  integer ::  iref, iv, jv, ia, ja, ib, i, nant, nbas, j, k, nant_old
  integer ::  lia, lja, igood, isol, iflag
  integer :: ibad, kbad, icount, itest, vgood, vbad, sever
  logical :: err, ok
  !
  integer ::  al(mant)  !Physical number of Sequential number
  integer ::  la(mant)  !Sequential number of Physical number
  real :: ua(mant), va(mant), ampsnr(mant)
  real(8) ::  ca(mant), cp(mant), wp(mant)
  real(8) ::  wk2(mant,mant), wk3(mant)
  logical :: isbad(mant)
  integer :: jbad(mant)
  !
  integer ::  iant(mbas), jant(mbas)      ! Start & End antenna of baseline
  real(8) ::  x(mbas), y(mbas), w(mbas), amp(mbas), pha(mbas), wa(mbas), ss(mbas)
  ! For debug only
  integer ::  lpairs(mant), lpair(mant,mant),   array(mant), indx(mant) 
  integer :: iunit
  !-----------------------------------------------------------------------
  !
  error =.false.
  err = .false.
  !
  iunit = 4
  open(unit=iunit,file='selfcal.tmp',status='unknown')
  rewind(unit=iunit)
  !
  nbas = 0
  igood = 0
  isol = 0
  vgood = 0
  vbad = 0
  do j=2, mant
    do i=1, j-1
      nbas = nbas+1
      iant(nbas) = i
      jant(nbas) = j
    enddo
  enddo
  !
  ! The algorithm will find a better value for ref antenna,
  ! the one nearest to the array center.
  iref = refant
  !
  ! Loop on visibilities
  !
  told = -1d10  ! An impossibly old time...
  ntimes = 0
  nantes = 0
  do iv=1, nvis
    t = times(iv)
    !
    ! Time change ?
    if (told.ne.t) then
      !
      ! Identify a new time range
      ntimes = ntimes+1
      !Print *,'New output time ',iv,told,t,ntimes
      told = t
      nant_old = 0
      jv = iv
      !
      ! Find starting visibility < Told-Tinteg/2
      do while (jv.gt.1 .and. t .ge. told-tinteg/2)
        jv = jv - 1
        t = times(jv)
      enddo
      la = 0
      ca = 0.0
      cp = 0.0
      x = 0.0
      y = 0.0
      w = 0.0
      !
      ! Search how many antennas at this time, and average
      ! over all visibilities which fit the time range
      !
      ok = (jv.lt.nvis .and. t.le.told+tinteg/2.)
      lpairs = 0
      lpair  = 0
      nant = 0
      do while (ok)
        !
        ! Only Select the UN-FLAGGED data
        !
        if (basegain(10,jv).gt.0.0) then
          !
          ! Build the antenna pointer list "la" and "al"
          !
          ! In the end, we use this formula...
          !    ia = la(nint(basegain(6,iv)))
          !    ja = la(nint(basegain(7,iv)))
          ! which figures out which sequence number is each antenna
          !
          ia = nint(basegain(6,jv))
          if (la(ia).eq.0) then
            nant = nant+1
            la(ia) = nant
            al(nant) = ia ! The reverse pointer
          endif
          ja = nint(basegain(7,jv))
          if (la(ja).eq.0) then
            nant = nant+1
            la(ja) = nant
            al(nant) = ja
          endif
          !
          !! Build the antenna pairs (for debug only)
          !! lpairs(la(ia)) = lpairs(la(ia))+1
          !! lpair(lpairs(la(ia)),la(ia)) = la(ja)
          !!
          !! lpairs(la(ja)) = lpairs(la(ja))+1
          !! lpair(lpairs(la(ja)),la(ja)) = la(ia)        

          ! Here we set in UA,VA the "Antenna" U,V coordinate
          ! relative to Antenna #1
          !   Note: we do not average UA,VA over time since it
          !   is only used to determine the Reference antenna,
          !   a nearly irrelevant number.
          lia = la(ia)
          lja = la(ja)
          if (lia.eq.1) then
            ua(lja) = basegain(1,jv)
            va(lja) = basegain(2,jv)
          elseif (lja.eq.1) then
            ua(lia) = -basegain(1,jv)
            va(lia) = -basegain(2,jv)
          endif
          !
          ! Here we average the visibility into the X,Y,W buffer
          ! we also set start antenna < end antenna
          if (lia.eq.lja) then
            Print *,'Ignoring autocorrelation for ',lia,al(lia)
          else
            if (lia.lt.lja) then
              ib = (lja-1)*(lja-2)/2+lia
              y(ib) = y(ib) + basegain(9,jv)*basegain(10,jv)        
            else !! if (lja.lt.lia) then
              ib = (lia-1)*(lia-2)/2+lja
              y(ib) = y(ib) - basegain(9,jv)*basegain(10,jv)
            endif
            x(ib) = x(ib) + basegain(8,jv)*basegain(10,jv)
            w(ib) = w(ib) + basegain(10,jv)
          endif
          !
        endif  ! End selection of Un-Flagged data
        !
        jv = jv + 1
        t = times(jv)
        ok = (jv.lt.nvis .and. t.le.told+tinteg/2.)
      enddo
      !
      ! get the reference antenna, by locating the one
      ! with the shortest baselines
      !
      nbas = nant*(nant-1)/2
      !
      ! Compute the centroid of antenna positions (still relative to Antenna #1)
      ug = 0
      vg = 0
      do ia=1, nant
        ug = ug+ua(ia)
        vg = vg+va(ia)
      enddo
      ug = ug/nant
      vg = vg/nant
      dmin = 1e10
      !
      ! Locate the antenna closest to centroid (this is independent of absolute pos.)
      iref = 1
      do ia=1, nant
        d2 = (ua(ia)-ug)**2 + (va(ia)-vg)**2
        if (d2.lt.dmin) then
          dmin = d2
          iref = ia
        endif
      enddo
      !
      ! This is wrong if antenna renumbering occured
      ! It should be 
      !       la(iref) = refant
      if (refant.ne.0) iref = refant
      !
      ! Check if any antenna has no closure 
      ibad = 0
      do lia=1,nant
        icount = 0
        do lja=1,nant
          if (lia.ne.lja) then
            if (lia.lt.lja) then
              ib = (lja-1)*(lja-2)/2+lia
            else !! if (lja.lt.lia) then
              ib = (lia-1)*(lia-2)/2+lja
            endif
            if (w(ib).ne.0) then
              icount = icount+1
            endif
          endif
        enddo
        if (icount.lt.2) then
          Print *,'Antenna Seq.',lia,' (Phys. ',al(lia),') has no closure'
          ibad = ibad+1
          jbad(ibad) = lia
          isbad(lia) = .true.
        else
          isbad(lia) = .false.
        endif
      enddo
      !
      if (ibad.eq.nant) then
        Print *,'No antenna can be calibrated at this time'
      else if (ibad.ne.0) then
        Print *,ibad,' antennas with no solution'
      endif
      !
      ! Normalize the time averaged complex gains 
      do ib=1, nbas
        if (w(ib).ne.0) then
          x(ib) = x(ib)/w(ib)
          y(ib) = y(ib)/w(ib)
        endif
      enddo
      !
      !
      ! Here, normally, each antenna should have at least
      ! 2 baselines, otherwise it is not possible...
      !
      if (ibad.ne.nant) then
        ! Solve for amplitude first to estimate S/N ratio
        ! Use an intermediate weight array "wa" for this
        do ib=1, nbas
          if (w(ib).ne.0) then
            amp(ib) = log(x(ib)**2+y(ib)**2)/2.
            wa(ib)  = w(ib)*(x(ib)**2+y(ib)**2)
          else
            wa(ib) = 0.0
          endif
        enddo
        call gain_ant(1, nbas, iant, jant, iref,   &
     &          nant, amp, wa, wk2, wk3, ss, ca, wp, err)
        !
        do ia = 1, nant
          isol = isol + 1
!
! We should NOT overwrite WA here -- we can compute the SNR directly            
!            aa(ia) = exp(2*ca(ia))
!            wa(ia) = wp(ia)/aa(ia)**2
!            ampsnr(ia) = aa(ia)*sqrt(wa(ia))*1e3
! so directly
!            ampsnr(ia) = aa(ia) * sqrt(wp(ia)/aa(ia)**2)) *1e3
! which is
          ampsnr(ia) = sqrt(wp(ia)) * 1e3 ! The 1e3 is because of MHz unit
          !!Print *,'ia ',ia,wp(ia),ampsnr(ia)
          if (isbad(ia)) ampsnr(ia) = 0.0 !S.Guilloteau
          !
        enddo
        maxsnr = maxval(ampsnr(1:nant))
        minsnr = maxsnr
        do ia = 1, nant
          if (ampsnr(ia).ne.0) minsnr = min(minsnr,ampsnr(ia))
        enddo
      else
        maxsnr = 0.0
        minsnr = 0.0
      endif
      !
      if (maxsnr.gt.snr) then
        ! phases
        if (do_pha) then
          !
          ! If enough SNR, solve for the Phases for the good
          ! antennas. Use the initial weights "w" here.
          do ib=1, nbas
            if (w(ib).ne.0) then
              pha(ib) = atan2(y(ib),x(ib))
              !
              ! 1-Mar-2018 S.Guilloteau
              ! Normally, the phase error in radian is the Noise to Signal ratio,
              ! so the weight of that phase should be  (Signal/Noise)^2
              ! i.e. wa(ib) = (x(ib)^2+y(ib)^2) * w(ib)
              ! since w(ib) is the 1/Noise^2 for the (real, imaginary) parts,
              ! i.e. like used above for the Amplitude
              !
            else
              pha(ib) = 0.0
            endif
          enddo
          call gain_ant(2, nbas, iant, jant, iref,   &
     &            nant, pha, w, wk2, wk3, ss, cp, wp, err)
          iflag = 0
          !
          ! Reset amplitude to 1 now
          ca(1:nant) = 1.0
          !
        else if (do_amp) then
          ! Here, we should check that each antenna should have at least
          ! 3 baselines, otherwise it is not possible...
          !
          ! Here, we use the raw initial weights also, not the SNR weights
          ! or if we should use the SNR weights, it is already solved...
          call gain_ant(1, nbas, iant, jant, iref,   &
     &          nant, amp, w, wk2, wk3, ss, ca, wp, err)
          iflag = 0
          !
          ! Go back to Gain factors instead of their Log
          ca(1:nant) = exp(ca(1:nant))
          !
          ! De-bias from the noise < 6 sigma 
          !   
          ! The factor SCAL is  because of the convention of 
          ! the SNR (per antenna vs per baseline ?...)
          where (ampsnr.ge.smin)  
            ca(1:nant) = ca(1:nant) - 0.5*(scal/ampsnr(1:nant))**2
          end where
          !
          ! Reset Phase to Zero now
          cp(1:nant) = 0
        endif
        !
        do ia =1, nant
          !
          ! Keep only antenna solution with required snr
          if (ampsnr(ia).lt.snr) then
            cp(ia) = 0.0      ! Set phase correction to Zero
            ca(ia) = 1.0      ! Set amplitude correction to 10^0 = 1
            itest = 0
            !
            ! Check whether this antenna was already expected
            ! to be without solution or not.
            do kbad=1,ibad
              if (jbad(kbad).eq.ia) then
                !!Print *,'** OK ** NO Solution for flagged antenna ',ia,al(ia)
                itest = kbad
                exit
              endif
            enddo
            if (itest.eq.0) then
              Print *,'** Warning *** Flagged one more antenna ',ia,al(ia)
              isbad(ia) = .true.
            endif
            iflag = iflag+1
          else
            ! This was happening when AMPSNR was not set to Zero for
            ! antennas with no closure.
            !do kbad=1,ibad
            !  if (jbad(kbad).eq.ia) then
            !    Print *,'** Warning *** Solution for flagged antenna ',ia,al(ia)
            !    Print *,' Amp SNR ',ampsnr(ia),snr,aa(ia),wa(ia)
            !    exit
            !  endif
            !enddo
            igood = igood + 1
          endif
        enddo
      else 
        isbad(1:nant) = flag   ! Flag antennas if asked for...
        ca(1:nant) = 1.0 ! Insufficient SNR, reset Amplitude
        cp(1:nant) = 0.0 !    and Phase gain
        iflag = nant
      endif
      !
      if (iflag.ne.0) then
        write(mess,100) told,iref,maxsnr,minsnr,iflag
      else
        write(mess,100) told,iref,maxsnr,minsnr
      endif
      !!Print *,'SNR range ',minsnr,maxsnr
100   format('Time ',F16.1,' Ref ',i3,' SNR: Max ',F7.1,' Min ',F7.1,I5,' antennas ignored')
      call map_message(seve%i,rname,mess)
      !
      write(iunit,*) iref,told,nant  ! Reference antenna
      write(iunit,102) al(1:nant)    ! Antenna list
      write(iunit,104) ca(1:nant)
      write(iunit,101) cp(1:nant)*180.0/pi
      write(iunit,103) ampsnr(1:nant)
      !
101   format (8(2x,f9.3))
102   format(16(1x,i3))
103   format (8(1x,f9.3))
104   format (8(1x,f10.4))
      nantes = max(nantes,nant)
      !
      !!Print *,'BAD ',isbad(1:nant)
!!      Print *,'Solving for IV ',iv,nvis
!!    else
!!      Print *,'Just Filling IV ',iv,nvis
    endif
    !
    ! Fill in the antenna gains in "antegain"
    do k=1,7
      antegain(k,iv) = basegain(k,iv)
    enddo
    ia = la(nint(basegain(6,iv)))
    ja = la(nint(basegain(7,iv)))
    ampli =   ca(ia) * ca(ja)     ! After trial, this  
    phase = - cp(ia) + cp(ja)     ! is THE solution
    !! Print *,'IV ',ampli, 180*phase/3.14159
    antegain(8,iv) = ampli * cos(phase)
    antegain(9,iv) = ampli * sin(phase)
    !
    ! Flag data with no solution
    !! Print *,'IV ',iv,' IA ',ia,isbad(ia),' JA ',ja,isbad(ja)
    if (isbad(ia).or.isbad(ja)) then
       antegain(10,iv) = -abs(basegain(10,iv))
       vbad = vbad+1
    else
       antegain(10,iv) = basegain(10,iv)
       vgood = vgood+1
    endif
  enddo
  !
  ! Return an error if not enough good visibilities or no solution
  if (igood.eq.0) then
    sever = seve%e
    error = .true.
  else
    sever = seve%i
  endif
  write(mess,'(A,I0,A,I0,A)') "Found ",igood,"/",isol," good solutions"
  call map_message(sever,rname,mess)
  if (vgood.lt.100) then
    sever = seve%e
    error = .true.
  else
    sever = seve%i
  endif
  write(mess,'(A,I0,A,I0,A)') "Retained ",vgood," valid visibilities, ", &
    vbad," flagged ones"
  call map_message(sever,rname,mess)
end subroutine do_ante_gain
!
subroutine do_base_gain(do_amp,do_pha,nvis,ncol,icol,times,index,   &
     &    data,model,gain)
  !---------------------------------------------------------------------
  ! @ public
  !
  ! IMAGER command SOLVE
  !   developped from Task UV_GAIN
  !
  !     S.Guilloteau & V.Pietu, from R.Lucas CLIC code
  !
  !   Compute the Baseline-Based Gain by comparing the Data
  !   to the Model, retaining either Amplitude or Phase
  !   (or both, but this is not used by the calling routines so far)
  ! 
  !   We use channel Icol from Data table for the Data.
  !   Model and Gain are assumed to be continuum (i.e. single-channel)
  !   tables.
  !   Gain will contain the observed baseline gains, in an increasing 
  !   time order.
  !   Times is a Real(8) array to sort out date/time 
  !   Index is an integer array yielding the ordering
  !     gain(i) = data/model (Index(i))
  !---------------------------------------------------------------------
  logical, intent(in) :: do_amp                 ! Calibrate amplitude
  logical, intent(in) :: do_pha                 ! Calibrate phase
  integer, intent(in) :: nvis                   ! Number of visibilities
  integer, intent(in) :: ncol                   ! Size of a visibility
  integer, intent(in) :: icol                   ! Reference column
  real(8), intent(out) :: times(nvis)           ! Time stamps of visibilities
  integer, intent(out) :: index(nvis)           ! Index of visibilities
  real, intent(in) :: data(ncol,nvis)           ! Raw visibilities
  real, intent(in) :: model(10,nvis)            ! Modeled visibilities
  real, intent(out) :: gain(10,nvis)            ! Gain solution
  ! Local
  logical :: error
  ! Local:
  integer :: iv, i, jv, k
  complex :: zgain, zdata, zmodel
  real :: wgain, wdata, again, date0
  !-----------------------------------------------------------------------
  !
  ! Get the chronological order:
  date0 = data(4,1)
  do iv=1, nvis
    ! Beware of Real(8) precision ...
    times(iv) = (data(4,iv)-date0)*86400.d0+data(5,iv)  
  enddo
  call gr8_trie (times,index,nvis,error)
  !
  ! Sorted data in gain:
  do iv=1,nvis
    jv = index(iv)
    do i=1, 7
      gain(i,iv) = data(i,jv)
    enddo
    k = (icol-1)*3+7
    zdata = cmplx(data(k+1,jv),data(k+2,jv))
    wdata = data(k+3,jv)
    zmodel = cmplx(model(8,jv),model(9,jv))
    if (zmodel.ne.0) then
      zgain = zdata/zmodel
      wgain = wdata*abs(zmodel)**2
      if (.not.do_amp) then
        again = abs(zmodel)
        ! Here Zgain = Zdata modified by a phase factor .
        ! If we have a good model of the data, Zgain will
        ! have module of order Unity
        zgain = zgain*again 
        wgain = wdata
      else  ! if (.not.do_pha) then
        ! Even if we are only interested in the Amplitude gain,
        ! we cannot use a simple Amplitude factor, as it is
        ! a biased estimator of this amplitude gain. Hence, 
        ! it does not average properly with time.
        ! 
        ! So we keep the Zgain as it is, without any correction
        ! and with its default weight Wgain
        !
        ! Using the Phase correction term or only the Amplitude
        ! correction term is deferred to the do_ante_gain 
        ! routine, or to a time averaging routine, which
        ! does not yet exist (as of 05-May-2018). 
      endif
    else
      zgain = 0. ! It can be anything, since Wgain is Zero
      wgain = 0.
    endif
    gain(8,iv) = real(zgain)
    gain(9,iv) = aimag(zgain)
    gain(10,iv) = wgain
  enddo
end subroutine do_base_gain
!
subroutine gain_ant(iy,nbas,iant,jant,iref,nant,y,w,wk2,wk3,ss,c,wc,error)
  use gkernel_interfaces
  use gbl_message
  !---------------------------------------------------------------------
  ! @ public
  !
  ! IMAGER command SOLVE
  ! Task UV_GAIN
  !
  !     S.Guilloteau & V.Pietu, from R.Lucas CLIC code
  !
  ! gain_ant 
  !     computes a weighted least-squares approximation
  !     to the antenna amplitudes or phases
  !     for an arbitrary set of baseline data points.
  !---------------------------------------------------------------------
  integer, intent(in) :: iy                ! 1 for log(amplitude), 2 for phase
  integer, intent(in) :: nbas              ! the number of baselines
  integer, intent(in) :: iant(nbas)        ! start antenna for each baseline
  integer, intent(in) :: jant(nbas)        ! end  antenna for each baseline
  integer, intent(in) :: iref              ! Reference antenna for phases
  integer, intent(in) :: nant              ! the number of antennas
  real(8), intent(in) :: y(nbas)           ! the data values
  real(8), intent(in) :: w(nbas)           ! weights
  real(8), intent(inout) :: wk2(nant,nant) ! work space
  real(8), intent(inout) :: wk3(nant)      ! work space
  real(8), intent(out) :: ss(nbas)         ! rms of fit for each baseline
  real(8), intent(out) :: c(nant)          ! the gains
  real(8), intent(out) :: wc(nant)         ! the weights
  logical, intent(out) :: error            !
  ! Global
  integer, external :: zant
  character(len=*), parameter :: rname='GAIN_ANT'
  ! Local
  real(8) :: norm, tol
  !
  parameter (tol=1d-14)
  integer :: i, ia, ib, nantm1, ja, l, iter, ier
  real(8) ::  wi, ww, yi
  !------------------------------------------------------------------------
  ! Code
  !
  ss = 0.
  !
  ! Check that the weights are positive.
  !
  error = .false.
  do ib = 1, nbas
    if (w(ib).lt.0.0d0) then
      call map_message(seve%e,rname,'Weights not positive')
      error = .true.
      return
    endif
  enddo
  !
  ! Amplitude case is simple...
  !
  if (iy.eq.1) then
    wk2 = 0.0d0
    wk3 = 0.0d0
    !
    ! store the upper-triangular part of the normal equations in wk2
    ! and the right-hand side in wk3.
    do ib=1,nbas
      wi = w(ib)
      if (wi.gt.0) then
        ia = iant(ib)
        ja = jant(ib)
        wk2(ia,ia) = wk2(ia,ia)+wi
        wk2(ia,ja) = wk2(ia,ja)+wi
        wk2(ja,ia) = wk2(ja,ia)+wi
        wk2(ja,ja) = wk2(ja,ja)+wi
      endif
    enddo
    do ib=1, nbas
      ia = iant(ib)
      ja = jant(ib)
      wi = w(ib)*y(ib)
      wk3(ia) = wk3(ia) + wi
      wk3(ja) = wk3(ja) + wi
    enddo
    !
    ! Solve the system of normal equations by first computing the Cholesky
    ! factorization
    call mth_dpotrf ('GAIN_ANT','U',nant,wk2,nant,error)
    if (error) return
    call mth_dpotrs ('GAIN_ANT','U',nant,1,wk2,nant,wk3,nant,ier)
    if (ier.ne.0) return
    do i=1,nant
      c(i) = wk3(i)
      wc(i) = wk2(i,i)**2
    enddo
    !
    ! Phase is more complicated ...
  elseif (iy.eq.2) then
    nantm1 = nant-1
    do i=1,nant
      c(i) = 0.0d0
      wc(i) = 0.0d0
    enddo
    !
    ! start iterating
    norm = 1e10
    iter = 0
    do while (norm.gt.tol .and. iter.lt.100)
      iter = iter + 1
      do i=1,nantm1
        do l=1,nantm1
          wk2(l,i) = 0.0d0
        enddo
        wk3(i) = 0.0d0
      enddo
      do ib=1,nbas
        wi = w(ib)
        if (wi.gt.0) then
          ia = zant(iant(ib),iref)
          ja = zant(jant(ib),iref)
          if (ia.ne.0) then
            wk2(ia,ia) = wk2(ia,ia)+wi
          endif
          if (ja.ne.0) then
            wk2(ja,ja) = wk2(ja,ja)+wi
          endif
          if (ia.ne.0 .and. ja.ne.0) then
            wk2(ja,ia) = wk2(ja,ia)-wi
            wk2(ia,ja) = wk2(ia,ja)-wi
          endif
        endif
      enddo
      do ib=1, nbas
        if (w(ib).gt.0) then
          yi = y(ib)
          ia = iant(ib)
          ja = jant(ib)
          yi = yi+(c(ia)-c(ja))
        else
          yi = 0
        endif
        yi = sin(yi)
        ia = zant(iant(ib),iref)
        ja = zant(jant(ib),iref)
        wi = w(ib)*yi
        if (ia.ne.0) then
          wk3(ia) = wk3(ia) - wi
        endif
        if (ja.ne.0) then
          wk3(ja) = wk3(ja) + wi
        endif
      enddo
      !
      ! Solve the system of normal equations by first computing the Cholesky
      ! factorization
      call mth_dpotrf('GAIN_ANT','U',nantm1,wk2,nant,error)
      if (error) return
      call mth_dpotrs ('GAIN_ANT','U',nantm1,1,wk2,nant,   &
     &        wk3,nantm1,ier)
      if (ier.ne.0) return
      !  Add the result to c:
      norm = 0
      do ia=1,nant
        i = zant(ia,iref)
        if (i.ne.0) then
          ww = wk3(i)
          c(ia) = c(ia)+ww
          wc(ia) = wk2(i,i)**2
          norm = norm+ww**2
        endif
      enddo
    enddo
  endif
  !
end subroutine gain_ant
!
function zant(i,r)
  !
  ! Return the apparent number of Antenna #i when reference
  ! antenna is #r. Since #r is not in the list of antennas for
  ! which a solution is to be searched, this number
  ! is #i for #i < #r, and #i-1 for #i > #r
  !
  integer :: zant                   ! intent(out)
  integer, intent(in) :: i          !
  integer, intent(in) :: r          !
  if (i.eq.r) then
    zant = 0
  elseif (i.gt.r) then
    zant = i-1
  else
    zant = i
  endif
  return
end function zant
!*
!=========================================================================
! Linear Algebra: use LAPACK routines
!
subroutine mth_dpotrf (name, uplo, n, a, lda, error)
  character(len=*) :: name           !
  character(len=*) :: uplo           !
  integer :: n                       !
  integer :: lda                     !
  real(8) :: a(lda,*)                 !
  logical :: error                   !
  ! Local
  integer :: info
  !
  !  Purpose
  !  =======
  !
  !  DPOTRF computes the Cholesky factorization of a real symmetric
  !  positive definite matrix A.
  !
  !  The factorization has the form
  !     A = U**T * U,  if UPLO = 'U', or
  !     A = L  * L**T,  if UPLO = 'L',
  !  where U is an upper triangular matrix and L is lower triangular.
  !
  !  This is the block version of the algorithm, calling Level 3 BLAS.
  !
  !  Arguments
  !  =========
  !
  !  UPLO    (input) CHARACTER*1
  !          = 'U':  Upper triangle of A is stored;
  !          = 'L':  Lower triangle of A is stored.
  !
  !  N       (input) INTEGER
  !          The order of the matrix A.  N >= 0.
  !
  !  A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)
  !          On entry, the symmetric matrix A.  If UPLO = 'U', the leading
  !          N-by-N upper triangular part of A contains the upper
  !          triangular part of the matrix A, and the strictly lower
  !          triangular part of A is not referenced.  If UPLO = 'L', the
  !          leading N-by-N lower triangular part of A contains the lower
  !          triangular part of the matrix A, and the strictly upper
  !          triangular part of A is not referenced.
  !
  !          On exit, if INFO = 0, the factor U or L from the Cholesky
  !          factorization A = U**T*U or A = L*L**T.
  !
  !  LDA     (input) INTEGER
  !          The leading dimension of the array A.  LDA >= max(1,N).
  !
  !  INFO    (output) INTEGER
  !          = 0:  successful exit
  !          < 0:  if INFO = -i, the i-th argument had an illegal value
  !          > 0:  if INFO = i, the leading minor of order i is not
  !                positive definite, and the factorization could not be
  !                completed.
  !
  ! Call LAPACK routine
  call dpotrf  (uplo, n, a, lda, info )
  call mth_fail(name,'MTH_DPOTRF',info,error)
end subroutine mth_dpotrf
!
subroutine mth_dpotrs (name,   &
     &    uplo, n, nrhs, a, lda, b, ldb, info )
  character(len=*) :: name           !
  character(len=*) :: uplo           !
  integer :: n                       !
  integer :: nrhs                    !
  integer :: lda                     !
  real(8) :: a(lda,*)                 !
  integer :: ldb                     !
  real(8) :: b(ldb,*)                 !
  ! Local
  integer :: info
  logical :: error
  !
  !  Purpose
  !  =======
  !
  !  DPOTRS solves a system of linear equations A*X = B with a symmetric
  !  positive definite matrix A using the Cholesky factorization
  !  A = U**T*U or A = L*L**T computed by DPOTRF.
  !
  !  Arguments
  !  =========
  !
  !  UPLO    (input) CHARACTER*1
  !          = 'U':  Upper triangle of A is stored;
  !          = 'L':  Lower triangle of A is stored.
  !
  !  N       (input) INTEGER
  !          The order of the matrix A.  N >= 0.
  !
  !  NRHS    (input) INTEGER
  !          The number of right hand sides, i.e., the number of columns
  !          of the matrix B.  NRHS >= 0.
  !
  !  A       (input) DOUBLE PRECISION array, dimension (LDA,N)
  !          The triangular factor U or L from the Cholesky factorization
  !          A = U**T*U or A = L*L**T, as computed by DPOTRF.
  !
  !  LDA     (input) INTEGER
  !          The leading dimension of the array A.  LDA >= max(1,N).
  !
  !  B       (input/output) DOUBLE PRECISION array, dimension (LDB,NRHS)
  !          On entry, the right hand side matrix B.
  !          On exit, the solution matrix X.
  !
  !  LDB     (input) INTEGER
  !          The leading dimension of the array B.  LDB >= max(1,N).
  !
  !  INFO    (output) INTEGER
  !          = 0:  successful exit
  !          < 0:  if INFO = -i, the i-th argument had an illegal value
  !
  ! Call LAPACK routine
  call dpotrs  (uplo, n, nrhs, a, lda, b, ldb, info )
  call mth_fail(name,'MTH_DPOTRF',info,error)
end subroutine mth_dpotrs
!
subroutine mth_dpbtrf (name, uplo, n, kd, ab, ldab, error)
  character(len=*) :: name             !
  character(len=*) :: uplo             !
  integer :: n                         !
  integer :: kd                        !
  integer :: ldab                      !
  real(8) :: ab(ldab,*)                 !
  logical :: error                     !
  ! Local
  integer :: info
  !
  !  Purpose
  !  =======
  !
  !  DPBTRF computes the Cholesky factorization of a real symmetric
  !  positive definite band matrix A.
  !
  !  The factorization has the form
  !     A = U**T * U,  if UPLO = 'U', or
  !     A = L  * L**T,  if UPLO = 'L',
  !  where U is an upper triangular matrix and L is lower triangular.
  !
  !  Arguments
  !  =========
  !
  !  UPLO    (input) CHARACTER*1
  !          = 'U':  Upper triangle of A is stored;
  !          = 'L':  Lower triangle of A is stored.
  !
  !  N       (input) INTEGER
  !          The order of the matrix A.  N >= 0.
  !
  !  KD      (input) INTEGER
  !          The number of superdiagonals of the matrix A if UPLO = 'U',
  !          or the number of subdiagonals if UPLO = 'L'.  KD >= 0.
  !
  !  AB      (input/output) DOUBLE PRECISION array, dimension (LDAB,N)
  !          On entry, the upper or lower triangle of the symmetric band
  !          matrix A, stored in the first KD+1 rows of the array.  The
  !          j-th column of A is stored in the j-th column of the array AB
  !          as follows:
  !          if UPLO = 'U', AB(kd+1+i-j,j) = A(i,j) for max(1,j-kd)<=i<=j;
  !          if UPLO = 'L', AB(1+i-j,j)    = A(i,j) for j<=i<=min(n,j+kd).
  !
  !          On exit, if INFO = 0, the triangular factor U or L from the
  !          Cholesky factorization A = U**T*U or A = L*L**T of the band
  !          matrix A, in the same storage format as A.
  !
  !  LDAB    (input) INTEGER
  !          The leading dimension of the array AB.  LDAB >= KD+1.
  !
  !  INFO    (output) INTEGER
  !          = 0:  successful exit
  !          < 0:  if INFO = -i, the i-th argument had an illegal value
  !          > 0:  if INFO = i, the leading minor of order i is not
  !                positive definite, and the factorization could not be
  !                completed.
  !
  !  Further Details
  !  ===============
  !
  !  The band storage scheme is illustrated by the following example, when
  !  N = 6, KD = 2, and UPLO = 'U':
  !
  !  On entry:                       On exit:
  !
  !      *    *   a13  a24  a35  a46      *    *   u13  u24  u35  u46
  !      *   a12  a23  a34  a45  a56      *   u12  u23  u34  u45  u56
  !     a11  a22  a33  a44  a55  a66     u11  u22  u33  u44  u55  u66
  !
  !  Similarly, if UPLO = 'L' the format of A is as follows:
  !
  !  On entry:                       On exit:
  !
  !     a11  a22  a33  a44  a55  a66     l11  l22  l33  l44  l55  l66
  !     a21  a32  a43  a54  a65   *      l21  l32  l43  l54  l65   *
  !     a31  a42  a53  a64   *    *      l31  l42  l53  l64   *    *
  !
  !  Array elements marked * are not used by the routine.
  !
  ! Call LAPACK routine
  call dpbtrf  (uplo, n, kd, ab, ldab, info )
  call mth_fail(name,'MTH_DPBTRF',info,error)
end subroutine mth_dpbtrf
!
subroutine mth_dpbtrs (name,   &
     &    uplo, n, kd, nrhs, ab, ldab, b, ldb, error)
  character(len=*) :: name             !
  character(len=*) :: uplo             !
  integer :: n                         !
  integer :: kd                        !
  integer :: nrhs                      !
  integer :: ldab                      !
  real(8) :: ab(ldab,*)                 !
  integer :: ldb                       !
  real(8) :: b(ldb,*)                   !
  logical :: error                     !
  ! Local
  integer :: info
  !
  !  Purpose
  !  =======
  !
  !  DPBTRS solves a system of linear equations A*X = B with a symmetric
  !  positive definite band matrix A using the Cholesky factorization
  !  A = U**T*U or A = L*L**T computed by DPBTRF.
  !
  !  Arguments
  !  =========
  !
  !  UPLO    (input) CHARACTER*1
  !          = 'U':  Upper triangular factor stored in AB;
  !          = 'L':  Lower triangular factor stored in AB.
  !
  !  N       (input) INTEGER
  !          The order of the matrix A.  N >= 0.
  !
  !  KD      (input) INTEGER
  !          The number of superdiagonals of the matrix A if UPLO = 'U',
  !          or the number of subdiagonals if UPLO = 'L'.  KD >= 0.
  !
  !  NRHS    (input) INTEGER
  !          The number of right hand sides, i.e., the number of columns
  !          of the matrix B.  NRHS >= 0.
  !
  !  AB      (input) DOUBLE PRECISION array, dimension (LDAB,N)
  !          The triangular factor U or L from the Cholesky factorization
  !          A = U**T*U or A = L*L**T of the band matrix A, stored in the
  !          first KD+1 rows of the array.  The j-th column of U or L is
  !          stored in the j-th column of the array AB as follows:
  !          if UPLO ='U', AB(kd+1+i-j,j) = U(i,j) for max(1,j-kd)<=i<=j;
  !          if UPLO ='L', AB(1+i-j,j)    = L(i,j) for j<=i<=min(n,j+kd).
  !
  !  LDAB    (input) INTEGER
  !          The leading dimension of the array AB.  LDAB >= KD+1.
  !
  !  B       (input/output) DOUBLE PRECISION array, dimension (LDB,NRHS)
  !          On entry, the right hand side matrix B.
  !          On exit, the solution matrix X.
  !
  !  LDB     (input) INTEGER
  !          The leading dimension of the array B.  LDB >= max(1,N).
  !
  !  INFO    (output) INTEGER
  !          = 0:  successful exit
  !          < 0:  if INFO = -i, the i-th argument had an illegal value
  !
  ! Call LAPACK routine
  call dpbtrs (uplo, n, kd, nrhs, ab, ldab, b, ldb, info )
  call mth_fail(name,'MTH_DPBTRS',info,error)
end subroutine mth_dpbtrs
! End of Linear Algebra
!
subroutine mth_fail (fac,prog,ifail,error)
  use gbl_message
  !---------------------------------------------------------------------
  ! Error handling routine
  !---------------------------------------------------------------------
  character(len=*) :: fac           !
  character(len=*) :: prog          !
  integer :: ifail                  !
  logical :: error                  !
  ! Local
  character(len=60) :: chain
  !
  if (ifail.eq.0) then
    error = .false.
  else
    write(chain,'(A,A,A,I4)')   &
     &      'ERROR in ',trim(prog),', ifail = ',ifail
    call map_message(seve%e,fac,chain)
    error = .true.
  endif
end subroutine mth_fail
!
subroutine overlap(a,n,b,m,c,k)
  !
  ! Find the intersection of ensembles A and B
  !
  integer, intent(in) :: n
  integer, intent(in) :: a(n)
  integer, intent(in) :: m
  integer, intent(in) :: b(m)
  integer, intent(inout) :: k
  integer, intent(inout) ::c(*)
  !
  integer i,j
  !
  k = 0
  do i=1,n
    do j=1,m
      if (a(i).eq.b(j)) then
        k = k+1
        c(k) = a(i)
        exit
      endif
    enddo
  enddo
  !! Print *,'Overlap ',n,m,k,' = ',c(1:K)
end subroutine overlap
!
subroutine union(a,n,b,m,c,k)
  !
  ! Find the Union of ensembles A and B
  !
  integer, intent(in) :: n
  integer, intent(in) :: a(n)
  integer, intent(in) :: m
  integer, intent(in) :: b(m)
  integer, intent(inout) :: k
  integer, intent(inout) ::c(*)
  !
  integer i,j
  logical :: found
  !
  k = n
  c(1:k) = a(1:n)
  !
  do j=1,m
    found = .false.
    do i=1,n
      if (c(i).eq.b(j)) then
        found = .true.
        exit
      endif
    enddo
    if (.not.found) then
      k = k+1
      c(k) = b(j)
    endif
  enddo
end subroutine union
!
subroutine do_get_cgain(ntimes,nantes,hsol,again,refant,scale_gain,error)
  use gildas_def
  use gkernel_interfaces
  use image_def
  use gbl_message
  !---------------------------------------------------------------------
  ! @ public-mandatory
  ! 
  ! IMAGER Command SOLVE
  ! Task UV_GAIN
  !
  ! Prepare the Solution Table: Amplitude & Phase correction per antenna.
  !
  ! Convert the formatted temporary files to a Gildas Table
  !---------------------------------------------------------------------
  integer, intent(in) :: ntimes   ! Number of times
  integer, intent(in) :: nantes   ! Maximum number of antennas
  integer, intent(in) :: refant   ! Reference antenna
  type(gildas), intent(inout) :: hsol  ! Antenna Solution table
  real, allocatable, intent(out) :: again(:,:)  ! Antenna Solution array
  real, intent(out) :: scale_gain ! Scaling Amplitude factor
  logical, intent(inout) :: error ! Error flag
  !
  character(len=*), parameter :: rname='SOLVE'
  !
  integer :: iref, nant, ier, i, j, k, l
  real(8) :: time, ztime, date, secs
  integer(4) :: jant, kant, mant, iunit
  character(len=60) :: mess
  ! A few automatic arrays, taken on the stack
  real(4) :: amplis(0:nantes) 
  real(4) :: phases(0:nantes) 
  real(4) :: ampsnr(nantes) 
  real(4) :: rphase  
  real(8) :: mean_gain, weig_gain
  integer(4) :: al(nantes)  
  !
  ! Larger allocatable arrays (one could use re-allocation instead,
  ! but they are still small anyway)
  integer(4), allocatable :: itmp(:),ialways(:)
  !
  allocate(itmp(ntimes*nantes),ialways(ntimes*nantes),stat=ier)
  if (ier.ne.0) then
    error = .true.
    return
  endif
  !
  ztime = 0
  amplis = 0.
  phases = 0.
  ampsnr = 0.
  itmp = 0
  ialways = 0
  !
  iunit = 4  ! Amplitude + Phase
  rewind(unit=iunit)
  !
  ! Find the common antennas
  read(iunit,*,iostat=ier) iref, time, nant  ! Read the time step
  read(iunit,*,iostat=ier) al(1:nant)        ! Read the antenna list
  ialways(1:nant) = al(1:nant)
  jant = nant
  read(iunit,*,iostat=ier) amplis(1:nant)
  read(iunit,*,iostat=ier) phases(1:nant)
  read(iunit,*,iostat=ier) ampsnr(1:nant)
  do i=2,ntimes
    read(iunit,*,iostat=ier) iref, time, nant  ! Read the time step
    read(iunit,*,iostat=ier) al(1:nant)        ! Read the antenna list
    call union(ialways,jant,al,nant,itmp,kant)
    jant = kant
    ialways(1:kant) = itmp(1:kant)
    read(iunit,*,iostat=ier) amplis(1:nant)
    read(iunit,*,iostat=ier) phases(1:nant)
    read(iunit,*,iostat=ier) ampsnr(1:nant)
  enddo
  rewind(iunit)
  !
  mant = maxval(ialways(1:kant))
  write(mess,'(I0,A)') kant,' antennas present:'
  call map_message(seve%i,rname,mess)
  write(*,'(16(1x,I3))') ialways(1:kant)
  if (mant.ne.kant) then
    write(mess,'(A,I0,A,I0)') 'Maximum Antenna number ',mant,' exceeds number of antennas ',kant
    call map_message(seve%w,rname,mess)
  endif
  !
  hsol%gil%ndim = 2
  hsol%gil%dim(1) = ntimes
  !
  ! This has been modified to use
  !   kant  instead of    nantes
  ! to use the unambiguous antenna number, but a backward pointer 
  ! to ialways is then needed.
  !
  hsol%gil%dim(2) = 4+3*mant  !
  !
  allocate(again(hsol%gil%dim(1),hsol%gil%dim(2)), stat=ier)
  again = 0
  mean_gain = 0.d0
  weig_gain = 0.d0
  !
  do i=1,ntimes
    read(iunit,*,iostat=ier) iref, time, nant  ! Read the time step
    read(iunit,*,iostat=ier) al(1:nant)        ! Read the antenna list
    if (ztime.eq.0) ztime = time
    time = time-ztime
    secs = mod(time,86400.d0)
    date = (time-secs)/86400.d0 
    again(i,1) = secs
    again(i,2) = date     
    again(i,3) = nant
    again(i,4) = iref
    !
    read(iunit,*) amplis(1:nant)
    read(iunit,*) phases(1:nant)
    read(iunit,*) ampsnr(1:nant)
    !
    ! Locate the reference antenna
    rphase = phases(refant)
    do l=1,kant
      if (ialways(l).eq.refant) then
        rphase = phases(refant)
        exit
      endif
    enddo
    !
    do j=1,nant
      k = j ! By default...
      ! Here we should find K such that ialways(k) == al(j)
      ! and use K instead of J for the output columns
      do l=1,kant
        if (ialways(l).eq.al(j)) then
          k = ialways(l)
          exit
        endif
      enddo
      again(i,2+3*k) = amplis(j) 
      again(i,3+3*k) = phases(j) - rphase 
      again(i,4+3*k) = ampsnr(j) 
      mean_gain = mean_gain + amplis(j)/ampsnr(j)**2
      weig_gain = weig_gain + 1./ampsnr(j)**2
    enddo
  enddo
  scale_gain = mean_gain / weig_gain  ! Per antenna
  scale_gain = scale_gain ** 2        ! Per baseline
  close(unit=iunit)
  !
  hsol%loca%size = hsol%gil%dim(1)*hsol%gil%dim(2)
end subroutine do_get_cgain
!
subroutine do_normalize_v(ncol,nvis,duvbg,scale_gain)
  use gbl_message
  use gkernel_interfaces
  !---------------------------------------------------------------------
  ! @ private
  !   IMAGER
  !     Normalize the per-baseline amplitude gains so that the Weighted 
  !   mean is 1.0
  !---------------------------------------------------------------------
  integer, intent(in) :: ncol           ! Visibility size
  integer, intent(in) :: nvis           ! Number of visibilities
  real, intent(in) :: duvbg(ncol,nvis)  ! Visibilities
  real, intent(out) :: scale_gain       ! Computed Scaling factor
  !
  real(8) :: fr,fw,w
  integer :: iv, ig, ier
  integer(kind=index_length) :: ng
  real, allocatable :: gain(:)
  real :: wmean, rmean, median
  logical :: error
  character(len=256) :: chain
  !
  allocate(gain(nvis),stat=ier)
  !
  fr = 0.
  fw = 0.
  w = 0.
  ig = 0
  do iv=1,nvis
    if (duvbg(10,iv).gt.0) then
      ig = ig+1
      gain(ig) = sqrt((duvbg(8,iv)**2+duvbg(9,iv)**2))
      fw = fw + gain(ig)*duvbg(10,iv)
      fr = fr + gain(ig)
      w = w + duvbg(10,iv)
    endif
  enddo
  wmean = fw/w
  rmean = fr/ig
  !
  ng = ig
  call gr4_median(gain,ng,0.0,-1.0,median,error)  
  !
  write(chain,'(A,F6.3,A,F6.3,A,F6.3)') 'Scale factors: Raw ',rmean, &
    & ', Weighted ',wmean,' Median ',median
  call message_colour(1)
  call map_message(seve%w,'SOLVE',chain)
  call message_colour(-1)
  !
  scale_gain = wmean ! In general, the best
end subroutine do_normalize_v
