!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine mrtcal_chunkset_2d_swi_fill(swmode,swdesc,chunkset2d,error)
  use mrtcal_messaging
  use mrtcal_calib_types
  use mrtcal_interfaces, except_this => mrtcal_chunkset_2d_swi_fill
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  integer(kind=4),     intent(in)    :: swmode
  type(switch_desc_t), intent(in)    :: swdesc
  type(chunkset_2d_t), intent(inout) :: chunkset2d
  logical,             intent(inout) :: error
  ! Local
  type(chunkset_t), pointer :: chunkset
  integer(kind=size_length) :: ipix,iset,ichunk
  character(len=*), parameter :: rname='CHUNKSET>2D>SWI>FILL'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  do ipix=1,chunkset2d%npix
     do iset=1,chunkset2d%nset
        chunkset => chunkset2d%chunkset(iset,ipix)
        do ichunk=1,chunkset%n
           call mrtcal_chunk_swi_fill(swmode,swdesc,chunkset%chunks(ichunk),error)
           if (error) return
        enddo ! ichunk
     enddo ! iset
  enddo ! ipix
  !
end subroutine mrtcal_chunkset_2d_swi_fill
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine mrtcal_chunkset_2d_copy_data(in,out,error)
  use mrtcal_messaging
  use mrtcal_calib_types
  use mrtcal_interfaces, except_this => mrtcal_chunkset_2d_copy_data
  !---------------------------------------------------------------------
  ! @ private
  ! Data are copied
  !---------------------------------------------------------------------
  type(chunkset_2d_t), intent(in)    :: in
  type(chunkset_2d_t), intent(inout) :: out
  logical,             intent(inout) :: error
  ! Local
  type(chunkset_t), pointer :: inset,outset
  integer(kind=size_length) :: ipix,iset,ichunk
  character(len=*), parameter :: rname='CHUNKSET>2D>COPY>DATA'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  do ipix=1,out%npix
     do iset=1,out%nset
        inset => in%chunkset(iset,ipix)
        outset => out%chunkset(iset,ipix)
        do ichunk=1,outset%n
           call outset%chunks(ichunk)%copy_data(inset%chunks(ichunk),error)
           if (error) return
        enddo ! ichunk
     enddo ! iset
  enddo ! ipix
  !
end subroutine mrtcal_chunkset_2d_copy_data
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine mrtcal_chunkset_2d_interpolate_init(prev,next,slope,offset,interp,error)
  use mrtcal_messaging
  use mrtcal_calib_types
  use mrtcal_interfaces, except_this => mrtcal_chunkset_2d_interpolate_init
  !---------------------------------------------------------------------
  ! @ private
  ! Initialize linear interpolation
  !---------------------------------------------------------------------
  type(chunkset_2d_t), intent(in)    :: prev
  type(chunkset_2d_t), intent(in)    :: next
  type(chunkset_2d_t), intent(inout) :: slope
  type(chunkset_2d_t), intent(inout) :: offset
  type(chunkset_2d_t), intent(inout) :: interp
  logical,             intent(inout) :: error
  ! Local
  integer(kind=size_length) :: ipix,iset,ichunk
  character(len=*), parameter :: rname='CHUNKSET>2D>INTERPOLATE>INIT'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  call prev%consistency(rname,next,error)
  if (error) return
  call mrtcal_chunkset_2d_interpolate_init_as_ref(prev,slope,offset,interp,error)
  if (error) return
  !
  do ipix=1,prev%npix
     do iset=1,prev%nset
        do ichunk=1,prev%chunkset(iset,ipix)%n
           call mrtcal_chunk_interpolate_init(&
                prev%chunkset(iset,ipix)%chunks(ichunk),&
                next%chunkset(iset,ipix)%chunks(ichunk),&
                slope%chunkset(iset,ipix)%chunks(ichunk),&
                offset%chunkset(iset,ipix)%chunks(ichunk),&
                error)
           if (error) return
        enddo ! ichunk
     enddo ! iset
  enddo ! ipix
  !
end subroutine mrtcal_chunkset_2d_interpolate_init
!
subroutine mrtcal_chunkset_2d_interpolate_init_as_ref(ref,slope,offset,interp,error)
  use mrtcal_messaging
  use mrtcal_calib_types
  use mrtcal_interfaces, except_this => mrtcal_chunkset_2d_interpolate_init_as_ref
  !---------------------------------------------------------------------
  ! @ private
  ! Reallocate as ref and copy header from ref
  !---------------------------------------------------------------------
  type(chunkset_2d_t), intent(in)    :: ref
  type(chunkset_2d_t), intent(inout) :: slope
  type(chunkset_2d_t), intent(inout) :: offset
  type(chunkset_2d_t), intent(inout) :: interp
  logical,             intent(inout) :: error
  ! Local
  character(len=*), parameter :: rname='CHUNKSET>2D>INTERPOLATE>INIT>AS>REF'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  call slope%clone(ref,.true.,error)
  if (error) return
  call offset%clone(ref,.true.,error)
  if (error) return
  call interp%clone(ref,.true.,error)
  if (error) return
  !
end subroutine mrtcal_chunkset_2d_interpolate_init_as_ref
!
subroutine mrtcal_chunkset_2d_interpolate_do(mjd,slope,offset,interp,error)
  use mrtcal_messaging
  use mrtcal_calib_types
  use mrtcal_interfaces, except_this => mrtcal_chunkset_2d_interpolate_do
  !---------------------------------------------------------------------
  ! @ private
  ! Compute linear interpolation
  !---------------------------------------------------------------------
  real(kind=8),        intent(in)    :: mjd
  type(chunkset_2d_t), intent(inout) :: slope
  type(chunkset_2d_t), intent(inout) :: offset
  type(chunkset_2d_t), intent(inout) :: interp
  logical,             intent(inout) :: error
  ! Local
  integer(kind=size_length) :: ipix,iset,ichunk
  character(len=*), parameter :: rname='CHUNKSET>2D>INTERPOLATE>DO'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  call slope%consistency(rname,offset,error)
  if (error) return
  call slope%consistency(rname,interp,error)
  if (error) return
  !
  do ipix=1,slope%npix
     do iset=1,slope%nset
        do ichunk=1,slope%chunkset(iset,ipix)%n
           call mrtcal_chunk_interpolate_do(mjd,&
                slope%chunkset(iset,ipix)%chunks(ichunk),&
                offset%chunkset(iset,ipix)%chunks(ichunk),&
                interp%chunkset(iset,ipix)%chunks(ichunk),&
                error)
           if (error) return
        enddo ! ichunk
     enddo ! iset
  enddo ! ipix
  !
end subroutine mrtcal_chunkset_2d_interpolate_do
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine mrtcal_chunkset_2d_blank(ref,blank,error)
  use class_types
  use mrtcal_messaging
  use mrtcal_interfaces, except_this=>mrtcal_chunkset_2d_blank
  use mrtcal_calib_types
  !---------------------------------------------------------------------
  ! @ private
  ! Create a blank 'chunkset_2d' (all 'bad' data), duplicate of the
  ! reference, with relevant sections blanked or kept.
  !---------------------------------------------------------------------
  type(chunkset_2d_t), intent(in)    :: ref
  type(chunkset_2d_t), intent(inout) :: blank
  logical,             intent(inout) :: error
  ! Local
  integer(kind=4) :: ipix,iset,ichunk
  character(len=*), parameter :: rname='CHUNKSET2D>BLANK'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  ! Clone and duplicate headers, in particular the spectroscopic axis
  ! description
  call blank%clone(ref,.true.,error)
  if (error)  return
  !
  ! Reset irrelevant header values
  do ipix=1,blank%npix
    do iset=1,blank%nset
      do ichunk=1,blank%chunkset(iset,ipix)%n
! *** JP Still to be done
!        blank%chunkset(iset,ipix)%chunks(ichunk)%pos%sourc = ''
      enddo
    enddo
  enddo
  !
  ! Blank data and continuum, 0 weight.
  call blank%init_data(class_bad,0.,class_bad,error)
  if (error) return
  !
end subroutine mrtcal_chunkset_2d_blank
!
subroutine mrtcal_chunkset_2d_accumulate_init(ref,acc,error)
  use mrtcal_messaging
  use mrtcal_interfaces, except_this=>mrtcal_chunkset_2d_accumulate_init
  use mrtcal_calib_types
  !---------------------------------------------------------------------
  ! @ private
  ! (Re)allocate and initialize a 'chunkset_2d' structure for future
  ! use in mrtcal_chunkset_2d_accumulate_2d.
  !---------------------------------------------------------------------
  type(chunkset_2d_t), intent(in)    :: ref
  type(chunkset_2d_t), intent(inout) :: acc
  logical,             intent(inout) :: error
  ! Local
  integer(kind=4) :: ipix,iset,ichunk
  character(len=*), parameter :: rname='CHUNKSET2D>ACCUMULATE>INIT'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  call acc%clone(ref,.true.,error)
  if (error)  return
  !
  ! Reset integration time in 'accumulate' instance
  do ipix=1,acc%npix
    do iset=1,acc%nset
      do ichunk=1,acc%chunkset(iset,ipix)%n
        acc%chunkset(iset,ipix)%chunks(ichunk)%gen%time = 0.
        acc%chunkset(iset,ipix)%chunks(ichunk)%swi%duree(:) = 0.
      enddo
    enddo
  enddo
  !
  ! Reset values and weights in 'accumulate' instance
  call acc%init_data(0.,0.,0.,error)
  if (error) return
  !
end subroutine mrtcal_chunkset_2d_accumulate_init
!
subroutine mrtcal_chunkset_3d_accumulate_init(ref,acc,error)
  use mrtcal_messaging
  use mrtcal_interfaces, except_this=>mrtcal_chunkset_3d_accumulate_init
  use mrtcal_calib_types
  !---------------------------------------------------------------------
  ! @ private
  ! (Re)allocate and initialize a 'chunkset_3d' structure for future
  ! use in mrtcal_chunkset_accumulate_do.
  !---------------------------------------------------------------------
  type(chunkset_3d_t), intent(in)    :: ref
  type(chunkset_3d_t), intent(inout) :: acc
  logical,             intent(inout) :: error
  ! Local
  integer(kind=4) :: itime,ipix,iset,ichunk
  character(len=*), parameter :: rname='CHUNKSET3D>ACCUMULATE>INIT'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  call acc%clone(ref,.true.,error)
  if (error)  return
  !
  ! Reset integration time in 'accumulate' instance
  do itime=1,acc%ntime
    do ipix=1,acc%npix
      do iset=1,acc%nset
        do ichunk=1,acc%chunkset(iset,ipix,itime)%n
          acc%chunkset(iset,ipix,itime)%chunks(ichunk)%gen%time = 0.
          acc%chunkset(iset,ipix,itime)%chunks(ichunk)%swi%duree(:) = 0.
        enddo
      enddo
    enddo
  enddo
  !
  ! Reset values and weights in 'accumulate' instance
  call acc%init_data(0.,0.,0.,error)
  if (error) return
  !
end subroutine mrtcal_chunkset_3d_accumulate_init
!
subroutine mrtcal_chunkset_2d_accumulate_setweight(diff,tscale,dowei,error)
  use mrtcal_interfaces, except_this=>mrtcal_chunkset_2d_accumulate_setweight
  use mrtcal_calib_types
  !---------------------------------------------------------------------
  ! @ private
  ! ZZZ
  ! Quick and dirty subroutine to enforce chunks dataw to something
  ! non-zero (needed by simple_waverage). Currently set to 1.0 i.e.
  ! equal weights. Should probably come early and cleverly e.g.
  ! weight equal, tsys, time, maybe in mrtcal_on_minus_off.
  !---------------------------------------------------------------------
  type(chunkset_2d_t), intent(inout) :: diff
  type(chunkset_2d_t), intent(in)    :: tscale
  logical,             intent(in)    :: dowei   ! Compute real weights or dummy?
  logical,             intent(inout) :: error
  ! Local
  integer(kind=size_length) :: ipix,iset
  !
  do ipix=1,diff%npix
    do iset=1,diff%nset
      call mrtcal_chunkset_accumulate_setweight(  &
        diff%chunkset(iset,ipix),    &
        tscale%chunkset(iset,ipix),  &
        dowei,error)
      if (error)  return
    enddo ! iset
  enddo ! ipix
  !
end subroutine mrtcal_chunkset_2d_accumulate_setweight
!
subroutine mrtcal_chunkset_3d_accumulate_setweight(diff,tscale,dowei,error)
  use mrtcal_interfaces, except_this=>mrtcal_chunkset_3d_accumulate_setweight
  use mrtcal_calib_types
  !---------------------------------------------------------------------
  ! @ private
  ! ZZZ
  ! Quick and dirty subroutine to enforce chunks dataw to something
  ! non-zero (needed by simple_waverage). Currently set to 1.0 i.e.
  ! equal weights. Should probably come early and cleverly e.g.
  ! weight equal, tsys, time, maybe in mrtcal_on_minus_off.
  !---------------------------------------------------------------------
  type(chunkset_3d_t), intent(inout) :: diff
  type(chunkset_2d_t), intent(in)    :: tscale
  logical,             intent(in)    :: dowei   ! Compute real weights or dummy?
  logical,             intent(inout) :: error
  ! Local
  integer(kind=size_length) :: itime,ipix,iset
  !
  do itime=1,diff%ntime
    do ipix=1,diff%npix
      do iset=1,diff%nset
        call mrtcal_chunkset_accumulate_setweight(  &
          diff%chunkset(iset,ipix,itime),    &
          tscale%chunkset(iset,ipix),        &
          dowei,error)
        if (error)  return
      enddo ! iset
    enddo ! ipix
  enddo ! itime
  !
end subroutine mrtcal_chunkset_3d_accumulate_setweight
!
subroutine mrtcal_chunkset_2d_accumulate_do(in2d,ou2d,error)
  use mrtcal_messaging
  use mrtcal_interfaces, except_this=>mrtcal_chunkset_2d_accumulate_do
  use mrtcal_calib_types
  !---------------------------------------------------------------------
  ! @ private
  ! Accumulate the input chunkset_2d into the running 'ou2d'
  ! chunkset_2d.
  !---------------------------------------------------------------------
  type(chunkset_2d_t), intent(in)    :: in2d
  type(chunkset_2d_t), intent(inout) :: ou2d
  logical,             intent(inout) :: error
  ! Local
  integer(kind=size_length) :: ipix,iset
  character(len=*), parameter :: rname='CHUNKSET2D>ACCUMULATE>DO'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  ! ZZZ Something to be done on acc%corr?
  !
  ! ZZZ Something to be done on acc%isub? Makes probably no sense
  !
  do ipix=1,in2d%npix
    do iset=1,in2d%nset
      call mrtcal_chunkset_accumulate_do(  &
        in2d%chunkset(iset,ipix),    &
        ou2d%chunkset(iset,ipix),    &
        error)
    enddo ! iset
  enddo ! ipix
  !
end subroutine mrtcal_chunkset_2d_accumulate_do
!
subroutine mrtcal_chunkset_3d_accumulate_do(in3d,ou3d,error)
  use mrtcal_messaging
  use mrtcal_interfaces, except_this=>mrtcal_chunkset_3d_accumulate_do
  use mrtcal_calib_types
  !---------------------------------------------------------------------
  ! @ private
  ! Accumulate the input chunkset_3d into the running 'ou3d'
  ! chunkset_3d.
  !---------------------------------------------------------------------
  type(chunkset_3d_t), intent(in)    :: in3d
  type(chunkset_3d_t), intent(inout) :: ou3d
  logical,             intent(inout) :: error
  ! Local
  integer(kind=size_length) :: itime,ipix,iset
  character(len=*), parameter :: rname='CHUNKSET3D>ACCUMULATE>DO'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  ! ZZZ Something to be done on acc%corr?
  !
  ! ZZZ Something to be done on acc%isub? Makes probably no sense
  !
  do itime=1,in3d%ntime  ! Not a time dimension here
    do ipix=1,in3d%npix
      do iset=1,in3d%nset
        call mrtcal_chunkset_accumulate_do(  &
          in3d%chunkset(iset,ipix,itime),    &
          ou3d%chunkset(iset,ipix,itime),    &
          error)
      enddo ! iset
    enddo ! ipix
  enddo ! itime
  !
end subroutine mrtcal_chunkset_3d_accumulate_do
!
subroutine mrtcal_chunkset_3d_append_init(ref,acc,error)
  use mrtcal_messaging
  use mrtcal_interfaces, except_this=>mrtcal_chunkset_3d_append_init
  use mrtcal_calib_types
  !---------------------------------------------------------------------
  ! @ private
  ! (Re)allocate and initialize a 'chunkset_3d' structure for future
  ! use in mrtcal_chunkset_append_do
  !---------------------------------------------------------------------
  type(chunkset_3d_t), intent(in)    :: ref
  type(chunkset_3d_t), intent(inout) :: acc
  logical,             intent(inout) :: error
  ! Local
  integer(kind=4) :: itime,ipix,iset
  character(len=*), parameter :: rname='CHUNKSET3D>APPEND>INIT'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  call acc%clone(ref,.true.,error)
  if (error)  return
  !
  ! In append mode, the 'acc' object must start with 0 chunk in
  ! each chunkset. Just nullify their number in use (chunkset%n).
  ! Avoid deallocation as we will reallocate soon.
  do itime=1,acc%ntime
    do ipix=1,acc%npix
      do iset=1,acc%nset
        acc%chunkset(iset,ipix,itime)%n = 0
      enddo
    enddo
  enddo
  !
end subroutine mrtcal_chunkset_3d_append_init
!
subroutine mrtcal_chunkset_3d_append_do(in3d,ou3d,error)
  use mrtcal_messaging
  use mrtcal_interfaces, except_this=>mrtcal_chunkset_3d_append_do
  use mrtcal_calib_types
  !---------------------------------------------------------------------
  ! @ private
  ! Append the input chunkset_3d into the running 'ou3d'
  ! chunkset_3d.
  !---------------------------------------------------------------------
  type(chunkset_3d_t), intent(in)    :: in3d
  type(chunkset_3d_t), intent(inout) :: ou3d
  logical,             intent(inout) :: error
  ! Local
  integer(kind=size_length) :: itime,ipix,iset
  character(len=*), parameter :: rname='CHUNKSET3D>APPEND>DO'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  ! ZZZ Something to be done on acc%corr?
  !
  ! ZZZ Something to be done on acc%isub? Makes probably no sense
  !
  do itime=1,in3d%ntime  ! Not a time dimension here
    do ipix=1,in3d%npix
      do iset=1,in3d%nset
        call mrtcal_chunkset_append_do(  &
          in3d%chunkset(iset,ipix,itime),    &
          ou3d%chunkset(iset,ipix,itime),    &
          error)
      enddo ! iset
    enddo ! ipix
  enddo ! itime
  !
end subroutine mrtcal_chunkset_3d_append_do
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine mrtcal_chunkset_2d_noise_init(chunkset_2d,error)
  use mrtcal_messaging
  use mrtcal_calib_types
  use mrtcal_interfaces, except_this => mrtcal_chunkset_2d_noise_init
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  type(chunkset_2d_t), intent(inout) :: chunkset_2d
  logical,             intent(inout) :: error
  ! Local
  integer(kind=4) :: ipix,iset,ichunk
  type(chunkset_t), pointer :: chunkset
  character(len=*), parameter :: rname='CHUNKSET2D>NOISE>INIT'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  do ipix=1,chunkset_2d%npix
     do iset=1,chunkset_2d%nset
        chunkset => chunkset_2d%chunkset(iset,ipix)
        do ichunk=1,chunkset%n
           call mrtcal_chunk_noise_init(chunkset%chunks(ichunk),error)
           if (error)  return
        enddo ! ichunk
     enddo ! iset
  enddo ! ipix
  !
end subroutine mrtcal_chunkset_2d_noise_init
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
