!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine mrtcal_calib_tracked_psw(mrtset,backcal,backsci,filebuf,error)
  use gbl_message
  use gkernel_interfaces
  use mrtcal_buffer_types
  use mrtcal_setup_types
  use mrtcal_interfaces, except_this => mrtcal_calib_tracked_psw
  !---------------------------------------------------------------------
  ! @ private
  ! Gather all needed steps to read, calibrate, and write a 
  ! tracked position switched scan for a given backend
  !---------------------------------------------------------------------
  type(mrtcal_setup_t),    intent(in)    :: mrtset
  type(calib_backend_t),   intent(in)    :: backcal
  type(science_backend_t), intent(inout) :: backsci
  type(imbfits_buffer_t),  intent(inout) :: filebuf
  logical,                 intent(inout) :: error
  ! Local
  character(len=*), parameter :: rname='CALIB>TRACKED>PSW'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  call mrtcal_iterate_cycle_trackedpsw(mrtset,filebuf%imbf,  &
    filebuf%subscanbuf,backcal,backsci,error)
  if (error)  return
  !
end subroutine mrtcal_calib_tracked_psw
!
subroutine mrtcal_calib_tracked_psw_cycle(mrtset,imbf,ifirst,nswitch,  &
  subscanbuf,backcal,backsci,error)
  use gbl_message
  use mrtcal_interfaces, except_this=>mrtcal_calib_tracked_psw_cycle
  use mrtcal_buffer_types
  use mrtcal_setup_types
  !---------------------------------------------------------------------
  ! @ private
  ! Calibrate a TRACKED PSW cycle of subscans
  !---------------------------------------------------------------------
  type(mrtcal_setup_t),    intent(in)            :: mrtset      !
  type(imbfits_t),         intent(in)            :: imbf        !
  integer(kind=4),         intent(in)            :: ifirst      ! First subscan in cycle
  integer(kind=4),         intent(in)            :: nswitch     ! Number of subscans in cycle
  type(subscan_buffer_t),  intent(inout)         :: subscanbuf  !
  type(calib_backend_t),   intent(in)            :: backcal     !
  type(science_backend_t), intent(inout), target :: backsci     !
  logical,                 intent(inout)         :: error       ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='CALIB>TRACKED>PSW>CYCLE'
  integer(kind=4) :: isub
  logical, parameter :: iscal=.false.
  type(chunkset_2d_t) :: curr  ! Buffer for reading a ON or OFF subscan
  type(chunkset_2d_t), pointer :: cumul  ! Pointer to current ON or OFF cumulation
  logical :: initon,initoff
  character(len=23) :: iso
  character(len=message_length) :: mess
  !
  initon = .true.
  initoff = .true.
  do isub=ifirst,ifirst+nswitch-1
    call mrtcal_average_times(mrtset,iscal,isub,'track',imbf,subscanbuf,curr,error)
    if (error)  goto 10
    !
    if (backsci%list%onoff%bak(isub).eq.backsci%list%on) then
      if (initon) then
        ! Use first ON subscan to initialize the ON structure (in particular
        ! regarding offsets)
        call mrtcal_chunkset_2d_accumulate_init(curr,backsci%on%curr,error)
        if (error)  goto 10
        initon = .false.
      endif
      cumul => backsci%on%curr
    else
      if (initoff) then
        ! Use first OFF subscan to initialize the OFF structure (in particular
        ! regarding offsets)
        if (.not.associated(backsci%off%curr)) then
          ! Because this one is a pointer => allocate a scalar object
          allocate(backsci%off%curr)
        endif
        call mrtcal_chunkset_2d_accumulate_init(curr,backsci%off%curr,error)
        if (error)  goto 10
        initoff = .false.
      endif
      cumul => backsci%off%curr
    endif
    !
    call mrtcal_chunkset_2d_accumulate_setweight(curr,backsci%tscale,  &
      mrtset%out%weight,error)
    if (error)  goto 10
    call mrtcal_chunkset_2d_accumulate_do(curr,cumul,error)
    if (error)  goto 10
  enddo
  !
  backsci%switch%cycle%ion = 0   ! Deactivated in this context
  backsci%switch%cycle%ioff = 0  ! Deactivated in this context
  call mrtcal_on_minus_off(istracked,notfsw,backsci,error)
  if (error)  goto 10
  call mrtcal_tscale_computation(backcal,backsci,error)
  if (error)  goto 10
  call mrtcal_tscale_application(backsci%tscale,backsci%diff,error)
  if (error)  goto 10
  !
  call gag_mjd2isodate(backsci%off%curr%chunkset(1,1)%chunks(1)%mjd,iso,error)
  write(mess,'(6a)') 'Average OFF    date: ',iso
  call mrtcal_message(seve%i,rname,mess)
  call gag_mjd2isodate(backsci%on%curr%chunkset(1,1)%chunks(1)%mjd,iso,error)
  write(mess,'(6a)') 'Average ON     date: ',iso
  call mrtcal_message(seve%i,rname,mess)
  call gag_mjd2isodate(backsci%diff%chunkset(1,1,1)%chunks(1)%mjd,iso,error)
  write(mess,'(6a)') 'Average ON-OFF date: ',iso
  call mrtcal_message(seve%i,rname,mess)
  !
  if (mrtset%out%accmode.eq.accmode_cycl) then
    call mrtcal_write_toclass(backsci%diff,mrtset%out,backsci%nspec,error)
    if (error)  goto 10
  endif
  !
10 continue
  call free_chunkset_2d(curr,error)
  if (error)  return
  !
end subroutine mrtcal_calib_tracked_psw_cycle
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! Following code is generic to OTF and TRACKED PSW
!
subroutine mrtcal_psw_read_surrounding_offs(mrtset,imbf,subscanbuf,backsci,error)
  use gbl_message
  use gkernel_types
  use mrtcal_buffer_types
  use mrtcal_setup_types
  use mrtcal_interfaces, except_this=>mrtcal_psw_read_surrounding_offs
  !---------------------------------------------------------------------
  ! @ private
  ! Get in the current list of subscans the number of the previous and 
  ! the next OFF subscans, read them, average them in time, and store 
  ! them into backsci%off
  !
  ! That's a stack. The code must start the previous OFF subscan, because 
  ! it probably is the current next OFF subscan, as the subscans are 
  ! ordered by increasing time. This saves data reading. Setting the 
  ! subscan number to zero means that we did not find either the previous 
  ! or the next off
  !---------------------------------------------------------------------
  type(mrtcal_setup_t),            intent(in)    :: mrtset
  type(imbfits_t),                 intent(in)    :: imbf
  type(subscan_buffer_t),          intent(inout) :: subscanbuf
  type(science_backend_t), target, intent(inout) :: backsci
  logical,                         intent(inout) :: error
  ! Local
  logical, parameter :: iscal = .false.
  logical :: found
  integer(kind=4) :: ioff,iprev,inext
  type(chunkset_2d_t), pointer :: altoff
  character(len=*), parameter :: rname='PSW>READ>SURROUNDING>OFFS'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  ! Stack previous off
  ioff = backsci%on%curr%isub
  call eclass_2dble_getprev(backsci%list%onoff,backsci%list%off,ioff,found,error)
  if (error) return
  if (found) then
     iprev = backsci%list%isub(ioff)
     if (backsci%off%prev%isub.eq.iprev) then
        ! Nothing to be done...
     else if (backsci%off%next%isub.eq.iprev) then
        altoff => backsci%off%prev
        backsci%off%prev => backsci%off%next
        backsci%off%next => altoff
     else
        call mrtcal_average_times(mrtset,iscal,backsci%list%isub(ioff),'track',imbf,subscanbuf,backsci%off%prev,error)
        if (failed_calibrate(rname,backsci%list%isub(ioff),error))  return
     endif
  else
     backsci%off%prev%isub = 0 ! Nevertheless, leave the type allocated
  endif
  ! Stack next off
  ioff = backsci%on%curr%isub
  call eclass_2dble_getnext(backsci%list%onoff,backsci%list%off,ioff,found,error)
  if (error) return
  if (found) then
     inext = backsci%list%isub(ioff)
     if (backsci%off%prev%isub.eq.inext) then
        altoff => backsci%off%next
        backsci%off%next => backsci%off%prev
        backsci%off%prev => altoff
     else if (backsci%off%next%isub.eq.inext) then
        ! Nothing to be done...
     else
        call mrtcal_average_times(mrtset,iscal,backsci%list%isub(ioff),'track',imbf,subscanbuf,backsci%off%next,error)
        if (error)  return
     endif
  else
     backsci%off%next%isub = 0 ! Nevertheless, leave the type allocated
  endif
  !
end subroutine mrtcal_psw_read_surrounding_offs
!
subroutine mrtcal_psw_interpolate_off_init(off,error)
  use gbl_message
  use mrtcal_calib_types
  use mrtcal_interfaces, except_this=>mrtcal_psw_interpolate_off_init
  !---------------------------------------------------------------------
  ! @ private
  ! *** JP In output, interp%isub = prev%isub or interp%isub = next%isub
  ! *** JP It would be better to have the averaged value stored as a real
  ! *** JP If this subscan number is used at read time, some additional
  ! *** JP protection would be needed.
  !---------------------------------------------------------------------
  type(off_stack_t), target, intent(inout) :: off
  logical,                   intent(inout) :: error
  ! Local
  type(chunkset_2d_t), pointer :: prev,next,offset,slope,interp
  character(len=*), parameter :: rname='PSW>INTERPOLATE>OFF>INIT'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  prev => off%prev
  next => off%next
  slope  => off%slope
  offset => off%offset
  interp => off%interp
  !
  if ((prev%isub.gt.0).and.(next%isub.gt.0)) then
     ! Both are there => Interpolation possible
     call mrtcal_chunkset_2d_interpolate_init(prev,next,slope,offset,interp,error)
     if (error) return
  else if ((prev%isub.le.0).and.(next%isub.le.0)) then
     ! Both are missing => Something wrong
     call mrtcal_message(seve%e,rname,'No subscans associated to previous and next OFF')
     error = .true.
     return
  else
     ! Only one is missing => Use the other one
     if (error) return
     if (prev%isub.le.0) then
        ! Previous is missing, just use the next one
        call mrtcal_chunkset_2d_interpolate_init_as_ref(next,slope,offset,interp,error)
        if (error) return
        call mrtcal_chunkset_2d_copy_data(next,offset,error)
        if (error) return
     endif
     if (next%isub.le.0) then
        ! Next is missing, just use the previous one
        call mrtcal_chunkset_2d_interpolate_init_as_ref(prev,slope,offset,interp,error)
        if (error) return
        call mrtcal_chunkset_2d_copy_data(prev,offset,error)
        if (error) return
     endif
     ! Set slope to zero (This ones must come after the header copy)
     call mrtcal_chunkset_2d_init_data(slope,0.,0.,0.,error)
  endif
  ! 
  off%curr => off%interp
  !
end subroutine mrtcal_psw_interpolate_off_init
!
subroutine mrtcal_psw_prepare_nextoff(mrtset,filebuf,backsci,error)
  use gbl_message
  use mrtcal_buffer_types
  use mrtcal_setup_types
  use mrtcal_interfaces, except_this=>mrtcal_psw_prepare_nextoff
  !---------------------------------------------------------------------
  ! @ private
  ! Read the OFF subscans surrounding the current ON subscan and prepare
  ! the linear interpolation in time, i.e., compute the segment slope and
  ! constant
  !---------------------------------------------------------------------
  type(mrtcal_setup_t),    intent(in)    :: mrtset
  type(imbfits_buffer_t),  intent(inout) :: filebuf
  type(science_backend_t), intent(inout) :: backsci
  logical,                 intent(inout) :: error
  ! Local
  character(len=*), parameter :: rname='PSW>PREPARE>NEXTOFF'
  !
  call mrtcal_psw_read_surrounding_offs(mrtset,&
       filebuf%imbf,&
       filebuf%subscanbuf,&
       backsci,error)
  if (error) return
  call mrtcal_psw_interpolate_off_init(backsci%off,error)
  if (error) return
  !
end subroutine mrtcal_psw_prepare_nextoff
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
