!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine doplace(map,table,cube,gweight,time,error)
  use gbl_message
  use classmap_dependencies_interfaces
  use classmap_interfaces, except_this=>doplace
  use xymap_types
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  type(xymap_t), intent(in)    :: map ! Gridding description
  real(kind=4),  intent(in)    :: table(map%tab%nchan,map%tab%nposi)
  real(kind=4),  intent(inout) :: cube(map%cub%nchan,map%cub%nx,map%cub%ny)
  real(kind=4),  intent(inout) :: gweight(map%cub%nx,map%cub%ny)
  type(time_t),  intent(inout) :: time
  logical,       intent(inout) :: error
  ! Local
  character(len=*), parameter :: rname='XY_MAP'
  real(kind=8) :: rx,ry
  integer(kind=index_length) :: ilin,ix,iy
  character(len=message_length) :: mess
  !
  call class_message(seve%d,rname,'Placing')
  !
  ! Put spectrum at appropriate place
  do ilin=1,map%tab%nposi
     call class_controlc(rname,error)
     if (error)  return
     !
     rx = map%xconv(1)+(map%tab%x(ilin)-map%xconv(2))/map%xconv(3)
     ry = map%yconv(1)+(map%tab%y(ilin)-map%yconv(2))/map%yconv(3)
     ix = nint(rx)
     iy = nint(ry)
     if ((ix.lt.1).or.(ix.gt.map%cub%nx)) then
        write(mess,*) 'Table line #',ilin,' out of x grid'
        call class_message(seve%w,rname,mess)
        cycle
     endif
     if ((iy.lt.1).or.(iy.gt.map%cub%ny)) then
        write(mess,*) 'Table line #',ilin,' out of y grid'
        call class_message(seve%w,rname,mess)
        cycle
     endif
     cube(:,ix,iy) = table(:,ilin)
     gweight(ix,iy) = map%tab%w(ilin)
     !
     call gtime_current(time)
  enddo
  !
end subroutine doplace
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine docoor(n,xref,xval,xinc,x)
  use gildas_def
  !---------------------------------------------------------------------
  ! @ private
  ! Compute coordinate array from conversion formula
  !---------------------------------------------------------------------
  integer(kind=index_length), intent(in)  :: n     ! Number of pixel
  real(kind=8),               intent(in)  :: xref  ! Reference pixel
  real(kind=8),               intent(in)  :: xval  ! Value at reference pixel
  real(kind=8),               intent(in)  :: xinc  ! Pixel size
  real(kind=4),               intent(out) :: x(n)  ! Axis coordinate
  ! Local
  integer(kind=index_length) :: i
  !
  do i=1,n
     x(i) = (dble(i)-xref)*xinc+xval
  enddo
end subroutine docoor
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine gag_cputime_add(sum,last)
  use gkernel_types
  use gkernel_interfaces
  !---------------------------------------------------------------------
  ! @ private
  !   Get the times since last call for 'last', and add the times to
  ! the structure 'sum'. Note that the reference times in 'sum' have
  ! not much meaning in this context.
  ! ---
  !   This subroutine is helpful to add non-contiguous time counts,
  ! while the official cputime_t is made to count times from a reference
  ! or from last call. Should this be merged in gsys?
  !---------------------------------------------------------------------
  type(cputime_t), intent(inout) :: sum
  type(cputime_t), intent(inout) :: last
  !
  call gag_cputime_get(last)
  sum%curr%elapsed = sum%curr%elapsed + last%diff%elapsed
  sum%curr%user    = sum%curr%user    + last%diff%user
  sum%curr%system  = sum%curr%system  + last%diff%system
  !
end subroutine gag_cputime_add
!
subroutine print_cputime_feedback(time)
  use gbl_message
  use classmap_dependencies_interfaces
  use classmap_interfaces, except_this=>print_cputime_feedback
  use xymap_types
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  type(xymap_time_t), intent(in) :: time
  ! Local
  character(len=*), parameter :: rname='XY_MAP'
  character(len=message_length) :: mess
  !
  ! Nothing shown if command is faster than 10 sec (NB: 10 sec is also
  ! the threshold used by the gtime statistics)
  if (time%total%diff%elapsed.lt.10.)  return
  !
  print *,''
  !
  write(mess,10)  &
    'Time elapsed in command (total):',time%total%diff%elapsed,' sec'
  call class_message(seve%i,rname,mess)
  !
  write(mess,10)  &
    'Time elapsed reading XYW:',time%xyw%diff%elapsed,' sec'
  call class_message(seve%i,rname,mess)
  !
  write(mess,10)  &
    'Time elapsed reading the table:',time%read%curr%elapsed,' sec'
  call class_message(seve%i,rname,mess)
  !
  write(mess,10)  &
    'Time elapsed sorting the table:',time%sort%curr%elapsed,' sec'
  call class_message(seve%i,rname,mess)
  !
  write(mess,10)  &
    'Time elapsed transposing table or cube:',time%tran%curr%elapsed,' sec'
  call class_message(seve%i,rname,mess)
  !
  write(mess,10)  &
    'Time elapsed convolving:',time%conv%curr%elapsed,' sec'
  call class_message(seve%i,rname,mess)
  !
  write(mess,10)  &
    'Time elapsed writing the cube:',time%writ%curr%elapsed,' sec'
  call class_message(seve%i,rname,mess)
  !
10 format(A,T40,F10.2,A)
end subroutine print_cputime_feedback
!
subroutine reallocate_tab(array,n1,n2,error)
  use gildas_def
  use gbl_message
  use classmap_dependencies_interfaces
  use classmap_interfaces, except_this=>reallocate_tab
  !---------------------------------------------------------------------
  ! @ private
  !  Reallocate a 2D table
  !---------------------------------------------------------------------
  real(kind=4),               allocatable   :: array(:,:)
  integer(kind=index_length), intent(in)    :: n1,n2
  logical,                    intent(inout) :: error
  ! Local
  character(len=*), parameter :: rname='XY_MAP>REALLOCATE>2D'
  logical :: alloc
  integer(kind=4) :: ier
  character(len=message_length) :: mess
  !
  if (n1.le.0 .or. n2.le.0) then
    write(mess,'(A,2(I0,A))')  &
      'Array size can not be zero nor negative (got ',n1,'x',n2,')'
    call class_message(seve%e,rname,mess)
    error = .true.
    return
  endif
  !
  alloc = .true.
  if (allocated(array)) then
    if (ubound(array,1).eq.n1 .and.  &
        ubound(array,2).eq.n2) then
      call print_size(rname,'Workspace already allocated at an appropriate size',n1,n2)
      alloc = .false.
    else
      deallocate(array)
    endif
  endif
  !
  if (alloc) then
    allocate(array(n1,n2),stat=ier)
    if (failed_allocate(rname,'XY_MAP WORKSPACE',ier,error))  return
    call print_size(rname,'Allocated workspace of size',n1,n2)
  endif
  !
contains
  subroutine print_size(rname,start,n1,n2)
    use gildas_def
    use gbl_message
    use classmap_interfaces
    character(len=*),           intent(in) :: rname
    character(len=*),           intent(in) :: start
    integer(kind=index_length), intent(in) :: n1,n2
    ! Local
    character(len=message_length) :: mess
    integer(kind=size_length) :: nw
    nw = n1*n2
    write(mess,'(a,a,i0,a,i0,a,a)')  &
      trim(start),': ',n1,' x ',n2,' = ',pretty_size(nw)
    call class_message(seve%d,rname,mess)
  end subroutine print_size
  !
end subroutine reallocate_tab
!
subroutine reallocate_cub(array,n1,n2,n3,error)
  use gildas_def
  use gbl_message
  use classmap_dependencies_interfaces
  use classmap_interfaces, except_this=>reallocate_cub
  !---------------------------------------------------------------------
  ! @ private
  !  Reallocate a 3D cube
  !---------------------------------------------------------------------
  real(kind=4),               allocatable   :: array(:,:,:)
  integer(kind=index_length), intent(in)    :: n1,n2,n3
  logical,                    intent(inout) :: error
  ! Local
  character(len=*), parameter :: rname='XY_MAP>REALLOCATE>3D'
  character(len=message_length) :: mess
  logical :: alloc
  integer(kind=4) :: ier
  !
  if (n1.le.0 .or. n2.le.0 .or. n3.le.0) then
    write(mess,'(A,3(I0,A))')  &
      'Array size can not be zero nor negative (got ',n1,'x',n2,'x',n3,')'
    call class_message(seve%e,rname,mess)
    error = .true.
    return
  endif
  !
  alloc = .true.
  if (allocated(array)) then
    if (ubound(array,1).eq.n1 .and.  &
        ubound(array,2).eq.n2 .and.  &
        ubound(array,3).eq.n3) then
      call print_size(rname,'Workspace already allocated at an appropriate size',n1,n2,n3)
      alloc = .false.
    else
      deallocate(array)
    endif
  endif
  !
  if (alloc) then
    allocate(array(n1,n2,n3),stat=ier)
    if (failed_allocate(rname,'XY_MAP WORKSPACE',ier,error))  return
    call print_size(rname,'Allocated workspace of size',n1,n2,n3)
  endif
  !
contains
  subroutine print_size(rname,start,n1,n2,n3)
    use gildas_def
    use gbl_message
    use classmap_interfaces
    character(len=*),           intent(in) :: rname
    character(len=*),           intent(in) :: start
    integer(kind=index_length), intent(in) :: n1,n2,n3
    ! Local
    character(len=message_length) :: mess
    integer(kind=size_length) :: nw
    nw = n1*n2*n3
    write(mess,'(a,a,i0,a,i0,a,i0,a,a)')  &
      trim(start),': ',n1,' x ',n2,' x ',n3,' = ',pretty_size(nw)
    call class_message(seve%d,rname,mess)
  end subroutine print_size
  !
end subroutine reallocate_cub
!
function pretty_size(nwords)
  use gildas_def
  !---------------------------------------------------------------------
  ! @ private
  !  Return a string describing the input size (words) in a bytes
  ! multiple
  !---------------------------------------------------------------------
  character(len=20) :: pretty_size     ! Function value on return
  integer(kind=size_length) :: nwords  ! [words]
  ! Local
  integer(kind=index_length), parameter :: ten=10_8
  integer(kind=index_length), parameter :: kb=1024_8
  integer(kind=index_length), parameter :: mb=1024_8*1024_8
  integer(kind=index_length), parameter :: gb=1024_8*1024_8*1024_8
  integer(kind=size_length) :: siz
  !
  siz = nwords*4_8
  !
  if (siz.gt.ten*gb) then
    write(pretty_size,'(F0.1,A)')  real(siz,kind=8)/gb,' GB'
  elseif (siz.gt.gb) then
    write(pretty_size,'(F0.2,A)')  real(siz,kind=8)/gb,' GB'
    !
  elseif (siz.gt.ten*mb) then
    write(pretty_size,'(F0.1,A)')  real(siz,kind=8)/mb,' MB'
  elseif (siz.gt.mb) then
    write(pretty_size,'(F0.2,A)')  real(siz,kind=8)/mb,' MB'
    !
  elseif (siz.gt.ten*kb) then
    write(pretty_size,'(F0.1,A)')  real(siz,kind=8)/kb,' kB'
  elseif (siz.gt.kb) then
    write(pretty_size,'(F0.2,A)')  real(siz,kind=8)/kb,' kB'
    !
  else
    write(pretty_size,'(I0,A)')  siz,' B'
  endif
  !
end function pretty_size
