module sumlin_mod_first
  !---------------------------------------------------------------------
  !  Support variables for first run through index, in order to find
  ! what should be the new header (in particular axis parameters)
  !---------------------------------------------------------------------
  !
  ! Input observations: variables for statistics displayed to user (just
  !                    for feedback).
  real(kind=8) :: allrdopplermin,allrdopplermax
  real(kind=8) :: allrresomin,allrresomax
  !
  ! Output sum: values to be exported in header
  real(kind=8)      :: sxmin     ! Minimum abscissa of the X axis (i.e. left side of 1st channel if res>0)
  real(kind=8)      :: sxmax     ! Maximum abscissa of the X axis (i.e. right side of last channel if res>0)
  integer(kind=4)   :: smod         ! Output switching mode
  real(kind=8)      :: sdoppler     ! Doppler factor              for the output sum
  real(kind=8)      :: stime        ! Integration time            for the output sum
  real(kind=8)      :: sweight      ! Output sum weight (sum of input weights)
  character(len=12) :: sline        ! Line name                   for the output sum
  logical           :: sline_l      ! Are all line names the same?
  character(len=12) :: stele        ! Telescope name              for the output sum
  logical           :: stele_c(12)  ! Characters to be compared
  real(kind=8)      :: smjd         ! MJD                         for the output sum
  real(kind=4)      :: selevation   ! Elevation                   for the output sum
  ! Azimuth: beware of the 2 pi discontinuity...
  !
end module sumlin_mod_first
!
subroutine sumlin_header(set,aver,refer,cons,sumio,error,user_function)
  use gbl_constant
  use gbl_message
  use gkernel_types
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>sumlin_header
  use class_averaging
  use class_index
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  !  Run through the index to set the sum header. If required,
  ! automatically define the X axis resampling.
  ! 'sumlin_init' must have been called before.
  ! ---
  !  WARNING: this subroutine is duplicated in 'accumulate_generic'
  !  in order to loop on R & T instead of CX. Please duplicate there
  !  any modification made here!
  !---------------------------------------------------------------------
  type(class_setup_t), intent(in)    :: set       !
  type(average_t),     intent(inout) :: aver      !
  type(header),        intent(in)    :: refer     ! Reference header
  type(consistency_t), intent(inout) :: cons      !
  type(observation),   intent(inout) :: sumio     ! The sum. Header set on return
  logical,             intent(inout) :: error     ! Logical error flag
  logical,             external      :: user_function
  ! Local
  type(observation) :: obs
  integer(kind=entry_length) :: iobs,nobs
  integer(kind=4) :: nchan
  type(time_t) :: time
  !
  ! 1) Parse the inputs parameters
  call sumlin_init(set,cons,aver,error)
  if (error)  return
  !
  ! 2) Set the header of the output sum, using reference observation and
  ! user's axis (if any)
  call sumlin_header_init(aver,refer,sumio,error)
  if (error)  return
  !
  ! 3) Prepare the new 'axis', prepare internal (global) variables for the addition
  call sumlin_init_variables(aver,refer,sumio%head,error)
  if (error)  return
  !
  ! 4) Loop on the observations to store their axis parameters. Include
  !    also some checks.
  nobs = cx%next-1
  aver%done%nchanmax = 0
  call init_obs(obs)
  call gtime_init(time,nobs,error)
  if (error)  return
  do iobs = 1,nobs
    call gtime_current(time)
    !
    ! Exit when asked by user
    call class_controlc(aver%do%rname,error)
    if (error)  exit
    !
    ! Fill header structure from buffer. Data not needed at this stage.
    call rheader(set,obs,cx%ind(iobs),user_function,error)
    if (error)  exit
    !
    ! Apply MODIFY FREQUENCY if requested
    if (aver%do%modfreq) then
      call modify_frequency(obs,aver%do%restf,error)
      if (error)  exit
    endif
    ! Apply MODIFY VELOCITY if requested
    if (aver%do%modvelo) then
      call modify_velocity(obs,aver%do%voff,error)
      if (error)  exit
    endif
    !
    ! Check consistency. NB: on the difference of the command CONSISTENCY,
    ! we keep running on checking all observations (i.e. to check if
    ! resampling is needed in mode AUTO) even if one is inconsistent
    ! On return of the current subroutine, 'cons' is just the consistency
    ! of the last observation against the reference one.
    call observation_consistency_check(set,refer,obs%head,cons)
    if (aver%done%kind_is_spec) then
      if ((cons%gen%check.and.cons%gen%prob) .or.  &
          (cons%sou%check.and.cons%sou%prob) .or.  &
          (cons%pos%check.and.cons%pos%prob) .or.  &
          (cons%off%check.and.cons%off%prob) .or.  &
          (cons%lin%check.and.cons%lin%prob) .or.  &
          (cons%cal%check.and.cons%cal%prob) .or.  &
          (cons%swi%check.and.cons%swi%prob)) then
        error = .true.
      endif
      if (cons%spe%check.and.cons%spe%prob) then
        if (aver%do%resampling.eq.resample_no) then
          call class_message(seve%e,aver%do%rname,'Inconsistent spectroscopic '//  &
            'axes, use option /RESAMPLE to enforce resampling')
          error = .true.
        elseif (aver%do%resampling.eq.resample_auto) then
          aver%done%resample = .true.
        endif
      endif
    else
      if ((cons%gen%check.and.cons%gen%prob) .or.  &
          (cons%sou%check.and.cons%sou%prob) .or.  &
          (cons%pos%check.and.cons%pos%prob) .or.  &
          (cons%off%check.and.cons%off%prob)) then
        error = .true.
      endif
      if (cons%dri%check.and.cons%dri%prob) then
        if (aver%do%resampling.eq.resample_no) then
          call class_message(seve%e,aver%do%rname,'Inconsistent drift '//  &
            'axes, use option /RESAMPLE to enforce resampling')
          error = .true.
        elseif (aver%do%resampling.eq.resample_auto) then
          aver%done%resample = .true.
        endif
      endif
    endif
    if (error) then
      call class_message(seve%e,aver%do%rname,'Index is inconsistent')
      exit
    endif
    !
    call sumlin_header_register(obs,sumio,aver,error)
    if (error)  exit
    !
    if (aver%done%kind_is_spec) then
      nchan = obs%head%spe%nchan
    else
      nchan = obs%head%dri%npoin
    endif
    if (nchan.gt.aver%done%nchanmax)  aver%done%nchanmax = nchan
    !
  enddo
  call free_obs(obs)
  if (error)  return
  !
  ! 5) Set the sum header and X axis description
  call sumlin_header_xaxis(set,aver,sumio,nobs,error)
  if (error)  return
  !
end subroutine sumlin_header
!
subroutine sumlin_init(set,cons,aver,error)
  use gbl_constant
  use gbl_message
  use classcore_interfaces, except_this=>sumlin_init
  use class_averaging
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  ! Set some shared variables, ruled by SET methods, which we do not
  ! want to test each time in the addition loop for efficiency reasons.
  ! Should be called once, out the addition loop, i.e. not in
  ! sumlin_wadd.
  !---------------------------------------------------------------------
  type(class_setup_t), intent(in)    :: set    !
  type(consistency_t), intent(in)    :: cons   !
  type(average_t),     intent(inout) :: aver   !
  logical,             intent(inout) :: error  ! Logical error flag
  !
  select case (aver%do%weight)
  case ('E')
    aver%done%weight = weight_equal
  case ('T')
    aver%done%weight = weight_time
  case ('S')
    aver%done%weight = weight_sigma
  case ('A')
    aver%done%weight = weight_assoc
  case default
    call class_message(seve%e,aver%do%rname, &
      aver%do%weight//' weighting is not understood')
    error = .true.
    return
  end select
  !
  aver%done%composite =  &
     aver%do%composition.eq.composite_union .or.  &
    (aver%do%composition.eq.composite_user .and. set%alig2.eq.'C')
  aver%done%kind_is_spec = aver%do%kind.eq.kind_spec
  !
  select case (aver%do%resampling)
  case (resample_user)
    ! User-defined X axis (/RESAMPLE Nx Ref Val Inc Unit)
    ! Well, ok, input X axis may match or not, but the user wants its own
    ! resampling. So, we change nothing of what he requested, and
    ! resampling is enforced.
    aver%done%resample = .true.
    if (aver%do%axis%unit.eq.'V') then
      aver%done%align = align_velo
    elseif (aver%do%axis%unit.eq.'F') then
      aver%done%align = align_freq
    elseif (aver%do%axis%unit.eq.'I') then
      aver%done%align = align_imag
    elseif (aver%do%axis%unit.eq.'P') then
      aver%done%align = align_posi
    else
      call class_message(seve%e,aver%do%rname,  &
        'Resampling in '//aver%do%axis%unit//' is not supported')
      error = .true.
      return
    endif
    !
  case (resample_auto)
    ! Automatic mode: code decides by itself if resampling is needed or not
    if (cons%spe%check) then
      ! Default is to disable the resampling. It will be enabled if needed
      ! when checking all the observation headers during the first pass.
      aver%done%resample = .false.
    else
      ! e.g. AVERAGE /RESAMPLE /NOCHECK SPECTRO: user does not want we check
      ! the spectrocopy consistency. Resampling is decided once for all,
      ! according to user's SET ALIGN.
      if (set%align.eq.'C') then
        ! Non-sense: user asks for resampling (/RESAMPLE) but channel
        ! alignment (SET ALIGN C)
        call class_message(seve%e,aver%do%rname,  &
          'Invalid combination of /NOCHECK SPECTRO + /RESAMPLE + SET ALIGN CHANNEL')
        call class_message(seve%e,aver%do%rname,  &
          'Reenable checking the spectroscopic axes (automatic detection, best choice), or')
        call class_message(seve%e,aver%do%rname,  &
          'do not use /RESAMPLE if you know the spectra are aligned, or')
        call class_message(seve%e,aver%do%rname,  &
          'choose another SET ALIGN unit if you know the spectra are misaligned.')
        error = .true.
        return
      else
        aver%done%resample = .true.
      endif
    endif
    !
    if (aver%do%alignment.eq.align_auto) then
      ! In which unit should the consistency be checked (if not disabled),
      ! and the resampling be performed if we find it is really needed?
      if (set%align.eq.'V') then
        aver%done%align = align_velo
      elseif (set%align.eq.'F') then
        aver%done%align = align_freq
      elseif (set%align.eq.'P') then
        aver%done%align = align_posi
      elseif (set%align.eq.'C') then
        ! SET ALIGN CHANNEL makes no sense for consistency check, neither
        ! for resampling if it is actually needed: implicitly switch to a
        ! cleverer alignment
        if (aver%done%kind_is_spec) then
          aver%done%align = align_freq
        else
          aver%done%align = align_posi
        endif
      endif
    else
      ! Alignment was decided at input time
      aver%done%align = aver%do%alignment
    endif
    !
  case (resample_no)
    ! No resampling
    aver%done%resample = .false.  ! Strictly
    !
    ! In the "No resampling" case, the alignment makes sense only for
    ! the spectroscopic axes consistency checks (if not disabled by /NOCHECK)
    if (aver%do%alignment.eq.align_auto) then
      ! In which unit should the consistency be performed?
      if (set%align.eq.'V') then
        aver%done%align = align_velo
      elseif (set%align.eq.'F') then
        aver%done%align = align_freq
      elseif (set%align.eq.'P') then
        aver%done%align = align_posi
      elseif (set%align.eq.'C') then
        ! SET ALIGN CHANNEL makes no sense for consistency check: implicitly
        ! switch to a cleverer alignment
        if (aver%done%kind_is_spec) then
          aver%done%align = align_freq
        else
          aver%done%align = align_posi
        endif
      endif
    else
      ! Alignment was decided at input time
      aver%done%align = aver%do%alignment
    endif
    !
  end select
  !
  if (aver%done%kind_is_spec) then
    if (aver%do%resampling.eq.resample_user .or.  &
        aver%do%resampling.eq.resample_auto) then
      if (aver%done%align.ne.align_velo .and.  &
          aver%done%align.ne.align_freq .and.  &
          aver%done%align.ne.align_imag) then
        call class_message(seve%e,aver%do%rname,  &
          'Unsupported align mode for spectra.')
        error = .true.
        return
      endif
    endif
    !
  else
    if (aver%do%resampling.eq.resample_user .or.  &
        aver%do%resampling.eq.resample_auto) then
      if (aver%done%align.ne.align_posi) then
        call class_message(seve%e,aver%do%rname,  &
          'Unsupported align mode for continuum.')
        error = .true.
        return
      endif
    endif
  endif
  !
end subroutine sumlin_init
!
subroutine sumlin_header_init(aver,refer,sumio,error)
  use phys_const
  use gkernel_interfaces
  use classcore_interfaces, except_this=>sumlin_header_init
  use class_parameter
  use class_averaging
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  ! Initialize the header of the output sum
  !---------------------------------------------------------------------
  type(average_t),   intent(in)    :: aver   !
  type(header),      intent(in)    :: refer  ! Spectrum to add
  type(observation), intent(inout) :: sumio  ! Future sum
  logical,           intent(inout) :: error  ! Logical error flag
  ! Local
  real*8 :: Dv,Df
  !
  sumio%head = refer    ! Inherit all from 1st observation
  sumio%head%xnum = -1  ! Program-generated
  !
  ! General
  sumio%head%gen%num  = 0  ! Automatically set to an unused number at write time.
  sumio%head%gen%ver  = 0  ! Automatically incremented to 1 at write time.
  sumio%head%gen%time = 0.
  sumio%head%gen%az   = 0.
  sumio%head%gen%el   = 0.
! sumio%head%gen%scan =
  call sic_gagdate(sumio%head%gen%dred)  ! '0' date has no sense (-32768 = 10-DEC-1934)
  if (error)  return
  !
  ! Spectro. 'restf' of the sum is set here. Must be set definitely before
  ! the registration loop.
  if (aver%do%resampling.eq.resample_user) then
    !
    select case (aver%done%align)
    case(align_velo)  ! ALIGN VELOCITY
      sumio%head%spe%vres  = aver%do%axis%inc
      sumio%head%spe%voff  = aver%do%axis%val
      sumio%head%spe%rchan = aver%do%axis%ref
      sumio%head%spe%nchan = aver%do%axis%nchan
      ! Looking for corresponding 'restf' and 'fres'
      Dv = sumio%head%spe%voff-refer%spe%voff
      Df = -Dv/clight_kms*refer%spe%restf
      sumio%head%spe%restf = refer%spe%restf+Df
      sumio%head%spe%fres  = -sumio%head%spe%restf*sumio%head%spe%vres/clight_kms
      sumio%head%spe%doppler = 0.d0 ! We perform the resamplings in the rest frame,
                                    ! and the output spectrum is in the rest frame.
      !
    case(align_freq)  ! ALIGN FREQUENCY
      sumio%head%spe%fres  = aver%do%axis%inc/(1.d0+refer%spe%doppler)  ! In the rest frame
      sumio%head%spe%restf = aver%do%axis%val
      sumio%head%spe%rchan = aver%do%axis%ref
      sumio%head%spe%nchan = aver%do%axis%nchan
      ! Looking for corresponding 'voff' and 'vres'
      Df = sumio%head%spe%restf - refer%spe%restf
      Dv = -clight_kms*Df/sumio%head%spe%restf
      sumio%head%spe%voff = refer%spe%voff+Dv
      sumio%head%spe%vres = -clight_kms*sumio%head%spe%fres/sumio%head%spe%restf
      sumio%head%spe%doppler = 0.d0 ! We perform the resamplings in the rest frame,
                                    ! and the output spectrum is in the rest frame.
      !
    case(align_imag)  ! ALIGN IMAGE
      sumio%head%spe%fres  = -aver%do%axis%inc/(1.d0+refer%spe%doppler)  ! In the rest frame
      sumio%head%spe%image = aver%do%axis%val
      sumio%head%spe%rchan = aver%do%axis%ref
      sumio%head%spe%nchan = aver%do%axis%nchan
      ! Looking for corresponding 'voff' and 'vres'
      Df = sumio%head%spe%image - refer%spe%image
      Dv = -clight_kms*Df/sumio%head%spe%restf
      sumio%head%spe%voff = refer%spe%voff+Dv
      sumio%head%spe%vres = -clight_kms*sumio%head%spe%fres/sumio%head%spe%restf
      sumio%head%spe%doppler = 0.d0 ! We perform the resamplings in the rest frame,
                                    ! and the output spectrum is in the rest frame.
      !
    case(align_posi)  ! ALIGN POSITION
      sumio%head%dri%ares  = aver%do%axis%inc
      sumio%head%dri%aref  = aver%do%axis%val
      sumio%head%dri%rpoin = aver%do%axis%ref
      sumio%head%dri%npoin = aver%do%axis%nchan
      !
    end select
    !
  else
    ! Use the X axis of the 1st spectrum:
    ! sumio%head%spe = refer%spe  (already done)
    continue
  endif
  !
  ! Switching mode:
  ! Is duplicated from the first observation. If the full set is
  ! consistent in terms of switching mode, it will be kept. If not,
  ! it will be emptied with proper switching code.
  !
  ! Calibration. Keep beeff, foeff and gaini from first observation
  ! (the calibration consistency of the index is active by default).
  ! Reset all the other values:
! sumio%head%cal%beeff   = refer%cal%beeff (already done)
! sumio%head%cal%foeff   = refer%cal%foeff (already done)
! sumio%head%cal%gaini   = refer%cal%gaini (already done)
  sumio%head%cal%h2omm   = 0.
  sumio%head%cal%pamb    = 0.
  sumio%head%cal%tamb    = 0.
  sumio%head%cal%tatms   = 0.
  sumio%head%cal%tchop   = 0.
  sumio%head%cal%tcold   = 0.
  sumio%head%cal%taus    = 0.
  sumio%head%cal%taui    = 0.
  sumio%head%cal%tatmi   = 0.
  sumio%head%cal%trec    = 0.
  sumio%head%cal%cmode   = 0
  sumio%head%cal%atfac   = 0.
  sumio%head%cal%alti    = 0.
  sumio%head%cal%count   = 0.
  sumio%head%cal%lcalof  = 0.
  sumio%head%cal%bcalof  = 0.
  sumio%head%cal%geolong = 0.d0
  sumio%head%cal%geolat  = 0.d0
  !
  ! History will be used to keep list of summed spectra
  sumio%head%presec(class_sec_his_id) = .false.  ! Not yet reimplemented
  !
  ! Disable the plot section since new limits will be probably
  ! very different
  sumio%head%presec(class_sec_plo_id) = .false.
  sumio%head%plo%amin = 0.  ! In addition of disabling the section,
  sumio%head%plo%amax = 0.  ! also reset the values since subroutine
  sumio%head%plo%vmin = 0.  ! newlimy looks at those values instead of
  sumio%head%plo%vmax = 0.  ! section present/not-present status.
  !
  ! Disable the Associated Array. We are far from being able to average them...
  sumio%head%presec(class_sec_assoc_id) = .false.
  call rzero_assoc(sumio)
  !
  ! Deactivate sections which have no meaning for the average
  if (aver%done%kind_is_spec) then
    sumio%head%presec(class_sec_dri_id) = .false.
  else
    sumio%head%presec(class_sec_spe_id) = .false.
  endif
  sumio%head%presec(class_sec_bas_id) = .false.  ! Sigma has no sense, windows may or not
  sumio%head%presec(class_sec_gau_id) = .false.
  sumio%head%presec(class_sec_she_id) = .false.
  sumio%head%presec(class_sec_hfs_id) = .false.
  sumio%head%presec(class_sec_abs_id) = .false.
  !
end subroutine sumlin_header_init
!
subroutine sumlin_init_variables(aver,refer,sumio,error)
  use gkernel_interfaces
  use gbl_constant
  use gbl_message
  use classcore_interfaces, except_this=>sumlin_init_variables
  use class_averaging
  use class_types
  use sumlin_mod_first
  !---------------------------------------------------------------------
  ! @ private
  ! Initialize some global variables related to the output sum: running
  ! means, some extrema, and so on. Must be called *after* the
  ! I/O sum header is set.
  !---------------------------------------------------------------------
  type(average_t), intent(inout) :: aver   !
  type(header),    intent(in)    :: refer  ! Reference header
  type(header),    intent(in)    :: sumio  ! Future sum header
  logical,         intent(inout) :: error  ! Logical error flag
  ! Local
  real(8) :: xs1,xs2
  !
  ! Doppler (running mean)
  if (aver%done%kind_is_spec)  sdoppler = 0.d0
  !
  ! Switching mode (running sum)
  smod = refer%swi%swmod
  !
  ! Integration time (running sum)
  stime = 0.d0
  !
  ! time*res/Tsys**2 (running sum)
  sweight = 0.d0
  !
  ! Elevation (running sum)
  selevation = 0.
  !
  ! Telescope name (running name)
  stele = sumio%gen%teles
  stele_c(:) = .true.  ! At start, compare the 12 characters
  !
  if (aver%done%kind_is_spec) then
    aver%done%axis%nchan = sumio%spe%nchan
    !
    ! Line name (running name)
    sline = sumio%spe%line
    sline_l = .true.
  else
    aver%done%axis%nchan = sumio%dri%npoin
  endif
  !
  ! Observation date-time
  call gag_gagut2mjd(sumio%gen%dobs,sumio%gen%ut,smjd,error)
  !
  ! X axis extrema
  select case (aver%done%align)
  case (align_freq)  ! SET ALIGN FREQUENCY. NB: work in single precision so
                     ! the sumio 'restf' is removed in the offset quantity.
    ! Doppler-corrected signal frequency axis
    aver%done%axis%unit = 'F'
    aver%done%axis%inc = sumio%spe%fres/(1.d0+sumio%spe%doppler)
    aver%done%axis%ref = 0.d0
    call abscissa_chan2sigoff(sumio,aver%done%axis%ref,aver%done%axis%val)
    call abscissa_sigoff_left(sumio,xs1)
    call abscissa_sigoff_right(sumio,xs2)
    sxmin = min(xs1,xs2)
    sxmax = max(xs1,xs2)
    !
    allrdopplermin = refer%spe%doppler
    allrdopplermax = refer%spe%doppler
    allrresomin = refer%spe%fres
    allrresomax = refer%spe%fres
    !
  case (align_imag)  ! SET ALIGN IMAGE. NB: work in single precision so
                     ! the sumio 'image' is removed in the offset quantity.
    ! Doppler-corrected image frequency axis
    aver%done%axis%unit = 'I'
    aver%done%axis%inc = -sumio%spe%fres/(1.d0+sumio%spe%doppler)
    aver%done%axis%ref = 0.d0
    call abscissa_chan2imaoff(sumio,aver%done%axis%ref,aver%done%axis%val)
    call abscissa_imaoff_left(sumio,xs1)
    call abscissa_imaoff_right(sumio,xs2)
    sxmin = min(xs1,xs2)
    sxmax = max(xs1,xs2)
    !
    allrdopplermin = refer%spe%doppler
    allrdopplermax = refer%spe%doppler
    allrresomin = - refer%spe%fres
    allrresomax = - refer%spe%fres
    !
  case (align_velo)  ! SET ALIGN VELOCITY
    aver%done%axis%unit = 'V'
    aver%done%axis%inc = sumio%spe%vres
    aver%done%axis%ref = 0.d0
    call abscissa_chan2velo(sumio,aver%done%axis%ref,aver%done%axis%val)
    call abscissa_velo_left(sumio,xs1)
    call abscissa_velo_right(sumio,xs2)
    sxmin = min(xs1,xs2)
    sxmax = max(xs1,xs2)
    !
    allrdopplermin = refer%spe%doppler
    allrdopplermax = refer%spe%doppler
    allrresomin = refer%spe%vres
    allrresomax = refer%spe%vres
    !
  case (align_posi)  ! SET ALIGN POSITION
    aver%done%axis%unit = 'P'
    aver%done%axis%inc = sumio%dri%ares
    aver%done%axis%ref = 0.d0
    call abscissa_chan2angl(sumio,aver%done%axis%ref,aver%done%axis%val)
    call abscissa_angl_left(sumio,xs1)
    call abscissa_angl_right(sumio,xs2)
    sxmin = min(xs1,xs2)
    sxmax = max(xs1,xs2)
    !
    allrresomin = refer%dri%ares
    allrresomax = refer%dri%ares
    !
  case default
    call class_message(seve%e,aver%do%rname,  &
      'Internal error, unsupported alignment')
    error = .true.
    return
  end select
  !
end subroutine sumlin_init_variables
!
subroutine sumlin_header_register(obs,refer,aver,error)
  use gildas_def
  use gbl_constant
  use gbl_message
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>sumlin_header_register
  use class_averaging
  use class_types
  use sumlin_mod_first
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  type(observation), intent(in)    :: obs    ! Spectrum to add
  type(observation), intent(in)    :: refer  ! The reference spectrum
  type(average_t),   intent(inout) :: aver   ! The new axis resolution may be updated on return
  logical,           intent(inout) :: error  ! Logical error flag
  ! Local
  real(kind=8) :: xr1,xr2,dfreq,rxmin,rxmax,rreso,omjd
  integer(kind=4) :: rnchan
  real(kind=4) :: weight
  logical :: error2
  !
  call sumlin_header_check(aver,obs,refer,error)
  if (error)  return
  !
  ! Keep track of important parameters
  if (aver%done%kind_is_spec) then
    rnchan = obs%head%spe%nchan
  else
    rnchan = obs%head%dri%npoin
  endif
  !
  ! Compute the resolution and increments of 'obs' according to the
  ! SET ALIGN method.
  select case(aver%done%align)
  case (align_freq)  ! SET ALIGN FREQUENCY. NB: work in single precision so the
                     ! refer 'restf' is removed in the offset quantity.
                     ! => This looks like a MODIFY FREQUENCY! (SB, 28-oct-2011)
    dfreq = obs%head%spe%restf - refer%head%spe%restf
    !
    ! Doppler-corrected signal frequency axis
    rreso = obs%head%spe%fres/(1.d0+obs%head%spe%doppler)
    xr1 = (                   .5d0-obs%head%spe%rchan)*rreso + dfreq
    xr2 = (obs%head%spe%nchan+.5d0-obs%head%spe%rchan)*rreso + dfreq
    rxmin = min(xr1,xr2)
    rxmax = max(xr1,xr2)
    !
    allrdopplermin = min(allrdopplermin,obs%head%spe%doppler)
    allrdopplermax = max(allrdopplermax,obs%head%spe%doppler)
    allrresomin = min(allrresomin,obs%head%spe%fres)
    allrresomax = max(allrresomax,obs%head%spe%fres)
    !
  case (align_imag)  ! SET ALIGN IMAGE. NB: work in single precision so the
                     ! refer 'image' is removed in the offset quantity.
                     ! => This looks like a MODIFY FREQUENCY! (SB, 28-oct-2011)
    dfreq = obs%head%spe%image - refer%head%spe%image
    !
    ! Doppler-corrected image frequency axis
    rreso = -obs%head%spe%fres/(1.d0+obs%head%spe%doppler)
    xr1 = (                   .5d0-obs%head%spe%rchan)*rreso + dfreq
    xr2 = (obs%head%spe%nchan+.5d0-obs%head%spe%rchan)*rreso + dfreq
    rxmin = min(xr1,xr2)
    rxmax = max(xr1,xr2)
    !
    allrdopplermin = min(allrdopplermin,obs%head%spe%doppler)
    allrdopplermax = max(allrdopplermax,obs%head%spe%doppler)
    allrresomin = min(allrresomin,-obs%head%spe%fres)
    allrresomax = max(allrresomax,-obs%head%spe%fres)
    !
  case (align_velo)  ! SET ALIGN VELOCITY
    rreso = obs%head%spe%vres
    call abscissa_velo_left(obs%head,xr1)
    call abscissa_velo_right(obs%head,xr2)
    rxmin = min(xr1,xr2)
    rxmax = max(xr1,xr2)
    !
    allrdopplermin = min(allrdopplermin,obs%head%spe%doppler)
    allrdopplermax = max(allrdopplermax,obs%head%spe%doppler)
    allrresomin = min(allrresomin,obs%head%spe%vres)
    allrresomax = max(allrresomax,obs%head%spe%vres)
    !
  case (align_posi)  ! SET ALIGN POSITION
    rreso = dble(obs%head%dri%ares)
    call abscissa_angl_left(obs%head,xr1)
    call abscissa_angl_right(obs%head,xr2)
    rxmin = min(xr1,xr2)
    rxmax = max(xr1,xr2)
    !
    allrresomin = min(allrresomin,obs%head%dri%ares)
    allrresomax = max(allrresomax,obs%head%dri%ares)
    !
  case default
    call class_message(seve%e,aver%do%rname,  &
      'Internal error, unsupported alignment')
    error = .true.
    return
  end select
  !
  ! Compute the new X range
  if (aver%done%composite) then  ! COMPOSITE
    sxmin = min(rxmin,sxmin)
    sxmax = max(rxmax,sxmax)
  else                 ! INTERSECT
    sxmin = max(rxmin,sxmin)
    sxmax = min(rxmax,sxmax)
    if (sxmin.ge.sxmax) then
      call class_message(seve%e,aver%do%rname,  &
        trim(align_name(aver%done%align))//' ranges do not intersect')
      error = .true.
      return
    endif
  endif
  !
  ! Compute the new resolution (can be positive or negative)
  if (abs(aver%done%axis%inc).lt.abs(rreso)) then
    if (aver%do%resampling.eq.resample_user) then
      ! User has made his choice: nothing to be done
    elseif (aver%do%resampling.eq.resample_auto) then
      aver%done%axis%inc = rreso
    elseif (aver%do%resampling.eq.resample_no) then
      ! Can not happen, X axes compatibility has been tested above.
    endif
  endif
  !
  ! Check for the output switching mode
  if (obs%head%swi%swmod.ne.smod)  smod = mod_mix
  !
  ! Compute the new integration time
  stime = stime + obs%head%gen%time
  !
  ! Compute the new elevation
  selevation = selevation + obs%head%gen%el
  !
  ! Compute the new telescope name
  call sumlin_header_telescope(obs%head%gen%teles,stele_c,stele)
  !
  ! Compute the new sum of time*res/tsys^2 (and new Doppler factor if spectro)
  error2 = .false.
  call obs_weight_time(aver%do%rname,obs,weight,error2,verbose=.false.)
  if (.not.error2)  sweight = sweight + weight  ! Not a fatal error
  if (aver%done%kind_is_spec) then
    sdoppler = sdoppler + obs%head%spe%doppler
    ! Compute the new line name
    if (sline_l) then
      if (obs%head%spe%line.ne.sline) then
        sline = 'Unknown'
        sline_l = .false.
      endif
    endif
  endif
  !
  ! Observation date-time: use the greatest of all observations, because
  ! 1) there is no '0' gag_date
  ! 2) today is not really useful, some information is lost. One value chosen
  !    in the real observation dates is more relevant
  ! 3) the greatest one has the advantage to indicate when the average was last
  !    done, in particular when observing over several days.
  call gag_gagut2mjd(obs%head%gen%dobs,obs%head%gen%ut,omjd,error)
  smjd = max(smjd,omjd)
  !
  ! New History
  ! call add_history_new(obs,sumin,sumout)  ZZZ
  !
end subroutine sumlin_header_register
!
subroutine sumlin_header_check(aver,obs,refer,error)
  use gbl_constant
  use gbl_message
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>sumlin_header_check
  use class_averaging
  use class_types
  use sumlin_mod_first
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  type(average_t),   intent(in)    :: aver   !
  type(observation), intent(in)    :: obs    ! The new spectrum
  type(observation), intent(in)    :: refer  ! The reference spectrum
  logical,           intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=message_length) :: mess
  real(kind=4) :: weight
  !
  ! The test below is disabled since because of all the optimizations
  ! we are not able to check xnum at this stage (header has been read but
  ! not the data).
  ! if (obs%head%xnum.eq.0) then
  !   call class_message(seve%e,aver%do%rname,'No spectrum in input observation')
  !   error = .true.
  !   goto 100
  ! endif
  !
  ! Irregularly sampled data
  if (obs%head%presec(class_sec_xcoo_id)) then
    call class_message(seve%e,aver%do%rname,  &
      'Irregularly sampled data not yet supported')
    error = .true.
    goto 100
  endif
  !
  if (aver%done%kind_is_spec) then
    ! Doppler
    if (obs%head%spe%doppler.eq.-1.d0) then
      ! This should never happen
      call class_message(seve%e,aver%do%rname,'No Doppler factor defined')
      error = .true.
      goto 100
    endif
    ! Frequency compatibility
    if (obs%head%spe%vtype.ne.refer%head%spe%vtype) then
      mess = 'Input spectra have different velocity definitions'
      call class_message(seve%w,aver%do%rname,mess)
    endif
  endif
  !
  ! Check the header values for the future observation weight. At this stage this
  ! is needed only for the sanity checks. We will compute them again when actually
  ! needed when averaging data, but we keep this here in order to raise the error
  ! asap, in the header loop.
  select case (aver%done%weight)
  case (weight_sigma)  ! Sigma weighting
    call obs_weight_sigma(aver%do%rname,obs,weight,error)
    !
  case (weight_time)  ! Time weighting
    call obs_weight_time(aver%do%rname,obs,weight,error)
    !
  case (weight_equal)  ! Equal weighting
    continue  ! Nothing to check
    !
  case (weight_assoc)  ! From 'W' Associated Array
    if (.not.class_assoc_exists(obs,'W')) then
      call class_message(seve%e,aver%do%rname,  &
        'No Associated Array ''W'' while SET WEIGHT is ASSOC')
      error = .true.
    endif
    !
  case default
    call class_message(seve%e,aver%do%rname,'Internal error, unknown weighting')
    error = .true.
  end select
  if (error)  goto 100
  return
  !
100 continue
  write(mess,'(A,I0)')  'Invalid header for observation #',obs%head%gen%num
  call class_message(seve%e,aver%do%rname,mess)
  !
end subroutine sumlin_header_check
!
subroutine sumlin_header_xaxis(set,aver,sumio,nobs,error)
  use gbl_message
  use classcore_interfaces, except_this=>sumlin_header_xaxis
  use class_averaging
  use class_types
  use sumlin_mod_first
  !---------------------------------------------------------------------
  ! @ private
  !  Set the global variables defining the X axis of the output sum.
  !---------------------------------------------------------------------
  type(class_setup_t),        intent(in)    :: set    !
  type(average_t),            intent(inout) :: aver   !
  type(observation),          intent(inout) :: sumio  ! I/O sum
  integer(kind=entry_length), intent(in)    :: nobs   ! Number of observations averaged
  logical,                    intent(inout) :: error  ! Logical error flag
  !
  if (nobs.le.0) then
    error = .true.
    call class_message(seve%e,aver%do%rname,'Internal error, Nobs<=0')
    return
  endif
  !
  if (aver%do%resampling.eq.resample_auto .and. .not.aver%done%resample) then
    ! Resampling is still disabled after consistency checks in sumlin_header
    call class_message(seve%i,aver%do%rname,   &
      trim(align_name(aver%done%align))//  &
      ' axes match, no resampling will be performed')
  endif
  !
  call sumlin_header_xaxis_compute(aver,sumio,nobs,error)
  if (error)  return
  !
  call sumlin_header_xaxis_feedback(set,aver,sumio)
  !
end subroutine sumlin_header_xaxis
!
subroutine sumlin_header_xaxis_compute(aver,sumio,nobs,error)
  use gbl_message
  use classcore_interfaces, except_this=>sumlin_header_xaxis_compute
  use class_averaging
  use class_types
  use sumlin_mod_first
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  type(average_t),            intent(inout) :: aver   !
  type(observation),          intent(inout) :: sumio  ! I/O sum
  integer(kind=entry_length), intent(in)    :: nobs   ! Number of observations averaged
  logical,                    intent(inout) :: error  ! Logical error flag
  !
  ! Axis redefinition, if any
  if (aver%do%resampling.eq.resample_auto .and. aver%done%resample) then
    ! AUTOMATIC resampling to the coarsest resolution
    call sumlin_header_xaxis_resample(aver,sumio,error)
    if (error)  return
  endif
  ! If USER resampling: Nothing to do: all has been set before.
  ! if NO resampling: Channel alignment. Only 'aver%done%axis%nchan' is
  !                   required in 'simple_waverage'. It is already set.
  !
  ! Update the output header
  !
  ! Switching
  if (smod.eq.mod_mix) then
    call class_message(seve%w,aver%do%rname,'Mixed switching modes')
    sumio%head%swi%swmod = mod_mix
    sumio%head%swi%nphas = 0
    sumio%head%swi%decal = 0.d0
    sumio%head%swi%duree = 0.
    sumio%head%swi%poids = 0.
    sumio%head%swi%ldecal = 0.
    sumio%head%swi%bdecal = 0.
  endif
  !
  ! General
  sumio%head%gen%el = selevation/nobs
  sumio%head%gen%time = stime
  sumio%head%gen%teles = stele
  call gag_mjd2gagut(smjd,sumio%head%gen%dobs,sumio%head%gen%ut,error)
  if (error)  return
  ! Recompute Tsys (after time and swmod are set)
  if (aver%done%kind_is_spec) then
    call obs_tsys_time(aver%do%rname,sumio,sweight,error)
    if (error)  return
  else
    call obs_tsys_time(aver%do%rname,sumio,sweight,error)
    if (error)  return
  endif
  !
  ! Spectro
  if (aver%done%kind_is_spec) then
    if (.not.aver%done%resample) then
      ! X axes match
      ! In these cases the input Doppler factors were not taken into
      ! account in the input resolutions. On return the output
      ! spectrum must have a non-zero Doppler factor.
      sdoppler = sdoppler/nobs
    else
      sdoppler = 0.d0
    endif
    sumio%head%spe%doppler = sdoppler
    sumio%head%spe%nchan = aver%done%axis%nchan
    sumio%head%spe%line = sline
  else
    sumio%head%dri%npoin = aver%done%axis%nchan
  endif
  if (aver%do%range) then
    ! Now that the spectroscopic axis is fully set (including Doppler),
    ! apply range cut
    call sumlin_header_xaxis_range(aver,sumio,error)
    if (error)  return
  endif
  !
end subroutine sumlin_header_xaxis_compute
!
subroutine sumlin_header_xaxis_resample(aver,sumio,error)
  use phys_const
  use classcore_interfaces, except_this=>sumlin_header_xaxis_resample
  use class_types
  use class_averaging
  use sumlin_mod_first
  !---------------------------------------------------------------------
  ! @ private
  !  AUTOMATIC resampling of the header to the coarsest resolution <=>
  ! all but channel alignment.
  !---------------------------------------------------------------------
  type(average_t),   intent(inout) :: aver   !
  type(observation), intent(inout) :: sumio  ! I/O sum
  logical,           intent(inout) :: error  ! Logical error flag
  !
  ! Output number of channels. NB: sxmin is the left side of the 1st channel,
  ! and sxmax the right side of the last channel
  aver%done%axis%nchan = ceiling((sxmax-sxmin)/abs(aver%done%axis%inc))
  !
  aver%done%axis%ref = 0.d0
  if (aver%done%axis%inc.lt.0.d0) then
    aver%done%axis%val = sxmax - aver%done%axis%inc/2.d0  ! Value at center of channel #0
  else
    aver%done%axis%val = sxmin - aver%done%axis%inc/2.d0  ! Value at center of channel #0
  endif
  !
  select case(aver%done%align)
  case(align_velo)  ! ALIGN VELOCITY
    sumio%head%spe%vres  = aver%done%axis%inc
    sumio%head%spe%rchan = (sumio%head%spe%voff-aver%done%axis%val)/aver%done%axis%inc
    sumio%head%spe%fres  = -sumio%head%spe%restf*sumio%head%spe%vres/clight_kms
    sumio%head%spe%nchan = aver%done%axis%nchan
    !
  case(align_freq)  ! ALIGN FREQUENCY
    sumio%head%spe%fres  = aver%done%axis%inc
    sumio%head%spe%rchan = -aver%done%axis%val/aver%done%axis%inc
    sumio%head%spe%vres  = -clight_kms*sumio%head%spe%fres/sumio%head%spe%restf
    sumio%head%spe%nchan = aver%done%axis%nchan
    !
  case(align_imag)  ! ALIGN IMAGE
    sumio%head%spe%fres  = -aver%done%axis%inc  ! Warning: fres has the _signal_ frequency sign!
    sumio%head%spe%rchan = -aver%done%axis%val/aver%done%axis%inc
    sumio%head%spe%vres  = -clight_kms*sumio%head%spe%fres/sumio%head%spe%restf  ! Velocity
    sumio%head%spe%nchan = aver%done%axis%nchan
    ! resolution is always in the signal band in Class.
    !
  case(align_posi)  ! ALIGN POSITION
    sumio%head%dri%ares = aver%done%axis%inc
    sumio%head%dri%rpoin = (sumio%head%dri%aref-aver%done%axis%val)/aver%done%axis%inc
    sumio%head%dri%npoin = aver%done%axis%nchan
    !
  end select
  !
end subroutine sumlin_header_xaxis_resample
!
subroutine sumlin_header_xaxis_range(aver,sumio,error)
  use gbl_message
  use classcore_interfaces, except_this=>sumlin_header_xaxis_range
  use class_averaging
  use class_types
  use sumlin_mod_first
  !---------------------------------------------------------------------
  ! @ private
  !  Apply a range cut. The range unit can be in any unit (i.e. other
  ! than aver%done%align)
  !  NB: the sumio spectroscopic axis must have been fully set
  ! (resolution, Doppler, etc) so that it is usable with the abscissa
  ! routines
  !---------------------------------------------------------------------
  type(average_t),   intent(inout) :: aver   !
  type(observation), intent(inout) :: sumio  ! I/O sum
  logical,           intent(inout) :: error  ! Logical error flag
  ! Local
  real(kind=8) :: ch1,ch2,uchmin,uchmax,schmin,schmax,ux1,ux2
  character(len=message_length) :: mess
  !
  ! Convert user range to channels
  select case(aver%do%rangeval%unit)
  case('C')
    ch1 = aver%do%rangeval%xmin
    ch2 = aver%do%rangeval%xmax
  case('V')
    call abscissa_velo2chan(sumio%head,aver%do%rangeval%xmin,ch1)
    call abscissa_velo2chan(sumio%head,aver%do%rangeval%xmax,ch2)
  case('F')
    call abscissa_sigabs2chan(sumio%head,aver%do%rangeval%xmin,ch1)
    call abscissa_sigabs2chan(sumio%head,aver%do%rangeval%xmax,ch2)
  case('I')
    call abscissa_imaabs2chan(sumio%head,aver%do%rangeval%xmin,ch1)
    call abscissa_imaabs2chan(sumio%head,aver%do%rangeval%xmax,ch2)
  case('P')
    call abscissa_angl2chan(sumio%head,aver%do%rangeval%xmin,ch1)
    call abscissa_angl2chan(sumio%head,aver%do%rangeval%xmax,ch2)
  case default
    call class_message(seve%e,aver%do%rname,'Range unit not supported here')
    error = .true.
    return
  end select
  uchmin = min(ch1,ch2)
  uchmax = max(ch1,ch2)
  !
  ! Convert sum range to channels, and convert user range to working unit
  select case(aver%done%align)
  case(align_velo)  ! ALIGN VELOCITY
    call abscissa_velo2chan(sumio%head,sxmin,ch1)
    call abscissa_velo2chan(sumio%head,sxmax,ch2)
    call abscissa_chan2velo(sumio%head,uchmin,ux1)
    call abscissa_chan2velo(sumio%head,uchmax,ux2)
  case(align_freq)  ! ALIGN FREQUENCY
    call abscissa_sigoff2chan(sumio%head,sxmin,ch1)
    call abscissa_sigoff2chan(sumio%head,sxmax,ch2)
    call abscissa_chan2sigoff(sumio%head,uchmin,ux1)
    call abscissa_chan2sigoff(sumio%head,uchmax,ux2)
  case(align_imag)  ! ALIGN IMAGE
    call abscissa_imaoff2chan(sumio%head,sxmin,ch1)
    call abscissa_imaoff2chan(sumio%head,sxmax,ch2)
    call abscissa_chan2imaoff(sumio%head,uchmin,ux1)
    call abscissa_chan2imaoff(sumio%head,uchmax,ux2)
  case(align_posi)  ! ALIGN POSITION
    call abscissa_angl2chan(sumio%head,sxmin,ch1)
    call abscissa_angl2chan(sumio%head,sxmax,ch2)
    call abscissa_chan2angl(sumio%head,uchmin,ux1)
    call abscissa_chan2angl(sumio%head,uchmax,ux2)
  end select
  schmin = min(ch1,ch2)
  schmax = max(ch1,ch2)
  !
  if (uchmax.lt.schmin .or. uchmin.gt.schmax) then
    ! ZZZ can this check be moved in 'sumlin_header_register'? i.e. can
    ! we reject the whole index as soon we know nothing will intersect
    ! with user's range? Probably yes if intersection mode, no if
    ! composition.
    write(mess,'(A,2(F0.4,1X),A,A)')  &
      'Requested range (',aver%do%rangeval%xmin,aver%do%rangeval%xmax,  &
      aver%do%rangeval%unit,') does not intersect the whole spectra range'
    call class_message(seve%e,aver%do%rname,mess)
    error = .true.
    return
  endif
  !
  if (aver%done%resample) then
    ! Resampling is needed. Let sumlin_header_xaxis_resample recompute
    ! the axis with the new limits
    sxmin = min(ux1,ux2)
    sxmax = max(ux1,ux2)
    call sumlin_header_xaxis_resample(aver,sumio,error)
    if (error)  return
  else
    ! No resampling needed. Just "extract" (ceiling/floor in order
    ! to keep the grids ligned - same as do_extract-)
    aver%done%axis%nchan = ceiling(uchmax)-floor(uchmin)+1
    if (aver%done%kind_is_spec) then
      sumio%head%spe%nchan = aver%done%axis%nchan
      sumio%head%spe%rchan = sumio%head%spe%rchan-floor(uchmin)+1.d0
      aver%done%axis%ref = sumio%head%spe%rchan
    else
      sumio%head%dri%npoin = aver%done%axis%nchan
      sumio%head%dri%rpoin = sumio%head%spe%rchan-floor(uchmin)+1.d0
      aver%done%axis%ref = sumio%head%dri%rpoin
    endif
    ! Enable the resampling flag. Subroutine 'do_resample' (used by
    ! TABLE) is clever enough to make a resampling or an extraction
    ! if grids are aligned (we took care of this just above)
    ! ZZZ This has to be implemented if the option /RANGE is added
    ! to other commands
    aver%done%resample = .true.
  endif
  !
end subroutine sumlin_header_xaxis_range
!
subroutine sumlin_header_xaxis_feedback(set,aver,sumio)
  use gbl_message
  use classcore_interfaces, except_this=>sumlin_header_xaxis_feedback
  use class_averaging
  use class_types
  use class_setup_new
  use sumlin_mod_first
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  type(class_setup_t), intent(in) :: set    !
  type(average_t),     intent(in) :: aver   !
  type(observation),   intent(in) :: sumio  !
  ! Local
  character(len=message_length) :: mess
  real(kind=8) :: v1,v2,f1,f2
  !
  if (.not.aver%done%resample) then
    write(mess,'(a)') 'Channel alignment, no resampling:'
  else
    if (aver%do%resampling.eq.resample_auto) then
      write(mess,'(2a)') trim(align_name(aver%done%align)),  &
        ' alignment, automatic resampling:'
    elseif (aver%do%resampling.eq.resample_user) then
      write(mess,'(2a)') trim(align_name(aver%done%align)),  &
        ' alignment, custom resampling:'
    endif
  endif
  call class_message(seve%r,aver%do%rname,mess)
  !
  ! Input axes statistics
  call class_message(seve%r,aver%do%rname,'- Input axes:')
  if (aver%done%kind_is_spec) then
    if (allrdopplermin.eq.allrdopplermax) then
      write(mess,105) 'Doppler:',allrdopplermin
    else
      write(mess,106) 'Doppler:',allrdopplermin,allrdopplermax
    endif
    call class_message(seve%r,aver%do%rname,mess)
  endif
  if (aver%done%resample) then
    if (allrresomin.eq.allrresomax) then
      write(mess,103)  'Resolution:',allrresomin,align_unit(aver%done%align)
    else
      write(mess,104)  'Resolution:',allrresomin,allrresomax,align_unit(aver%done%align)
    endif
    call class_message(seve%r,aver%do%rname,mess)
  endif
  !
  ! Output axis definition
  call class_message(seve%r,aver%do%rname,'- Output axis:')
  if (aver%do%resampling.eq.resample_auto .and. aver%done%resample) then
    if (aver%done%kind_is_spec) then
      ! Always display F and V ranges
      call abscissa_sigabs_left(sumio%head,f1)
      call abscissa_sigabs_right(sumio%head,f2)
      write(mess,102) 'Frequency range:',f1,f2,align_unit(align_freq)
      call class_message(seve%r,aver%do%rname,mess)
      call abscissa_velo_left(sumio%head,v1)
      call abscissa_velo_right(sumio%head,v2)
      write(mess,102) 'Velocity range:',v1,v2,align_unit(align_velo)
      call class_message(seve%r,aver%do%rname,mess)
      if (aver%done%align.eq.align_imag) then
        ! Image range only if the working unit
        call abscissa_imaabs_left(sumio%head,f1)
        call abscissa_imaabs_right(sumio%head,f2)
        write(mess,102) 'Image range:',f1,f2,align_unit(align_imag)
        call class_message(seve%r,aver%do%rname,mess)
      endif
    else
      ! Print range in requested unit
      write(mess,102) trim(align_name(aver%done%align))//' range:',  &
        sxmin,sxmax,align_unit(aver%done%align)
      call class_message(seve%r,aver%do%rname,mess)
    endif
  endif
  write(mess,201) 'Nchan:',aver%done%axis%nchan
  call class_message(seve%r,aver%do%rname,mess)
  if (aver%done%kind_is_spec) then
    write(mess,101) 'Rchan:',sumio%head%spe%rchan
    call class_message(seve%r,aver%do%rname,mess)
    write(mess,101) 'Restf:',sumio%head%spe%restf,align_unit(align_freq)
    call class_message(seve%r,aver%do%rname,mess)
    write(mess,101) 'Image:',sumio%head%spe%image,align_unit(align_imag)
    call class_message(seve%r,aver%do%rname,mess)
    write(mess,103) 'Fres:',sumio%head%spe%fres,align_unit(align_freq)
    call class_message(seve%r,aver%do%rname,mess)
    write(mess,105) 'Doppler:',sumio%head%spe%doppler
    call class_message(seve%r,aver%do%rname,mess)
    write(mess,101) 'Voff:',sumio%head%spe%voff,align_unit(align_velo)
    call class_message(seve%r,aver%do%rname,mess)
    write(mess,103) 'Vres:',sumio%head%spe%vres,align_unit(align_velo)
    call class_message(seve%r,aver%do%rname,mess)
  else
    write(mess,101) 'Rpoin:',sumio%head%dri%rpoin
    call class_message(seve%r,aver%do%rname,mess)
    write(mess,103) 'Ares:',class_setup_get_fangle()*sumio%head%dri%ares
    call class_message(seve%r,aver%do%rname,mess)
    write(mess,103) 'Aref:',class_setup_get_fangle()*sumio%head%dri%aref
    call class_message(seve%r,aver%do%rname,mess)
  endif
  !
  ! Floats, 3 digits
101 format(4x,a,1x,f0.3,1x,a)
102 format(4x,a,1x,'from',1x,f0.3,1x,'to',1x,f0.3,1x,a)
  ! Floats, 6 digits
103 format(4x,a,1x,f0.6,1x,a)
104 format(4x,a,1x,'from',1x,f0.6,1x,'to',1x,f0.6,1x,a)
  ! Floats, 5 significative digits
105 format(4x,a,1x,1pg12.5,1x,a)
106 format(4x,a,1x,'from',1x,1pg12.5,1x,'to',1x,1pg12.5,1x,a)
  ! Integers
201 format(4x,a,1x,i0,1x,a)
! 202 format(4x,a,1x,'from',1x,i12,1x,'to',1x,i12,1x,a)
  !
end subroutine sumlin_header_xaxis_feedback
!
subroutine add_history_new(in1,in2,out)
  use class_types
  use gbl_message
  use classcore_interfaces, except_this=>add_history_new
  !---------------------------------------------------------------------
  ! @ private
  ! Add histories input observations into output observation
  ! * nseq     : the number of sequences of consecutive scan numbers
  ! * start(i) : the first scan of sequence 'i'
  ! * end(i)   : the last  scan of sequence 'i'
  !---------------------------------------------------------------------
  type (observation), intent(inout) :: in1  ! New observation
  type (observation), intent(inout) :: in2  ! Old sum
  type (observation), intent(inout) :: out  ! New sum
  ! Local
  integer :: ir,it,i
  !
  ! Origin of spectra
  if (in1%head%his%nseq.eq.0) then
     in1%head%his%nseq     = 1
     in1%head%his%start(1) = in1%head%gen%scan
     in1%head%his%end(1)   = in1%head%gen%scan
  endif
  if (in2%head%his%nseq.eq.0) then
     in2%head%his%nseq     = 1
     in2%head%his%start(1) = in2%head%gen%scan
     in2%head%his%end(1)   = in2%head%gen%scan
  endif
  !
  out%head%his%nseq = 0
  it = 1
  ir = 1
  !
90 continue
  if (it.gt.in2%head%his%nseq) goto 91  ! on first passage, false
  if (ir.gt.in1%head%his%nseq) goto 92  ! on first passage, false
  if (in2%head%his%start(it).gt.in1%head%his%start(ir)) goto 91
  !
  ! start(in2) <= start(in1)
92 continue
  if (out%head%his%nseq.eq.0) then
     out%head%his%nseq     = 1
     out%head%his%start(1) = in2%head%his%start(it)
     out%head%his%end(1)   = in2%head%his%end(it)
  elseif (out%head%his%end(out%head%his%nseq).lt.in2%head%his%start(it)-1) then
     ! new interval
     if(out%head%his%nseq.eq.mseq) go to 925
     out%head%his%nseq = out%head%his%nseq+1
     out%head%his%start(out%head%his%nseq) = in2%head%his%start(it)
     out%head%his%end(out%head%his%nseq)   = in2%head%his%end(it)
  else
     ! extend current interval
     out%head%his%end(out%head%his%nseq) = &
          max(out%head%his%end(out%head%his%nseq),in2%head%his%end(it))
  endif
  it = it+1
  goto 90
  !
  ! start(in2) > start(in1)
91 continue
  if (ir.gt.in1%head%his%nseq) goto 93
  if (out%head%his%nseq.eq.0) then
     out%head%his%nseq = 1
     out%head%his%start(out%head%his%nseq) = in1%head%his%start(ir)
     out%head%his%end(out%head%his%nseq)   = in1%head%his%end(ir)
  else if (out%head%his%end(out%head%his%nseq).lt.in1%head%his%start(ir)-1) then
     if (out%head%his%nseq.eq.mseq) go to 925
     out%head%his%nseq = out%head%his%nseq+1
     out%head%his%start(out%head%his%nseq) = in1%head%his%start(ir)
     out%head%his%end(out%head%his%nseq)   = in1%head%his%end(ir)
  else
     out%head%his%end(out%head%his%nseq) =  &
          max(out%head%his%end(out%head%his%nseq),in1%head%his%end(ir))
  endif
  ir = ir+1
  goto 90
  !
  ! Overflow
925 call class_message(seve%w,'ADD_HISTORY_NEW','Origin table overflow. Cannot store history.')
  !
  ! End
93 continue
  do i=1,out%head%his%nseq
     in1%head%his%start(i) = out%head%his%start(i)
     in1%head%his%end(i)   = out%head%his%end(i)
  enddo
  in1%head%his%nseq = out%head%his%nseq
end subroutine add_history_new
!
subroutine sumlin_header_telescope(addteles,dochars,aveteles)
  !---------------------------------------------------------------------
  ! @ private
  ! Compute an average telescope name from input name and current
  ! running average. In practice, individual characters are preserved as
  ! long as they are identical. They are changed to "-" of they differ.
  ! For example:
  !   30ME0HLI-W01
  ! + 30ME0VLO-W01
  ! = 30ME0-L--W01
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: addteles     ! The telescope to be added
  logical,          intent(inout) :: dochars(12)  ! Remaining characters to be checked
  character(len=*), intent(inout) :: aveteles     ! The running sum
  ! Local
  integer(kind=4) :: ic
  !
  do ic=1,12
    if (dochars(ic)) then
      if (aveteles(ic:ic).ne.addteles(ic:ic)) then
        aveteles(ic:ic) = '-'
        dochars(ic) = .false.
      endif
    endif
  enddo
  !
  if (.not.any(dochars))  aveteles = 'Unknown'
  !
end subroutine sumlin_header_telescope
!
!-----------------------------------------------------------------------
! ZZZ Include this for the continuum
!   !
!   ! Incorporate offset projection along the drift into value at reference pixel:
!   ! Project offsets onto drift system
!   cosa = cos(r%head%dri%apos)
!   sina = sin(r%head%dri%apos)
!   along = +r%head%pos%lamof*cosa+r%head%pos%betof*sina
!   perp  = -r%head%pos%betof*sina+r%head%pos%betof*cosa
!   ! Include projection of offsets along the drift into position at reference
!   ! pixel, and reproject the perpendicular component onto original system
!   r%head%dri%aref = r%head%dri%aref+along
!   r%head%pos%lamof = -perp*sina
!   r%head%pos%betof = +perp*cosa
!   ! Bring  the position angle difference back to [-PI/2,PI/2]
!   if (r%head%dri%apos.ge.t%head%dri%apos) then
!      i = nint((r%head%dri%apos-t%head%dri%apos)/pi)
!      r%head%dri%apos = r%head%dri%apos-i*pi
!   else
!      i = nint((t%head%dri%apos-r%head%dri%apos)/pi)
!      r%head%dri%apos = r%head%dri%apos+i*pi
!   endif
!   if (mod(i,2).eq.1) then
!      r%head%dri%aref = -r%head%dri%aref
!      r%head%dri%ares = -r%head%dri%ares
!   endif
