!-------------------------------------- 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 --------------------------------------
!

      SUBROUTINE SETERRGPSGB(lobsSpaceData,ldata) 1,24
*
*s/r SETERRGPSGB - SET OBSERVATION ERROR COVARIANCES FOR GB-GPS ZTD DATA
*
*Author  : S. Macpherson  March 2013
*Revision: 
*
*
**    Purpose:
*             - initialize observation error standard deviations for GB-GPS ZTD data
*               (GPS sfc met errors are set before in s/r SUCOVO (SETERR))
*             - returns ldata=.false. if no GPS ZTD data to assimilate
*               and also sets modgpsztd_mod variable numGPSZTD = 0.
*
      use EarthConstants_mod
      use MathPhysConstants_mod
      use obsSpaceData_mod
      use bufr
      use modgpsztd_mod
      IMPLICIT NONE
C
C NOTE: YZDERRWGT IN modgpsztd_mod (FROM NML FILE) IS USED FOR ERROR WEIGHTING
C       OF TIME SERIES (FGAT) GPS ZTD OBSERVATIONS TO ACCOUNT FOR TEMPORAL ERROR
C       CORRELATIONS.
C
      type(struct_obs) :: lobsSpaceData
      logical          :: ldata

      INTEGER INDEX_BODY, INDEX_HEADER, ITYP, IASS, IZTDJ, NBRPDATE, ICOUNT
      integer ielem, imonth

      LOGICAL LLCZTDE, LLFER, LLFZTDE, LLZTD, LLRZTDE, ASSIM, ERRSET, DEBUG

C
      REAL*8  ZTDERR, ZZTD, ZMINZDE, ZPSFC, ZHD, ZWD, ZTDOER, ZLEV, ZVAL
     
C
C     ZZDERMIN = MIN ZTD OER VALUE (M), ZZFERREJ = MAX FERR VALUE (M) FOR REJECTION
C     ZZDERMAX = MAX ZTD OER VALUE (M)
C     ZTDERFAC = MULTIPLICATION FACTOR FOR FORMAL ZTD MEASUREMENT ERROR
C     ZOPEFAC  = FRACTION OF REGRESSION EQUATION SD(O-P) TO USE AS ZTD OBSERVATION ERROR
C     ----------------------------------------------------------------------------------
C
      REAL*8 ZZDERMIN, ZZFERREJ, ZZDERMAX, ZTDERFAC, ZOPEFAC
      DATA ZZDERMIN /0.004D0/
      DATA ZZFERREJ /0.015D0/
      DATA ZZDERMAX /0.030D0/
      DATA ZTDERFAC /3.0D0/
      DATA ZOPEFAC  /1.0D0/
C
C     FOR ESTIMATION OF PSFC (IF MISSING)
C       ZGAMMA = (NEG. OF) TEMPERATURE LAPSE RATE (K/M)
C       ZPSMSL = STANDARD ATMOSPHERE MEAN SEA LEVEL PRESSURE (Pa)
C       ZTSFC  = REFERENCE SURFACE TEMPERATURE (K)
C
      REAL*8 ZGAMMA, ZPSMSL, ZTSFC
      DATA ZGAMMA /0.0065D0/
      DATA ZPSMSL /101300.0D0/
      DATA ZTSFC  /280.0D0/
C
C     MONTHLY LINEAR REGRESSION EQUATION CONSTANTS AND COEFF FOR ZTD ERROR (SD(O-P))
c     - Gives ZTDerror (mm) [SD(O-P)] as function of ZWD (m).
C     - From NOAA network NRT monthly monitoring stats 2008-2010
c
      REAL*8 ZRCONST(12), ZRCOEFF(12)
      DATA  ZRCONST / 2.6D0, 2.8D0, 2.1D0, 3.3D0, 5.1D0, 8.4D0, 12.8D0,
     &                9.9D0, 7.8D0, 2.6D0, 2.4D0, 2.5D0 /
      DATA  ZRCOEFF / 102.4D0, 96.5D0, 110.3D0, 101.2D0, 83.9D0,
     &                 73.5D0, 54.3D0, 64.0D0, 62.4D0, 98.0D0,
     &                 99.4D0, 101.5D0 /
C
C
      WRITE(*,*) 'ENTER SETERRGPSGB'
C
      DEBUG = .FALSE.

      LLCZTDE = .FALSE.
      LLRZTDE = .FALSE.
      LLFZTDE = .FALSE.
      IF (YZTDERR .LT. 0.0D0) THEN
         LLFZTDE = .TRUE.
      ELSE IF (YZTDERR .GT. 0.0D0) THEN
         LLCZTDE = .TRUE.
      ELSE
         LLRZTDE = .TRUE.
      ENDIF
      
      ldata = .false.
      ICOUNT = 0
C
C     Loop over all header indices of the 'GP' family:
C
      call obs_set_current_header_list(lobsSpaceData,'GP')
      HEADER: DO
         index_header = obs_getHeaderIndex(lobsSpaceData)
         if (index_header < 0) exit HEADER
         NBRPDATE  = obs_headElem_i(lobsSpaceData,OBS_DAT,INDEX_HEADER)
         LLZTD     = .FALSE.
         LLFER     = .FALSE.
         ASSIM     = .FALSE.
         ERRSET    = .FALSE.
         ZZTD      = -1.0D0
         ZPSFC     = -1.0D0
c      Get the month
         imonth = INT(nbrpdate/100.0)
         imonth = MOD(imonth,100)
         if ( imonth .lt. 1 .or. imonth .gt. 12 ) then
           CALL ABORT3D('SETERRGPSGB: imonth is out of range!')
         endif
c
C    Loop over all body indices of current report; Set the ZTD error if
C    constant value specified (LLCZTDE=true).
c
         call obs_set_current_body_list(lobsSpaceData, INDEX_HEADER)
         BODY: DO 
            index_body = obs_getBodyIndex(lobsSpaceData)
            if (index_body < 0) exit BODY
            ITYP   = obs_bodyElem_i(lobsSpaceData,OBS_VNM,INDEX_BODY)
            IASS   = obs_bodyElem_i(lobsSpaceData,OBS_ASS,INDEX_BODY)
            ZVAL   = obs_bodyElem_r(lobsSpaceData,OBS_VAR,INDEX_BODY)
C         Store Psfc
            IF ( ITYP .EQ. BUFR_NEPS ) THEN
                IF ( ZVAL .GT. 0.0D0 ) ZPSFC = ZVAL
            ENDIF
C         Set ZTDOER to constant value (if LLCZTDE); get value of ZTD, 
C         ZTD formal error and antenna height.
            IF ( ITYP .EQ. BUFR_NEZD ) THEN
                IF ( LLCZTDE ) THEN
                  ZTDOER = YZTDERR
                  ERRSET = .TRUE.
                ENDIF
                ZLEV   = obs_bodyElem_r(lobsSpaceData,OBS_PPP,INDEX_BODY)
                ZTDERR = obs_bodyElem_r(lobsSpaceData,OBS_OER,INDEX_BODY)
                IF ( ZTDERR .NE. 1.0D0 ) LLFER = .TRUE.
                IZTDJ = INDEX_BODY
                IF ( ZVAL .GT. 0.0D0 ) THEN
                  ZZTD = ZVAL
                  LLZTD = .TRUE.
                ENDIF
                IF ( IASS .EQ. 1 ) ASSIM = .TRUE.
            ENDIF
         ENDDO BODY

c      Replace formal ZTD error with real error for all ZTD to be assimilated

         IF ( ASSIM ) THEN
           IF ( LLZTD ) THEN
             ldata = .true.
             ICOUNT = ICOUNT + 1
             IF ( .NOT. ERRSET ) THEN
c             If Psfc is missing, estimate the pressure based on station height using
c             hydrostatic approx. and assumed MSL pressure ZPSMSL and temperature ZTSFC
                IF ( ZPSFC .LT. 0.0D0 ) THEN
                  ZPSFC  = ZPSMSL *
     &                (1.0D0-(ZGAMMA/ZTSFC)*ZLEV)**(RG/(MPC_RGAS_DRY_AIR_R8*ZGAMMA))
                ENDIF
c               Compute the hydrostatic delay ZHD (m) from Psfc (Pa)
                ZHD = 2.2766D-05 * ZPSFC
c               Compute the wet delay (m) from ZTD and ZHD
                IF ( ZHD .GT. ZZTD ) THEN
                  ZWD = 0.0D0
                ELSE
                  ZWD = ZZTD - ZHD
                ENDIF
C             Compute ZTD error as a function of ZWD using regression coeff (SD(O-P) vs ZWD).
c             Take fraction ZOPEFAC of computed error and convert from mm to m.
c             Ensure error is > ZZDERMIN and < ZZDERMAX
                ZMINZDE = ZRCONST(imonth) + ZRCOEFF(imonth)*ZWD
                ZMINZDE = ZMINZDE * ZOPEFAC * 0.001D0
                IF (LLRZTDE) THEN
                  ZTDOER = MAX(ZZDERMIN, ZMINZDE)
                  ZTDOER = MIN(ZZDERMAX, ZTDOER)
                ELSE
                  IF (LLFER) THEN
                    ZTDOER = MAX(ZZDERMIN, ZTDERR*ZTDERFAC)
                  ELSE
                    ZTDOER = MAX(ZZDERMIN, ZMINZDE)
                    ZTDOER = MIN(ZZDERMAX, ZTDOER)
                  ENDIF
                ENDIF
C  Ensure that error is not less than formal error ZTDERR
                IF (LLFER) THEN
                  IF (DEBUG .AND. ICOUNT .LE. 50) THEN
                    WRITE(*,*) obs_elem_c(lobsSpaceData,'STID',INDEX_HEADER),
     &               ' FORMAL ERR, OBS ERROR (mm) = ', 
     &               ZTDERR*1000.D0, ZTDOER*1000.D0
                  ENDIF
                  ZTDOER = MAX(ZTDOER, ZTDERR)
                ENDIF
             ENDIF
C  *** APPLY TIME-SERIES WEIGHTING FACTOR TO OBSERVATION ERROR (YZDERRWGT=1 FOR 3D THINNING)
             call obs_bodySet_r(lobsSpaceData,OBS_OER,IZTDJ, ZTDOER*YZDERRWGT)
           ELSE
               CALL ABORT3D('SETERRGPSGB: ERROR:NEGATIVE ZTD VALUE!')
           ENDIF
         ENDIF
         
         IF (DEBUG .AND. ICOUNT .LE. 50) THEN
            WRITE(*,*) 'TAG  SITE  ITYP  IASS  VAR  OER'
            call obs_set_current_body_list(lobsSpaceData, INDEX_HEADER)
            BODY2: DO 
              index_body = obs_getBodyIndex(lobsSpaceData)
              if (index_body < 0) exit BODY2
              ITYP   = obs_bodyElem_i(lobsSpaceData,OBS_VNM,INDEX_BODY)
              IASS   = obs_bodyElem_i(lobsSpaceData,OBS_ASS,INDEX_BODY)
              ZVAL   = obs_bodyElem_r(lobsSpaceData,OBS_VAR,INDEX_BODY)
              ZTDERR = obs_bodyElem_r(lobsSpaceData,OBS_OER,INDEX_BODY)
              WRITE(*,*) 'ERRDEBUG ', obs_elem_c(lobsSpaceData,'STID',INDEX_HEADER),
     &          ITYP, IASS, ZVAL, ZTDERR     
            ENDDO BODY2
         ENDIF
         
c
      ENDDO HEADER

c      IF (DEBUG) CALL ABORT3D('******DEBUG STOP*******')
      
      IF (.not.ldata) numGPSZTD = 0
      
      IF (ldata) WRITE(*,*) ' numGPSZTD = ', ICOUNT
      
      WRITE(*,*) 'EXIT SETERRGPSGB'
      
      RETURN

      END SUBROUTINE SETERRGPSGB