subroutine class_uvt(set,line,r,error,user_function)
  use gildas_def
  use image_def
  use gbl_constant
  use gbl_message
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>class_uvt
  use class_types
  !----------------------------------------------------------------------
  ! @ public (for libclass only)
  ! CLASS Support routine for command
  !  UV_ZERO Name [/VERBOSE]
  ! Create a Zero Spacing UV Table from the current R spectrum
  !----------------------------------------------------------------------
  type(class_setup_t), intent(in)    :: set            !
  character(len=*),    intent(in)    :: line           ! Input command line
  type(observation),   intent(in)    :: r              !
  logical,             intent(inout) :: error          ! Logical flag
  logical,             external      :: user_function  !
  ! Local
  character(len=*), parameter :: rname='UV_ZERO'
  character(len=filename_length) :: chain
  integer(kind=4) :: i,j,ier,nc
  integer(kind=4) :: chfirs, chlast, ltypem
  type(gildas) :: tab
  real(kind=4), allocatable :: dtab(:)
  real(kind=4) :: xoff,yoff,weight
  type(indx_t) :: ind
  integer(kind=4), parameter :: optverb=1  ! /VERBOSE
  integer(kind=4), parameter :: optnew=2  ! /NEW
  !
  if (sic_present(optnew,0)) then
    call class_uvzero_new(set,line,error,user_function)
    return
  endif
  !
  if (r%head%xnum.eq.0) then
    call class_message(seve%e,rname,'No R spectrum in memory')
    error = .true.
    return
  endif
  !
  call sic_ch (line,0,1,chain,nc,.true.,error)
  if (error) return
  call gildas_null(tab, type = 'UVT')
  !
  call sic_parse_file(chain,' ','.uvt',tab%file)
  !
  ! Feedback
  if (sic_present(optverb,0)) then
    call class_message(seve%i,rname,  &
      'Creating UV table '//trim(tab%file)//' from spectrum:')
    !
    call index_fromobs(r%head,ind,error)
    if (error)  return
    call out0('Terminal',0.,0.,error)
    if (error)  return
    call class_list_default(set,ind)
  endif
  !
  chfirs = r%cimin   ! 1
  chlast = r%cimax   ! r%cnchan
  !
  ! Prepare header
  tab%gil%ndim   = 2
  !
  tab%gil%dim(1) = 7+3*(chlast-chfirs+1)
  tab%gil%dim(2) = 1
  !
  tab%gil%ref(1) = r%head%spe%rchan-chfirs+1.d0
  tab%gil%val(1) = r%head%spe%restf ! Sky frequency
  tab%gil%inc(1) = r%head%spe%fres  ! Frequency resolution ...
  !
  tab%gil%ref(2) = 0.d0
  tab%gil%val(2) = 0.d0
  tab%gil%inc(2) = 1.d0
  !
  ! Projection information
  ltypem = r%head%pos%system
  if (ltypem.eq.type_eq) then
    tab%gil%epoc = r%head%pos%equinox
    tab%gil%ra = r%head%pos%lam
    tab%gil%dec = r%head%pos%bet
    call equ_to_gal(tab%gil%ra,tab%gil%dec,0.0,0.0,tab%gil%epoc,   &
                    tab%gil%lii,tab%gil%bii,xoff,yoff,error)
    if (error)  return
    tab%gil%a0 = tab%gil%ra
    tab%gil%d0 = tab%gil%dec
    tab%char%syst = 'EQUATORIAL'
    tab%gil%xaxi = 2
    tab%gil%yaxi = 3
  elseif (ltypem.eq.type_ga) then
    tab%gil%epoc = set%equinox
    tab%gil%lii = r%head%pos%lam
    tab%gil%bii = r%head%pos%bet
    call gal_to_equ(tab%gil%lii,tab%gil%bii,0.0,0.0,   &
                    tab%gil%ra,tab%gil%dec,xoff,yoff,tab%gil%epoc,error)
    if (error)  return
    tab%gil%a0 = tab%gil%lii
    tab%gil%d0 = tab%gil%bii
    tab%char%syst = 'GALACTIC'
    tab%gil%xaxi = 2
    tab%gil%yaxi = 3
  elseif (ltypem.eq.type_ic) then
    tab%gil%epoc = equinox_null
    tab%gil%ra = r%head%pos%lam
    tab%gil%dec = r%head%pos%bet
    tab%gil%lii = 0.d0
    tab%gil%bii = 0.d0
    tab%gil%a0 = tab%gil%ra
    tab%gil%d0 = tab%gil%dec
    tab%char%syst = 'ICRS'
    tab%gil%xaxi = 2
    tab%gil%yaxi = 3
  endif
  tab%gil%bval = r%head%spe%bad
  tab%gil%eval = -1.0
  !
  tab%char%name = r%head%pos%sourc
  !
  ! Projection
  tab%gil%ptyp = r%head%pos%proj
  tab%gil%pang = r%head%pos%projang
  tab%gil%xaxi = 2
  tab%gil%yaxi = 3
  !
  ! Spectroscopy
  tab%char%line = r%head%spe%line
  tab%gil%freq  = r%head%spe%restf
  tab%gil%voff  = r%head%spe%voff
  tab%gil%vres  = r%head%spe%vres
  tab%gil%fima  = r%head%spe%image
  tab%gil%fres  = r%head%spe%fres
  tab%gil%faxi  = 1
  !
  ! Here define the order of the basic "columns".
  ! No "extra" ones
  tab%gil%column_size = 0
  tab%gil%column_pointer(code_uvt_u) = 1
  tab%gil%column_pointer(code_uvt_v) = 2
  tab%gil%column_pointer(code_uvt_w) = 3
  tab%gil%column_pointer(code_uvt_date) = 4
  tab%gil%column_pointer(code_uvt_time) = 5
  tab%gil%column_pointer(code_uvt_anti) = 6
  tab%gil%column_pointer(code_uvt_antj) = 7
  do i=1,code_uvt_last
    if (tab%gil%column_pointer(i).ne.0) tab%gil%column_size(i) = 1
  enddo
  !
  ! Finalize the UV Table header
  tab%gil%natom = 3
  tab%gil%nstokes = 1
  tab%gil%nvisi = 1
  tab%gil%nchan = (chlast-chfirs+1)
  tab%gil%type_gdf = code_gdf_uvt
  call gdf_setuv (tab,error)
  if (error) return
  !
  ! call gdf_print_header(tab)
  ! Prepare data
  !
  allocate(dtab(tab%gil%dim(1)),stat=ier)
  if (failed_allocate(rname,'dtab',ier,error))  return
  tab%loca%size = tab%gil%dim(1)*tab%gil%dim(2)
  dtab(:) = 0.
  !
  select case (set%weigh)
  case ('S')
    call obs_weight_sigma(rname,r,weight,error)
  case ('T')
    call obs_weight_time(rname,r,weight,error)
  case ('E')
    weight = 1.
  case default
    call class_message(seve%e,rname,'SET WEIGHT '//set%weigh//' is not supported')
    error = .true.
  end select
  if (error)  return
  !
  j = 0
  do i=chfirs,chlast
    dtab(8+j) = r%spectre(i)
    if (r%spectre(i).eq.r%head%spe%bad) then
      dtab(10+j) = 0.
    else
      dtab(10+j) = weight
    endif
    j = j+3
  enddo
  call gdf_write_image(tab,dtab,error)
  if (error) then
    call class_message(seve%f,rname,'Cannot create output table')
  endif
  deallocate(dtab)
  !
end subroutine class_uvt
!
subroutine class_uvzero_new(set,line,error,user_function)
  use phys_const
  use image_def
  use gbl_message
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>class_uvzero_new
  use class_index
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  ! Support routine for command
  !   UV_ZERO file.uvt /NEW
  !---------------------------------------------------------------------
  type(class_setup_t), intent(in)    :: set
  character(len=*),    intent(in)    :: line
  logical,             intent(inout) :: error
  logical,             external      :: user_function
  ! Local
  type(gildas) :: inuvhead,ouhead
  real(kind=4), allocatable :: oudata(:,:)
  real(kind=4), allocatable :: uvoffxy(:,:),cxoffxy(:,:)
  integer(kind=4) :: ixycol(2)
  integer(kind=4) :: noff,nc
  integer(kind=4), parameter :: optnocheck=3
  integer(kind=4), parameter :: optlike=4
  character(len=filename_length) :: infile,oufile
  character(len=message_length) :: mess
  logical :: dolike
  type(resampling) :: faxis
  character(len=*), parameter :: rname='UV_ZERO'
  !
  call sic_ch(line,0,1,infile,nc,.true.,error)
  if (error) return
  dolike = sic_present(optlike,0)
  if (dolike) then
    call resample_parse_like(rname,line,optlike,faxis,error)
    if (error)  return
  endif
  !
  call uvzero_consistency(set,line,cx,error,user_function)
  if (error) return
  call read_uvhead(infile,inuvhead,error)
  if (error) return
  call read_offsets(inuvhead,ixycol,noff,uvoffxy,error)
  if (error)  return
  call reproject_offsets(cx%cons%head,inuvhead,noff,uvoffxy,cxoffxy,error)
  if (error) return
  call prepare_uvtable(noff,oufile,inuvhead,ouhead,oudata,error)
  if (error) return
  call get_and_fill_uvdata(set,cx,ixycol,noff,uvoffxy,cxoffxy,dolike,faxis,  &
    ouhead,oudata,error,user_function)
  if (error) return
  call write_uvtable(ouhead,oudata,error)
  if (error) return
  !
contains
  subroutine uvzero_consistency(set,line,idx,error,user_function)
    use class_types
    type(class_setup_t), intent(in)    :: set
    character(len=*),    intent(in)    :: line
    type(optimize),      intent(inout) :: idx
    logical,             intent(inout) :: error
    logical,             external      :: user_function
    !
    call consistency_check_selection(set,line,optnocheck,idx%cons,error)
    if (error) return
    idx%cons%off%check = .false. ! We assume the data represent some kind of mapping of the source
    call consistency_check_do(set,rname,idx,error,user_function)
    if (error) return
    if (idx%cons%prob)  error = .true.
  end subroutine uvzero_consistency
  !
  subroutine read_uvhead(name,uvhead,error)
    use image_def
    character(len=*), intent(in)    :: name
    type(gildas),     intent(out)   :: uvhead
    logical,          intent(inout) :: error
    !
    call gildas_null(uvhead,type='UVT')
    uvhead%file = trim(name)
    call gdf_read_header(uvhead,error)
    if (error) return
    call class_message(seve%i,rname,'Input UV Table is '//trim(uvhead%file))
  end subroutine read_uvhead
  !
  subroutine read_offsets(huv,ixycol,noff,offxy,error)
    use image_def
    type(gildas),     intent(inout)            :: huv
    integer(kind=4),  intent(out)              :: ixycol(2)
    integer(kind=4),  intent(out)              :: noff
    real(kind=4),     intent(out), allocatable :: offxy(:,:)
    logical,          intent(inout)            :: error
    ! Local
    integer(kind=4), parameter :: code_uvzero_single=0 ! Single field UV table
    integer(kind=4), parameter :: code_uvzero_phase=1  ! Mosaic UV table with phase offsets
    integer(kind=4), parameter :: code_uvzero_point=2  ! Mosaic UV table with pointing offsets
    real(kind=4), allocatable :: duv(:,:)
    integer(kind=4) :: np,nv,loff,moff,xoff,yoff,uvmode,ier
    !
    loff = huv%gil%column_pointer(code_uvt_loff)
    moff = huv%gil%column_pointer(code_uvt_moff)
    xoff = huv%gil%column_pointer(code_uvt_xoff)
    yoff = huv%gil%column_pointer(code_uvt_yoff)
    !
    ! Allocate and fill offxy
    if ((loff.ne.0).or.(moff.ne.0)) then
       write(mess,'(A,I0,A,I0)') 'Phase offset columns at loff: ',loff,', moff: ',moff
       call class_message(seve%i,rname,mess)
       if (moff.ne.loff+1) then
          call class_message(seve%e,rname,'moff should be equal to loff+1')
          error = .true.
          return
       endif
       ixycol(1:2) = [loff,moff]
       uvmode = code_uvzero_phase
    elseif ((xoff.ne.0).or.(yoff.ne.0)) then
       write(mess,'(A,I0,A,I0)') 'Pointing offset columns at xoff: ',xoff,', yoff: ',yoff
       call class_message(seve%i,rname,mess)
       if (yoff.ne.xoff+1) then
          call class_message(seve%e,rname,'yoff should be equal to xoff+1')
          error = .true.
          return
       endif
       ixycol(1:2) = [xoff,yoff]
       uvmode = code_uvzero_point
    else
       call class_message(seve%i,rname,'Single field uv table')
       uvmode = code_uvzero_single
    endif
    !
    if ((uvmode.eq.code_uvzero_phase).or.(uvmode.eq.code_uvzero_point)) then
       np = 2
       nv = huv%gil%dim(2)
       huv%blc(1:2) = [ixycol(1),0]
       huv%trc(1:2) = [ixycol(2),0]
       allocate (duv(np,nv),stat=ier)
       if (failed_allocate(rname,'Mosaic offsets',ier,error)) return
       call gdf_read_data(huv,duv,error)
       if (error) return
       call mosaic_getfields(duv,np,nv,1,2,noff,offxy)
       deallocate(duv)
    else if (uvmode.eq.code_uvzero_single) then
       noff = 1
       allocate (offxy(2,1),stat=ier)
       if (failed_allocate(rname,'Single field offsets',ier,error)) return
       offxy = 0.0
    endif
  end subroutine read_offsets
  !
  subroutine reproject_offsets(idxref,uvhead,noff,uvoffxy,idxoffxy,error)
    use phys_const
    use image_def
    use gkernel_types
    use classcore_dependencies_interfaces
    use class_types
    !---------------------------------------------------------------------
    !
    !---------------------------------------------------------------------
    type(header),              intent(in)    :: idxref
    type(gildas),              intent(in)    :: uvhead
    integer(kind=4),           intent(in)    :: noff
    real(kind=4),              intent(in)    :: uvoffxy(:,:)
    real(kind=4), allocatable, intent(out)   :: idxoffxy(:,:)
    logical,                   intent(inout) :: error
    !
    type(projection_t) :: uvproj,idxproj
    integer(kind=4) :: ioff,ier
    real(kind=8) :: rxoff,ryoff
    real(kind=8) :: axoff,ayoff
    !
    ! Setup projections
    call gwcs_projec(&
         uvhead%gil%a0,uvhead%gil%d0,&
         uvhead%gil%pang,uvhead%gil%ptyp,&
         uvproj,error)
    if (error)  return
    call gwcs_projec(&
         idxref%pos%lam,idxref%pos%bet,&
         idxref%pos%projang,idxref%pos%proj,&
         idxproj,error)
    if (error) return
    allocate(idxoffxy(2,noff),stat=ier)
    if (failed_allocate(rname,'Mosaic offsets in class index projection',ier,error))  return
    do ioff=1,noff
       rxoff = uvoffxy(1,ioff)
       ryoff = uvoffxy(2,ioff)
       call rel_to_abs(uvproj,rxoff,ryoff,axoff,ayoff,1)
       call abs_to_rel(idxproj,axoff,ayoff,rxoff,ryoff,1)
       idxoffxy(1,ioff) = rxoff 
       idxoffxy(2,ioff) = ryoff
       write(mess,'(A,I4,2(A,f9.2,A,f9.2,A))') &
            'Field #',ioff,&
            ', uv: (',uvoffxy(1,ioff)*sec_per_rad,',',uvoffxy(2,ioff)*sec_per_rad,')',&
            ', cx: (',idxoffxy(1,ioff)*sec_per_rad,',',idxoffxy(2,ioff)*sec_per_rad,')'
       call class_message(seve%r,rname,mess)
    enddo ! ioff
  end subroutine reproject_offsets
  !
  subroutine prepare_uvtable(nvisi,oufile,inuvhead,ouhead,oudata,error)
    use image_def
    !---------------------------------------------------------------------
    !
    !---------------------------------------------------------------------
    integer(kind=4),           intent(in)    :: nvisi
    character(len=*),          intent(in)    :: oufile
    type(gildas),              intent(in)    :: inuvhead
    type(gildas),              intent(out)   :: ouhead
    real(kind=4), allocatable, intent(inout) :: oudata(:,:)
    logical,                   intent(inout) :: error
    !
    integer(kind=4) :: ier
    character(len=filename_length) :: oext,odir
    !
    call gildas_null(ouhead,type='UVT')
    call gdf_copy_header(inuvhead,ouhead,error)
    if (error) return
    call sic_parse_name(inuvhead%file,ouhead%file,oext,odir)
    ouhead%file = trim(odir)//trim(ouhead%file)//'-uvzero.'//trim(oext)
    ouhead%gil%nvisi = nvisi
    ouhead%gil%dim(2) = nvisi
    ouhead%loca%size = ouhead%gil%dim(1)*ouhead%gil%dim(2)
    ! Sanity checks
    if (ouhead%gil%natom.ne.3) then
       call class_message(seve%e,rname,'Do not know how to handle a uv table order different from (real,imag,weight)')
       error = .true.
       return
    endif
    if (ouhead%gil%nstokes.ne.1) then
       call class_message(seve%e,rname,'Do not know how to handle a uv table with more than one stokes parameter')
       error = .true.
       return
    endif
    if (ouhead%gil%column_pointer(code_uvt_scan).ne.3) then
       call class_message(seve%e,rname,'Changing uv table 3rd column to scan number')
       ouhead%gil%column_pointer(code_uvt_scan) = 3
    endif
    call gdf_setuv(ouhead,error)
    if (error) return
    allocate(oudata(ouhead%gil%dim(1),ouhead%gil%dim(2)),stat=ier)
    if (failed_allocate(rname,'uvzero table',ier,error)) return
  end subroutine prepare_uvtable
  !
  subroutine get_and_fill_uvdata(set,idx,ixycol,noff,uvoffxy,idxoffxy,  &
    dolike,faxis,ouhead,oudata,error,user_function)
    use class_parameter
    use class_index
    !---------------------------------------------------------------------
    ! On purpose, there is no protection against duplicate found. The user
    ! needs to know what it does.
    !---------------------------------------------------------------------
    type(class_setup_t), intent(in)    :: set
    type(optimize),      intent(in)    :: idx
    integer(kind=4),     intent(in)    :: ixycol(2)
    integer(kind=4),     intent(in)    :: noff
    real(kind=4),        intent(in)    :: uvoffxy(2,noff)
    real(kind=4),        intent(in)    :: idxoffxy(2,noff)
    logical,             intent(in)    :: dolike
    type(resampling),    intent(in)    :: faxis
    type(gildas),        intent(in)    :: ouhead
    real(kind=4),        intent(inout) :: oudata(:,:)
    logical,             intent(inout) :: error
    logical,             external      :: user_function
    ! Local
    type(optimize) :: mycx
    type(observation) :: obs
    logical, parameter :: output_scaling = .true.
    logical, parameter :: dofft = .false.
    logical :: myerror = .false.
    integer(kind=entry_length) :: nfound
    integer(kind=4) :: ioff,gagdate
    !
    ! Loop on all offsets
    write(mess,'(I4,A)') noff,' fields in UV table'
    call class_message(seve%r,rname,mess)
    ! Initialize 'class_list_defbrieflong' output to terminal
    call out0('Terminal',0.,0.,error)
    if (error)  return
    ! Initialize gagdate, local obs and index
    call sic_gagdate(gagdate)
    call init_obs(obs)
    do ioff=1,noff
      ! Tune the searching flags used by subroutine FIX. NB: the other flags
      ! have been reset at the end of previous call to FIX.
      flg%off1 = .true.  ! Enable search by X offset
      smin%off1 = idxoffxy(1,ioff) - set%tole
      smax%off1 = idxoffxy(1,ioff) + set%tole
      flg%off2 = .true.  ! Enable search by Y offset
      smin%off2 = idxoffxy(2,ioff) - set%tole
      smax%off2 = idxoffxy(2,ioff) + set%tole
      ! Find from given IDX
      mycx%next = 1
      call fix(set,idx,mycx,nfound,error)
      if (error)  exit
      write(mess,'(A,I4,A,I4,A,f9.2,f9.2)')  &
        'Field #',ioff,', averaging ',nfound,' entries around ',  &
        idxoffxy(1,ioff)/rad_per_sec,idxoffxy(2,ioff)/rad_per_sec
      if (nfound.eq.0) then
         call class_message(seve%e,rname,mess)
         error = .true.
         exit
      else
         call class_message(seve%r,rname,mess)
      endif
      call class_list_defbrieflong(set,mycx,rix,0,error) ! *** JP Should be only in verbose mode
      if (error) exit
      ! Read closest spectrum
      ! *** JP Right now only first one
      call get_it(set,obs,mycx%ind(1),user_function,error)
      if (error) exit
!      call modify_scale(obs,yunit_Jyperbeam,output_scaling,error)
!      if (error) exit
      if (dolike) then
         call do_resample(set,obs,faxis,dofft,error)
         if (error)  exit
      endif
      call obs2uvline(set,obs,gagdate,ouhead,ixycol,uvoffxy(:,ioff),oudata(:,ioff),error)
      if (error) exit
    enddo ! ioff
    ! Cleanup
    call free_obs(obs)
    call deallocate_optimize(mycx,myerror)
    if (myerror) error = myerror
  end subroutine get_and_fill_uvdata
  !
  subroutine obs2uvline(set,obs,gagdate,uvhead,ixycol,uvoffxy,uvline,error)
    type(class_setup_t), intent(in)    :: set
    type(observation),   intent(in)    :: obs
    integer(kind=4),     intent(in)    :: gagdate
    integer(kind=4),     intent(in)    :: ixycol(2)
    type(gildas),        intent(in)    :: uvhead
    real(kind=4),        intent(in)    :: uvoffxy(2)
    real(kind=4),        intent(inout) :: uvline(:)
    logical,             intent(inout) :: error
    !
    real(kind=4) :: weight
    integer(kind=4) :: ichan,icol,iu,iv,iscan,idate,itime,ianti,iantj
    integer(kind=4), parameter :: code_sd_iant = -1
    !
    if (obs%head%spe%nchan.ne.uvhead%gil%nchan) then
       write(mess,'(A,I0,A,I0,A)')  &
            'Different number of channels (uvt: ',uvhead%gil%nchan,', obs: ',obs%head%spe%nchan,')'
       call class_message(seve%e,rname,mess)
       call class_message(seve%e,rname,'Use the /LIKE option')
       error = .true.
       return
    endif
    select case (set%weigh)
    case ('S')
       call obs_weight_sigma(rname,obs,weight,error)
       if (error) return
    case ('T')
       call obs_weight_time(rname,obs,weight,error)
       if (error) return
    case ('E')
       weight = 1.
    case default
       call class_message(seve%e,rname,'SET WEIGHT '//set%weigh//' is not supported')
       error = .true.
       if (error)  return
    end select
    iu    = uvhead%gil%column_pointer(code_uvt_u)
    iv    = uvhead%gil%column_pointer(code_uvt_v)
    iscan = uvhead%gil%column_pointer(code_uvt_scan)
    idate = uvhead%gil%column_pointer(code_uvt_date)
    itime = uvhead%gil%column_pointer(code_uvt_time)
    ianti = uvhead%gil%column_pointer(code_uvt_anti)
    iantj = uvhead%gil%column_pointer(code_uvt_antj)
    ianti = uvhead%gil%column_pointer(code_uvt_anti)
    iantj = uvhead%gil%column_pointer(code_uvt_antj)
    uvline(iu) = 0.0
    uvline(iv) = 0.0
    uvline(iscan) = real(obs%head%gen%scan)
    uvline(idate) = gagdate
    uvline(itime) = 0.0 ! 00:00 UT
    uvline(ianti) = code_sd_iant
    uvline(iantj) = code_sd_iant
    if (ixycol(1).ne.0) uvline(ixycol(1)) = uvoffxy(1)
    if (ixycol(2).ne.0) uvline(ixycol(2)) = uvoffxy(2)
    icol = 0
    do ichan=1,obs%head%spe%nchan
       if (obs%spectre(ichan).ne.obs%head%spe%bad) then
          uvline(8+icol) = obs%spectre(ichan) ! Real
          uvline(9+icol) = 0.0                ! Imag
          uvline(10+icol) = weight            ! Weight
       else
          uvline(8+icol) = uvhead%gil%bval ! Real
          uvline(9+icol) = uvhead%gil%bval ! Imag
          uvline(10+icol) = 0.             ! Imag
       endif
       icol = icol+3
    enddo
  end subroutine obs2uvline
  !
  subroutine write_uvtable(ouhead,oudata,error)
    type(gildas), intent(inout) :: ouhead
    real(kind=4), intent(inout) :: oudata(:,:)
    logical,      intent(inout) :: error
    !
    call gdf_write_image(ouhead,oudata,error)
    if (error) then
       call class_message(seve%e,rname,'Error writing '//trim(ouhead%file)//' table')
       return
    endif
    write(mess,'(I0,A)') ouhead%gil%nvisi,' visibilities written'
    call class_message(seve%i,rname,mess)
    call gdf_print_header(ouhead) ! *** JP should be called in verbose mode only
  end subroutine write_uvtable
end subroutine class_uvzero_new
!
subroutine mosaic_getfields(visi,np,nv,ixoff,iyoff,nf,doff)
  use gkernel_types
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>mosaic_getfields
  !----------------------------------------------------------------------
  ! @ private
  !  Count number of fields and get their coordinates
  !----------------------------------------------------------------------
  integer(kind=4), intent(in)    :: np                    ! Size of a visibility
  integer(kind=4), intent(in)    :: nv                    ! Number of visibilities
  real(kind=4),    intent(in)    :: visi(np,nv)           ! Input visibilities
  integer(kind=4), intent(in)    :: ixoff                 ! X pointer
  integer(kind=4), intent(in)    :: iyoff                 ! Y pointer
  integer(kind=4), intent(out)   :: nf                    ! Number of fields
  real(kind=4),    intent(out), allocatable :: doff(:,:)  ! Field offsets
  ! Local
  type(eclass_2dble_t) :: eclass
  integer(kind=4) :: ier
  logical :: error
  !
  ! ZZZ Single precision floats should be enough, but gmath does not
  !     (yet) provide the corresponding type. Work with double instead.
  !
  error = .false.
  nf = 0
  !
  call reallocate_eclass_2dble(eclass,nv,error)
  if (error)  return
  !
  eclass%val1(1:nv) = visi(ixoff,1:nv)
  eclass%val2(1:nv) = visi(iyoff,1:nv)
  eclass%cnt(1:nv) = 1
  !
  call eclass_2dble(mosaic_getfields_offset_eq,eclass)
  !
  nf = eclass%nequ
  allocate(doff(2,nf),stat=ier)
  if (.not.failed_allocate('UV_ZERO','offsets array',ier,error)) then
    doff(1,1:eclass%nequ) = eclass%val1(1:nf)
    doff(2,1:eclass%nequ) = eclass%val2(1:nf)
  endif
  !
  call free_eclass_2dble(eclass,error)
  !
end subroutine mosaic_getfields
!
function mosaic_getfields_offset_eq(x1,x2,y1,y2)
  use phys_const
  !---------------------------------------------------------------------
  ! @ private
  ! Equality routine between two pairs of offset (real*8) with a
  ! tolerance.
  ! ---
  ! This subroutine should be kept in 'mosaic_getfields' under a
  ! contains statement, but gfortran 4.4 is not able to compile this...
  !---------------------------------------------------------------------
  logical :: mosaic_getfields_offset_eq
  real(kind=8), intent(in) :: x1,x2  ! [rad]
  real(kind=8), intent(in) :: y1,y2  ! [rad]
  ! Local
  real(kind=8), parameter :: tol=1.d-2*rad_per_sec  ! 0.01 sec is enough
  !
  mosaic_getfields_offset_eq = abs(x1-x2).le.tol .and. abs(y1-y2).le.tol
  !
end function mosaic_getfields_offset_eq
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
