  subroutine uv_select_buffer(rname,nu,nv,error)
!-----------------------------------------------------------------------
!*
! The use of UV buffers in IMAGER
!
! IMAGER has three virtual UV buffers, named
! "UVI" (Initial), "UVS" (Sorted) and "UVR" (Resampled).
! UVR and UVS are used indifferently, depending on which one is
! available, rather than using UVS only for sorting and UVR only
! for Resampling. Only one of those two is allocated at any time
! (except temporarily when using one as input and the other as output).
!
! UVR and UVS may point to UVI, as sorting is not always needed.
!
! Command READ uses UVI, and nullifies or deallocate UVR and UVS.
!
! Commands UV_MAP, UV_CONT, UV_TIME, UV_RESIDUAL, UV_COMPRESS
! and UV_RESAMPLE use the UVR and UVS buffers.
!   A little tricky logic allows to select UVS or UVR
! for the output, depending on which one is busy as input,
! allocating on demand as needed.
!
! Through the use of a pointer, "UV" (actually a header
! HUV and a pointer to the data DUV), the so-called "current UV data"
! points towards one of them, depending on the last issued commands.
!
! Other commands like UV_BASELINE, UV_FILTER, UV_REWEIGHT or UV_FLAG
! work on the "current UV data". UV_FLAG is partially reversible.
!
! Finally, UV_SORT does not affect the "current UV data", but produces
! a transposed copy of it (which thus cannot be written by WRITE UV),
! called UVT.
!
! The whole thing is a little complex and perhaps should be changed.
!
! In addition to the buffer use, the code must account for the
! weight computation optimization.
!
! NOTE: In an earlier version, commands UV_COMPRESS and UV_RESAMPLE 
! only worked with UVI as input. This makes little sense, as a 
! combination of UV_TIME - UV_COMPRESS did not give the same as 
! UV_COMPRESS - UV_TIME for example. The only "nice" feature of 
! this behaviour was to allow the spectral resampling to start 
! from the full resolution data.
!
! The original data can always be recovered through a READ, which
! is optimized by proper caching if no modification has been done
! to the data.
!!
!-----------------------------------------------------------------------
  use clean_def
  use clean_arrays
  use clean_types
  use gbl_message
  use imager_interfaces, only : map_message
  !---------------------------------------------------------------------
  ! @ private
  !*
  ! IMAGER -- Utility routine
  !
  !   Select the next available UV buffer (UVR or UVS) for
  ! commands using them.
  !!
  !---------------------------------------------------------------------
  character(len=*), intent(in) :: rname    !! Caller name
  integer, intent(in) :: nu                !! Visibility size
  integer, intent(in) :: nv                !! Number of visibilities
  logical, intent(out) :: error            !! Error flag
  !
  ! Local ---
  integer :: ier
  !
  ! Code ----
  if (associated(duvr)) then
    allocate (duvs(nu,nv),stat=ier)
    if (ier.ne.0) then
      error = .true.
      call map_message(seve%f,rname,'Memory allocation failure on UVS')
      return
    endif
    if (associated(duvr,duvi)) then
      nullify(duvr)
    else if (associated(duvr)) then
      deallocate (duvr)     ! Free the old one
    endif
    duv => duvs             ! Point to new one
  else
    allocate (duvr(nu,nv),stat=ier)
    if (ier.ne.0) then
      error = .true.
      call map_message(seve%f,rname,'Memory allocation failure on UVR')
      return
    endif
    if (associated(duvs,duvi)) then
      nullify(duvs)
    else if (associated(duvs)) then
      deallocate (duvs)      ! Free the old one
    endif
    duv => duvr               ! Point to new one
  endif
  optimize(code_save_uv)%change = optimize(code_save_uv)%change+1
  error = .false.
end subroutine uv_select_buffer
!
subroutine uv_reset_buffer(rname)
  use gkernel_interfaces
  use clean_def
  use clean_arrays
  use clean_beams
  use clean_types
  use gbl_message
  use imager_interfaces, only : map_message
  !---------------------------------------------------------------------
  ! @ private
  !*
  ! IMAGER -- Utility routine
  !
  !   Reset pointers to UV datasets (back to UVI). Deallocate
  ! UVR or UVS if needed, as well as the "transposed" buffer UVT
  !---------------------------------------------------------------------
  character(len=*) :: rname  !! Caller name
  !
  ! Local ---
  logical :: error
  !
  ! Code ---
  !
  ! What happens when no compressed data is defined ?
  ! well we have to set the same pointers DUV and DUVR as in READ...
  !
  if (allocated(duvt)) deallocate (duvt)        ! UV data not plotted
  !
  if (.not.allocated(duvi)) then
    call map_message(seve%w,rname,'No UV data (DUVI not allocated)')
    return
  endif
  !
  ! Find out which one DUVI is pointing about
  if (associated(duvr,duvi)) then
    ! !Print *,'DUVR was pointing towards DUVI'
    nullify(duvr)
  else if (associated(duvr)) then
    ! !Print *,'DUVR was allocated '
    deallocate (duvr)     ! Free the old one
  else
    ! !Print *,'DUVR not allocated '
  endif
  if (associated(duvs,duvi)) then
    ! !Print *,'DUVS was pointing towards DUVI'
    nullify(duvs)
  else if (associated(duvs)) then
    ! !Print *,'DUVS was allocated '
    deallocate (duvs)     ! Free the old one
  else
    ! !Print *,'DUVS not allocated '
  endif
  !
  ! Copy back the UV header and re-define the file name
  call gdf_copy_header(huvi,huv, error)
  huv%file = huvi%file
  !
  duvr => duvi     ! As in READ
  !
  ! This means we were already pointing to the previous UV data set
  if (associated(duv,duvi)) return
  !
  ! Here we point back...
  if (optimize(code_save_uv)%change.gt.1) then
    optimize(code_save_uv)%change = optimize(code_save_uv)%change - 1
    call map_message(seve%i,rname,'Returning to previous UV data set')
  else
    optimize(code_save_uv)%change = 0
    call map_message(seve%i,rname,'Returning to original UV data set')
    ! Delete the BEAM_RANGES array if any
    nbeam_ranges = -1    ! Beam ranges unchecked
    call sic_delvariable ('BEAM_RANGES',.false.,error)
  endif
  duv => duvi
  do_weig = .true. ! Recompute weight
  call sic_delvariable ('UV',.false.,error)
  call sic_delvariable ('UVS',.false.,error)
  !
end subroutine uv_reset_buffer
!
subroutine uv_dump_buffers(rname)
  use clean_def
  use clean_arrays
  use gbl_message
  use gkernel_interfaces
  use imager_interfaces, only : map_message
  !---------------------------------------------------------------------
  ! @ private
  !*
  ! IMAGER -- Utility routine
  !
  !   Dump the allocation status of the UV buffers. (Debugging only)
  !!
  !---------------------------------------------------------------------
  character(len=*), intent(in) :: rname    !! Caller name
  !
  ! Local ---
  integer(kind=index_length) :: udim(2)
  logical :: error
  !
  ! Code ----
  if (associated(duvr)) then
    if (associated(duvr,duvi)) then
      call map_message(seve%w,rname,'DUVR associated to DUVI')
    else
      call map_message(seve%w,rname,'DUVR allocated')
    endif
    !
    ! Redefine SIC variables
    udim(1) = ubound(duvr,1)
    udim(2) = ubound(duvr,2)
    call sic_delvariable ('UVR',.false.,error)
    call sic_def_real ('UVR',duvr,2,udim,.false.,error)
  else
    call map_message(seve%w,rname,'no DUVR ...')
  endif
  !
  if (associated(duvs)) then
    if (associated(duvs,duvi)) then
      call map_message(seve%w,rname,'DUVS associated to DUVI')
    else
      call map_message(seve%w,rname,'DUVS allocated')
    endif
    ! Redefine SIC variables
    udim(1) = ubound(duvs,1)
    udim(2) = ubound(duvs,2)
    call sic_delvariable ('UVS',.false.,error)
    call sic_def_real ('UVS',duvs,2,udim,.false.,error)
  else
    call map_message(seve%w,rname,'no DUVS ...')
  endif
  !
  if (allocated(duvt)) call map_message(seve%w,rname,'Transposed buffer allocated.')
  !
  if (associated(duv,duvi)) then
    call map_message(seve%w,rname,'DUV associated to DUVI')
  else if (associated(duv,duvr)) then
    call map_message(seve%w,rname,'DUV associated to DUVR')
  else if (associated(duv,duvs)) then
    call map_message(seve%w,rname,'DUV associated to DUVS')
  else if (associated(duv,duvm)) then
    call map_message(seve%w,rname,'DUV associated to DUVM (Model)')
  else if (associated(duv,duvf)) then
    call map_message(seve%w,rname,'DUV associated to DUVF (Fit residual)')
  else if (associated(duv,duvself)) then
    call map_message(seve%w,rname,'DUV associated to DUVSELF (Self cal)')
  else if (associated(duv,duvraw)) then
    call map_message(seve%w,rname,'DUV associated to DUVRAW (Raw for self-cal)')
  else if (associated(duv)) then
    call map_message(seve%w,rname,'DUV is associated to some other buffer (neither DUVI, DUVR nor DUVS)')
  else
    call map_message(seve%w,rname,'DUV is undefined')
  endif
  !
end subroutine uv_dump_buffers
!
subroutine uv_free_buffers
  use clean_def
  use clean_arrays
  !---------------------------------------------------------------------
  !*
  ! IMAGER -- Utility routine
  !
  !   Deallocate all UV buffers.
  !!
  !---------------------------------------------------------------------
  integer :: ier
  !
  ! Free the previous zone
  ! ! Print *,'Into uv_free_buffers'
  if (associated(duvr)) then
    if (associated(duvr,duvi)) then
      nullify(duvr)
      ! !print *,'Nullify duvr'
    else
      ! !print *,'Deallocate duvr'
      deallocate(duvr,stat=ier)
    endif
  endif
  if (associated(duvs)) then
    if (associated(duvs,duvi)) then
      ! !print *,'Nullify duvs'
      nullify(duvs)
    else
      ! !print *,'Deallocate duvs'
      deallocate(duvs,stat=ier)
    endif
  endif
  if (allocated(duvi)) deallocate(duvi,stat=ier)
  if (allocated(duvt)) deallocate(duvt,stat=ier)
  if (allocated(dchanflag)) deallocate(dchanflag,stat=ier)
  ! !Print *,'Done uv_free_buffers'
end subroutine uv_free_buffers
!
subroutine uv_find_buffers (rname,nu,nv,duv_previous, duv_next,error)
  use clean_arrays
  use gbl_message
  use imager_interfaces, only : map_message
  !---------------------------------------------------------------------
  ! @ private-mandatory
  !*
  ! IMAGER -- Utility routine
  !
  !   Find the next available UV buffer (UVR or UVS).
  !!
  !---------------------------------------------------------------------
  character(len=*), intent(in) :: rname       !! Caller name
  integer, intent(in) :: nu                   !! Size of a visiblity
  integer, intent(in) :: nv                   !! Number of visibilities
  real, pointer, intent(out) :: duv_previous(:,:)  !! Pointer to previous buffer
  real, pointer, intent(out) :: duv_next(:,:) !! Pointer to next available buffer
  logical, intent(out) :: error               !! Logical error flag
  !       
  ! Local ---
  integer :: ier
  !
  ! Code ----
  if (associated(duvr)) then
    allocate (duvs(nu,nv),stat=ier)
    if (ier.ne.0) then
      error = .true.
      call map_message(seve%f,rname, &
      & 'UV_FIND_BUFFERS: Memory allocation failure on UVS')
      return
    endif
    call map_message(seve%d,rname,'Storing in DUVS')
    duv_previous => duvr
    duv_next => duvs
  else
    allocate (duvr(nu,nv),stat=ier)
    if (ier.ne.0) then
      error = .true.
      call map_message(seve%f,rname, &
      & 'UV_FIND_BUFFERS: Memory allocation failure on UVR')
      return
    endif
    call map_message(seve%d,rname,'Storing in DUVR')
    duv_previous => duvs
    duv_next => duvr
  endif
  error = .false.
end subroutine uv_find_buffers
!
subroutine uv_clean_buffers(duv_previous,duv_next,error)
  use clean_arrays
  !---------------------------------------------------------------------
  ! @ private-mandatory
  !*
  ! IMAGER -- Utility routine
  !
  !   Take care of freeing the unused UV buffer, and set UV to point to
  ! the new one.
  !---------------------------------------------------------------------
  real, pointer, intent(inout) :: duv_previous(:,:) !! Previous buffer
  real, pointer, intent(inout) :: duv_next(:,:)     !! Next buffer
  logical, intent(in) :: error  !! Logical error flag
  !
  if (associated(duv_previous,duvr)) then
    if (error) then
      deallocate(duvs)
      nullify (duv_previous, duv_next)
      return
    endif
    !
    if (associated(duvr,duvi)) then
      nullify(duvr)
    else
      deallocate (duvr)      ! Free the old one
    endif
    duv => duvs              ! Point to new one
  else if (associated(duv_previous,duvs)) then
    if (error) then
      deallocate(duvr)
      nullify (duv_previous, duv_next)
      return
    endif
    !
    if (associated(duvs,duvi)) then
      nullify(duvs)
    else
      deallocate (duvs)     ! Free the old one
    endif
    duv => duvr             ! Point to new one
  endif
end subroutine uv_clean_buffers
!
subroutine uv_discard_buffers(duv_previous,duv_next,error)
  use clean_arrays
  !---------------------------------------------------------------------
  ! @ private-mandatory
  !
  ! IMAGER -- Utility routine
  !
  !   Take care of freeing the last used UV buffer, and reset 
  !   UV to point to the previous one.
  !!
  !---------------------------------------------------------------------
  real, pointer, intent(inout) :: duv_previous(:,:) !! Previous buffer
  real, pointer, intent(inout) :: duv_next(:,:)     !! Next buffer
  logical, intent(in) :: error  !! Logical error flag
  !
  if (associated(duv_next,duvr)) then
    if (error) then
      deallocate(duvr)
      nullify (duv_previous, duv_next)
      return
    endif
    !
    if (associated(duvr,duvi)) then
      nullify(duvr)
    else
      deallocate (duvr)      ! Free it 
    endif
    duv => duvs              ! Point to new one
  else if (associated(duv_next,duvs)) then
    if (error) then
      deallocate(duvs)
      nullify (duv_previous, duv_next)
      return
    endif
    !
    if (associated(duvs,duvi)) then
      nullify(duvs)
    else
      deallocate (duvs)     ! Free it
    endif
    duv => duvr             ! Point to new one
  endif
end subroutine uv_discard_buffers
!<FF>
subroutine uv_buffer_finduv(code) 
  use clean_arrays
  !! IMAGER -- Find code of current buffer 
  character(len=1), intent(out) :: code
  !! Code (i,r,s or space) of current buffer
  !
  ! Order matters a lot here ...
  if (associated(duv,duvi)) then
    code = 'i'
  else if (associated(duv,duvr)) then
    code = 'r'
  else if (associated(duv,duvs)) then
    code = 's'
  else
    code = ' '
  endif
end subroutine uv_buffer_finduv
!
subroutine uv_buffer_resetuv(code) 
  use clean_arrays
  !! IMAGER -- Reset current buffer to the specified code
  character(len=1), intent(in) :: code  !! Code (i,r,s or space) of current buffer
  !
  if (code.eq.'r') then
    duv => duvr
  else if (code.eq.'s') then
    duv => duvs
  else if (code.eq.'i') then
    duv => duvi
  else
    nullify(duv)
  endif
end subroutine uv_buffer_resetuv
!
subroutine uv_new_data (weight,resample)
  use gkernel_interfaces
  use clean_arrays
  use clean_types
  use imager_interfaces, only : map_uvgildas
  !---------------------------------------------------------------------
  ! @ private-mandatory
  !*
  ! IMAGER -- Internal routine
  !
  ! Declare that the UV data has been modified 
  ! so that   
  ! - the sorting must be redone (no longer needed)  
  ! - the transposed UV data is no longer consistent  
  ! - Data should be read again when asked by the user  
  ! - (optionally) Weights should be re-computed by UV_MAP  
  ! - and SIC variables must be re-defined  
  ! - The "uvself" data set must be discarded  
  !!
  !---------------------------------------------------------------------
  logical, intent(in), optional :: weight    !! Should Weight be discarded
  logical, intent(in), optional :: resample  !! Has resampling be performed 
  !
  logical :: error, increase
  integer :: ier
  !
  error = .false.
  increase = .true.
  if (present(resample)) increase = resample
  if (present(weight)) do_weig = weight
  !
  ! Increase the Optimization level if not going back
  if (increase) then
    optimize(code_save_uv)%change = optimize(code_save_uv)%change + 1
    save_data(code_save_uv) = .true.
  endif
  ! Redefine SIC variables (mandatory)
  ! !Print *,'Address in UV_NEW_DATA before ',locwrd(duv), huv%loca%addr
  huv%file = ' '  ! Reset associated file name
  call map_uvgildas ('UV',huv,error,duv)
  ! !Print *,'Address in UV_NEW_DATA after ',locwrd(duv), huv%loca%addr
  !
  ! Discard the transposed, sorted equivalent
  if (allocated(duvt)) deallocate(duvt)
  !
  ! Set the Channel Flags to 1 (good)
  if (present(resample)) then
    if (allocated(dchanflag)) deallocate(dchanflag)
    allocate(dchanflag(huv%gil%nchan),stat=ier)
    dchanflag = 1
    call sic_def_inte('DCHANFLAG',dchanflag,1,huv%gil%nchan,.false.,error)
  endif
  !
  hself%loca%size =0 ! Discard the "uvself" data
end subroutine uv_new_data
!
subroutine map_uvgildas(name,uvh,error,duv)
  use image_def
  use gkernel_types
  use gkernel_interfaces
  !---------------------------------------------------------------------
  ! @ private-mandatory
  !*
  !   IMAGER  -- This should be in GILDAS kernel
  !
  !   (re-)Define the NAME% SIC header variable and corresponding
  !   NAME data area for UV-like data.
  !
  !   Also define additional variables in the NAME% SIC variable
  !   to handle the pointers towards extra columns for UV data.
  !!
  !---------------------------------------------------------------------
  character(len=*), intent(in) :: name               !! SIC variable name
  type(gildas), intent(inout), target :: uvh         !! Header
  logical, intent(inout) :: error                    !! Logical Error flag
  real, intent(in), target :: duv(:,:)               !! Data area
  !
  ! Local ---
  integer :: i, ier
  logical :: found
  integer(kind=address_length) :: dim(2)
  !
  integer :: iname, jname(code_uvt_last)
  character(len=12) :: lower
  character(len=12), allocatable, save :: enames(:)
  integer, allocatable, save :: ecols(:)
  !
  ! Code ---
  call sic_delvariable(name,.false.,error)
  error = .false.
  !
  call sic_mapgildas (name,uvh,error,duv)
  if (error) return
  !
  if (uvh%gil%uvda_words.eq.0) return
  !
  ! Here print the UV data layout if non standard
  ! This code should normally be in SIC
  if (name.ne.'UV') return    ! For the time being, we only need this for UV%
  !                           ! in the Imager Scripts.
  !
  found = .false.
  iname = 0
  !
  do i=code_uvt_scan,code_uvt_last
    if (uvh%gil%column_pointer(i).gt.0) then
      iname = iname+1
      jname(iname) = i
    endif
  enddo
  if (iname.eq.0) return
  !
  !
  if (allocated(ecols)) deallocate(ecols,enames)
  allocate(ecols(iname),enames(iname),stat=ier)
  !
  dim(1) = iname
  call sic_def_inte('UV%EXTRA_COLUMNS',ecols,1,dim,.false.,error)
  call sic_def_charn('UV%EXTRA_NAMES',enames,1,dim,.false.,error)
  do i=1,iname
    lower = uv_column_name(jname(i))
    call sic_lower(lower)
    enames(i) = lower
    ecols(i) = uvh%gil%column_pointer(jname(i))
  enddo
  !
end subroutine map_uvgildas  
!
!<FF>
!
subroutine discard_uvdata(error)
  use clean_def
  use clean_arrays
  use clean_default
  use clean_types
  use gkernel_interfaces, only : sic_delvariable, gildas_null
  !! IMAGER -- Discard all UV data
  logical, intent(inout) :: error
  !
  ! Local ---
  integer :: atype, ier
  logical :: err
  !
  ! Free the previous zone
  error = .false.
  !
  call uv_free_buffers
  nullify(duv)
  if (allocated(duvi)) deallocate(duvi,stat=ier)
  !
  save_data(code_save_uv) = .false.
  call gildas_null(huv, type='UVT')
  ! No UV_PREVIEW done, then...
  err = .false.
  call sic_delvariable ('PREVIEW',.false.,err)
  call sic_delvariable ('UV',.false.,err)
  call sic_delvariable ('UVS',.false.,err) 
  if (allocated(drobust)) then
    deallocate(drobust)
    call sic_delvariable ('ROBUST_BEAMS',.false.,err)
  endif
  !
  ! Unset optimization (this seems done automatically on other buffers ?)
  atype = 2
!    Print *,'Optimize status ',optimize(atype)%change, optimize(atype)%lastnc, ' change ',optimize(atype)%modif%modif 
!    Print *,'         file ',trim(optimize(atype)%modif%file)
!    
!  type mfile_t
!    character(len=filename_length) :: file=''  ! File name
!    ! Last modification time (to the file system granularity)
!    integer(kind=8) :: mtime
!    ! Last time a modification was probed (to the OS granularity)
!    integer(kind=8) :: ptime
!    ! Was the file modified before last evaluation?
!    logical         :: modif
!  end type mfile_t
!
  optimize(atype)%change = 2          ! Make sure it has changed
  optimize(atype)%modif%file = ' '    ! Reset the filename
  !
  mosaic_mode = 'NONE'
  call sic_delvariable ('FIELDS',.false.,err)
  call reset_fields(themap)
  !
  ! Undo the Weights buffers also
  if (allocated(g_weight)) deallocate(g_weight)
  if (allocated(g_v)) deallocate(g_v)
  do_weig = .true.
end subroutine discard_uvdata
!
subroutine set_buffer_modified(bufnam)
  use clean_types
  !! IMAGER -- Indicate the named buffer has been modified
  character(len=*), intent(in) :: bufnam  !! Buffer name 
  !!  It must be among the known list
  !
  ! Local ---
  integer :: i, atype
  !
  ! Code ----
  do i=1,mtype
    if (bufnam.eq.vtype(i)) then
      atype = i
      optimize(atype)%change = 10 ! Has been modified
      exit
    endif
  enddo
end subroutine set_buffer_modified
