subroutine write_sdm_calAtmosphere(error)
  !---------------------------------------------------------------------
  ! Write the calAtmosphere SDM table.
  !
  !
  !---------------------------------------------------------------------
  use gildas_def
  use gkernel_interfaces
  use sdm_CalAtmosphere
  use sdm_CalData
  use sdm_CalReduction
  use sdm_Antenna
  use sdm_SpectralWindow
  use sdm_Enumerations
  ! Dummy
  logical error
  ! Global variables:
  include 'clic_parameter.inc'
  include 'clic_par.inc'
  include 'clic_dheader.inc'
  include 'clic_constant.inc'
  include 'gbl_memory.inc'
  include 'sdm_identifiers.inc'
  character*20 version
  ! Local
  type(CalAtmosphereRow) :: caRow
  type(CalAtmosphereKey) :: caKey
  type(CalAtmosphereOpt) :: caOpt
  type(CalDataRow) :: cdRow
  type(CalDataKey) :: cdKey
  type(CalReductionRow) :: crRow
  type(CalReductionKey) :: crKey
  type(AntennaKey) :: aKey
  type(AntennaRow) :: aRow
  type(SpectralWindowRow) :: swRow
  type(SpectralWindowKey) :: swKey
  type(SpectralWindowOpt) :: swOpt
  integer  :: sig, ima, nfreq, ia, isb, ier, numChan,   &
    numReceptor, ip, l, lAmbient, lCold
  integer  :: ireturn, sdm_addCalDataRow, sdm_addCalReductionRow,   &
    sdm_addCalAtmosphereRow
  logical  :: present
  character  :: sdmTable*16, bureRecName(4)*5
  parameter (sdmTable = 'calAtmosphere')
  data bureRecName /'3mm','2mm','1.3mm','0.8mm'/
  !---------------------------------------------------------------------
  include 'clic_version.inc'
  call sdmMessage(1,1,sdmTable ,'starting...')
  !
  ! for the time being ...
  !
  ! cal data table:
  cdRow%numScan = 1
  call allocCalDataRow(cdRow, error)
  if (error) return
  !
  cdRow%scanSet(1) = r_scan
  cdRow%calType = CalType_CAL_ATMOSPHERE
  cdRow%calDataType = CalDataOrigin_TOTAL_POWER
  !     this is not stricly true, but we lost track of the time of actual
  !     load observations...
  cdRow%startTimeObserved = time_interval(1)
  cdRow%endTimeObserved = time_interval(1)+time_interval(2)
  l = lenc(execBlock_uid)
  cdRow%execBlockUID = '<EntityRef entityId="' //   &
    execBlock_uid(1:l)//   &
    '" partId="X00000000" entityTypeName="ExecBlock" '//   &
    'documentVersion="1"/>'//char(0)
  !print *, 'call addCalDataRow(cdKey, cdRow, error)'
  call addCalDataRow(cdKey, cdRow, error)
  if (error) goto 99
  !
  caKey%CalDataId = cdKey%CalDataId
  !
  ! cal reduction table:
  !
  crRow%numApplied = 1
  crRow%numParam = 2
!!!   call allocCalReductionRow(crRow, crRow%numApplied, crRow%numParam,   &
!!!     1, error)
  crRow%numInvalidConditions = 1
  call allocCalReductionRow(crRow, error)
  if (error) goto 99
  !!crRow%calAppliedArray(1) = 'None'
  crRow%appliedCalibrations(1) = 'None'
  crRow%timeReduced = time_Interval(1) + time_Interval(2)
  crRow%messages = 'None'
  crRow%software = 'CLIC'
  crRow%softwareVersion = version
  ! Nothing better ? should be none...
  crRow%invalidConditions(1) =   &
    InvalidatingCondition_ANTENNA_DISCONNECT
  do isb = 1, r_lnsb
    crRow%appliedCalibrations(1) = 'None'
    !! crRow%calAppliedArray(1) = 'None'
    if (isb.eq.1) then
      crRow%paramSet(1) = 'USB'
    elseif (isb.eq.2) then
      crRow%paramSet(1) = 'LSB'
    endif
    crRow%paramSet(2)='???'
    if ((r_nrec.gt.0).and.(r_nrec.le.4)) then
      crRow%paramSet(2)=bureRecName(r_nrec)
    endif
    !print *, 'call addCalReductionRow(crKey, crRow, error)'
    call addCalReductionRow(crKey, crRow, error)
    if (error) goto 99
    !
    caKey%CalReductionId = crKey%CalReductionId
    ! these are ordered properly...
    caKey%receiverBand = ReceiverBand_BURE_01 + (r_nrec-1)
    !
    ! cal atmosphere  table:
    !
    carow%startValidTime = cdRow%startTimeObserved
    ! assumed valid one hour
    carow%endValidTime = cdRow%endTimeObserved + 3600d9
    carow%syscalType = SyscalMethod_TEMPERATURE_SCALE
    carow%groundPressure = r_pamb*1d5  ! convert in Pascals
    carow%groundTemperature = r_tamb
    carow%groundRelHumidity = r_humid
    !
    ! the spectra here refer to the continuum detector since it is used for derivation.
    ! so for each antenna we have two results, one for LSB and one for USB.
    ! the number of frequencies each time is 1.
    numChan = 1
    if (r_isb.eq.1) then
      sig = 1
      ima = 2
    else
      sig = 2
      ima = 1
    endif
    !
    caRow%numFreq = 1
    caRow%numReceptor = r_npol_rec
    caRow%numLoad = 2
    lAmbient=2
    lCold=1
    !print *, 'call allocCalAtmosphereRow(caRow, error)'
    call allocCalAtmosphereRow(caRow, error)
    if (error) return
    call allocCalAtmosphereOpt(caRow, caOpt, error)
    if (error) return
    !
    do ia=1, r_nant
      !
      ! Get the ANtenna Name in Antenna Table:
      aKey%antennaId = Antenna_id(ia)
      !print *, 'call allocAntennaRow( aRow, error)'
      call allocAntennaRow( aRow, error)
      if (error) return
      call getAntennaRow(aKey, aRow, error) 
      if (error) return
      caKey%antennaName = aRow%name
      !
      !
      !     Get frequency range from SpectralWindow Table;
      !     totPowSpectralWindow must point to a single channel spectral
      !     window.
      do ip=1, r_npol_rec
        if (ip.eq.1) then
          caRow%polarizationTypes(ip) = PolarizationType_X
        else
          caRow%polarizationTypes(ip) = PolarizationType_Y
        endif
      enddo
      !     might be just as well b ethe reverse...
      !
      ! Remember all this is single-polarization !!!
      !
      ! not quite now ...
      swKey%spectralWindowId =  totPowSpectralWindow_Id(isb)
      !print *, 'call getSpectralWindowRow(swKey, swRow, error)'
      call getSpectralWindowRow(swKey, swRow, error)
      if (error) goto 99
!!!       caRow%frequencyRange(1) = swRow%chanFreq(1) -   &
!!!         swRow%chanWidth(1)/2
!!!       caRow%frequencyRange(2) = swRow%chanFreq(1) +   &
!!!         swRow%chanWidth(1)/2
!!!       caRow%frequencySpectrum(1) = swRow%chanFreq(1)
      !print *, 'call getSpectralWindowChanFreqStart(swKey, swOpt, error)'
      call getSpectralWindowChanFreqStart(swKey, swOpt, present, error)
      !print *, 'call getSpectralWindowChanWidth(swKey, swOpt, error)'
      call getSpectralWindowChanWidth(swKey, swOpt, present, error)
      if (error) goto 99
! these are 0?
      caRow%frequencyRange(1) = swOpt%chanFreqStart - swOpt%chanWidth/2
      caRow%frequencyRange(2) = swOpt%chanFreqStart + swOpt%chanWidth/2
      caRow%frequencySpectrum(1) = swOpt%chanFreqStart
!!!
      do ip=1, r_npol_rec
        carow%tRecSpectrum(1,ip) = r_trec(ip,ia)
        carow%tRec(ip) = r_trec(ip,ia)
        carow%water(ip) = r_h2omm(ip,ia)
        carow%waterError(ip) = 0.0 ! not in Bure data
        carow%powerSkySpectrum(1,ip) = r_csky(ip, ia)
        carow%powerLoadSpectrum(1,ip,lambient) = r_cchop(ip, ia)
        carow%powerLoadSpectrum(1,ip,lcold) = r_ccold(ip, ia)
       
        if (isb.eq.sig) then
          carow%tSysSpectrum(1,ip) = r_tsyss(ip,ia)
          carow%tSys(ip) = r_tsyss(ip,ia)
          carow%tAtmSpectrum(1,ip) = r_tatms(ip,ia)
          carow%tAtm(ip) = r_tatms(ip,ia)
          caopt%sbGainSpectrum(1,ip) = 1./(1.+r_gim(ip,ia))
          caopt%sbGain(ip) = 1./(1.+r_gim(ip,ia))
          carow%tauSpectrum(1,ip) = r_taus(ip,ia)
          carow%tau(ip) = r_taus(ip,ia)
        elseif (isb.eq.ima) then
          carow%tSysSpectrum(1,ip) = r_tsysi(ip,ia)
          carow%tSys(ip) = r_tsysi(ip,ia)
          carow%tAtmSpectrum(1,ip) = r_tatmi(ip,ia)
          carow%tAtm(ip) = r_tatmi(ip,ia)
          caopt%sbGainSpectrum(ip,1) = r_gim(ip,ia)/(1.+r_gim(ip,ia))
          caopt%sbGain(ip) = r_gim(ip,ia)/(1.+r_gim(ip,ia))
          carow%tauSpectrum(1,ip) = r_taui(ip,ia)
          carow%tau(ip) = r_taui(ip,ia)
        endif
        caopt%forwardEfficiency(ip) = r_feff(ip,ia)
        carow%forwardEffSpectrum(1,ip) = r_feff(ip,ia)
      enddo
      !print *, 'call addCalAtmosphereRow(cakey, carow, error)'
      call addCalAtmosphereRow(cakey, carow, error)
      if (error) goto 99
      call addCalAtmosphereForwardEfficiency(cakey, caopt, error)
      if (error) goto 99
      !print *, 'call addCalAtmosphereSbGain(cakey, carow, error)'
      call addCalAtmosphereSbGain(cakey, caopt, error)
      if (error) goto 99
      !print *, 'call addCalAtmosphereSbGainSpectrum(cakey, caopt, error)'
      call addCalAtmosphereSbGainSpectrum(cakey, caopt, error)
      if (error) goto 99
    enddo ! antenna
  enddo   ! side band
  call sdmMessage(1,1,sdmTable ,'Written.')
99 return
end subroutine write_sdm_calAtmosphere
!---------------------------------------------------------------------
subroutine get_sdm_calAtmosphere(error)
  use gkernel_interfaces
  !---------------------------------------------------------------------
  !     Read the calAtmosphere SDM table, and associated cal_data and
  !     cal_reduction tables...
  !
  !
  !---------------------------------------------------------------------
  use gildas_def
  use sdm_CalAtmosphere
  !      use sdm_SpectralWindow
  use sdm_Antenna
  ! Dummy
  logical error
  ! Global variables:
  include 'clic_parameter.inc'
  include 'clic_par.inc'
  include 'clic_dheader.inc'
  include 'clic_clic.inc'
  include 'clic_constant.inc'
  include 'gbl_memory.inc'
  include 'sdm_identifiers.inc'
  character*20 version
  ! Local
  type(CalAtmosphereRow) :: caRow
  type(CalAtmosphereOpt) :: caOpt
  type(CalAtmosphereKey), allocatable  :: caKeyList(:)
  !$$$      type(SpectralWindowKey) :: swKey
  !$$$      type(SpectralWindowRow) :: swRow
  type(AntennaKey) :: aKey
  type(AntennaRow) :: aRow
  integer mscan, mcalApp, mfreq, mparam, mreceptors
  parameter (mscan=10, mcalApp=10, mparam=10, mfreq = 1, mreceptors   &
    =2)
  integer sig, ima, nreceptors, nfreq,   &
    ia, isb, ier , numChan, numReceptor
  character sdmTable*16
  logical  :: present
  real*8 fmin, fmax, freq
  !
  parameter (sdmTable = 'calAtmosphere')
  integer atmSize, lenz, i, l, l1, ip
  integer imax, eps(2)
  integer*8 tmin, tmax
  data eps /1, -1/
  !---------------------------------------------------------------------
  call sdmMessage(1,1,sdmTable ,'starting...')
  !
  !$$$      call allocSpectralWindowRow(swRow, mch, error)
  !$$$      if (error) goto 99
  !
  !     cal data table is ignored...
  !
  !     read the calAtmosphere
  call getCalAtmosphereTableSize(atmSize, error)
  if (error) goto 99
  if (atmSize.le.0) then
    call sdmmessage(2,2,sdmTable,'No table present')
    goto 90
  endif
  allocate(caKeyList(atmSize), stat=ier)
  if (ier.ne.0) then
    call sdmmessageI(8,4,sdmTable,'Memory allocation error: ier '   &
      ,ier)
    error = .true.
    goto 99
  endif
  call getCalAtmosphereKeys(atmSize, caKeyList, error)
  if (error) goto 99
  !
  !     set dimension parameters
  numChan = 1
  numReceptor = r_npol_rec
  !!call allocCalAtmosphereRow(caRow, numChan, numReceptor, error)
  call allocCalAtmosphereRow(caRow, error)
  if (error) goto 99
  !
  !     find the latest one one that applies:
  !
  !     Loop on antennas and side bands.
  do ia = 1, r_nant
    ! get antenna name in antenna table (in aRow%name)
    aKey%antennaId = Antenna_id(ia)
    call getAntennaRow(aKey, aRow, error)
    if (error) return
    l1 = lenc(aRow%name)
    aRow%name = aRow%name(1:l1)
    !
    do isb = 1, 2
      !c            if (new_receivers) then
      !     this actually depends on the frequency setup. We should do better.
      !               fmin = 1d6*min(r_flo1+eps(isb)*4200.,r_flo1+eps(isb)*7800
      !     &              .)
      !               fmax = 1d6*max(r_flo1+eps(isb)*4200.,r_flo1+eps(isb)*7800
      !     &              .)
      !            else
      !     at this point we have a single tsys for each side band in CLIC. We
      !     estimate it applies to the interval of 100-800 MHz IF2.
      fmin = 1d6*min(r_flo1+eps(isb)*(r_flo2(1)-100.),r_flo1   &
        +eps(isb)*(r_flo2(1)-800.))
      fmax = 1d6*max(r_flo1+eps(isb)*(r_flo2(1)-100.),r_flo1   &
        +eps(isb)*(r_flo2(1)-800.))
      !            endif
      tmin = time_Interval(1)
      tmax = time_Interval(1)
      imax = -1
      do i = 1, atmSize
        l = lenc(caKeyList(i)%antennaName)
        if (caKeyList(i)%antennaName(1:l) .eq. aRow%name(1:l1))   &
          then
          call GetCalAtmosphereRow(caKeyList(i), caRow, error)
          if (error) goto 99
          !
          ! at this point we need to read the sp window to get the frequency
          ! SS2: no,  we have it here now.
          ! use the mid-range point. We could be more strict and check the limits.
          freq = (caRow%frequencyRange(1) +   &
            caRow%frequencyRange(2)) /2.
          if ((caRow%startValidTime.le.tmin .and.   &
            caRow%endValidTime.ge.tmax) .and. (freq .gt. fmin   &
            ) .and. (freq .le. fmax)) then
            tmax = caRow%endValidTime
            imax = i
          endif
        endif
      enddo
      if (imax.lt.0) then
        call sdmMessage(8,2,sdmTable   &
          ,'No valid atmosphere calibration!')
        imax = 1
      endif
      call GetCalAtmosphereRow(caKeyList(imax), caRow, error)
      if (error) return
      r_pamb = caRow%groundPressure/1d5
      r_tamb = caRow%groundTemperature
      r_humid = caRow%groundRelHumidity
      call GetCalAtmosphereSbGainSpectrum(caKeyList(imax), caOpt, present, error)
      if (error) return
      !
      !     signal band:
      !
      do ip = 1, r_npol_rec
        !     note we use 1 receptor in CLIC - no check...
        if (r_isb.eq.eps(isb)) then
          r_trec(ip,ia) = caRow%tRecSpectrum(ip,1)
          r_tsyss(ip,ia) = caRow%tSysSpectrum(ip,1)
          r_tatms(ip,ia) = caRow%tAtmSpectrum(ip,1)
          r_taus(ip,ia) = caRow%tauSpectrum(ip,1)
          !!r_gim(ip,ia) = 1./caRow%sbGainSpectrum(ip,1) - 1
          r_gim(ip,ia) = 1./caOpt%sbGainSpectrum(ip,1) - 1
          r_feff(ip,ia) =    caRow%forwardEffSpectrum(ip,1)
          r_totscale(ip,ia) =  1.0
        !
        !     image band:
        else
          r_tsysi(ip,ia) = caRow%tSysSpectrum(ip,1)
          r_tatmi(ip,ia) = caRow%tAtmSpectrum(ip,1)
          r_taui(ip,ia) = caRow%tauSpectrum(ip,1)
        endif
      enddo
    enddo
  enddo
90 call sdmMessage(1,1,sdmTable ,'Read.')
  !
99 if (allocated(caKeyList)) then
    deallocate(caKeyList, stat=ier)
    if (ier.ne.0) then
      call sdmmessageI(8,4,sdmTable   &
        ,'Memory deallocation error 1 ier ',ier)
      error = .true.
    endif
  endif
  return
end subroutine get_sdm_calAtmosphere
!---------------------------------------------------------------------
!!! subroutine allocCalAtmosphereRow(row, numChan, numReceptor, error   &
!!!     )
!!!   use sdm_CalAtmosphere
!!!   type(CalAtmosphereRow) :: row
!!!   integer :: numChan, numReceptor, ier
!!!   logical :: error
!!!   character, parameter :: sdmTable*16 = 'calAtmosphere'
!!!   ! frequencyRange
!!!   if (allocated(row%frequencyRange)) then
!!!     deallocate(row%frequencyRange, stat=ier)
!!!     if (ier.ne.0) goto 98
!!!   endif
!!!   allocate(row%frequencyRange(2), stat=ier)
!!!   if (ier.ne.0) goto 99
!!!   ! frequencySpectrum
!!!   if (allocated(row%frequencySpectrum)) then
!!!     deallocate(row%frequencySpectrum, stat=ier)
!!!     if (ier.ne.0) goto 98
!!!   endif
!!!   allocate(row%frequencySpectrum(numChan), stat=ier)
!!!   if (ier.ne.0) goto 99
!!!   ! tRecSpectrum
!!!   if (allocated(row%tRecSpectrum)) then
!!!     deallocate(row%tRecSpectrum, stat=ier)
!!!     if (ier.ne.0) goto 98
!!!   endif
!!!   allocate(row%tRecSpectrum(numReceptor, numChan), stat=ier)
!!!   if (ier.ne.0) goto 99
!!!   ! tSysSpectrum
!!!   if (allocated(row%tSysSpectrum)) then
!!!     deallocate(row%tSysSpectrum, stat=ier)
!!!     if (ier.ne.0) goto 98
!!!   endif
!!!   allocate(row%tSysSpectrum(numReceptor, numChan), stat=ier)
!!!   if (ier.ne.0) goto 99
!!!   ! tAtmSpectrum
!!!   if (allocated(row%tAtmSpectrum)) then
!!!     deallocate(row%tAtmSpectrum, stat=ier)
!!!     if (ier.ne.0) goto 98
!!!   endif
!!!   allocate(row%tAtmSpectrum(numReceptor, numChan), stat=ier)
!!!   if (ier.ne.0) goto 99
!!!   ! tauSpectrum
!!!   if (allocated(row%tauSpectrum)) then
!!!     deallocate(row%tauSpectrum, stat=ier)
!!!     if (ier.ne.0) goto 98
!!!   endif
!!!   allocate(row%tauSpectrum(numReceptor, numChan), stat=ier)
!!!   if (ier.ne.0) goto 99
!!!   ! sbGainSpectrum
!!!   if (allocated(row%sbGainSpectrum)) then
!!!     deallocate(row%sbGainSpectrum, stat=ier)
!!!     if (ier.ne.0) goto 98
!!!   endif
!!!   allocate(row%sbGainSpectrum(numReceptor, numChan), stat=ier)
!!!   if (ier.ne.0) goto 99
!!!   ! forwardEffSpectrum
!!!   if (allocated(row%forwardEffSpectrum)) then
!!!     deallocate(row%forwardEffSpectrum, stat=ier)
!!!     if (ier.ne.0) goto 98
!!!   endif
!!!   allocate(row%forwardEffSpectrum(numReceptor, numChan), stat=ier)
!!!   if (ier.ne.0) goto 99
!!!   ! polarizationTypes
!!!   if (allocated(row%polarizationTypes)) then
!!!     deallocate(row%polarizationTypes, stat=ier)
!!!     if (ier.ne.0) goto 98
!!!   endif
!!!   allocate(row%polarizationTypes(numReceptor), stat=ier)
!!!   if (ier.ne.0) goto 99
!!!   ! sbGain
!!!   !$$$      if (allocated(row%sbGain)) then
!!!   !$$$         deallocate(row%sbGain, stat=ier)
!!!   !$$$         if (ier.ne.0) goto 98
!!!   !$$$      endif
!!!   !$$$      allocate(row%sbGain(numReceptor), stat=ier)
!!!   !$$$      if (ier.ne.0) goto 99
!!!   ! forwardEfficiency
!!!   !$$$      if (allocated(row%forwardEfficiency)) then
!!!   !$$$         deallocate(row%forwardEfficiency, stat=ier)
!!!   !$$$         if (ier.ne.0) goto 98
!!!   !$$$      endif
!!!   !$$$      allocate(row%forwardEfficiency(numReceptor), stat=ier)
!!!   !$$$      if (ier.ne.0) goto 99
!!!   return
!!!   !
!!! 98 call sdmmessageI(8,4,sdmTable ,'Deallocation error ier ',ier)
!!!   error = .true.
!!!   return
!!!   !
!!! 99 call sdmmessageI(8,4,sdmTable ,'Allocation error ier ',ier)
!!!   error = .true.
!!!   return
!!! end
!---------------------------------------------------------------------
!!! subroutine allocCalDataRow(row, numScan, error)
!!!   use sdm_CalData
!!!   type(CalDataRow) :: row
!!!   integer :: numScan, ier
!!!   logical :: error
!!!   character, parameter :: sdmTable*8 = 'calData'
!!!   !
!!!   ! scanSet
!!!   if (allocated(row%scanSet)) then
!!!     deallocate(row%scanSet, stat=ier)
!!!     if (ier.ne.0) goto 98
!!!   endif
!!!   allocate(row%scanSet(numScan), stat=ier)
!!!   if (ier.ne.0) goto 99
!!!   return
!!!   !
!!! 98 call sdmmessageI(8,4,sdmTable ,'Deallocation error ier ',ier)
!!!   error = .true.
!!!   return
!!!   !
!!! 99 call sdmmessageI(8,4,sdmTable ,'Allocation error ier ',ier)
!!!   error = .true.
!!!   return
!!! end
!---------------------------------------------------------------------
!!! subroutine allocCalReductionRow(row, numApplied, numParam,   &
!!!     numInvalidConditions, error)
!!!   use sdm_CalReduction
!!!   type(CalReductionRow) :: row
!!!   integer :: numApplied, numParam, numInvalidConditions, ier
!!!   logical :: error
!!!   character, parameter :: sdmTable*8 = 'calReduction'
!!!   ! calAppliedArray
!!!   if (allocated(row%calAppliedArray)) then
!!!     deallocate(row%calAppliedArray, stat=ier)
!!!     if (ier.ne.0) goto 98
!!!   endif
!!!   allocate(row%calAppliedArray(numApplied), stat=ier)
!!!   if (ier.ne.0) goto 99
!!!   ! paramSet
!!!   if (allocated(row%paramSet)) then
!!!     deallocate(row%paramSet, stat=ier)
!!!     if (ier.ne.0) goto 98
!!!   endif
!!!   allocate(row%paramSet(numParam), stat=ier)
!!!   if (ier.ne.0) goto 99
!!!   ! InvalidConditions
!!!   if (allocated(row%InvalidConditions)) then
!!!     deallocate(row%InvalidConditions, stat=ier)
!!!     if (ier.ne.0) goto 98
!!!   endif
!!!   allocate(row%InvalidConditions(numInvalidConditions), stat=ier)
!!!   if (ier.ne.0) goto 99
!!!   return
!!!   !
!!! 98 call sdmmessageI(8,4,sdmTable ,'Deallocation error ier ',ier)
!!!   error = .true.
!!!   return
!!!   !
!!! 99 call sdmmessageI(8,4,sdmTable ,'Allocation error ier ',ier)
!!!   error = .true.
!!!   return
!!! end
