!
subroutine map_parameters(task,map,freq,uvmax,uvmin,error,print)
  use gkernel_interfaces
  use mapping_interfaces, only: map_message, primary_beam
  use clean_def
  use clean_arrays
  use clean_types
  use clean_default
  use gbl_message
  !----------------------------------------------------------------------
  ! @ private-mandatory
  !
  ! Prepare the MAP parameters for UV_MAP, MX or UV_RESTORE
  ! Reads this from SIC variables
  !-----------------------------------------------------------------------
  character(len=*), intent(in)    :: task ! Input task name (UV_MAP or MX)
  type (uvmap_par), intent(inout) :: map  ! Map parameters
  real(8), intent(inout) :: freq          ! Observing frequency
  real(4), intent(in) :: uvmax, uvmin     ! Min & Max UV in m
  logical, intent(inout) :: error
  logical, optional :: print
  !
  real(8), parameter :: pi=3.14159265358979323846d0
  real(8), parameter :: f_to_k = 2.d0*pi/299792458.d-6
  real(4), parameter :: pixel_per_beam=5.0
  real(4) :: map_range(2)  ! Range of offsets
  character(len=80) :: chain
  character(len=12) :: prefix
  real :: uvmi, uvma, xp, xm, diam, hppb, rsize, bsize
  integer :: i, ms, k, np, isize
  type (uvmap_par), save :: last_map
  logical :: do_print
  integer :: osize(2)
  logical, parameter :: fromressection=.true.
  !
  do_print = present(print)
  !
  ! For UV_STAT, reset all parameters to Zero
  if (task.eq.'UV_STAT') then
    map%size = 0
    map%field = 0
    map%xycell = 0
  endif
  !
  freq = gdf_uv_frequency(huv)
  if (do_print) then                                            
    write(chain,'(A,F12.6,A)') "Observed rest frequency       ", &
      & freq*1d-3," GHz"
    call map_message(seve%i,task,chain)
  endif
  !
  uvma = uvmax/(freq*f_to_k)
  uvmi = uvmin/(freq*f_to_k)
  if (do_print) then
    write(chain,100) huv%gil%dim(2),huv%gil%nchan
    call map_message(seve%i,task,chain)
    write(chain,101) uvmi,uvma,' meters'
    call map_message(seve%i,task,chain)
    write(chain,101) uvmin*1e-3/2.0/pi,uvmax*1e-3/2.0/pi,' kiloWavelength'
    call map_message(seve%i,task,chain)
  endif
  !
  ! Get beam size (in radians)
  bsize = primary_beam(task,huv,fromressection)
  !
  if (bsize.eq.0) then
    !
    ! Default to IRAM Plateau de Bure case
    hppb = 63.0*(12.0/15.0)*(100.e3/freq) ! ["] Primary beam size
    write(chain,'(A,F12.1,A)') "Half power primary beam defaulted to ", &
      & hppb," arcsec"
    call map_message(seve%w,task,chain)                         
    bsize = hppb*pi/3600.0/180.0
  else if (do_print .or. map%size(1).eq.0) then                                           
    write(chain,'(A,F12.1,A)') "Half power primary beam       ", &
      & bsize*180*3600/pi," arcsec"
    call map_message(seve%i,task,chain)                         
  endif
  hppb = bsize*3600.*180./pi                                                        
  !
  ! Only 2 out of the 3 MAP_FIELD, MAP_SIZE and MAP_CELL
  !   can be non-zero. This should be tested in some way
  !
  if (map%xycell(1)*map%size(1)*map%field(1).ne.0) then
    if (abs(map%field(1)-map%size(1)*map%xycell(1)).gt.0.01*map%field(1)) then
      call map_message(seve%w,task,'User specified MAP_FIELD, MAP_SIZE and MAP_CELL do not match')
    else
      call map_message(seve%w,task,'MAP_FIELD, MAP_SIZE and MAP_CELL specified by user')    
    endif
  endif
  !
  ! Now get MAP_CELL and MAP_SIZE if Zero.
  if (map%xycell(1).eq.0) then
    if (map%size(1)*map%field(1).eq.0) then
      map%xycell(1) = 0.01*nint(360.0*3600.0*100.0/uvmax/pixel_per_beam)
      if (map%xycell(1).le.0.02) then
        map%xycell(1) =   &
             &        0.002*nint(360.0*3600.0*500.0/uvmax/pixel_per_beam)
      endif
      map%xycell(2) = map%xycell(1)  ! In ", rounded to 0.02 or 0.002"
    else
      map%xycell(1) = map%field(1)/map%size(1)
      map%xycell(2) = map%xycell(1)
    endif
  endif
  !
  ! Get MAP_SIZE if non Zero
  if (map%size(1).ne.0) then
    if (map%size(2).eq.0) map%size(2) = map%size(1)
    if (map%field(1).eq.0) map%field = map%size * map%xycell
  endif
  !
  ! Get a wide enough field of view (in ")
  if (map%field(1).ne.0) then
    if (map%field(2).eq.0) map%field(2) = map%field(1)
  else
    !
    if (map%nfields.ne.0) then
      ! The factor 2.5 on the primary beam size is to go down 
      ! low enough by default
      map%field = 2.5*hppb
      ! Enlarge the field of view by the Offset range
      np = abs(map%nfields)
      xm = minval(map%offxy(1,1:np))
      xp = maxval(map%offxy(1,1:np))
      map_range(1) = xp-xm
      xm = minval(map%offxy(2,1:np))
      xp = maxval(map%offxy(2,1:np))
      map_range(2) = xp-xm
      map_range = map_range*180*3600/pi
      !
      map%field = map%field + map_range
    else
      ! The factor 2 on the primary beam size is to go down to 6.25 % level by default
      map%field(1) = 2*hppb
      ! Map Field = 1.13*Lambda/Dmin - but round to 1.3
      if (uvmin.ne.0) then
        map%field(2) = 2.6*360*3600/uvmin ! " In arcsec
      else
        map%field(2) = map%field(1)
      endif
      ! The Min is to avoid going to very large images when uvmin is close to 0
      ! e.g. when short or Zero spacings have been added
      map%field = min(map%field(1),map%field(2))    
    endif
  endif
  !
  if (map%size(1).eq.0) then
    !
    map%size = map%field/map%xycell !
    !
    ! map%size =   2**nint(log(real(map%size))/log(2.0))
    call gi4_round_forfft(map%size(1),osize(1),error,map_rounding,map_power)
    call gi4_round_forfft(map%size(1),osize(2),error,map_rounding,map_power)
    map%size = osize
  else if ( (mod(map%size(1),2).ne.0) .or. (mod(map%size(2),2).ne.0) ) then
    call map_message(seve%e,task,'Number of pixels (MAP_SIZE) must be even')
    error = .true.
  endif
  !
  if (task.eq.'UV_STAT') then
    prefix = 'Recommended '
  else
    if (error) return
    prefix = 'Current '
  endif
  write(chain,'(A,A,F12.1,a,F12.1,A)') prefix,'Field of view / Largest Scale ' &
    & ,map%field(1),' x ',map%field(2),' "'
  call map_message(seve%i,task,chain)
  write(chain,'(A,A,F11.1,A,F11.1,A)') prefix,'Image size ', &
    & map%size(1)*map%xycell(1),' x ',map%size(2)*map%xycell(2),'" '
  call map_message(seve%i,task,chain)
  !
  write(chain,'(A,A,I0,A,I0,A)') prefix,'Map size ', &
    & map%size(1),' x ',map%size(2)
  call map_message(seve%i,task,chain)
  write(chain,'(A,A,F8.3,A,F8.3,A)') prefix,'Pixel size ', &
    & map%xycell(1),' x ',map%xycell(2),' "'
  call map_message(seve%i,task,chain)
  !
  ! Do NOT adjust the Field while keeping the Cell size 
  !     map%field = map%size * map%xycell
  ! it is useless or incorrect...
  !
  if (task.eq.'UV_STAT') return
  ! This part is only for UV_MAP / UV_MOSAIC, not for UV_STAT
  !
  ! Check whether Weights have to be recomputed
  if (map%mode.ne.last_map%mode) do_weig = .true.
  if (map%mode.ne.'NATURAL ') then
    if (map%uniform(1).ne.last_map%uniform(1)) do_weig = .true.
    if (map%uniform(2).ne.last_map%uniform(2)) do_weig = .true.
  endif
  if (map%ctype.ne.last_map%ctype) do_weig = .true.
  do i=1,4
    if (map%taper(i).ne.last_map%taper(i)) do_weig = .true.
  enddo
  last_map = map
  !
  ! Subroutine DOWEI uses map%uniform = 0.0 for Natural Weighting
  if (map%mode.eq.'NATURAL ') map%uniform(1) = 0
  !
100 format('Found ',i12,' Visibilities, ',i4,' channels')
101 format('Baselines ',f9.1,' - ',f9.1,a)
103 format('Map size is   ',i4,' by ',i4)
104 format('Pixel size is ',f8.3,' by ',f8.3,'"')
end subroutine map_parameters
!
subroutine uv_stat_comm(line,error)
  use gkernel_interfaces
  use mapping_interfaces, except_this=>uv_stat_comm
  use clean_def
  use clean_default
  use clean_arrays
  use gbl_message
  !------------------------------------------------------------------------
  ! @ private
  !
  ! MAPPING   Support for command UV_STAT
  !       Analyse a UV data set to define approximate beam size,
  !       field of view, expected "best beam", etc...
  ! Input :
  !     a precessed UV table
  ! Output :
  !     a precessed, rotated, shifted UV table, sorted in V,
  !     ordered in (U,V,W,D,T,iant,jant,nchan(real,imag,weig))
  !     a beam image ?
  !------------------------------------------------------------------------
  character(len=*), intent(inout) :: line
  logical, intent(out) :: error
  !
  real(kind=8), parameter :: pi=3.14159265358979323846d0
  real(kind=8), parameter :: f_to_k = 2.d0*pi/299792458.d-6
  !
  integer, parameter :: mt=100
  integer datelist(mt)
  !
  type (uvmap_par), save :: amap  ! To get the New variable names
  !
  integer i
  integer ndates
  character(len=8) mode, argum
  character(len=4) :: wei
  real, allocatable :: beams(:,:), fft(:)
  real uv_taper(3),map_cell(2),uniform(2),uvmax,uvmin,uvm
  real start,step,taper
  integer map_size(2),wcol,ctype,n,mcol(2),ier,nu,nv,noff
  integer(kind=index_length) :: dim(4)
  logical sorted, shift
  real(kind=8) :: freq, new(3)
  real(kind=4) :: map_field(2)
  real(4), save :: bmax, bmin
  logical, save :: first = .true.
  real, save :: result(10,8)
  logical :: print
  character(len=message_length) :: chain
  character(len=7) :: rname = 'UV_STAT'
  integer, parameter :: mmode=8
  character(len=8) :: smode(mmode)
  data smode /'ADVISE','ALL','BEAM','CELL','HEADER','SETUP','TAPER','WEIGHT'/
  !
  if (sic_present(0,1)) then
    call sic_ke(line,0,1,argum,n,.false.,error)
    if (error) return
    call sic_ambigs (rname,argum,mode,n,smode,mmode,error)
    if (error) return
  else
    mode = 'ALL'
  endif
  !
  freq = gdf_uv_frequency(huv)
  !
  select case (mode)
  case ('CELL','TAPER','WEIGHT')
    !
    start = 0.0
    call sic_r4(line,0,2,start,.false.,error)
    start = abs(start)
    step = 0.0
    call sic_r4(line,0,3,step,.false.,error)
    step = abs(step)
    !
    ctype = 1
    ! That is no longer correct -
!    call sic_get_real('UV_TAPER[1]',uv_taper(1),error)
!    if (error) return
!    call sic_get_real('UV_TAPER[2]',uv_taper(2),error)
!    call sic_get_real('UV_TAPER[3]',uv_taper(3),error)
!    call sic_get_real('UV_CELL[1]',uniform(1),error)
!    call sic_get_real('UV_CELL[2]',uniform(2),error)
!    call get_weightmode(rname,wei,error)
    !
    ! Must do like UV_MAP now
    call map_prepare(rname,amap,error)
    uniform(:) = amap%uniform(:)
    uv_taper(:) = amap%taper(1:3) 
! Unclear ...
!    call sic_get_inte('WCOL',wcol,error)
! This were useless anyway...
!    call sic_get_inte('MCOL[1]',mcol(1),error)
!    call sic_get_inte('MCOL[2]',mcol(2),error)
!    !
    if (error) return
    !
    ! First sort the input UV Table, leaving UV Table in UV_*
    shift = .false.
    call uv_sort (error,sorted,shift,new,uvmax,uvmin)
    if (error) return
  case ('ADVISE','ALL','HEADER','SETUP','BEAM')
    ! For HEADERS, do the minimum work for speed...
    ! The UV table is available in HUV%
    if (huv%loca%size.eq.0) then
      call map_message(seve%e,rname,'No UV data loaded')
      error = .true.
      return
    endif
    call uvgmax (huv,duv,uvmax,uvmin)
    ! Now transform UVMAX in kiloWavelength (including 2 pi factor)
    uvmax = uvmax*freq*f_to_k
    uvmin = uvmin*freq*f_to_k
    error = .false.
  end select
  !
  ! New code: For the time being, this is somewhat inconsistent
  ! with the use of uv_sort which uses a different frequency
  !
  bmax = uvmax/(freq*f_to_k)
  bmin = uvmin/(freq*f_to_k)
  if (first) then
!    call sic_defstructure('UVSTAT',.true.,error)
!    call sic_def_real('UVSTAT%BMAX',bmax,0,dim,.false.,error)
!    call sic_def_real('UVSTAT%BMIN',bmin,0,dim,.false.,error)
    call sic_def_real('UV_BMAX',bmax,0,dim,.false.,error)
    call sic_def_real('UV_BMIN',bmin,0,dim,.false.,error)
    first = .false.
  endif
  !
  ! That's all for HEADER
  select case (mode)
  case ('BEAM') 
    call map_beamsize(huv,duv,bmax,error)
  case ('HEADER')
    call gdf_print_header(huv)
    call uv_listheader(huv,duv,mt,datelist,ndates,freq)
    call uv_printoffset('HEADER',themap)
  case ('ADVISE')
    call map_copy_par(default_map,themap)
    call map_parameters(rname,themap,freq,uvmax,uvmin,error,print)
    error = .false.
  case ('ALL')
    call gdf_print_header(huv)
    call uv_listheader(huv,duv,mt,datelist,ndates,freq)
    call uv_printoffset('HEADER',themap)
    call map_copy_par(default_map,themap)
    call map_parameters(rname,themap,freq,uvmax,uvmin,error,print)
  case ('SETUP')
    call map_copy_par(default_map,themap)
    call map_parameters(rname,themap,freq,uvmax,uvmin,error,print)
    if (error) return
    call map_copy_par(themap,default_map) ! Copy Back ...
    error = .false.
  case default
    !
    ! back to usual code
    uvm = uvmax/(freq*f_to_k)
    !
    if (mode.eq.'TAPER') then
      if (step.eq.0.) step = sqrt(2.0)
      if (start.eq.0.) start = 10*nint(uvm/160.0)
      taper = 16*start
!      if (wei.eq.'NATU') then
!        uniform(1) = 0.
!        uniform(2) = 0.
!     endif
    else
      taper = sqrt(uv_taper(1)*uv_taper(2))
      if (taper.ne.0) then
        taper = min(taper,uvm)
      else
        taper = uvm
      endif
    endif
    !
    ! Define MAP_CELL and MAP_SIZE
    taper = uvm*freq*f_to_k
    map_cell(1) = 0.02*nint(180.0*3600.0*50.0/taper/4.0)
    if (map_cell(1).le.0.02) then
      map_cell(1) = 0.002*nint(180.0*3600.0*500.0/taper/4.0)
    endif
    map_cell(2) = map_cell(1)    ! In ", rounded to 0.01"
    if (mode.eq.'TAPER') then
      map_size(1) = 256
      map_size(2) = 256
    else
      map_size(1) = 64
      map_size(2) = 64
    endif
    !
    write(chain,102) uvm,uvmax*1e-3/2.0/pi
    call map_message(seve%i,rname,chain)
    write(chain,103) map_size
    call map_message(seve%i,rname,chain)
    write(chain,104) map_cell
    call map_message(seve%i,rname,chain)
    !
    ! Redefine some parameters
    map_cell(1) = map_cell(1)*pi/180.0/3600.0   ! In radians
    map_cell(2) = map_cell(2)*pi/180.0/3600.0
    !
    ! Process sorted UV Table according to the type of beam produced
    n = 2*max(map_size(1),map_size(2))
    allocate (beams(map_size(1),map_size(2)),fft(n),stat=ier)
    if (ier.ne.0) then
      call map_message(seve%e,rname,'Memory allocation failure')
      error = .true.
      return
    endif
    call uniform_beam (' ',uv_taper,   &
       &    map_size,map_cell,uniform,wcol,mcol,fft,   &
       &    error,mode,beams,1,start,step,uvm,result,huv,duv)
    deallocate (beams,fft)
    !
    call sic_delvariable('BEAM_SHAPE',.false.,error)
    dim(1) = 10
    dim(2) =  8
    call sic_def_real('BEAM_SHAPE',result,2,dim,.true.,error)
    error = .false.
  end select
  !
  102   format('Maximum baseline is   ',f8.1,' m,  ',f8.1,' kWavelength')
  103   format('Map size is   ',i4,' by ',i4)
  104   format('Pixel size is ',f6.3,' by ',f5.3,'"')
end subroutine uv_stat_comm
!
subroutine uv_printoffset(rname,map)
  use clean_def
  use gbl_message
  use mapping_interfaces, only : map_message
  ! @ private
  character(len=*), intent(in) :: rname
  type(uvmap_par), intent(in) :: map
  !
  real(8), parameter :: pi=3.14159265358979323846d0
  real(4), parameter :: rad_to_sec = 180.0*3600.0/pi
  integer :: n,j
  character(len=60) :: chain
  !
  if (map%nfields.eq.0) return
  !
  n = abs(map%nfields)
  if (map%nfields.lt.0) then
    write(chain,'(I5,A)') n, ' Phase offsets in mosaic'
  else
    write(chain,'(I5,A)') n, ' Pointing offsets in mosaic'
  endif
  call map_message(seve%i,rname,chain)
  do j=1,n-1,2
    write(*,'(2(A,F12.4,A,F12.4,A))') &
    &   '(',map%offxy(1,j)*rad_to_sec,' ,',map%offxy(2,j)*rad_to_sec,' )', &
    &   '(',map%offxy(1,j+1)*rad_to_sec,' ,',map%offxy(2,j+1)*rad_to_sec,' )'
  enddo
  if (mod(n,2).ne.0)     write(*,'(A,F12.2,A,F12.2,A)') &
    &   '(',map%offxy(1,n)*rad_to_sec,' ,',map%offxy(2,n)*rad_to_sec,' )'
end subroutine uv_printoffset
!
!
subroutine map_beamsize(huv,duv,uvmax,error)
  use image_def
  use gbl_message
  use gkernel_interfaces
  !
  ! @ public
  !     Get the natural synthesized beam size
  !
  type(gildas), intent(in) :: huv   ! UV Header
  real, intent(in) :: duv(:,:)      ! UV data
  real, intent(in) :: uvmax         ! Maximum UV value
  logical, intent(out) :: error     ! Error flag
  !
  character(len=*), parameter :: rname='MAP_BEAMSIZE'
  real(8), parameter :: pi=3.14159265358979323846d0
  real(8), parameter :: f_to_k = 2.d0*pi/299792458.d-6
  !
  ! Customized values
  real(4) :: pixel_per_beam=4.0     ! A good compromise
  integer, parameter :: nsize=128   ! Large enough for most cases
  real, save :: abeam(nsize,nsize), work(2*nsize)
  ! FFT arrays
  complex :: ipft(nsize*nsize), ipf(nsize*nsize)
  integer :: lx,ly,lw, nu,nv, nx,ny, ix_patch, iy_patch
  integer :: ndim, nn(2)
  real :: uvcell, map_cell, thre, rtmp
  real(kind=8) :: convert(6)
  real :: major_axis, minor_axis, pos_angle 
  !
  nu = huv%gil%dim(1)
  nv = huv%gil%nvisi
  lx = nsize  ! Grid size
  ly = nsize
  nx = nsize  ! Map size
  ny = nsize
  !
  ! Compute FFT's
  lw = max(10,7 + 3*(2*huv%gil%nchan/3))   ! Weight channel
  !
  ! Make sure all baselines are accounted for
  ! and beam is properly sampled
  uvcell = 2.0*uvmax/(lx-2)  * pixel_per_beam  
  !
  call doqfft (nu,nv,   &      ! Size of visibility array
     &    duv,          &      ! Visibilities
     &    1,2,lw,       &      ! U, V pointers
     &    lx,ly,        &      ! Cube size
     &    ipft,         &      ! FFT cube
     &    uvcell)              ! U and V grid coordinates
  !
  ! Make beam, not normalized
  ndim = 2
  nn(1) = nx
  nn(2) = ny
  call fourt_plan(ipf,nn,ndim,-1,1)
  call extracs(1,nx,ny,1,ipft,ipf,lx,ly)
  call fourt  (ipf,nn,ndim,-1,1,work)
  call cmtore (ipf,abeam,nx,ny)
  !
  ! Normalize beam - no grid correction needed here
  rtmp = abeam(nx/2+1,ny/2+1)
  abeam = abeam/rtmp
  !
  ! Define MAP_CELL
  rtmp = uvmax*huv%gil%freq*f_to_k
  map_cell = 0.002*nint(180.0*3600.0*500.0/rtmp/pixel_per_beam)
  map_cell = map_cell*pi/180.0/3600.0
  convert = (/dble(nx/2+1),0.d0,-dble(map_cell),   &
     &    dble(ny/2+1),0.d0,dble(map_cell)/)
  !
  ! Get Fitting Threshold 
  rtmp  = minval(abeam(:,:)) 
  thre = max(min(abs(-1.5*rtmp),0.7),0.3)
  !
  ! Fit beam
  ix_patch = nx/2
  iy_patch = ny/2
  major_axis = 0.
  minor_axis = 0.
  pos_angle  = 0.
  call fibeam (rname,abeam,nx,ny,   &
   &      ix_patch,iy_patch,thre,   &
   &      major_axis,minor_axis,pos_angle,   &
   &      convert,error)
  !
  if (sic_present(0,2)) then
    call gr_exec('CLEAR')
    call gr4_rgive(nx,ny,convert,abeam)
    call gr_exec('LIMITS /RG')
    call gr_exec('SET BOX SQUARE')
    call gr_exec('PLOT')
    call gr_exec('BOX /UNIT SEC')
    call gr_exec('WEDGE')
  endif
end subroutine map_beamsize

