subroutine uv_radial(line,rname,error)
  use clean_def
  use clean_arrays
  use clean_types
  use gkernel_types
  use phys_const
  use gbl_message
  use gkernel_interfaces
  use imager_interfaces, except_this => uv_radial
  !---------------------------------------------------------------------------
  ! Imager / Mapping
  !
  ! @ private
  !
  ! Support for commands
  !   UV_DEPROJECT X0 Y0 ROTA INCLI 
  ! and
  !   UV_RADIAL X0 Y0 ROTA INCLI [/SAMPLING QSTEP [Unit [QMIN QMAX]] [/ZERO]
  ! and
  !   UV_CIRCLE X0 Y0 ROTA INCLI [/SAMPLING QSTEP [Unit [QMIN QMAX]] [/ZERO]
  ! 
  !   Deproject from inclination effects and Compute the radial 
  !   profile of visibilities (or azimutal average of)
  !   using the specified values of X0, Y0, ROTA and INCLI
  !
  ! This combines
  !  - a u,v shift to X0,Y0
  !  - a rotation of the u,v coordinates by ROTA
  !  - a compression of the v axis by cos(INCLI)
  !  - a circular averaging
  !  - an azimutal spreading of the circularly averaged values
  !
  ! which were available in tasks UV_SHIFT, a script and UV_CIRCLE in an
  ! rather unconvenient way (see sg_create_circular.map script)
  !
  !---------------------------------------------------------------------------
  character(len=*), intent(in) :: line
  character(len=*), intent(in) :: rname
  logical, intent(out) :: error
  !
  integer, parameter :: o_fit=1
  integer, parameter :: o_zero=3
  integer, parameter :: o_sample=2
  !
  character(len=8) :: qunit, carg
  integer :: nf
  real(4) :: rpos(2),cs(2) 
  real(8) :: o_pang, freq
  type(gildas), save :: hou  ! Deprojected Visibilities, then Circular ones
  type(gildas), save :: hci  ! Circular average
  real, pointer :: duv_previous(:,:), duv_next(:,:)
  type(projection_t) :: proj
  integer :: nvisi
  real :: ang, pos(2),cosi
  integer :: i, eff_dim, ier, mq, nq, n
  integer :: nvs, nvi, kvi, nu, nv
  integer, allocatable :: array(:),flag(:)
  real, allocatable :: q(:), meter(:)
  real :: qstep, qmax, qmin, diam, daz, az, x1, x2, xd, klambda
  integer :: iaz,naz,iv,kv,iw,istart
  real, allocatable :: caz(:), saz(:), avisi(:)
  !
  if (.not.associated(duv)) then
    call map_message(seve%e,rname,'No UV data loaded')
    error = .true.
    return
  endif
  call sic_delvariable('UVRADIAL',.false.,error)
  error = .false.
  !
  !
  call gildas_null(hou,'UVT')
  call gdf_copy_header (huv,hou,error)
  !
  if (sic_present(o_fit,0)) then
  !   /FIT option
    if (sic_narg(0).ne.0) then
      call map_message(seve%e,rname,'/FIT option conflicts with argument(s)')
      error = .true.
      return
    endif
    !
    ! Check there is only 1 function, and that it is E_GAUSS or E_DISK to get 
    ! an orientation and an inclination
    nf = 0
    call sic_get_inte('UVF%NF',nf,error)
    if (nf.ne.1) then
      call map_message(seve%e,rname,'/FIT option is only valid after UV Fitting 1 function')
      error = .true.
      return
    endif
    !
    call sic_get_char('UVF%PAR1%NAME',carg,nf,error)
    select case (carg)
    case('E_GAUSS','E_DISK')
      continue
    case('E_RING') ! 
      call map_message(seve%e,rname,'/FIT option is not (yet) valid after UV Fitting '//carg) 
      error = .true.
      return    
    case default
      call map_message(seve%e,rname,'/FIT option is not valid after UV Fitting '//carg)
      error = .true.
      return
    end select
    !
    call sic_get_real('UVF%PAR1%RESULTS[4]',pos(1),error)
    call sic_get_real('UVF%PAR1%RESULTS[5]',pos(2),error)
    cosi = pos(2)/pos(1)
    !
    call sic_get_real('UVF%PAR1%RESULTS[1]',pos(1),error)
    call sic_get_real('UVF%PAR1%RESULTS[2]',pos(2),error)
    pos = pos*pi/180/3600     ! In radian
    !
    call sic_get_real('UVF%PAR1%RESULTS[6]',ang,error)
    ang = ang-90      ! This is Major axis, we want Minor axis
  else      
    ! 
    pos = 0
    ang = 0
    cosi = 1.0
    call sic_r4(line,0,1,pos(1),.false.,error)
    if (error) return
    call sic_r4(line,0,2,pos(2),.false.,error)
    if (error) return
    call sic_r4(line,0,3,ang,.false.,error)
    if (error) return
    !
    call sic_r4(line,0,4,cosi,.false.,error)
    if (error) return
    cosi = cos(cosi*pi/180.0)
  endif
  ! To bring the desired PA of the axis to the North, 
  ! we must counter-rotate the data.
  ang = -ang
  !
  ! Modify header 
  ! 1) Get new center. Offsets are relative to this one
  o_pang = hou%gil%pang
  call gwcs_projec(hou%gil%a0,hou%gil%d0,hou%gil%pang,hou%gil%ptyp,proj,error)
  call rel_to_abs (proj,dble(pos(1)),dble(pos(2)),hou%gil%a0,hou%gil%d0,1)
  ! 2) Set new Projection
  hou%gil%pang = ang*pi/180.0d0
  hou%gil%posi_words = 12
  hou%gil%proj_words = 9
  !
  ! Compute observing frequency, and new phase center in wavelengths
  ! need uv_frequency call here...
  freq = hou%gil%val(1)+hou%gil%fres*(hou%gil%val(1)/hou%gil%freq) &
          * (hou%gil%nchan+1)*0.5d0
  rpos(1) = - freq * f_to_k * pos(1)
  rpos(2) = - freq * f_to_k * pos(2)
  cs(1)  =  cos(hou%gil%pang-o_pang)
  cs(2)  = -sin(hou%gil%pang-o_pang)
  !
  nvisi = huv%gil%nvisi
  huv%r2d => duv
  !
  select case(rname)
  case ('UV_DEPROJECT') 
    nullify (duv_previous, duv_next)
    nu = huv%gil%dim(1)
    kv = nvisi
    call uv_find_buffers (rname,nu,kv,duv_previous,duv_next,error)
    if (error) return
    hou%r2d => duv_next
    !
    call shift_and_squeeze_uv(huv,hou,nvisi,rpos,cs,cosi)
    !
    call gdf_copy_header(hou,huv,error)
  case ('UV_RADIAL','UV_CIRCLE')
    !
    allocate (hou%r2d(hou%gil%dim(1),hou%gil%dim(2)), stat=ier)
    call shift_and_squeeze_uv(huv,hou,nvisi,rpos,cs,cosi)
    !
    ! Now define the circular average
    call gildas_null(hci,'UVT')
    call gdf_copy_header(huv,hci,error)
    !
    nvs = hou%gil%dim(1)
    nvi = hou%gil%dim(2)
    !
    ! Default sampling 1/2 of dish diameter
    diam = 0.
    if (huv%gil%nteles.ne.0) then
      diam = huv%gil%teles(1)%diam
    endif
    if (diam.eq.0) diam = 15.0  ! For NOEMA
    qstep = diam/2.0
    call uvgmax(huv,duv,qmax,qmin)
    !
    if (sic_present(o_sample,0)) then
      call sic_r4(line,o_sample,1,qstep,.true.,error)
      if (error) return
      qunit = 'METER'
      call sic_ke(line,o_sample,2,qunit,n,.false.,error)
      if (error) return   
      if (qunit.eq.'KWAVE') then
        klambda = 1.D3*299792.458d-3/huv%gil%freq
      else if (qunit.eq.'METER' .or. qunit.eq.'M') then
        klambda = 1.0
      else
        call map_message(seve%e,rname,'Unit must be Meter or kWave')
        error = .true.
        return
      endif
      qmin = qmin/klambda
      qmax = qmax/klambda
      call sic_r4(line,o_sample,3,qmin,.false.,error)
      if (error) return
      call sic_r4(line,o_sample,4,qmax,.false.,error)
      if (error) return
      qstep = qstep*klambda 
      qmin = qmin*klambda
      qmax = qmax*klambda
    endif
    !
    hci%gil%dim(2) = nint((qmax-qmin)/qstep)
    kvi = hci%gil%dim(2)
    mq = hci%gil%dim(2)+1
    allocate (q(mq), meter(mq), flag(mq), array(mq), stat=ier)
    !
    do i=1, mq
      q(i) = qmin+(i-1)*qstep
    enddo
    !
    ! Extrapolate the 0 visibility if possible ?
    if (sic_present(o_zero,0)) then
      istart = 2
    else
      istart = 1
    endif
    !
    ! Find actual size
    call uv_steps (hou%r2d,nvs,nvi, &
       &    q,kvi,eff_dim, array,meter,flag,mq)
    hci%gil%ndim = 2
    hci%gil%dim(2) = eff_dim+istart-1
    hci%gil%dim(3) = 1
    hci%gil%dim(4) = 1
    allocate (hci%r2d(hci%gil%dim(1),hci%gil%dim(2)),stat=ier)
    !
    hci%r2d = 0.0
    nq = eff_dim
    call uv_circle_average (nvs,nvi,hci%gil%nchan,hou%r2d,   &
       &    nq,hci%r2d(:,istart:nq),q,eff_dim,   &
       &    array,meter,mq)
    !
    if (istart.eq.2) then
      ! Extrapolate the 0 visibility if possible ?
      !
      ! Test: 0-centered parabola going through points 2 and 4
      x1 = hci%r2d(1,2)**2
      x2 = hci%r2d(1,4)**2
      xd = x2-x1
      x1 = x1/xd
      x2 = x2/xd
      hci%r2d(:,1) = 0
      do i=1,huv%gil%nchan
        hci%r2d(5+3*i,1) = x2*hci%r2d(5+3*i,2) - x1*hci%r2d(5+3*i,4)
        hci%r2d(7+3*i,1) = 0.25*hci%r2d(7+3*i,2)
      enddo
      Print *,'Zero spacing ',hci%r2d(:,1)
    endif
    hci%r2d(6,:) = 1  ! Fake antenna numbers
    hci%r2d(7,:) = 2  !
    !
    ! Do not forget to reset the number of visibilities & Size
    hci%gil%nvisi = eff_dim
    hci%gil%dim(2) = eff_dim
    !
    call sic_mapgildas('UVRADIAL',hci,error,hci%r2d)
    !
    if (rname.eq.'UV_CIRCLE') then
      nu = hci%gil%dim(1) 
      nv = hci%gil%nvisi
      nullify (duv_previous, duv_next)
      call uv_find_buffers (rname,nu,nv,duv_previous,duv_next,error)
      if (error) return
      !
      do iv = 1,nv
        duv_next(:,iv) = hci%r2d(:,iv)
      enddo
      hci%gil%basemax = hci%r2d(1,nv)
      hci%gil%basemin = hci%r2d(1,1)  
      call gdf_copy_header(hci,huv,error)
    else
      ! Now spread it over Azimut ...
      !
      ! Number of Azimut and Azimut step (half circle only...)
      naz = pi*qmax/qstep
      daz = pi/naz
      hou%gil%nvisi = hci%gil%nvisi * naz
      hou%gil%dim(2) = hou%gil%nvisi
      nu = hci%gil%dim(1) 
      nv = hou%gil%nvisi
      !
      nullify (duv_previous, duv_next)
      call uv_find_buffers (rname,nu,nv,duv_previous,duv_next,error)
      if (error) return
      allocate(caz(naz),saz(naz),avisi(hou%gil%dim(1)),stat=ier)
      if (ier.ne.0) then
        call map_message(seve%e,rname,'Memory allocation error')
        error = .true.
        return
      endif
      !
      do iaz = 1,naz
        az = (iaz-1)*daz
        caz(iaz) = cos(az)
        saz(iaz) = -sin(az)
      enddo
      !
      kv = 0
      do iv=1,nq
        avisi(:) = hci%r2d(:,iv)
        do iw=1,huv%gil%nchan
          avisi(6+3*iw) = 0.0 ! Set the imaginary part to Zero  
          avisi(7+3*iw) = avisi(7+3*iw)/naz  ! Spread the weight evenly         
        enddo
        do iaz=1,naz
          kv = kv+1
          duv_next(:,kv) = avisi
          duv_next(1,kv) = avisi(1)*caz(iaz)
          duv_next(2,kv) = avisi(1)*saz(iaz)
        enddo
      enddo
      hou%gil%basemax = qmax
      hou%gil%basemin = qmin  
      call gdf_copy_header(hou,huv,error)
    endif
  case default
    call map_message(seve%e,rname,'Not implemented')
    error = .true.
    return
  end select 
  !
  ! Point back to UV data set
  call uv_clean_buffers (duv_previous, duv_next,error)
  if (error) return
  !
  ! Indicate UV data has changed, and weight must be computed
  call uv_new_data(weight=.true.)
end subroutine uv_radial
!
!<FF>
subroutine parabola(x,y,a,b,c) 
  !----------------------------------------------------------------------
  !	Solve for Y = a + b*x() + c*x()^2
  !----------------------------------------------------------------------
  real, intent(in) :: x(3)
  real, intent(in) :: y(3)
  real, intent(out) :: a,b,c
  !
  c = (y(3)-y(2))*(x(2)-x(1))-(y(2)-y(1))*(x(3)-x(2))
  b = (x(2)-x(1))*(x(3)*x(3)-x(2)*x(2))-(x(2)*x(2)-x(1)*x(1))*(x(3)-x(2))
  c = c/b
  b = (y(2)-y(1))-c*(x(2)*x(2)-x(1)*x(1))
  b = b/(x(2)-x(1))
  a = y(1)-c*x(1)*x(1)-b*x(1)
end subroutine parabola
!
subroutine uv_steps(visx, n1, nvx, q, nq, eff_dim,   &
     &    array,meter,flag,nsize)
  !------------------------------------------------------------------
  ! IMAGER
  !   @ public 
  !
  !------------------------------------------------------------------
  integer, intent(in) :: n1              ! Size of a visibility
  integer, intent(in) :: nvx             ! Number of a visibilities
  real, intent(in) :: visx(n1,nvx)       ! Visibilities
  integer, intent(in) :: nq              ! Number of radii
  real, intent(in) :: q(nq+1)            ! Radii
  integer, intent(out) :: eff_dim        ! Actual size of radial array
  integer, intent(in) :: nsize           ! Size of radial array
  integer, intent(out) :: array(nsize)   ! Cell value
  real, intent(inout) :: meter(nsize)    ! Cell position
  integer, intent(out) :: flag(nsize)    ! Is there any data ?

  ! Local
  integer :: iq, iv, i
  real :: qq
  !
  flag = 0
  !
  do iv=1, nvx
    qq = sqrt(visx(1,iv)**2+visx(2,iv)**2)
    iq = int( (qq-q(1))/(q(2)-q(1))+1. )
    if (iq.gt.0 .and. iq.le.nq+1) then
      flag(iq) = 1
    endif
  enddo
  !
  eff_dim = 0
  do i=1,nsize
    if (flag(i).ne.0) then
      eff_dim = eff_dim+1
      meter(eff_dim) = (3*q(1)-q(2))/2+(q(2)-q(1))*i
    endif
    array(i) = eff_dim
  enddo
end subroutine uv_steps
!
subroutine uv_circle_average(n1, nvx, nc, visx, nq, visy, q, eff_dim,   &
     &    array, meter, nsize)
  !------------------------------------------------------------------
  ! IMAGER
  !   @ public 
  !
  !------------------------------------------------------------------
  integer, intent(in) :: n1              ! Size of a visibility
  integer, intent(in) :: nvx             ! Number of a visibilities
  integer, intent(in) :: nc              ! Number of channels
  real, intent(in) :: visx(n1,nvx)       ! Visibilities
  integer, intent(in) :: nq              ! Number of radii
  real, intent(in) :: q(nq+1)            ! Radii
  integer, intent(in) :: eff_dim         ! Actual size of radial array
  real, intent(out) :: visy(n1, eff_dim) ! Output visibilities        !
  integer, intent(in) :: nsize           ! Size of radial array
  integer, intent(in) :: array(nsize)    ! Cell value
  real, intent(inout) :: meter(nsize)    ! Cell position
  ! Local
  integer :: iq, iv, ic, i, ip, ier
  real :: w, qq
  real, allocatable :: true(:)
  !
  visy = 0.0
  allocate (true(nsize),stat=ier)
  if (ier.ne.0) stop
  !
  true = 0
  ic = (nc+1)/2
  !
  do iv = 1, nvx
    qq = sqrt(visx(1,iv)**2+visx(2,iv)**2)
    iq = int( (qq-q(1))/(q(2)-q(1))+1. )
    if (iq.gt.0 .and. iq.le.nq+1) then
      ip = array(iq)
      w = visx(3*ic+7,iv)
      if (w.gt.0) then
        true(ip) = true(ip)+w*qq
      endif
      do i=1, nc
        w = visx(3*i+7,iv)
        if (w.gt.0) then
          visy(3*i+5,ip)=visy(3*i+5,ip)+visx(3*i+5,iv)*w
          visy(3*i+6,ip)=visy(3*i+6,ip)+visx(3*i+6,iv)*w
          visy(3*i+7,ip)=visy(3*i+7,ip)+w
        endif
      enddo
    endif
  enddo
  !
  do iq = 1, eff_dim
    w = visy(3*ic+7,iq)
    if (w.ne.0) then
      visy(1,iq) = true(iq)/w
    else
      visy(1,iq) = meter(iq)
    endif
    do i=1, nc
      w = visy(3*i+7,iq)
      if (w.gt.0) then
        visy(3*i+5,iq)=visy(3*i+5,iq)/w
        visy(3*i+6,iq)=visy(3*i+6,iq)/w
      endif
    enddo
  enddo
  deallocate (true)
end subroutine uv_circle_average
!
subroutine shift_and_squeeze_uv(hin,hou,nvisi,xy,cs,cosi)
  use image_def
  !------------------------------------------------------------------
  ! IMAGER
  !   @ public 
  !
  ! Apply a Phase shift to the data (in the previous frame)
  ! then rotate the frame (u,v) coordinates.
  !------------------------------------------------------------------
  type(gildas), intent(in)  :: hin    ! Input UV data 
  type(gildas), intent(inout) :: hou  ! Output UV data
  integer, intent(in) :: nvisi        ! Number of visibilities
  real, intent(in) :: xy(2)  ! Phase Shift
  real, intent(in) :: cs(2)  ! Cos/Sin of Rotation
  real, intent(in) :: cosi   ! Cos of inclination
  !
  integer(kind=index_length) :: i
  integer :: ix, iu, iv
  real phi, sphi, cphi, u, v, reel, imag
  !
  iu = hin%gil%column_pointer(code_uvt_u)
  iv = hin%gil%column_pointer(code_uvt_v)
  !
  if (xy(1).eq.0. .and. xy(2).eq.0.) then
    do i = 1,nvisi
      hou%r2d(:,i) = hin%r2d(:,i)
      u = hin%r2d(iu,i)
      v = hin%r2d(iv,i)
      hou%r2d(iu,i) = cs(1)*u - cs(2)*v
      hou%r2d(iv,i) = cosi * (cs(2)*u + cs(1)*v)
    enddo
  else
    do i = 1,nvisi
      hou%r2d(1:hou%gil%nlead,i) = hin%r2d(1:hin%gil%nlead,i)
      u = hin%r2d(iu,i)
      v = hin%r2d(iv,i)
      hou%r2d(iu,i) = cs(1)*u - cs(2)*v
      hou%r2d(iv,i) = cs(2)*u + cs(1)*v
      phi = xy(1)*u + xy(2)*v
      cphi = cos(phi)
      sphi = sin(phi)
      do ix=hou%gil%fcol,hou%gil%lcol,hou%gil%natom
        reel = hin%r2d(ix,i) * cphi - hin%r2d(ix+1,i) * sphi
        imag = hin%r2d(ix,i) * sphi + hin%r2d(ix+1,i) * cphi
        hou%r2d(ix,i) = reel
        hou%r2d(ix+1,i) = imag
        hou%r2d(ix+2,i) = hin%r2d(ix+2,i)
      enddo
      ! Deproject the Y axis, i.e. shorten the V axis
      hou%r2d(iv,i) = cosi * hou%r2d(iv,i)
    enddo
  endif
end subroutine shift_and_squeeze_uv
