!!
subroutine mosaic_sort (huv_call,error,sorted,shift,newabs,uvmax,uvmin, &
  & ixoff,iyoff,idoff,nf,doff,voff)
  use gkernel_interfaces
  use imager_interfaces, except_this=>mosaic_sort
  use clean_def
  use clean_arrays
  use gbl_message
  !---------------------------------------------------------------------
  ! @ private-mandatory
  !*
  ! IMAGER -- UV_MAP: Sort the input Mosaic UV table
  !!
  !---------------------------------------------------------------------
  type(gildas), intent(inout) :: huv_call    !! UV Header & Data
  logical, intent(inout) :: sorted           !! Is table sorted ?
  logical, intent(inout) :: shift            !! Do we shift phase center ?
  logical, intent(out) :: error              !! Logical error flag
  real(kind=8), intent(inout) :: newabs(3)   !! New phase center and PA
  real, intent(out) :: uvmin                 !! Min baseline
  real, intent(out) :: uvmax                 !! Max baseline
  integer, intent(in) :: ixoff, iyoff, idoff !! Offset pointers
  integer, intent(inout) :: nf               !! Number of fields
  real, intent(inout) :: doff(:,:)           !! Field offsets
  integer, intent(inout) :: voff(:)          !! Field visibility pointers
  !
  ! Constants
  real(8), parameter :: pi=3.14159265358979323846d0
  real(8), parameter :: f_to_k = 2.d0*pi/299792458.d-6
  character(len=*), parameter :: rname='UV_MOSAIC'
  !
  ! Local ---
  type(gildas) :: hold  ! Temporary holder of unsorted UV data
  integer :: ioff, joff, itel, ier
  logical :: ismosaic
  real(kind=8) :: freq, off(3)
  real :: pos(2), cs(2)
  integer :: nu,nv
  !
  ! Code ----
  call imager_tree('MOSAIC_SORT',.false.)
  if (newabs(3).ne.0) then
    Print *,'Non zero angle, NEW ABS ',newabs
  endif
  !
  call print_buffer_asso('UV Unsorted ',huv_call)
  !
  ! The UV table is available in huv_call%
  if (huv_call%loca%size.eq.0) then
    call map_message(seve%e,rname,'No UV data loaded')
    error = .true.
    return
  endif
  nu = huv_call%gil%dim(1)
  nv = huv_call%gil%nvisi ! not %dim(2)
  !
  ! Correct for new phase center if required
  if (shift) then
    if (huv_call%gil%ptyp.eq.p_none) then
      call map_message(seve%w,rname,'No previous phase center info')
      huv_call%gil%a0 = huv_call%gil%ra
      huv_call%gil%d0 = huv_call%gil%dec
      huv_call%gil%pang = 0.d0
      huv_call%gil%ptyp = p_azimuthal
    elseif (huv_call%gil%ptyp.ne.p_azimuthal) then
      call map_message(seve%w,rname,'Previous projection type not SIN')
      huv_call%gil%ptyp = p_azimuthal
    endif
    call uv_shift_header (newabs,huv_call%gil%a0,huv_call%gil%d0,huv_call%gil%pang,   &
        &      off,shift)
    huv_call%gil%posi_words = def_posi_words
    huv_call%gil%proj_words = def_proj_words
    !
    call print_buffer_asso('UV Shifted ',huv_call)
  endif
  !
  sorted = .false.
  !
  if (.not.associated(huv_call%r2d)) then
    call map_message(seve%e,rname,'huv_call%R2d pointer not set ',seve%e)
    error = .true.
    return
  else
    if ( (huv_call%gil%dim(1).ne.size(huv_call%r2d,1)) .or. &
      & (huv_call%gil%dim(2).ne.size(huv_call%r2d,2)) ) then
      call map_message(seve%e,rname,'huv_call%r2d pointer size is incorrect ',seve%e)
      Print *,'Dimensions ',huv_call%gil%dim(1:2)
      Print *,'Sizes      ',size(huv_call%r2d,1),size(huv_call%r2d,2)
      error = .true.
      return
    endif
  endif
  call get_mosaic_cols(huv_call,ioff,joff,itel,ismosaic)  
  call uvsort_check_fields(huv_call,ioff,joff,itel,sorted)
  !
  ! Get center frequency
  freq = gdf_uv_frequency(huv_call,huv_call%gil%ref(1))
  !
  if (sorted) then
    !
    call mosaic_loadfield (huv_call%r2d,nu,nv,ioff,joff,nf,doff,voff,uvmax,uvmin)
  else
    !
    ! Else, create another copy
    call map_message(seve%w,rname,'Sorting UV table...')
    !
    ! Compute observing frequency, and new phase center in wavelengths
    if (shift) then
      huv_call%gil%a0 = newabs(1)
      huv_call%gil%d0 = newabs(2)
      huv_call%gil%pang = newabs(3)
      cs(1)  =  cos(off(3))
      cs(2)  = -sin(off(3))
      pos = off(1:2)  ! Real*8 to Real*4
    else
      pos(1) = 0.0
      pos(2) = 0.0
      cs(1) = 1.0
      cs(2) = 0.0
    endif
    !
    ! OK, copy, rotate, shift, and sort ...
    !
    call gildas_null(hold,type='UVT')
    call gdf_copy_header(huv_call,hold,error)
    ! First copy the data pointer
    allocate(hold%r2d(huv_call%gil%dim(1),huv_call%gil%dim(2)),stat=ier)
    if (ier.ne.0) then
      call map_message(seve%e,rname,'Pointer allocation failed')
      error = .true.
      return
    endif
    hold%r2d = huv_call%r2d   ! Copy data
    !
    ! This also loads the fields
    call mosaic_sortuv (huv_call,nu,nv,huv_call%gil%ntrail,hold%r2d, &
      & huv_call%r2d,freq,pos,cs,uvmax,uvmin,error, & 
      & ixoff,iyoff,idoff,nf,doff,voff)
    deallocate(hold%r2d,stat=ier)
  endif
  !
  ! Now transform UVMAX in kiloWavelength (including 2 pi factor)
  uvmax = uvmax*freq*f_to_k
  uvmin = uvmin*freq*f_to_k
  error = .false.
  call imager_tree('MOSAIC_SORT',.true.)
end subroutine mosaic_sort
!
subroutine mosaic_sortuv (huvl,np,nv,ntrail,vin,vout,freq,off,cs,uvmax,uvmin, &
  & error,ixoff,iyoff,idoff,nf,doff,voff)
  use image_def
  use gkernel_interfaces
  use gbl_message
  use clean_default
  use imager_interfaces, except_this=> mosaic_sortuv
  !---------------------------------------------------------------------
  ! @ private-mandatory
  !*
  ! IMAGER -- UV_MAP:  Sort a UV table by fields  
  !     Rotate, Shift and Sort a UV table for map making
  !     Differential precession should have been applied before.
  !!
  !---------------------------------------------------------------------
  type(gildas), intent(in) :: huvl    !! UV Header
  integer, intent(in) :: np           !! Size of a visibility
  integer, intent(in) :: nv           !! Number of visibilities
  integer, intent(in) :: ntrail       !! Number of trailing daps
  real, intent(in) :: vin(np,nv)      !! Input visibilities
  real, intent(out) :: vout(np,nv)    !! Output visibilities
  real(8), intent(in) :: freq         !! Reference Frequency
  real, intent(in) :: off(2)          !! Offset of Reference
  real, intent(in) :: cs(2)           !! Frame Rotation
  real, intent(out) :: uvmax          !! Max UV value
  real, intent(out) :: uvmin          !! Min UV value
  integer, intent(in) :: ixoff, iyoff, idoff  !! Offset pointers
  integer, intent(out) :: nf          !! Number of fields
  real, intent(out) :: doff(:,:)      !! Offsets of the fields
  integer, intent(out) :: voff(:)     !! Visibility offset - range
  logical, intent(out) :: error       !! Logical error flag
  !
  ! Constant
  real(8), parameter :: pi=3.14159265358979323846d0
  real(8), parameter :: f_to_k = 2.d0*pi/299792458.d-6
  integer, parameter :: mprint=0
  !
  ! Local ---
  logical, allocatable :: ips(:)       ! Sign of visibility
  real, allocatable :: rpu(:), rpv(:)  ! U,V coordinates
  real, allocatable :: spv(:)          ! Sorted V coordinates
  integer, allocatable :: ipi(:)       ! Index
  real(8), allocatable :: dtr(:)       ! Sorting number
  real, allocatable :: xy(:,:)         ! Phase Shifts
  logical :: sorted
  integer :: ier, ifi, iv, ioff, joff
  !
  ! Code ----
  call imager_tree('MOSAIC_SORTUV',.false.)
  !
  ! Load U,V coordinates, applying possible rotation (CS),
  ! and making all V negative
  allocate (ips(nv),rpu(nv),rpv(nv),ipi(nv),dtr(nv),stat=ier)
  if (ier.ne.0) then
    error = .true.
    return
  endif
  call loaduv (vin,np,nv,cs,rpu,rpv,ips,uvmax,uvmin)
  !TEST!Print *,'UVMIN ',uvmin,' UVMAX ',uvmax,' NP ',np,' NV ',nv
  !
  ! Modify the uv coordinates to minimize
  ! the projection errors ... See Sault et al 1996 Appendix 1
  ! Key question here
  ! - modification must be done before sorting
  ! - but should we use the modified or intrinsic UV coordinates ?
  !
  ! For the rotation above, it does not matter, actually: the
  ! matrix commutes (I think so - That can be check later...)
  !
  !  call remapuv(nv,cs,rpu,rpv,ixoff,iyoff,uvmax,uvmin)
  !
  ! Identify number of fields
  if (ixoff.ne.0 .and. iyoff.ne.0) then
    call loadfiuv_xy(vin,np,nv,dtr,ipi,sorted,ixoff,iyoff,rpv,nf,doff)
  else if (idoff.ne.0) then
    call map_message(seve%w,'LOADFIUV_ID', &
      & 'Sorting UV data set with associated Mosaic table is obsolescent')
    call loadfiuv_id(huvl,vin,np,nv,dtr,ipi,sorted,idoff,rpv,nf,doff)
  endif
  !
  allocate(xy(2,nf))
  ! Note that the new phase center is counter-rotated because rotations
  ! are applied before phase shift.
  if ((idoff.ne.0).and.(mosaic_mode.eq.'SAULT')) then
    !
    ! Should we Add the Global Offset ?
    ! We should also find the fractional pixel shift if needed here...
    ! The shifting should also always be done in this case, 
    ! and the initial UV table not changed ? 
    do ifi=1,nf
      xy(1,ifi) = - freq * f_to_k * ( doff(1,ifi)*cs(1) - doff(2,ifi)*cs(2) )
      xy(2,ifi) = - freq * f_to_k * ( doff(2,ifi)*cs(1) + doff(1,ifi)*cs(2) )
    enddo  
  else
    !
    ! In the GUETH method, add the global offset - CHECKPLEASE
    xy(1,:) = - freq * f_to_k * ( off(1)*cs(1) - off(2)*cs(2) )
    xy(2,:) = - freq * f_to_k * ( off(2)*cs(1) + off(1)*cs(2) )
  endif
  !
  ! Sort by fields (major number) then V (fractionary part)
  if (.not.sorted) then
    !!Print *,'Sorting UV data '
    call gr8_trie (dtr,ipi,nv,error)
    if (error) return
    deallocate (dtr,stat=ier)
    allocate (spv(nv),stat=ier)
    if (ier.ne.0) then
      error = .true.
      return
    endif
    !
    ! One must sort RPV here to use SORTUV later...
    do iv=1,nv
      spv(iv) = rpv(ipi(iv))
    enddo
    rpv(:) = spv(:)
    deallocate (spv,stat=ier)
  else
    deallocate (dtr,stat=ier)
    !! Print *,'UV Data is already sorted '
  endif
  ! !Read(5,*) ifi
  !
  ! Apply phase shift and copy to output visibilities
  !
  ! For Mosaics using the Sault et al method, this must be done
  ! per Pointing, as the phase shift to be applied is Pointing
  ! dependent. We may need an intermediate routine to do so, or
  ! to generalize the XY array to one per field.
  !
  call imager_tree('SUB_SORTUV',.false.)
  call sub_sortuv (vin,vout,np,nv,ntrail,xy,nf,idoff,rpu,rpv,ips,ipi)
  call imager_tree('SUB_SORTUV',.true.)
  !
  if (ixoff.ne.0 .and. iyoff.ne.0) then
    ifi = 1
    voff(ifi) = 1
    do iv=1,nv
      if ( (doff(1,ifi).ne.vout(ixoff,iv)) .or. &
        &  (doff(2,ifi).ne.vout(iyoff,iv)) ) then
        ifi = ifi+1
        voff(ifi) = iv
      endif
    enddo
    voff(nf+1) = nv+1
  else if (idoff.ne.0) then
    ifi = 0
    joff = -1 
    do iv=1,nv
      ioff = vout(idoff,iv)
      if (ioff.ne.joff) then
        ifi = ifi+1
        voff(ifi) = iv
        joff = ioff
      endif
    enddo
    voff(nf+1) = nv+1
  endif
  !
  if (mprint.eq.0) return
  !
  ! !Print *,'XOFF ',ixoff,' YOFF ',iyoff
  do ifi=1,min(nf,mprint)
    write(*,'(I4,A,2F12.4,2I10)') ifi,' DOFF ', &
      & doff(1,ifi)*180.*3600./pi, &
      & doff(2,ifi)*180.*3600./pi, &
      & voff(ifi), voff(ifi+1)-1
  enddo
  if (nf.gt.mprint) write(*,*) 'and ',nf-mprint,' more fields used but not printed above'
  !
  error = .false.
  !
  call imager_tree('MOSAIC_SORTUV',.true.)
end subroutine mosaic_sortuv
