!-------------------------------------- LICENCE BEGIN ------------------------------------
!Environment Canada - Atmospheric Science and Technology License/Disclaimer,
!                     version 3; Last Modified: May 7, 2008.
!This is free but copyrighted software; you can use/redistribute/modify it under the terms
!of the Environment Canada - Atmospheric Science and Technology License/Disclaimer
!version 3 or (at your option) any later version that should be found at:
!http://collaboration.cmc.ec.gc.ca/science/rpn.comm/license.html
!
!This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
!without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
!See the above mentioned License/Disclaimer for more details.
!You should have received a copy of the License/Disclaimer along with this software;
!if not, you can write to: EC-RPN COMM Group, 2121 TransCanada, suite 500, Dorval (Quebec),
!CANADA, H9P 1J3; or send e-mail to service.rpn@ec.gc.ca
!-------------------------------------- LICENCE END --------------------------------------


module observation_erreurs_mod 1,4

  use MathPhysConstants_mod
  use obsSpaceData_mod
  use tovs_nl_mod
  use bufr
  implicit none
  private

  ! public procedures
  ! -----------------

  public :: oer_set_obs_erreurs

  ! TOVS OBS ERRORS
  ! ---------------

  real(8) :: toverrst(jpchmax,jpnsatmax)

  !
  ! CONVENTIONAL OBS ERRORS
  ! -----------------------

  real(8) :: xstd_ua_ai_sw(20,11)
  real(8) :: xstd_sf(9,4)
  real(8) :: xstd_pr(2)
  real(8) :: xstd_sc(1)

  save
  contains

!-----------------------------------------------------------------------------------------
!-----------------------------------------------------------------------------------------
!-----------------------------------------------------------------------------------------


  subroutine oer_set_obs_erreurs(lobsSpaceData) 1,3
  !
  ! s/r set_observation_erreurs -SET OBSERVATION ERROR FOR ALL DATA 
  !
  ! Author  : S. Laroche  February 2014
  ! Revision: 
  !
  ! Purpose: read and set observation errors (from former sucovo subroutine).
  !
  !

  type(struct_obs) :: lobsSpaceData

  !
  ! Read in the observation stddev errors for radiance data
  !
  call oer_read_obs_erreurs_tovs

  !
  ! Read in the observation stddev errors for conventional data
  !
  call oer_read_obs_erreurs_conv

  !
  ! Set obs error information in obsSpaceData object
  !
  call oer_fill_obs_erreurs(lobsSpaceData)


  end subroutine oer_set_obs_erreurs

!-----------------------------------------------------------------------------------------
!-----------------------------------------------------------------------------------------


  subroutine oer_read_obs_erreurs_tovs 1,19
  !
  ! s/r oer_read_obs_erreurs_tovs
  ! - Read the observation erreur statistics and utilization flag for TOVS processing.
  !
  !
  ! Author  : J. Halle !CMDA/AES  May 08, 1996
  !
  ! Revision 01  : J. Halle !CMDA/AES  Oct 1999
  !               - change file name to stats_tovs
  !
  ! Revision 002  : J. Halle !CMDA/AES  dec 2000
  !                adapt to TOVS level 1b.
  !
  ! Revision 003  : J. Halle !CMDA/SMC  may 2002
  !                adapt to RTTOV-7.
  !
  ! Revision 004  : J. Halle !CMDA/SMC  sept 2006
  !                adapt to RTTOV-8.
  !
  ! Revision 005  : A. Beaulne !CMDA/SMC  fevr 2007
  !                adapt utilization flag for AIRS channels
  !
  ! Revision 006  : S. Heilliette
  !                adapt utilization flag for IASI channels
  !
  ! Revision 007: S. Macpherson ARMA, Feb 2013
  !              - add NPP/ATMS codtyp=192
  !
  ! Revision 008  : S. Macpherson      apr 2013
  !              - adapt for new-format stats_tovs file
  !
  ! Revision 008  : S. Laroche      Mar 2014
  !              - upgrade of former f77 subroutine sutovst
  !              - f90 conversion and cleanup 
  !
  !    -------------------
  !    Purpose: Read the observation error statistics and
  !             utilization flag for TOVS processing. This information
  !             resides on an ASCII file and is read using a free format.

      
  use topLevelControl_mod
  use hir_chans
  use mpivar_mod
  use tovs_nl_mod
  use rmatrix_mod
  implicit none

  integer,external  :: FNOM, FCLOS, ISRCHEQ
  integer  :: IER, ILUTOV, JI, JJ, JK, JL, JM, I, IPOS1, IPOS2, INUMSAT, ISAT, IPLF
  integer, dimension(JPNSATMAX)         :: IPLATFORM, ISATID, IINSTRUMENT, NUMCHN, NUMCHNIN
  integer, dimension(JPCHMAX,JPNSATMAX) :: IUTILST, ICHN, ICHNIN
  
  real :: ZDUM

  real(8), dimension(JPCHMAX,2,JPNSATMAX) :: TOVERRIN

  character (len=132) :: CLDUM,CPLATF,CINSTR

  WRITE(*,'(//,10x,"-oer_read_obs_erreurs_tovs: reading observation error statistics required for TOVS processing")')

  !
  !    1. Initialize
  !       ----------
  !
  DO JL = 1, JPNSATMAX  
     DO JI = 1, JPCHMAX
        TOVERRST(JI,JL) = 0.0D0
      TOVERRIN(JI,1,JL) = 0.0D0
      TOVERRIN(JI,2,JL) = 0.0D0
      IUTILST   (JI,JL) = 0
     ENDDO
  ENDDO

  DO JL = 1, JPNSATMAX
     IPLATFORM(JL) = 0
        NUMCHN(JL) = 0
      NUMCHNIN(JL) = 0
     DO JI = 1, JPCHMAX
        ICHN(JI,JL) = 0
      ICHNIN(JI,JL) = 0
     ENDDO
  ENDDO

  if (nobtov==0) return

  !
  !     2. Open the file
  !        -------------
  !
  ilutov = 0
  IER =  FNOM(ILUTOV,'stats_tovs','SEQ+FMT',0)
  IF(IER.LT.0)THEN
     WRITE ( *, '(" oer_read_obs_erreurs_tovs: Problem opening ","file stats_tovs ")' )
     CALL ABORT3D ('oer_read_obs_erreurs_tovs')
  END IF

  !
  !     3. Print the file contents
  !        -----------------------
  !
  IF(MPI_MYID.EQ.0) THEN
     WRITE(*,'(20X,"ASCII dump of stats_tovs file: "//)')
     DO JI = 1, 9999999
       READ (ILUTOV,'(A)',IOSTAT=IER) CLDUM
       IF(IER.EQ.-1) EXIT
       WRITE(*,'(A)')   CLDUM
     ENDDO
  ENDIF

  !
  !     4. Read number of satellites
  !        -------------------------
  !
  REWIND(ILUTOV)
  READ (ILUTOV,*)
  READ (ILUTOV,*) INUMSAT
  READ (ILUTOV,*)

  !
  !     5. Read the satellite identification, the number of channels,
  !        the observation errors and the utilization flags
  !        ----------------------------------------------------------
  !
  WRITE(*,'(5X,"oer_read_obs_erreurs_tovs: Reading stats_tovs file: "//)')

  DO JL = 1, INUMSAT

     READ (ILUTOV,*)
     READ (ILUTOV,'(A)') CLDUM
     WRITE(*,'(A)') CLDUM
     CINSTR=CLDUM
     call split(CINSTR," ",CPLATF)
     Write(*,*) "CINSTR: ",CINSTR
     Write(*,*) "CPLATF: ",CPLATF
     READ (ILUTOV,*)
     READ (ILUTOV,*) ISATID(JL), NUMCHNIN(JL)

     DO JI = 1, 3
       READ (ILUTOV,*)
     ENDDO

     IPLATFORM(JL) = -1    
     DO I = 1, MXPLATFORM
      IPOS1=LEN_TRIM(CPLATFORM(I))
      IPOS2 = INDEX(CPLATF,CPLATFORM(I)(1:IPOS1))
      IF ( IPOS2 .NE. 0 ) THEN
         IPLATFORM(JL) = NOPLATFORM(I)
         EXIT
      ENDIF
     ENDDO

     IF ( IPLATFORM(JL) .EQ. -1 ) THEN
      WRITE ( *, '(" oer_read_obs_erreurs_tovs: Unknown platform!"/)' )
      CALL ABORT3D ('oer_read_obs_erreurs_tovs')
     ENDIF

     IINSTRUMENT(JL) = -1    
     DO I = 1, MXINSTR
      IPOS1=LEN_TRIM(CINSTRUMENT(I))
      IPOS2 = INDEX(CINSTR,CINSTRUMENT(I)(1:IPOS1))
      IF ( IPOS2 .NE. 0 ) THEN
       IINSTRUMENT(JL) = NOINSTRUMENT(I)
      ENDIF
     ENDDO

     IF ( IINSTRUMENT(JL) .EQ. -1 ) THEN
       WRITE ( *, '(" oer_read_obs_erreurs_tovs: Unknown instrument!"/)' )
       CALL ABORT3D ('oer_read_obs_erreurs_tovs')
     ENDIF  

     DO JI = 1, NUMCHNIN(JL)
       READ (ILUTOV,*) ICHNIN(JI,JL), TOVERRIN(ICHNIN(JI,JL),1,JL), TOVERRIN(ICHNIN(JI,JL),2,JL), IUTILST(ICHNIN(JI,JL),JL), ZDUM
     ENDDO
     READ (ILUTOV,*)

  ENDDO

  !
  !   Select input error to use: if ANAL mode, use ERRANAL (JJ=2);
  !   otherwise use ERRBGCK (JJ=1)
  !
  IF ( top_AnalysisMode() ) THEN
     JJ = 2
  ELSE
     JJ = 1
  ENDIF

  !
  !   Fill the observation error array TOVERRST
  !
  WRITE(*,'(5X,"oer_read_obs_erreurs_tovs: Fill error array TOVERRST: "//)')
  DO JM= 1, INUMSAT
    DO JL = 1, NSENSORS
      IF ( PLATFORM (JL) .EQ. IPLATFORM(JM) .AND. SATELLITE(JL) .EQ. ISATID(JM) ) THEN
        IF ( INSTRUMENT (JL) .EQ. IINSTRUMENT(JM) ) THEN
          NUMCHN(JL)=NUMCHNIN(JM)
          DO JI = 1, JPCHMAX
            TOVERRST(JI,JL) = TOVERRIN(JI,JJ,JM)
            ICHN(JI,JL) = ICHNIN(JI,JM)
          ENDDO
          IF (top_AnalysisMode().and.rmat_lnondiagr) call rmat_setFullRMatrix ( TOVERRST(:,JL), JL, chanoffset(JL) )
        ENDIF
      ENDIF
    ENDDO
  ENDDO

  !
  !  Check that oberservation error statistics have been defined for
  !  all the satellites specified in the namelist.
  !
  DO JL = 1, NSENSORS
     IPLF = ISRCHEQ ( IPLATFORM  , INUMSAT, PLATFORM  (JL) )
     ISAT = ISRCHEQ ( ISATID     , INUMSAT, SATELLITE (JL) )
     IF ( IPLF .EQ. 0 .OR. ISAT .EQ. 0 ) THEN
       WRITE ( *, '(" oer_read_obs_erreurs_tovs: Observation errors not ","defined for sensor # ", I3)' ) JL
       CALL ABORT3D ('oer_read_obs_erreurs_tovs')
     END IF
     IF ( NUMCHN(JL) .EQ. 0 ) THEN 
       WRITE ( *, '(" oer_read_obs_erreurs_tovs: Problem setting errors ","for sensor # ", I3)' ) JL
       CALL ABORT3D ('oer_read_obs_erreurs_tovs')
     ENDIF
  ENDDO

  !
  !   Utilization flag for AIRS,IASI and CrIS channels (bgck mode only)
  !
  IF ( top_BgckIrMode() ) THEN
     DO JM= 1, INUMSAT
      IF (   IPLATFORM(JM) .EQ. 9  .AND. &
           IINSTRUMENT(JM) .EQ. 11 ) THEN

         call hir_set_assim_chan("AIRS",IUTILST(ICHNIN(1:NUMCHNIN(JM),JM),JM))
      END IF
      IF (   IPLATFORM(JM) .EQ. 10 .AND. &
           IINSTRUMENT(JM) .EQ. 16 ) THEN
         call hir_set_assim_chan("IASI",IUTILST(ICHNIN(1:NUMCHNIN(JM),JM),JM))
      END IF
      IF (   IPLATFORM(JM) .EQ. 17 .AND. &
           IINSTRUMENT(JM) .EQ. 27 ) THEN
         call hir_set_assim_chan("CRIS",IUTILST(ICHNIN(1:NUMCHNIN(JM),JM),JM))
      END IF
     ENDDO
  END IF

  !
  !    6. Print out observation errors for each sensor
  !       --------------------------------------------
  !
  IF(MPI_MYID.eq.0) THEN
     WRITE(*,'(//1X,"Radiance observation errors read from file")')
     WRITE(*,'(  1X,"------------------------------------------")')
     DO JL = 1, NSENSORS
      WRITE(*,'(/1X,"SENSOR #",I2,". Platform: ",A,"Instrument: ",A)') &
              JL, CSATID(JL), CINSTRUMENTID(JL)
      WRITE(*,'(1X,"Channel",5X,"  error   ")')
      DO JI = 1, NUMCHN(JL)
       WRITE (*,'(1X,I7,1(5X,F10.2))') ICHN(JI,JL),TOVERRST(ICHN(JI,JL),JL)
      ENDDO
     ENDDO
  ENDIF

  !
  !    7. Close the file
  !       --------------
  !
  IER = FCLOS(ILUTOV)
  IF(IER.NE.0)THEN
     CALL ABORT3D ('oer_read_obs_erreurs_tovs')
  END IF

      contains


      subroutine compact(str) 2
! Code from Benthien's module: http://www.gbenthien.net/strings/index.html
! Converts multiple spaces and tabs to single spaces; deletes control characters;
! removes initial spaces.

        character(len=*):: str
        character(len=1):: ch
        character(len=len_trim(str)):: outstr
        integer isp,k,lenstr,i,ich

        str=adjustl(str)
        lenstr=len_trim(str)
        outstr=' '
        isp=0
        k=0

        do i=1,lenstr
           ch=str(i:i)
           ich=iachar(ch)

           select case(ich)
           case(9,32)    ! space or tab character         
              if(isp==0) then
                 k=k+1
                 outstr(k:k)=' '
              end if
              isp=1
           case(33:)              ! not a space, quote, or control character
              k=k+1
              outstr(k:k)=ch
              isp=0
           end select

        end do

        str=adjustl(outstr)

      end subroutine compact


      subroutine split(str,delims,before) 2,2
! Code extracted from Benthien's module: http://www.gbenthien.net/strings/index.html
! Routine finds the first instance of a character from 'delims' in the
! the string 'str'. The characters before the found delimiter are
! output in 'before'. The characters after the found delimiter are
! output in 'str'. 

        character(len=*) :: str,delims,before
        character :: ch,cha
        integer lenstr,i,k,ipos,iposa
        str=adjustl(str)
        call compact(str)
        lenstr=len_trim(str)

        if(lenstr == 0) return ! string str is empty
        k=0
        before=' '
        do i=1,lenstr
           ch=str(i:i)
         
           ipos=index(delims,ch)

           if(ipos == 0) then ! character is not a delimiter
              k=k+1
              before(k:k)=ch
              cycle
           end if
           if(ch /= ' ') then ! character is a delimiter that is not a space
              str=str(i+1:)
              exit
           end if

         cha=str(i+1:i+1)  ! character is a space delimiter
         iposa=index(delims,cha)
         if(iposa > 0) then   ! next character is a delimiter 
            str=str(i+2:)
            exit
         else
            str=str(i+1:)
            exit
         end if
      end do
      if(i >= lenstr) str=''

      str=adjustl(str) ! remove initial spaces
   
      return

      end subroutine split

  end subroutine oer_read_obs_erreurs_tovs

!-----------------------------------------------------------------------------------------
!-----------------------------------------------------------------------------------------


  subroutine oer_read_obs_erreurs_conv 1,2
  !
  ! s/r oer_read_obs_erreurs_conv -READ OBSERVATION ERROR OF CONVENTIONAL DATA 
  !
  ! Author  : S. Laroche  February 2014
  ! Revision: 
  !          
  ! Purpose: read observation errors (modification of former readcovo subroutine).
  !

  implicit none

  integer :: FNOM, FCLOS
  integer :: IERR, JLEV, JELM, icodtyp, nulstat
  logical :: LnewExists

  character (len=128) :: ligne

  EXTERNAL FNOM,FCLOS
!
!     CHECK THE EXISTENCE OF THE NEW FILE WITH STATISTICS
!     !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
  INQUIRE(FILE='obserr',EXIST=LnewExists)
  IF (LnewExists )then
    WRITE(*,*) '--------------------------------------------------------'
    WRITE(*,*) 'read_obs_errors_conv: reads observation errors in obserr'
    WRITE(*,*) '--------------------------------------------------------'
  else
    CALL ABORT3D('read_obs_errors_conv: NO OBSERVATION STAT FILE FOUND!!')     
  ENDIF
!
!     Read observation errors from file obserr for conventional data
!     !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
  NULSTAT=0
  IERR=FNOM(NULSTAT,'obserr','SEQ',0)
  IF ( IERR .EQ. 0 ) THEN
    write(*,*) 'read_obs_errors_conv: File =  ./obserr'
    write(*,*) ' opened as unit file ',nulstat
    open(unit=nulstat, file='obserr', status='OLD')
  ELSE
    CALL ABORT3D('read_obs_errors_conv:COULD NOT OPEN FILE obserr!!!')
  ENDIF

write(*, '(A)') ' '

  do jlev = 1,3
    read(nulstat, '(A)') ligne
    write(*, '(A)') ligne
  enddo

  do jlev = 1, 19
    read(nulstat, * ) (xstd_ua_ai_sw(jlev,jelm), jelm=1,11)
    write(*, '(f6.0,10f6.1)' )  (xstd_ua_ai_sw(jlev,jelm), jelm=1,11)
  enddo

  do jlev = 1,5
    read(nulstat, '(A)') ligne
    write(*, '(A)') ligne
  enddo

  read(nulstat, * ) xstd_pr(1),xstd_pr(2)
  write(*, '(2f6.1)' )  xstd_pr(1),xstd_pr(2)

  do jlev = 1,5
    read(nulstat, '(A)') ligne
    write(*, '(A)') ligne
  enddo

  read(nulstat, * ) xstd_sc(1)
  write(*, '(f8.3)' )  xstd_sc(1)

  read(nulstat, '(A)') ligne
  write(*, '(A)') ligne

  do icodtyp = 1,9
    do jlev = 1,4
      read(nulstat, '(A)') ligne
      write(*, '(A)') ligne
    enddo
    read(nulstat, * ) (xstd_sf(icodtyp,jelm), jelm=1,4)
    write(*, '(f6.2,2f6.1,f8.3)' )  (xstd_sf(icodtyp,jelm), jelm=1,4)
  enddo

  write(*, '(A)') ' '

  CLOSE(UNIT=NULSTAT)
  IERR=FCLOS(NULSTAT)    

  end subroutine oer_read_obs_erreurs_conv

!-----------------------------------------------------------------------------------------
!-----------------------------------------------------------------------------------------


  subroutine oer_fill_obs_erreurs(lobsSpaceData) 1,62
  !
  ! s/r oer_fill_obs_erreurs -FILL OBSERVATION ERRORS IN lobsSpaceData
  !
  ! Author  : S. Laroche  February 2014
  ! Revision: 
  !          
  !
  ! Purpose: read observation errors (modification of former readcovo subroutine).
  !
  !

  implicit none

  type(struct_obs) :: lobsSpaceData

  integer :: JN, JI, INDEX_BODY, INDEX_HEADER, ITYP, IFLG, IASS, IDATA, IDATEND, IDBURP
  integer :: ISAT, ICHN, IPLATF, INSTR, IPLATFORM, INSTRUM
  integer :: ielem,icodtyp
  real(8) :: ZLAT, ZLON, ZLEV, ZVAL, zwb, zwt

  CHARACTER(len=2) :: SENSORTYPE,CFAM

  !
  !     ========================================================================== 
  !
  WRITE(*,'(10X,"Fill_obs_errors")')
  WRITE(*,'(10X,"-----------------",/)')
  WRITE(*,'(10X,"***********************************")')
  WRITE(*,'(10X,"Fill_obs_errors:",/)')
  WRITE(*,'(10X,"***********************************")')

  !
  !     SET STANDARD DEVIATION ERRORS FOR EACH DATA FAMILY
  !     ---------------------------------------------------
  !
  DO INDEX_HEADER = 1, obs_numheader(lobsSpaceData)

     IDATA   = obs_headElem_i(lobsSpaceData,OBS_RLN,INDEX_HEADER)
     IDATEND = obs_headElem_i(lobsSpaceData,OBS_NLV,INDEX_HEADER) + IDATA - 1
     CFAM    = obs_getFamily(lobsSpaceData,INDEX_HEADER)
     ZLAT    = obs_headElem_r(lobsSpaceData,OBS_LAT,INDEX_HEADER)
     ZLON    = obs_headElem_r(lobsSpaceData,OBS_LON,INDEX_HEADER)
     IDBURP  = obs_headElem_i(lobsSpaceData,OBS_ITY,INDEX_HEADER)
     IPLATF  = obs_headElem_i(lobsSpaceData,OBS_SAT,INDEX_HEADER)
     INSTR   = obs_headElem_i(lobsSpaceData,OBS_INS,INDEX_HEADER)

     DO INDEX_BODY  = IDATA, IDATEND

      ITYP  = obs_bodyElem_i(lobsSpaceData,OBS_VNM,INDEX_BODY)
      IFLG  = obs_bodyElem_i(lobsSpaceData,OBS_FLG,INDEX_BODY)
      IASS  = obs_bodyElem_i(lobsSpaceData,OBS_ASS,INDEX_BODY)
      ZVAL  = obs_bodyElem_r(lobsSpaceData,OBS_VAR,INDEX_BODY)

      IF ( IASS .EQ. 1 ) THEN

  !***********************************************************************
  !                           TOVS DATA
  !***********************************************************************

        IF ( CFAM .EQ. 'TO' ) THEN

         IF ( ITYP .EQ. BUFR_NBT1 .OR. &
              ITYP .EQ. BUFR_NBT2 .OR. &
              ITYP .EQ. BUFR_NBT3     )THEN

            ICHN = NINT(obs_bodyElem_r(lobsSpaceData,OBS_PPP,INDEX_BODY))
            CALL MAP_SAT(IPLATF,IPLATFORM,ISAT)
            CALL MAP_INSTRUM(INSTR,INSTRUM,SENSORTYPE)

             DO JN = 1, NSENSORS
                IF ( IPLATFORM .EQ.   PLATFORM(JN) .AND. &
                          ISAT .EQ.  SATELLITE(JN) .AND. &
                       INSTRUM .EQ. INSTRUMENT(JN)      ) THEN
                    call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,TOVERRST(ICHN,JN))
                ENDIF
             ENDDO

         ENDIF

  !***********************************************************************
  !                      RADIOSONDE DATA
  !***********************************************************************

        ELSE IF ( CFAM .EQ. 'UA' ) THEN

         ZLEV = obs_bodyElem_r(lobsSpaceData,OBS_PPP,INDEX_BODY)

         IF ( (ITYP .EQ. BUFR_NEUS) .OR. (ITYP .EQ. BUFR_NEVS) )THEN
            call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_sf(1,4))
         ELSE IF (ITYP .EQ. BUFR_NETS) THEN
            call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_sf(1,2))
         ELSE IF (ITYP .EQ. BUFR_NESS) THEN
            call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_sf(1,3))
         ELSE IF (ITYP .EQ. BUFR_NEPS ) THEN
            call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_sf(1,1))
         ELSE IF (ITYP .EQ. BUFR_NEPN ) THEN
            call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_sf(1,1))
         ELSE

            if ( (ITYP .EQ. BUFR_NEUU) .OR. (ITYP .EQ. BUFR_NEVV) ) then
              ielem = 4
            else if (ITYP .EQ. BUFR_NETT) then
              ielem = 2
            else if (ITYP .EQ. BUFR_NEES) then
              ielem = 3
            else if (ITYP .EQ. BUFR_NEGZ) then
              ielem = 5
            endif

            if ( (ZLEV*MPC_MBAR_PER_PA_R8) >= xstd_ua_ai_sw(1,1) ) then

               call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_ua_ai_sw(1,ielem))

            else if ( (ZLEV*MPC_MBAR_PER_PA_R8) <= xstd_ua_ai_sw(19,1) ) then

               call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_ua_ai_sw(19,ielem))

            else

               do jn = 1,18
                   if ( (ZLEV*MPC_MBAR_PER_PA_R8) >= xstd_ua_ai_sw(jn+1,1) ) exit
               end do

               zwb = log((ZLEV*MPC_MBAR_PER_PA_R8)/xstd_ua_ai_sw(JN,1)) / log(xstd_ua_ai_sw(JN+1,1)/xstd_ua_ai_sw(JN,1))
               zwt = 1.0D0 - zwb

               call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,zwt*xstd_ua_ai_sw(JN,ielem) + zwb*xstd_ua_ai_sw(JN+1,ielem))

            endif

         ENDIF

  !***********************************************************************
  !                          AMV, AIREP, AMDAR DATA
  !***********************************************************************

        ELSE IF ( CFAM .EQ. 'AI'.OR. CFAM .EQ. 'SW') THEN

         ZLEV=obs_bodyElem_r(lobsSpaceData,OBS_PPP,INDEX_BODY)

         IF ( IDBURP .EQ. 188 ) THEN ! AMV
            if ( (ITYP .EQ. BUFR_NEUU) .OR. (ITYP .EQ. BUFR_NEVV) ) then
               ielem = 11
            endif

         ELSE IF (IDBURP .EQ. 128 ) THEN ! AIREP
            if ( (ITYP .EQ. BUFR_NEUU) .OR. (ITYP .EQ. BUFR_NEVV) ) then
               ielem = 7
            else if ( ITYP .EQ. BUFR_NETT ) then
               ielem = 6
            endif

         ELSE IF (IDBURP .EQ. 42 .OR. IDBURP .EQ. 157 .OR. IDBURP .EQ. 177) THEN ! AMDAR
            if ( (ITYP .EQ. BUFR_NEUU) .OR. (ITYP .EQ. BUFR_NEVV) ) then
               ielem = 10
            else if ( ITYP .EQ. BUFR_NETT ) then
               ielem = 8
            else if ( ITYP .EQ. BUFR_NEES ) then
               ielem = 9
            endif

         ENDIF

         if ( (ZLEV*MPC_MBAR_PER_PA_R8) >= xstd_ua_ai_sw(1,1) ) then
            call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_ua_ai_sw(1,ielem))
         else if ( (ZLEV*MPC_MBAR_PER_PA_R8) <= xstd_ua_ai_sw(19,1) ) then
            call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_ua_ai_sw(19,ielem))
         else

            do jn = 1,18
               if ( (ZLEV*MPC_MBAR_PER_PA_R8) >= xstd_ua_ai_sw(jn+1,1) ) exit
            enddo

            zwb = log((ZLEV*MPC_MBAR_PER_PA_R8)/xstd_ua_ai_sw(JN,1)) / log(xstd_ua_ai_sw(JN+1,1)/xstd_ua_ai_sw(JN,1))
            zwt = 1.0D0 - zwb 

            call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,zwt*xstd_ua_ai_sw(JN,ielem) + zwb*xstd_ua_ai_sw(JN+1,ielem))

         endif

  !***********************************************************************
  !                         SURFACE DATA
  !***********************************************************************

        ELSE IF ( CFAM .EQ. 'SF' ) THEN
                               icodtyp = 1   ! Default values
        IF ( IDBURP .EQ. 12  ) icodtyp = 2   ! SYNOP
        IF ( IDBURP .EQ. 13  ) icodtyp = 3   ! SHIP NON-AUTOMATIQUE
        IF ( IDBURP .EQ. 14  ) icodtyp = 4   ! DRIBU
        IF ( IDBURP .EQ. 18  ) icodtyp = 5   ! DRIFTER
        IF ( IDBURP .EQ. 145 ) icodtyp = 6   ! STATION AUTOMATIQUE
        IF ( IDBURP .EQ. 146 ) icodtyp = 7   ! ASYNOP
        IF ( IDBURP .EQ. 147 ) icodtyp = 8   ! ASHIP
        IF ( (ITYP .EQ. BUFR_NEUU) .OR. (ITYP .EQ. BUFR_NEVV) .OR. &
             (ITYP .EQ. BUFR_NEGZ) .OR. (ITYP .EQ. BUFR_NETT) .OR. (ITYP .EQ. BUFR_NEES) ) icodtyp = 9  ! Others

        IF ( (ITYP .EQ. BUFR_NEUS) .OR. (ITYP .EQ. BUFR_NEVS) )THEN
           call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_sf(icodtyp,4))
        ELSE IF (ITYP .EQ. BUFR_NETS) THEN
           call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_sf(icodtyp,2))
        ELSE IF (ITYP .EQ. BUFR_NESS) THEN
           call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_sf(icodtyp,3))
        ELSE IF (ITYP .EQ. BUFR_NEPS ) THEN
           call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_sf(icodtyp,1))
        ELSE IF (ITYP .EQ. BUFR_NEPN ) THEN
           if(icodtyp == 2  .or. icodtyp == 7) then
            call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_sf(1,1))
           else
            call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_sf(icodtyp,1))
           endif
        ELSE IF ( (ITYP .EQ. BUFR_NEUU) .OR. (ITYP .EQ. BUFR_NEVV) )THEN
           call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_sf(icodtyp,4))
        ELSE IF (ITYP .EQ. BUFR_NEGZ) THEN
           call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_sf(icodtyp,1))
        ELSE IF (ITYP .EQ. BUFR_NETT) THEN
           call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_sf(icodtyp,2))
        ELSE IF (ITYP .EQ. BUFR_NEES) THEN
           call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_sf(icodtyp,3))
        ENDIF

  !***********************************************************************
  !                             GPS RO DATA
  !***********************************************************************

        ELSE IF ( CFAM .EQ. 'RO' ) THEN
  !     
  !                 Process only refractivity data (codtyp 169)
  !
         IF ( obs_headElem_i(lobsSpaceData,OBS_ITY,INDEX_HEADER) .EQ. 169 ) THEN

            IF ( ITYP .EQ. BUFR_NEPS ) THEN
               call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY, 50.D0)
            ENDIF
            IF ( ITYP .EQ. BUFR_NETT) THEN
               call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY, 10.D0)
            ENDIF
            IF ( ITYP .EQ. BUFR_NERF) THEN
               call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,1001.D0)
            ENDIF
            IF ( ITYP .EQ. BUFR_NEBD) THEN
               call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,1001.D0)
            ENDIF

         ENDIF

  !***********************************************************************
  !                          GB-GPS SFC MET DATA
  !***********************************************************************

  !              ERRORS ARE SET TO SYNO SFC OBS ERRORS FROM S/R SUCOVO
  !              AND WEIGHTED BY FACTOR YSFERRWGT FOR 3D-VAR FGAT OR 4D-VAR ASSIM.
  !              OF TIME-SERIES (YSFERRWGT = 1.0 FOR 3D THINNING) 
  !
        ELSE IF ( CFAM .EQ. 'GP' ) THEN

         IF ( ITYP .EQ. BUFR_NEPS ) THEN ! Psfc Error (Pa)
            call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_sf(2,1))
         ENDIF
         IF ( ITYP .EQ. BUFR_NETS ) THEN ! Tsfc Error (K)
            call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_sf(2,2))
         ENDIF
         IF ( ITYP .EQ. BUFR_NESS ) THEN ! T-Td Error (K)
            call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_sf(2,3))
         ENDIF
         ! ZTD Error (m) (value is formal error, real error set later in s/r seterrgpsgb)
         ! If error is missing, set to dummy value (1 m).
         IF ( ITYP .EQ. BUFR_NEZD ) THEN
            IF (obs_bodyElem_r(lobsSpaceData,OBS_OER,INDEX_BODY) .LE. 0.0D0) call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY, 1.0D0)
         ENDIF

  !***********************************************************************
  !        SCATTEROMETER, OZONE, WIND PROFILER DATA
  !***********************************************************************

        ELSE IF ( CFAM .EQ. 'SC' ) THEN

           call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_sc(1))

        ELSE IF ( CFAM .EQ. 'OZ' ) THEN

           call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,0.6D0*obs_bodyElem_r(lobsSpaceData,OBS_VAR,INDEX_BODY))

        ELSE IF ( CFAM .EQ. 'PR' ) THEN

          ZLEV= obs_bodyElem_r(lobsSpaceData,OBS_PPP,INDEX_BODY) - obs_headElem_r(lobsSpaceData,OBS_ALT,INDEX_HEADER)

          IF ( ZLEV .GE. 6000. ) THEN
             call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_pr(2))
          ELSE
             call obs_bodySet_r(lobsSpaceData,OBS_OER,INDEX_BODY,xstd_pr(1))
          ENDIF

        ELSE

           WRITE(*,*)' UNKNOWN DATA FAMILY:',CFAM

        ENDIF

  !***********************************************************************
  !              Check for case where error should have been set but was
  !              not. 3dvar will abort in this case.
  !***********************************************************************

        IF (obs_bodyElem_r(lobsSpaceData,OBS_OER,INDEX_BODY) .LE. 0.0D0) THEN

          WRITE(*,*)'  PROBLEM OBSERR VARIANCE FAM= ',CFAM

          WRITE(*,'(1X,"STNID= ",A10,"IDBURP= ",I5," LAT= ",F10.2," LON = ",F10.2)') &
             obs_elem_c(lobsSpaceData,'STID',INDEX_HEADER),    &
               IDBURP,                                           &
               ZLAT*MPC_DEGREES_PER_RADIAN_R8,                   &
               ZLON*MPC_DEGREES_PER_RADIAN_R8

          WRITE(*,'(1X,"ELEMENT= ",I6," LEVEL= ",F10.2," OBSERR = ",E10.2)')         &
               ITYP,                                             &
               obs_bodyElem_r(lobsSpaceData,OBS_PPP,INDEX_BODY), &
               obs_bodyElem_r(lobsSpaceData,OBS_OER,INDEX_BODY)

          CALL ABORT3D('oer_fill_obs_erreurs: PROBLEM OBSERR VARIANCE.')

        ENDIF

      ENDIF ! end of IASS .EQ. 1

    END DO ! end of INDEX_BODY loop 

  END DO ! end of INDEX_HEADER loop

  WRITE(*,'(10X,"Fill_obs_errors")')
  WRITE(*,'(10X,"---------------",/)')

  end subroutine oer_fill_obs_erreurs

!-----------------------------------------------------------------------------------------

end module observation_erreurs_mod