!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! TELCAL routines related to atmospheric calibration
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine telcal_chopper(chopper,error)
  use gbl_message
  use telcal_interfaces, except_this=>telcal_chopper
  use chopper_definitions
  !----------------------------------------------------------------------
  ! @ public
  !
  ! Compute Trec, Tcal, Tsys from the chop and atm values observed
  ! according to the usual chopper method (ulich and haas) Double side band
  ! operation.
  !
  ! Note that each for each frequency, an error status is set in
  ! chopper%errors(ifreq). It indicates if the operation could be performed
  ! or not. It is the responsibility of the caller to check them or not,
  ! e.g.
  !
  !   call telcal_chopper(chopper,error)
  !   if (error .or. any(chopper%errors(:))  return
  !
  ! If the error status of a given frequency is set to .true., the output
  ! parameters are also nullified to the value chopper%bad, so that the
  ! caller can identify them as bad values.
  ! ----------------------------------------------------------------------
  type(chopper_t), intent(inout) :: chopper
  logical,         intent(inout) :: error
  ! Local
  character(len=*), parameter :: rname='CHOPPER'
  type(dsb_value) :: freq,attenuation
  type(dsb_value) :: tcal,atsys,tsys
  type(chop_load) :: cold,hot
  type(atm_prop) :: atm
  type(mixer)     :: rec
  integer(kind=4) :: ifreq,ier
  real(kind=8) :: sky_count,tsky,temi
  character(len=25) :: atm_mess(3)
  character(len=message_length) :: mess
  integer(kind=4) :: flags(chopper%n) ! Automatic array
  !
  data atm_mess &
       /'zero atmospheric opacity', &
        'no oxygen in atmosphere', &
        'no water in atmosphere'/
  !
  ! Sanity check
  if (chopper%n.le.0) then
     call telcal_message(seve%e,rname,'The chopper type is not allocated')
     error = .true.
     return
  endif
  !
  ! First: Frequency independent stuffs
  flags(:) = flag_valid
  chopper%errors(:) = .true.  ! Default is error .true., kept in case on early exit
  ! 1. Compute air mass number
  chopper%atms%airmass = airmass(chopper%tel%elev,error)
  if (error) then
     call telcal_message(seve%e,rname,'Elevation is not available')
     return
  endif
  ! 2. Initialize atmospheric model
  !    This may be not used in some rare case (e.g. MANUAL mode)
  call atm_atmosp(real(chopper%tel%tout),real(chopper%tel%pres),real(chopper%tel%alti))
  !
  ! Second: Frequency dependent stuffs
  do ifreq = 1,chopper%n
    !
    freq      = chopper%freqs(ifreq)
    sky_count = chopper%loads(ifreq)%sky_count
    hot       = chopper%loads(ifreq)%hot
    cold      = chopper%loads(ifreq)%cold
    !
    if (sky_count.eq.chopper%bad) then
      flags(ifreq) = flag_nosky
      !
    else
      ! Sanity checks
      if (sky_count.ge.hot%count) then
        write(mess,'(A,F0.4,A)') 'Signal stronger on SKY than on HOT load at ', &
            freq%s,' GHz => Bad atmosphere'
        call telcal_message(seve%w,rname,mess)
        flags(ifreq) = flag_badatm
      endif
      if (cold%count.ge.hot%count) then
        write(mess,'(A,F0.4,A)') 'Signal stronger on COLD than on HOT load at ', &
            freq%s,' GHz'
        call telcal_message(seve%w,rname,mess)
        flags(ifreq) = flag_badatm
      endif
    endif
    !
  enddo
  !
  ! Search for water vapor content when asked
  if (chopper%search%water.eq.chopper_water_elem) then
    ! One water vapor amount per frequency
    call telcal_chopper_NwaterN(chopper%search,chopper%tel,chopper%n,  &
      chopper%freqs,chopper%loads,chopper%recs,chopper%atms,flags)
  elseif (chopper%search%water.eq.chopper_water_set) then
    ! One water vapor amount for all frequencies
    call telcal_chopper_1waterN(chopper%search,chopper%tel,chopper%n,  &
      chopper%freqs,chopper%loads,chopper%recs,chopper%atms,flags)
  endif
  !
  !
  do ifreq=1,chopper%n
    !
    if (flags(ifreq).eq.flag_nosky) then
      ! No sky data
      ! Simple receiver temperature computation assuming 100% coupling efficiency of
      ! the hot and cold load. All other output parameters have no meaning.
      !
      rec = chopper%recs(ifreq)
      hot = chopper%loads(ifreq)%hot
      cold = chopper%loads(ifreq)%cold
      call telcal_chopper_nullify(chopper,ifreq)
      !
      rec%temp = (cold%temp*hot%count - hot%temp*cold%count) / (cold%count - hot%count)
      chopper%recs(ifreq)   = rec
      chopper%errors(ifreq) = .false.
      !
    elseif (flags(ifreq).ge.flag_badatm .and. chopper%search%strict) then
      call telcal_chopper_nullify(chopper,ifreq)
      chopper%errors(ifreq) = .true.
      !
    else
      rec   = chopper%recs(ifreq)
      atm   = chopper%atms(ifreq)
      freq  = chopper%freqs(ifreq)
      tcal  = chopper%tcals(ifreq)
      atsys = chopper%atsyss(ifreq)
      tsys  = chopper%tsyss(ifreq)
      !
      sky_count = chopper%loads(ifreq)%sky_count
      hot       = chopper%loads(ifreq)%hot
      !
      ! Compute atmosphere transmission when asked or needed
      if (chopper%search%atm .or. chopper%search%water.ne.chopper_water_fixed) then
        ! Atmospheric parameters are recomputed from water, airmass and frequency
        !   => The water vapor content is assumed to be known
        ier = 0
        call atm_dsb_transmission(freq,atm,ier)
        if (ier.ne.0 .and. atm%h2omm.gt.0.d0) then
          call telcal_message(seve%w,rname,'Calibration problem '//atm_mess(ier))
          if (chopper%search%strict) then
            call telcal_chopper_nullify(chopper,ifreq)
            cycle
          else
            flags(ifreq) = flag_calfailed
          endif
        endif
        ! Compute atmospheric attenuation
        attenuation%s = exp(-atm%taus%tot*atm%airmass)
        attenuation%i = exp(-atm%taui%tot*atm%airmass)
      else
        ! Atmospheric parameters are assumed to be known
        ! => Compute atmospheric attenuation and emission
        attenuation%s = exp(-atm%taus%tot*atm%airmass)
        attenuation%i = exp(-atm%taui%tot*atm%airmass)
        atm%temi%s = atm%temp%s*(1.-attenuation%s)
        atm%temi%i = atm%temp%i*(1.-attenuation%i)
      endif
      !
      ! Compute sky temperatures at signal and image frequency
      temi = (atm%temi%s + atm%temi%i*rec%sbgr) / (1.+rec%sbgr)
      tsky = temi*rec%feff + chopper%tel%tcab*(1.-rec%feff)
      !
      ! Compute Trec when asked
      if (chopper%search%trec) then
        rec%temp = (tsky * (sky_count*(1-hot%ceff) - hot%count) + sky_count * hot%ceff*hot%temp) &
              / (hot%count-sky_count)
      endif
      !
      ! Compute Tcal at zenith and at current elevation when asked
      if (chopper%search%tcal) then
        tcal%s = (hot%temp-tsky)*(1.+rec%sbgr) / rec%beff*hot%ceff
        tcal%i = (hot%temp-tsky)*(1.+1./rec%sbgr) / rec%beff*hot%ceff
      endif
      !
      ! Compute Tsys at zenith and at current elevation when asked
      if (chopper%search%tsys) then
        atsys%s = tcal%s*sky_count / (hot%count-sky_count)
        atsys%i = tcal%i*sky_count / (hot%count-sky_count)
        atsys%s = max(min(1d10,atsys%s),0.d0)
        atsys%i = max(min(1d10,atsys%i),0.d0)
        if (attenuation%s.ne.0.d0) then
           tsys%s = atsys%s / attenuation%s
           tsys%s = max(min(1d10,tsys%s),0.d0)
        endif
        if (attenuation%i.ne.0.d0) then
           tsys%i = atsys%i / attenuation%i
           tsys%i = max(min(1d10,tsys%i),0.d0)
        endif
      endif
      !
      ! Fill back the output structure
      chopper%recs(ifreq)   = rec
      chopper%atms(ifreq)   = atm
      chopper%tcals(ifreq)  = tcal
      chopper%atsyss(ifreq) = atsys
      chopper%tsyss(ifreq)  = tsys
      chopper%errors(ifreq) = flags(ifreq).ge.flag_badatm
    endif
    !
  enddo ! ifreq
  !
end subroutine telcal_chopper
!
subroutine telcal_chopper_NwaterN(search,tel,nfreq,freqs,loads,recs,atms,flags)
  use telcal_interfaces, except_this=>telcal_chopper_NwaterN
  use chopper_definitions
  !---------------------------------------------------------------------
  ! @ private
  ! Compute N independent water vapor amounts for the N frequencies
  !---------------------------------------------------------------------
  type(chop_mode), intent(in)    :: search
  type(telescope), intent(in)    :: tel
  integer(kind=4), intent(in)    :: nfreq
  type(dsb_value), intent(in)    :: freqs(nfreq)
  type(chop_meas), intent(in)    :: loads(nfreq)
  type(mixer),     intent(inout) :: recs(nfreq)
  type(atm_prop),  intent(inout) :: atms(nfreq)
  integer(kind=4), intent(inout) :: flags(nfreq)
  ! Local
  integer(kind=4) :: ifreq
  !
  ! Independent search for each frequency
  do ifreq=1,nfreq
    call telcal_chopper_1water1(search,tel,freqs(ifreq),loads(ifreq),  &
      recs(ifreq),atms(ifreq),flags(ifreq))
  enddo
  !
end subroutine telcal_chopper_NwaterN
!
subroutine telcal_chopper_1water1(search,tel,freq,load,rec,atm,flag)
  use gbl_message
  use telcal_interfaces, except_this=>telcal_chopper_1water1
  use chopper_definitions
  !---------------------------------------------------------------------
  ! @ private
  ! Compute 1 water vapor amount for 1 frequency
  !---------------------------------------------------------------------
  type(chop_mode), intent(in)    :: search
  type(telescope), intent(in)    :: tel
  type(dsb_value), intent(in)    :: freq
  type(chop_meas), intent(in)    :: load
  type(mixer),     intent(inout) :: rec
  type(atm_prop),  intent(inout) :: atm
  integer(kind=4), intent(inout) :: flag
  ! Local
  character(len=*), parameter :: rname='CHOPPER'
  integer(kind=4) :: kiter,ier
  real(kind=8) :: water,dwater,delta_water
  real(kind=8) :: temi0,temi,dtemi,delta_temi
  character(len=message_length) :: mess
  real(kind=8), parameter :: minwater=1d-6  ! [mm] 1 nm of water vapour. This almost
                                            ! nullifies water opacity even at 183 GHz
  !
  if (flag.eq.flag_nosky)  return
  if (flag.eq.flag_badatm .and. search%strict)  return
  !
  ! Compute rec%temp and temi0
  call telcal_chopper_temperatures(tel,load,search%trec,rec,temi0)
  !
  ! Initialize chopper%search parameters
  ier = 0
  water = min(10.d0,max(0.5d0,atm%h2omm)) ! [mm] Water vapor content (Use previous value if available and reasonable)
  dwater = .02                            ! [mm] Water vapor content offset used to determine the slope of the function: temi(water)
  !
  ! Iterate at most 20 times.
  do kiter=1,20
    !
    ! Atmospheric model 1
    atm%h2omm = water
    call atm_dsb_transmission(freq,atm,ier)
    temi = (atm%temi%s + atm%temi%i*rec%sbgr) / (1.+rec%sbgr)
    delta_temi = temi-temi0
    !
    ! Atmospheric model 2 (for derivation)
    atm%h2omm = water+dwater
    call atm_dsb_transmission(freq,atm,ier)
    dtemi = (atm%temi%s + atm%temi%i*rec%sbgr) / (1.+rec%sbgr) - temi
    !
    ! Exit condition?
    if (water.le.minwater) then
      ! At lower limit
      call telcal_message(seve%d,rname,'Precipitable water vapour very low')
      ! No flag raised = valid anyway
      exit
      !
    elseif (dtemi.eq.0.d0) then
      ! Local minimum => exit
      call telcal_message(seve%w,rname,'Blocked in a local minimum')
      flag = flag_calfailed
      if (search%strict)  exit
      !
    elseif (abs(delta_temi).lt.0.1) then
      ! Reached convergence => exit
      exit
      !
    elseif (kiter.eq.20) then
      ! Too many iterations and total opacity at signal frequency is
      ! large enough to be a real problem => exit
      write(mess,'(A,F0.4,A)')  &
        'Did not converge after 20 iterations at freq ',freq%s,' GHz'
      call telcal_message(seve%w,rname,mess)
      flag = flag_calfailed
      !
    else
      ! Not enough converged. Prepare new iteration:
      !  1. Compute value of water increment
      delta_water = (dwater/dtemi)*delta_temi
      !  2. Compute new water value
      if ((water-delta_water).gt.0) then
        ! New water value is positive => Limit optical depth to about 20. This assumes that: tau propto water
        water = min(water-delta_water,20.*water/(atm%taus%tot)/atm%airmass)
        ! water = min(water-delta_water,20.*water/max(atm%taus%tot,atm%taui%tot)/atm%airmass)
        !  3. Adapt water offset to compute derivative
        if (abs(dwater).ge.abs(delta_water/10.)) dwater = delta_water/10.
      else
        ! New water value would be negative:
        ! water = water-delta_water
        ! However, ATM2009/2016 returns NaN if this happens... Use a lower
        ! (positive) limit and exit right after
        water = minwater
        dwater = 0.d0
      endif
      !
    endif
    !
  enddo  ! kiter
  !
  ! Update structure whatever the result
  atm%h2omm = water
  !
end subroutine telcal_chopper_1water1
!
subroutine telcal_chopper_1waterN(search,tel,nfreq,freqs,loads,recs,atms,flags)
  use gbl_message
  use telcal_interfaces, except_this=>telcal_chopper_1waterN
  use chopper_definitions
  !---------------------------------------------------------------------
  ! @ private
  ! Compute 1 water vapor amount for the N frequencies
  !---------------------------------------------------------------------
  type(chop_mode), intent(in)    :: search
  type(telescope), intent(in)    :: tel
  integer(kind=4), intent(in)    :: nfreq
  type(dsb_value), intent(in)    :: freqs(nfreq)
  type(chop_meas), intent(in)    :: loads(nfreq)
  type(mixer),     intent(inout) :: recs(nfreq)
  type(atm_prop),  intent(inout) :: atms(nfreq)
  integer(kind=4), intent(inout) :: flags(nfreq)
  ! Local
  character(len=*), parameter :: rname='CHOPPER'
  integer(kind=4) :: ifreq,ier,kiter,nvalid
  real(kind=8) :: water,dwater,delta_water
  real(kind=8) :: temi,dtemi,delta_temi
  real(kind=8) :: mean_dtemi,mean_delta_temi,mean_taus,mean_airmass
  ! Automatic arrays
  real(kind=8) :: temi0(nfreq)
  !
  nvalid = 0
  water = 0.d0
  do ifreq=1,nfreq
    !
    if (flags(ifreq).eq.flag_nosky)  cycle
    if (flags(ifreq).ge.flag_badatm .and. search%strict)  cycle
    !
    ! Compute rec%temp and temi0
    call telcal_chopper_temperatures(tel,loads(ifreq),search%trec,recs(ifreq),temi0(ifreq))
    !
    nvalid = nvalid+1
    water = water + atms(ifreq)%h2omm
  enddo
  if (nvalid.eq.0)  return
  water = water/nvalid  ! Mean water guess
  !
  ! Initialize search parameters
  ier = 0
  water = min(10.d0,max(0.5d0,water)) ! [mm] Water vapor content
  dwater = .02                        ! [mm] Water vapor content offset used to determine the slope of the function: temi(water)
  !
  ! Iterate at most 20 times.
  do kiter = 1,20
    !
    nvalid = 0
    mean_delta_temi = 0.d0  ! [ K] Difference between predicted and measured sky emission temperature
    mean_dtemi      = 0.d0
    mean_taus       = 0.d0
    mean_airmass    = 0.d0
    !
    do ifreq=1,nfreq
      !
      if (flags(ifreq).eq.flag_nosky)  cycle
      if (flags(ifreq).ge.flag_badatm .and. search%strict)  cycle
      !
      ! Atmospheric model 1
      atms(ifreq)%h2omm = water
      call atm_dsb_transmission(freqs(ifreq),atms(ifreq),ier)
      temi = (atms(ifreq)%temi%s + atms(ifreq)%temi%i*recs(ifreq)%sbgr) / (1.+recs(ifreq)%sbgr)
      delta_temi = temi - temi0(ifreq)
      !
      ! Atmospheric model 2 (for derivation)
      atms(ifreq)%h2omm = water+dwater
      call atm_dsb_transmission(freqs(ifreq),atms(ifreq),ier)
      dtemi = (atms(ifreq)%temi%s + atms(ifreq)%temi%i*recs(ifreq)%sbgr) / (1.+recs(ifreq)%sbgr) - temi
      !
      ! Exit condition?
      if (dtemi.eq.0.d0) then
        ! Local minimum => exit
        call telcal_message(seve%w,rname,'Blocked in a local minimum')
        flags(ifreq) = flag_calfailed
        if (search%strict)  cycle
      endif
      !
      nvalid = nvalid + 1
      mean_delta_temi = mean_delta_temi + delta_temi
      mean_dtemi = mean_dtemi + dtemi
      mean_taus = mean_taus + atms(ifreq)%taus%tot
      mean_airmass = mean_airmass + atms(ifreq)%airmass
      !
    enddo  ! ifreq
    !
    if (nvalid.eq.0) then
      ! Not a single valid chunk remains (they are all flagged)... nothing more
      ! to be minimized
      exit
    endif
    !
    mean_delta_temi = mean_delta_temi/nvalid
    mean_dtemi = mean_dtemi/nvalid
    mean_taus = mean_taus/nvalid
    mean_airmass = mean_airmass/nvalid
    !
    ! Convergence or not?
    if (abs(mean_delta_temi).lt.0.1) then
      ! delta_temi is less than 0.1 K on average on all considered frequencies
      ! Reached convergence => exit
      exit  ! kiter
      !
    elseif (kiter.eq.20) then
      ! Too many iterations and total opacity at signal frequency is
      ! large enough to be a real problem => exit
      call telcal_message(seve%w,rname,'Did not converge after 20 iterations')
      where (flags.eq.flag_valid)
        flags(:) = flag_calfailed
      end where
      !
    else
      ! Not enough converged. Prepare new iteration:
      !  1. Compute value of water increment
      delta_water = (dwater/mean_dtemi)*mean_delta_temi
      !  2. Compute new water value
      if ((water-delta_water).gt.0) then
        ! New water value is positive => Limit optical depth to about 20. This assumes that: tau propto water
        water = min( water-delta_water,  &
                     20.*water/(mean_taus)/mean_airmass)
        ! water = min(water-delta_water,20.*water/max(atm%taus%tot,atm%taui%tot)/atm%airmass)
      else
        ! New water value is negative
        water = water-delta_water
      endif
      !  3. Adapt water offset to compute derivative
      if (abs(dwater).ge.abs(delta_water/10.)) dwater = delta_water/10.
      !
    endif
    !
  enddo  ! kiter
  !
  ! Update structure whatever the result
  atms(:)%h2omm = water

end subroutine telcal_chopper_1waterN
!
subroutine telcal_chopper_temperatures(tel,load,dotrec,rec,temi0)
  use chopper_definitions
  !---------------------------------------------------------------------
  ! @ private
  !  Compute:
  !   - Trec (if enabled)
  !   - Temi0
  !---------------------------------------------------------------------
  type(telescope), intent(in)    :: tel
  type(chop_meas), intent(in)    :: load
  logical,         intent(in)    :: dotrec
  type(mixer),     intent(inout) :: rec
  real(kind=8),    intent(out)   :: temi0
  ! Local
  real(kind=8) :: tsky
  !
  ! Local estimation Trec if needed
  ! This computation does *not* take the cold and hot coupling into account.
  if (dotrec) then
    rec%temp = (load%cold%temp*load%hot%count - load%hot%temp*load%cold%count) / &
               (load%cold%count - load%hot%count)
  endif
  !
  ! Now we are able to compute the sky emission temperature from sky and hot
  ! load measures. This value will be compared with the emission temperature
  ! predicted by ATM with different water vapor content.
  ! This computation takes into account the hot coupling. So there is
  ! some sort of inconsistency with above.
  tsky = ((load%hot%ceff*load%hot%temp + rec%temp) * load%sky_count / load%hot%count - rec%temp) &
               /  &
         (1. - load%sky_count * (1.-load%hot%ceff) / load%hot%count)
  !
  temi0 = (tsky - (1.-rec%feff) * tel%tcab) / rec%feff
  !
end subroutine telcal_chopper_temperatures
!
subroutine telcal_chopper_nullify(chopper,ifreq)
  use chopper_definitions
  !---------------------------------------------------------------------
  ! @ public
  !  Nullify the chopper results (only the outputs, not the inputs) e.g.
  ! in case of error
  !---------------------------------------------------------------------
  type(chopper_t), intent(inout) :: chopper
  integer(kind=4) :: ifreq
  !
  chopper%recs(ifreq)%temp = chopper%bad
  !
  chopper%atms(ifreq)%h2omm  = chopper%bad
  chopper%atms(ifreq)%temi%s = chopper%bad
  chopper%atms(ifreq)%temi%i = chopper%bad
  chopper%atms(ifreq)%temp%s = chopper%bad
  chopper%atms(ifreq)%temp%i = chopper%bad
  chopper%atms(ifreq)%taus%wat = chopper%bad
  chopper%atms(ifreq)%taus%oth = chopper%bad
  chopper%atms(ifreq)%taus%tot = chopper%bad
  chopper%atms(ifreq)%taui%wat = chopper%bad
  chopper%atms(ifreq)%taui%oth = chopper%bad
  chopper%atms(ifreq)%taui%tot = chopper%bad
  !
  chopper%tcals(ifreq)%s  = chopper%bad
  chopper%tcals(ifreq)%i  = chopper%bad
  chopper%atsyss(ifreq)%s = chopper%bad
  chopper%atsyss(ifreq)%i = chopper%bad
  chopper%tsyss(ifreq)%s  = chopper%bad
  chopper%tsyss(ifreq)%i  = chopper%bad
  !
end subroutine telcal_chopper_nullify
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
function airmass(el,error)
  use gbl_message
  use telcal_interfaces, except_this=>airmass
  !----------------------------------------------------------------------
  ! @ public
  ! Compute airmass number corresponding to elevation EL
  ! Use a curved atmosphere, equivalent height 5.5 km
  !----------------------------------------------------------------------
  real(8), intent(in)  :: el      ! Elevation [radian]
  logical, intent(out) :: error   ! Error flag
  real(8)              :: airmass ! Airmass
  !
  ! Local variables
  real(8) :: r0,h0,delev,eps,gamma,hz
  parameter (h0=5.5d0,r0=6370.d0)
  !
  error = .false.
  if (el.eq.0.) then
     call telcal_message(seve%e,'AIRMASS','Elevation is zero-valued')
     error = .true.
     return
  endif
  delev = el
  eps= asin(r0/(r0+h0)*cos(delev))
  gamma= delev + eps
  hz = r0*r0 + (r0+h0)**2 - 2.d0*r0*(r0+h0)*sin(gamma)
  hz = sqrt (max(h0**2,hz)) ! Avoid less than one airmass
  hz = hz/h0
  hz = min (hz, 20.d0)
  airmass = hz
end function airmass
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine atm_dsb_transmission(freq,atm,ier)
  use atm_interfaces_public
  use telcal_interfaces, except_this=>atm_dsb_transmission
  use chopper_definitions
  !----------------------------------------------------------------------
  ! @ private
  !----------------------------------------------------------------------
  type (dsb_value), intent(in)    :: freq !
  type (atm_prop),  intent(inout) :: atm  ! Atm%h2omm and others must be defined
  integer,          intent(inout) :: ier  ! Error flag
  !
  ! Local variables
  real :: temi,tatm,tau_wat,tau_oth,tau_tot
  !
  ! Signal frequency
  call atm_transm( &
       real(atm%h2omm), &
       real(atm%airmass), &
       real(freq%s), &
       temi,tatm, &
       tau_oth,tau_wat,tau_tot, &
       ier)
  ! Implicit casting from real to double
  atm%temi%s = temi
  atm%temp%s = tatm
  atm%taus%wat = tau_wat
  atm%taus%oth = tau_oth
  atm%taus%tot = tau_tot
  !
  ! Image frequency
  call atm_transm( &
       real(atm%h2omm), &
       real(atm%airmass), &
       real(freq%i), &
       temi,tatm, &
       tau_oth,tau_wat,tau_tot, &
       ier)
  ! Implicit casting from real to double
  atm%temi%i = temi
  atm%temp%i = tatm
  atm%taui%wat = tau_wat
  atm%taui%oth = tau_oth
  atm%taui%tot = tau_tot
  !
end subroutine atm_dsb_transmission
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
