subroutine selimx(obs,xc1,xc2,xv1,xv2,xf1,xf2,xfo,xi1,xi2,xio)
  use gildas_def
  use class_types
  use plot_formula
  !---------------------------------------------------------------------
  ! @ private
  ! CLASS	Internal routine
  !	Defines the four coordinates systems
  !---------------------------------------------------------------------
  type (observation),     intent(inout) :: obs      !
  real(kind=plot_length), intent(in)    :: xc1,xc2  ! Channel limits
  real(kind=plot_length), intent(in)    :: xv1,xv2  ! Velocity limits
  real(kind=plot_length), intent(in)    :: xf1,xf2  ! Rest frequency limits
  real(kind=8),           intent(in)    :: xfo      ! Rest frequency offset
  real(kind=plot_length), intent(in)    :: xi1,xi2  ! Image frequency limits
  real(kind=8),           intent(in)    :: xio      ! Image frequency offset
  !
  call get_box(gx1,gx2,gy1,gy2)
  gcx1 = xc1
  gcx2 = xc2
  gvx1 = xv1
  gvx2 = xv2
  gfx1 = xf1
  gfx2 = xf2
  gfxo = xfo
  gix1 = xi1
  gix2 = xi2
  gixo = xio
  gcx  = (gx2-gx1)/(gcx2-gcx1)
  gvx  = (gx2-gx1)/(gvx2-gvx1)
  gfx  = (gx2-gx1)/(gfx2-gfx1)
  gix  = (gx2-gx1)/(gix2-gix1)
  !
  ! Initialize cimin,cimax
  call obs_limits(obs)
end subroutine selimx
!
subroutine obs_limits(obs)
  use gildas_def
  use class_types
  use plot_formula
  !---------------------------------------------------------------------
  ! @ private
  !  Defines the Min Max range of the channels to be plotted. Note that
  ! this range is also used for BASElining, be careful...
  !---------------------------------------------------------------------
  type (observation), intent(inout) :: obs
  !
  ! - gcx1 and gcx2 are the range of channels to be selected, in
  !   NON-integer (floating point) channel unit. We apply the following
  !   rule: if less* than 1/2 channel is considered, it is not selected.
  ! * "Less than" or "less or equal"? The method should accomodate exact
  !   channel range selection by the user, e.g. 1.000 to 10.000 should
  !   include those boundaries. CEILING and FLOOR functions are perfect
  !   for this.
  ! - Also remember that because of its width, the channel #N runs from
  !   N-0.5 to N+0.5
  !
  if (gcx1.lt.gcx2) then
    obs%cimin = max(ceiling(gcx1),1)
    obs%cimax = min(floor(gcx2),obs%cnchan)
  else
    obs%cimin = max(ceiling(gcx2),1)
    obs%cimax = min(floor(gcx1),obs%cnchan)
  endif
end subroutine obs_limits
!
subroutine seunitx(set,r,unit_low,unit_up,error)
  use gbl_constant
  use gbl_message
  use classcore_interfaces, except_this=>seunitx
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  ! Change the current unit and modifies all parameters accordingly.
  ! If no R buffer is loaded, no error is raised.
  !---------------------------------------------------------------------
  type(class_setup_t), intent(inout) :: set       !
  type(observation),   intent(inout) :: r         !
  character(len=*),    intent(in)    :: unit_low  ! Lower axis unit
  character(len=*),    intent(in)    :: unit_up   ! Upper axis unit
  logical,             intent(inout) :: error     ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='UNIT'
  character(len=1) :: unitx_old(2)
  !
  unitx_old(:) = set%unitx(:)  ! Save previous value in case of error
  !
  set%unitx(2) = unit_up
  if (unit_low(1:1).eq.set%unitx(1))  return
  !
  ! New lower unit
  if (unit_low(1:1).ne.'C' .and. unit_low(1:1).ne.'V' .and.   &
      unit_low(1:1).ne.'F' .and. unit_low(1:1).ne.'I' .and.   &
      unit_low(1:1).ne.'A' .and. unit_low(1:1).ne.'T') then
    call class_message(seve%e,rname,'Invalid X unit type '//unit_low(1:1))
    error = .true.
    return
  endif
  !
  set%unitx(1) = unit_low(1:1)
  !
  if (r%head%xnum.eq.0) then
    ! No spectrum in memory. This is not an error, but since we do not
    ! know any abscissa conversion, we reset some global parameters:
    if (set%nwind.gt.0) then
      set%nwind = 0
      call class_message(seve%w,rname,  &
        'No R spectrum in memory: SET WINDOW reset to NO window')
    endif
    if (set%nmask.gt.0) then
      set%nmask = 0
      call class_message(seve%w,rname,  &
        'No R spectrum in memory: SET MASK reset to NO mask')
    endif
    if (set%modex.eq.'F') then
      set%modex = 'A'
      call class_message(seve%w,rname,  &
        'No R spectrum in memory: SET MODE X reset to Automatic')
    endif
    return
    !
  endif
  !
  if (r%head%gen%kind.eq.kind_spec   .and.  &
      r%head%spe%image.eq.image_null .and.  &
      any(set%unitx.eq.'I')) then
    ! SET UNIT I invalid in this case
    call class_message(seve%e,rname,'Spectrum has no image band defined')
    error = .true.
    set%unitx(:) = unitx_old(:)
    return
  endif
  !
  ! Reset SET WIND and SET MASK values
  call seunitx_wind_mask(set,r,unitx_old(1),set%unitx(1),error)
  ! if (error) continue?
  !
  ! Reset the unit-depending elements of the R% Fortran structure,
  ! reset the unit-depending elements of the R% Sic structure,
  ! reset the plotting limits according to SET MODE X:
  call newdat(set,r,error)
  !
end subroutine seunitx
!
subroutine seunitx_wind_mask(set,r,old,new,error)
  use gbl_message
  use classcore_interfaces, except_this=>seunitx_wind_mask
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  ! Update the SET WINDOW and SET MASK values according to the old and
  ! new units. Take Doppler factor correctly into account, i.e. use
  ! 'abscissa' subroutines.
  ! NB: if you plan to support irregularly spaced data, you should merge
  ! with abscissa_any2chan()
  !---------------------------------------------------------------------
  type(class_setup_t), intent(inout) :: set    !
  type(observation),   intent(inout) :: r      !
  character(len=*),    intent(in)    :: old    ! Old unit for values
  character(len=*),    intent(in)    :: new    ! New unit for values
  logical,             intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='UNIT'
  integer(kind=4) :: i
  real(kind=4) :: val
  !
  ! 1) Convert temporarily the SET WINDOW and SET MASK to channel units:
  if (old.eq.'C') then
    ! Already in channels, pass
    continue
  elseif (old.eq.'V') then
    do i=1,set%nwind
      call abscissa_velo2chan(r%head,set%wind1(i),val)
      set%wind1(i) = val
      call abscissa_velo2chan(r%head,set%wind2(i),val)
      set%wind2(i) = val
    enddo
    do i=1,set%nmask
      call abscissa_velo2chan(r%head,set%mask1(i),val)
      set%mask1(i) = val
      call abscissa_velo2chan(r%head,set%mask2(i),val)
      set%mask1(i) = val
    enddo
  elseif (old.eq.'F') then  ! Offset signal frequencies
    do i=1,set%nwind
      call abscissa_sigoff2chan(r%head,set%wind1(i),val)
      set%wind1(i) = val
      call abscissa_sigoff2chan(r%head,set%wind2(i),val)
      set%wind2(i) = val
    enddo
    do i=1,set%nmask
      call abscissa_sigoff2chan(r%head,set%mask1(i),val)
      set%mask1(i) = val
      call abscissa_sigoff2chan(r%head,set%mask2(i),val)
      set%mask1(i) = val
    enddo
  elseif (old.eq.'I') then  ! Offset image frequencies
    do i=1,set%nwind
      call abscissa_imaoff2chan(r%head,set%wind1(i),val)
      set%wind1(i) = val
      call abscissa_imaoff2chan(r%head,set%wind2(i),val)
      set%wind2(i) = val
    enddo
    do i=1,set%nmask
      call abscissa_imaoff2chan(r%head,set%mask1(i),val)
      set%mask1(i) = val
      call abscissa_imaoff2chan(r%head,set%mask2(i),val)
      set%mask1(i) = val
    enddo
  elseif (old.eq.'A') then
    do i=1,set%nwind
      call abscissa_angl2chan(r%head,set%wind1(i),val)
      set%wind1(i) = val
      call abscissa_angl2chan(r%head,set%wind2(i),val)
      set%wind2(i) = val
    enddo
    do i=1,set%nmask
      call abscissa_angl2chan(r%head,set%mask1(i),val)
      set%mask1(i) = val
      call abscissa_angl2chan(r%head,set%mask2(i),val)
      set%mask1(i) = val
    enddo
  elseif (old.eq.'T') then
    do i=1,set%nwind
      call abscissa_time2chan(r%head,set%wind1(i),val)
      set%wind1(i) = val
      call abscissa_time2chan(r%head,set%wind2(i),val)
      set%wind2(i) = val
    enddo
    do i=1,set%nmask
      call abscissa_time2chan(r%head,set%mask1(i),val)
      set%mask1(i) = val
      call abscissa_time2chan(r%head,set%mask2(i),val)
      set%mask1(i) = val
    enddo
  else
    call class_message(seve%e,rname,'Unit '//old//' not recognized')
    error = .true.
    return
  endif
  !
  ! 2) Convert SET WINDOW and SET MASK to target units:
  if (new.eq.'C') then
    ! Already in channels, pass
    continue
  elseif (new.eq.'V') then
    do i=1,set%nwind
      call abscissa_chan2velo(r%head,set%wind1(i),val)
      set%wind1(i) = val
      call abscissa_chan2velo(r%head,set%wind2(i),val)
      set%wind2(i) = val
    enddo
    do i=1,set%nmask
      call abscissa_chan2velo(r%head,set%mask1(i),val)
      set%mask1(i) = val
      call abscissa_chan2velo(r%head,set%mask2(i),val)
      set%mask1(i) = val
    enddo
  elseif (new.eq.'F') then  ! Offset signal frequencies
    do i=1,set%nwind
      call abscissa_chan2sigoff(r%head,set%wind1(i),val)
      set%wind1(i) = val
      call abscissa_chan2sigoff(r%head,set%wind2(i),val)
      set%wind2(i) = val
    enddo
    do i=1,set%nmask
      call abscissa_chan2sigoff(r%head,set%mask1(i),val)
      set%mask1(i) = val
      call abscissa_chan2sigoff(r%head,set%mask2(i),val)
      set%mask1(i) = val
    enddo
  elseif (new.eq.'I') then  ! Offset image frequencies
    do i=1,set%nwind
      call abscissa_chan2imaoff(r%head,set%wind1(i),val)
      set%wind1(i) = val
      call abscissa_chan2imaoff(r%head,set%wind2(i),val)
      set%wind2(i) = val
    enddo
    do i=1,set%nmask
      call abscissa_chan2imaoff(r%head,set%mask1(i),val)
      set%mask1(i) = val
      call abscissa_chan2imaoff(r%head,set%mask2(i),val)
      set%mask1(i) = val
    enddo
  elseif (new.eq.'A') then
    do i=1,set%nwind
      call abscissa_chan2angl(r%head,set%wind1(i),val)
      set%wind1(i) = val
      call abscissa_chan2angl(r%head,set%wind2(i),val)
      set%wind2(i) = val
    enddo
    do i=1,set%nmask
      call abscissa_chan2angl(r%head,set%mask1(i),val)
      set%mask1(i) = val
      call abscissa_chan2angl(r%head,set%mask2(i),val)
      set%mask1(i) = val
    enddo
  elseif (new.eq.'T') then
    do i=1,set%nwind
      call abscissa_chan2time(r%head,set%wind1(i),val)
      set%wind1(i) = val
      call abscissa_chan2time(r%head,set%wind2(i),val)
      set%wind2(i) = val
    enddo
    do i=1,set%nmask
      call abscissa_chan2time(r%head,set%mask1(i),val)
      set%mask1(i) = val
      call abscissa_chan2time(r%head,set%mask2(i),val)
      set%mask1(i) = val
    enddo
  else
    call class_message(seve%e,rname,'Unit '//new//' not recognized')
    error = .true.
    return
  endif
  !
end subroutine seunitx_wind_mask
!
subroutine gelimx(x0,x1,x2,dx,unit)
  use plot_formula
  !---------------------------------------------------------------------
  ! @ private
  !  Return current limits and conversion factor in given X unit
  !---------------------------------------------------------------------
  real(kind=8),           intent(out) :: x0     ! Offset, if any
  real(kind=plot_length), intent(out) :: x1,x2  ! Range
  real(kind=plot_length), intent(out) :: dx     ! Conversion factors
  character(len=*),       intent(in)  :: unit   ! X unit
  !
  x0 = 0.d0
  select case (unit)
  case ('C')
     x1 = gcx1
     x2 = gcx2
  case ('V')
     x1 = gvx1
     x2 = gvx2
  case ('F')
     x0 = gfxo
     x1 = gfx1
     x2 = gfx2
  case ('I')
     x0 = gixo
     x1 = gix1
     x2 = gix2
  case ('T')
     x1 = gfx1
     x2 = gfx2
  case ('A')
     x1 = gvx1
     x2 = gvx2
  end select
  dx = (gx2-gx1)/(x2-x1)
end subroutine gelimx
!
subroutine geunit(set,head,unit,unit_up)
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  !  Return the current units
  !---------------------------------------------------------------------
  type(class_setup_t), intent(in)  :: set      !
  type(header),        intent(in)  :: head     !
  character(len=*),    intent(out) :: unit     ! X unit
  character(len=*),    intent(out) :: unit_up  ! X unit
  !
  unit = set%unitx(1)
  if (head%presec(class_sec_xcoo_id)) then
     unit_up = ' '
  else
     unit_up = set%unitx(2)
  endif
end subroutine geunit
!
subroutine gulimx(x1,x2,dx)
  use plot_formula
  !---------------------------------------------------------------------
  ! @ private
  ! CLASS	Internal routine
  !	Return the current limits in current unit
  !---------------------------------------------------------------------
  real(kind=plot_length), intent(out) ::  x1,x2  ! Conversion factors
  real(kind=plot_length), intent(out) ::  dx     ! Conversion factors
  !
  x1 = gux1
  x2 = gux2
  gux = (gx2-gx1)/(gux2-gux1)
  dx = gux
end subroutine gulimx
!
subroutine get_box(ax1,ax2,ay1,ay2)
  use gbl_message
  use classcore_interfaces, except_this=>get_box
  use class_parameter
  !---------------------------------------------------------------------
  ! @ private
  ! Get box position from GreG
  !---------------------------------------------------------------------
  real(kind=plot_length), intent(out) :: ax1,ax2  !
  real(kind=plot_length), intent(out) :: ay1,ay2  !
  ! Local
  logical :: error
  !
  if (plot_length.eq.8) then
     call class_message(seve%e,'GET_BOX','PROGRAMMING ERROR: update needed')
     ! call sic_get_dble('BOX_XMIN',ax1,error)
     ! call sic_get_dble('BOX_XMAX',ax2,error)
     ! call sic_get_dble('BOX_YMIN',ay1,error)
     ! call sic_get_dble('BOX_YMAX',ay2,error)
  else
     call sic_get_real('BOX_XMIN',ax1,error)
     call sic_get_real('BOX_XMAX',ax2,error)
     call sic_get_real('BOX_YMIN',ay1,error)
     call sic_get_real('BOX_YMAX',ay2,error)
  endif
end subroutine get_box
