!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine reassociate_chunk_on_data(dataval,datawei,fchan,nchan,chunk,error)
  use gbl_message
  use mrtcal_interfaces, except_this=>reassociate_chunk_on_data
  use mrtcal_calib_types
  !---------------------------------------------------------------------
  ! @ private-generic reassociate_chunk
  !---------------------------------------------------------------------
  real(kind=4), target, intent(in)    :: dataval(:)  ! DATA target
  real(kind=4), target, intent(in)    :: datawei(:)  ! WEIGHT target
  integer(kind=4),      intent(in)    :: fchan       ! First channel
  integer(kind=4),      intent(in)    :: nchan       ! Number of channels
  type(chunk_t),        intent(inout) :: chunk       !
  logical,              intent(inout) :: error       ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='REASSOCIATE>CHUNK>ON>DATA'
  integer(kind=4) :: lchan
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  if (chunk%allocated.eq.code_pointer_allocated) then
    call mrtcal_message(seve%e,rname,  &
      'Internal error: attempt to reassociate an allocated pointer (memory leak)')
    error = .true.
    return
  endif
  !
  lchan = fchan + nchan - 1
  chunk%nchan = nchan
  chunk%data1 => dataval(fchan:lchan)
  chunk%dataw => datawei(fchan:lchan)
  chunk%allocated = code_pointer_associated
  !
end subroutine reassociate_chunk_on_data
!
subroutine reassociate_chunk_on_chunk(in,ou,error)
  use gbl_message
  use mrtcal_interfaces, except_this=>reassociate_chunk_on_chunk
  use mrtcal_calib_types
  !---------------------------------------------------------------------
  ! @ private-generic reassociate_chunk
  !---------------------------------------------------------------------
  type(chunk_t), intent(in)    :: in
  type(chunk_t), intent(inout) :: ou
  logical,       intent(inout) :: error
  ! Local
  character(len=*), parameter :: rname='REASSOCIATE>CHUNK>ON>CHUNK'
  !
  ! Data pointers part
  call reassociate_chunk_on_data(in%data1,in%dataw,1,in%nchan,ou,error)
  if (error)  return
  !
  ! Remaining part: duplicate...
  ! ZZZ use mrtcal_chunk_copy_header?
  ou%id   = in%id
  ou%mjd  = in%mjd
  ou%gen  = in%gen
  ou%pos  = in%pos
  ou%spe  = in%spe
  ou%cal  = in%cal
  ou%swi  = in%swi
  ou%res  = in%res
  ou%user = in%user
  ou%cont1 = in%cont1
  !
end subroutine reassociate_chunk_on_chunk
!
subroutine reassociate_chunkset(in,ou,error,ichunk)
  use gbl_message
  use mrtcal_interfaces, except_this=>reassociate_chunkset
  use mrtcal_calib_types
  !---------------------------------------------------------------------
  ! @ private
  !  Associate a chunkset onto another one.
  !  If 'ichunk' is present, associate only onto this single element
  ! (pointer to subset).
  !---------------------------------------------------------------------
  type(chunkset_t),          intent(in)    :: in
  type(chunkset_t),          intent(inout) :: ou
  logical,                   intent(inout) :: error
  integer(kind=4), optional, intent(in)    :: ichunk
  ! Local
  character(len=*), parameter :: rname='REASSOCIATE>CHUNKSET'
  integer(kind=4) :: first,last
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  if (present(ichunk)) then
    if (ichunk.lt.1 .or. ichunk.gt.in%n) then
      call mrtcal_message(seve%e,rname,'Invalid chunk number')
      error = .true.
      return
    endif
    first = ichunk
    last = first
  else
    first = 1
    last = in%n
  endif
  !
  if (ou%allocated.eq.code_pointer_allocated) then
    call free_chunkset(ou,error)
    if (error)  return
  endif
  !
  ou%n = last-first+1
  ou%chunks => in%chunks(first:last)
  ou%allocated = code_pointer_associated
  !
end subroutine reassociate_chunkset
!
subroutine reassociate_chunkset_2d_on_2d(in2d,ou2d,error)
  use gbl_message
  use mrtcal_interfaces, except_this=>reassociate_chunkset_2d_on_2d
  use mrtcal_calib_types
  !---------------------------------------------------------------------
  ! @ private-generic reassociate_chunkset_2d
  !---------------------------------------------------------------------
  type(chunkset_2d_t), intent(in)    :: in2d
  type(chunkset_2d_t), intent(inout) :: ou2d
  logical,             intent(inout) :: error
  ! Local
  character(len=*), parameter :: rname='REASSOCIATE>CHUNKSET>2DON2D'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  if (ou2d%allocated.eq.code_pointer_allocated) then
    call free_chunkset_2d(ou2d,error)
    if (error)  return
  endif
  !
  ! ZZZ Partial copy, this is not satisfying, something should be done...
  ou2d%mjd  = in2d%mjd
  ou2d%corr = in2d%corr
  ! ou2d%isub = in2d%isub  NOT THIS ONE! Controled elsewhere...
  ou2d%npix = in2d%npix
  ou2d%nset = in2d%nset
  ou2d%chunkset => in2d%chunkset
  ou2d%allocated = code_pointer_associated
  !
end subroutine reassociate_chunkset_2d_on_2d
!
subroutine reassociate_chunkset_2d_on_3d(itime,in3d,ou2d,error)
  use gbl_message
  use mrtcal_interfaces, except_this=>reassociate_chunkset_2d_on_3d
  use mrtcal_calib_types
  !---------------------------------------------------------------------
  ! @ private-generic reassociate_chunkset_2d
  !---------------------------------------------------------------------
  integer(kind=4),     intent(in)    :: itime  ! Position in in3d
  type(chunkset_3d_t), intent(in)    :: in3d   !
  type(chunkset_2d_t), intent(inout) :: ou2d   !
  logical,             intent(inout) :: error  !
  ! Local
  character(len=*), parameter :: rname='REASSOCIATE>CHUNKSET>2DON3D'
  character(len=message_length) :: mess
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  if (ou2d%allocated.eq.code_pointer_allocated) then
    call free_chunkset_2d(ou2d,error)
    if (error)  return
  endif
  !
  if (itime.lt.1 .or. itime.gt.in3d%ntime) then
    write(mess,'(A,I0,A,I0,A)')  'Trying to point to time #',itime,  &
        ', i.e., outside the target chunkset_3d (1:',in3d%ntime,')'
    call mrtcal_message(seve%e,rname,mess)
    error = .true.
    return
  endif
  !
  ou2d%nset = in3d%nset
  ou2d%npix = in3d%npix
  ou2d%chunkset => in3d%chunkset(:,:,itime)
  ou2d%allocated = code_pointer_associated
  !
end subroutine reassociate_chunkset_2d_on_3d
!
subroutine reassociate_chunkset_3d_on_2d(itime,in2d,ou3d,error)
  use gbl_message
  use mrtcal_interfaces, except_this=>reassociate_chunkset_3d_on_2d
  use mrtcal_calib_types
  !---------------------------------------------------------------------
  ! @ private-generic reassociate_chunkset_3d
  ! Associate a subset of a chunkset_3d onto a chunkset_2d. Note that
  ! this is kind of reverse operation done by
  ! reassociate_chunkset_2d_on_3d.
  !
  !   Note also that:
  !   - this is a problem of "arrays of pointers", which, in Fortran
  !     is not possible
  !   - chunkset_3d are always allocated, never associated
  ! which means we can not associate a chunkset_3d onto several
  ! chunkset_2d. But this is what we want to do!
  !   Knowing that:
  !   - chunkset are always allocated, never associated
  !   - chunks can be allocated or associated
  ! The solution is to allocate the chunkset_3d, plus its chunksets,
  ! but associate its chunks to the desired target at very low level...
  !---------------------------------------------------------------------
  integer(kind=4),     intent(in)    :: itime   ! Position in ou3d
  type(chunkset_2d_t), intent(in)    :: in2d   !
  type(chunkset_3d_t), intent(inout) :: ou3d   !
  logical,             intent(inout) :: error  !
  ! Local
  character(len=*), parameter :: rname='REASSOCIATE>CHUNKSET>3DON2D'
  character(len=message_length) :: mess
  integer(kind=4) :: iset,ipix
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  ! Sanity check: the output chunkset_3d must have allocated to the correct
  ! size
  if (itime.lt.1 .or. itime.gt.ou3d%ntime) then
    write(mess,'(A,I0,A,I0,A)')  'Trying to point to time #',itime,  &
        ', i.e., outside the chunkset_3d (1:',ou3d%ntime,')'
    call mrtcal_message(seve%e,rname,mess)
    error = .true.
    return
  endif
  if (in2d%nset.ne.ou3d%nset .or. in2d%npix.ne.ou3d%npix) then
    write(mess,'(4(A,I0))')  'Chunksets are inconsistent: nset = ',in2d%nset,  &
      ' vs ',ou3d%nset,', npix = ',in2d%npix,' vs ',ou3d%npix
    call mrtcal_message(seve%e,rname,mess)
    error = .true.
    return
  endif
  !
  do ipix=1,in2d%npix
    do iset=1,in2d%nset
      call reassociate_chunkset(in2d%chunkset(iset,ipix),ou3d%chunkset(iset,ipix,itime),error)
      if (error)  return
    enddo
  enddo
  !
end subroutine reassociate_chunkset_3d_on_2d
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine nullify_chunk(chunk,error)
  use gbl_message
  use mrtcal_interfaces, except_this => nullify_chunk
  use mrtcal_calib_types
  !-------------------------------------------------------------------
  ! @ private
  !-------------------------------------------------------------------
  type(chunk_t), intent(inout) :: chunk
  logical,       intent(inout) :: error
  ! Local
  character(len=*), parameter :: rname='NULLIFY>CHUNK'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  if (chunk%allocated.eq.code_pointer_associated) then
    chunk%nchan = 0
    chunk%data1 => null()
    chunk%dataw => null()
    chunk%allocated = code_pointer_null
    !
  elseif (chunk%allocated.eq.code_pointer_allocated) then
    call mrtcal_message(seve%e,rname,'Attempt to nullify an allocated pointer')
    error = .true.
    return
  endif
  !
end subroutine nullify_chunk
!
subroutine nullify_chunkset(chunkset,error)
  use gbl_message
  use mrtcal_interfaces, except_this=>nullify_chunkset
  use mrtcal_calib_types
  !-------------------------------------------------------------------
  ! @ private
  !-------------------------------------------------------------------
  type(chunkset_t), intent(inout) :: chunkset
  logical,          intent(inout) :: error
  ! Local
  character(len=*), parameter :: rname='NULLIFY>CHUNKSET'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  if (chunkset%allocated.eq.code_pointer_associated) then
    chunkset%n = 0
    chunkset%chunks => null()
    chunkset%allocated = code_pointer_null
    !
  elseif (chunkset%allocated.eq.code_pointer_allocated) then
    call mrtcal_message(seve%e,rname,'Attempt to nullify an allocated pointer')
    error = .true.
    return
  endif
  !
end subroutine nullify_chunkset
!
subroutine nullify_chunkset_2d(ck2d,error)
  use gbl_message
  use mrtcal_calib_types
  use mrtcal_interfaces, except_this=>nullify_chunkset_2d
  !---------------------------------------------------------------------
  ! @ private
  !  Nullify a chunkset_2d type.
  !  Nullify only the array. Its components are owned by the target,
  ! this is its responsibility, not ours here.
  !---------------------------------------------------------------------
  type(chunkset_2d_t), intent(inout) :: ck2d
  logical,             intent(inout) :: error
  ! Local
  character(len=*), parameter :: rname='NULLIFY>CHUNKSET>2D'
  !
  call mrtcal_message(seve%t,rname,'Welcome')
  !
  if (ck2d%allocated.eq.code_pointer_associated) then
    !
    if (.not.associated(ck2d%chunkset)) then
      ! This is unexpected, since ck2d%allocated tells us the array is in use!
      call mrtcal_message(seve%e,rname,'Chunkset 2D array is not associated!')
      error = .true.
      return
    endif
    !
    ck2d%chunkset => null()
    ck2d%npix = 0
    ck2d%nset = 0
    ck2d%allocated = code_pointer_null
    !
  elseif (ck2d%allocated.eq.code_pointer_allocated) then
    call mrtcal_message(seve%e,rname,'Attempt to nullify an allocated pointer')
    error = .true.
    return
    !
  else  ! ck2d%allocated.eq.code_pointer_null
    if (associated(ck2d%chunkset)) then
      ! This is unexpected, since ck2d%allocated tells us the array is NOT in use!
      call mrtcal_message(seve%e,rname,  &
        'Internal error: unexpected association status')
      error = .true.
      return
    endif
    !
  endif
  !
end subroutine nullify_chunkset_2d
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
