!-------------------------------------- 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 SETFGEDIF(CDFAM,lcolumng,lobsSpaceData) 2,46
!*
!***s/r SETFGEDIF - Interpolation of THE FIRST GUESS ERROR VARIANCES
!* for data derived through the diff self-differencing variables
!*
!*
!*Author : J.M. Aparicio *MSC/ARMA Nov 2004
!* Adapted Nov 2012 for both refractivity and bending angle data
!*
!** Purpose: -Construct the FIRST GUESS ERROR VARIANCES from the
!* diff-calculated dependencies and the primary errors.
!*
use EarthConstants_mod
use MathPhysConstants_mod
use modgps00base
, only : ngpscvmx
use modgps01ctphys
, only : p_TC, p_knot
use modgps02wgs84grav
, only : gpsgravitysrf
use modgps03diff
use modgps04profile
, only : gpsprofile, gpsstruct1sw
use modgps08refop
, only : gpsrefopv
use modgps09bend
, only : gpsbndopv1
use modgpsro_mod
use obsSpaceData_mod
use columnData_mod
IMPLICIT NONE
!C
type(struct_columnData) :: lcolumng
type(struct_obs) :: lobsSpaceData
!C
INTEGER INDEX_HEADER, IDATYP, INDEX_BODY, iProfile
CHARACTER*2 CDFAM
REAL*8 zLat, Lat, sLat
REAL*8 zLon, Lon
REAL*8 zAzm, Azm
INTEGER IAZM, ISAT
REAL*8 Rad, Geo, WFGPS
REAL*8, allocatable :: zPP(:)
REAL*8, allocatable :: zDP(:)
REAL*8, allocatable :: zTT(:)
REAL*8, allocatable :: zHU(:)
REAL*8, allocatable :: zUU(:)
REAL*8, allocatable :: zVV(:)
INTEGER JF, stat
INTEGER JL, JJ
REAL*8 ZP0, ZMT
REAL*8 HNH1, ZFGE, ZERR
INTEGER JV, NGPSLEV, NWNDLEV
LOGICAL ASSIM, LFIRST, FIRSTHEADER
INTEGER NH, NH1
! REAL*8 JAC(ngpscvmx)
REAL*8 DV (ngpscvmx)
TYPE(GPSPROFILE) :: PRF
REAL*8 , allocatable :: H (:),AZMV(:)
TYPE(GPSDIFF), allocatable :: RSTV(:),RSTVP(:),RSTVM(:)
type(struct_vco), pointer :: vco_anl
WRITE(*,*)'ENTER SETFGEDIFF'
!C
!C * 1. Initializations
!C * ---------------
!C
NGPSLEV=col_getNumLev
(lcolumng,'TH')
NWNDLEV=col_getNumLev
(lcolumng,'MM')
LFIRST=.FALSE.
if ( .NOT.allocated(vGPSRO_Jacobian) ) then
LFIRST = .TRUE.
allocate(zPP (NGPSLEV))
allocate(zDP (NGPSLEV))
allocate(zTT (NGPSLEV))
allocate(zHU (NGPSLEV))
allocate(zUU (NGPSLEV))
allocate(zVV (NGPSLEV))
allocate(vGPSRO_Jacobian(numGPSROProfiles,GPSRO_MAXPRFSIZE,2*NGPSLEV+1))
allocate(vGPSRO_lJac (numGPSROProfiles))
vGPSRO_lJac=.false.
allocate( H (GPSRO_MAXPRFSIZE) )
allocate( AZMV (GPSRO_MAXPRFSIZE) )
allocate( RSTV (GPSRO_MAXPRFSIZE) )
!C IF (LEVELGPSRO.EQ.1) THEN
!C allocate( RSTVP(GPSRO_MAXPRFSIZE) )
!C allocate( RSTVM(GPSRO_MAXPRFSIZE) )
!C ENDIF
endif
vco_anl => col_getVco
(lcolumng)
!C
!C Loop over all header indices of the 'RO' family:
!C
call obs_set_current_header_list
(lobsSpaceData,CDFAM)
FIRSTHEADER=.TRUE.
HEADER: do
index_header = obs_getHeaderIndex
(lobsSpaceData)
if (index_header < 0) exit HEADER
!C
!C * Process only refractivity data (codtyp 169)
!C
IDATYP = obs_headElem_i
(lobsSpaceData,OBS_ITY,INDEX_HEADER)
IF ( IDATYP .EQ. 169 ) THEN
!C
!C * Scan for requested data values of the profile, and count them
!C
ASSIM = .FALSE.
NH = 0
call obs_set_current_body_list
(lobsSpaceData, INDEX_HEADER)
BODY: do
INDEX_BODY = obs_getBodyIndex(lobsSpaceData)
if (INDEX_BODY < 0) exit BODY
IF ( obs_bodyElem_i
(lobsSpaceData,OBS_ASS,INDEX_BODY).EQ.1 ) THEN
ASSIM = .TRUE.
NH = NH + 1
ENDIF
ENDDO BODY
!C
!C * If assimilations are requested, prepare and apply the observation operator
!C
IF (ASSIM) THEN
iProfile=iProfile_from_index
(INDEX_HEADER)
!C
!C * Profile at the observation location:
!C
if (.not.vGPSRO_lJac(iProfile)) then
!C
!C * Basic geometric variables of the profile:
!C
zLat = obs_headElem_r
(lobsSpaceData,OBS_LAT,INDEX_HEADER)
zLon = obs_headElem_r
(lobsSpaceData,OBS_LON,INDEX_HEADER)
IAZM = obs_headElem_i
(lobsSpaceData,OBS_AZA,INDEX_HEADER)
ISAT = obs_headElem_i
(lobsSpaceData,OBS_SAT,INDEX_HEADER)
Rad = obs_headElem_r
(lobsSpaceData,OBS_TRAD,INDEX_HEADER)
Geo = obs_headElem_r
(lobsSpaceData,OBS_GEOI,INDEX_HEADER)
zAzm = 0.01d0*IAZM / MPC_DEGREES_PER_RADIAN_R8
zMT = col_getHeight
(lcolumng,NGPSLEV,INDEX_HEADER,'TH')/RG
WFGPS= 0.d0
DO JJ=1,NUMGPSSATS
IF (ISAT.EQ.IGPSSAT(JJ)) WFGPS=WGPS(JJ)
ENDDO
Lat = zLat * MPC_DEGREES_PER_RADIAN_R8
Lon = zLon * MPC_DEGREES_PER_RADIAN_R8
Azm = zAzm * MPC_DEGREES_PER_RADIAN_R8
sLat = sin(zLat)
zMT = zMT * RG / gpsgravitysrf
(sLat)
zP0 = col_getElem
(lcolumng,1,INDEX_HEADER,'P0')
DO JL = 1, NGPSLEV
!C
!C * Profile x
!C
zPP(JL) = col_getPressure
(lcolumng,JL,INDEX_HEADER,'TH')
!C * True implementation of zDP (dP/dP0)
zDP(JL) = col_getPressureDeriv
(lcolumng,JL,INDEX_HEADER,'TH')
zTT(JL) = col_getElem
(lcolumng,JL,INDEX_HEADER,'TT') - p_TC
zHU(JL) = col_getElem
(lcolumng,JL,INDEX_HEADER,'HU')
zUU(JL) = 0.d0
zVV(JL) = 0.d0
ENDDO
DO JL = 1, NWNDLEV
zUU(JL) = col_getElem
(lcolumng,JL,INDEX_HEADER,'UU') * p_knot
zVV(JL) = col_getElem
(lcolumng,JL,INDEX_HEADER,'VV') * p_knot
ENDDO
zUU(NGPSLEV) = zUU(NWNDLEV)
zVV(NGPSLEV) = zUU(NWNDLEV)
!C
!C * GPS profile structure:
!C
call gpsstruct1sw
(ngpslev,zLat,zLon,zAzm,zMT,Rad,geo,zPP,zDP,zTT,zHU,zUU,zVV,prf)
!C
!C * Prepare the vector of all the observations:
!C
NH1 = 0
call obs_set_current_body_list
(lobsSpaceData, INDEX_HEADER)
BODY_2: do
INDEX_BODY = obs_getBodyIndex(lobsSpaceData)
if (INDEX_BODY < 0) exit BODY_2
IF ( obs_bodyElem_i
(lobsSpaceData,OBS_ASS,INDEX_BODY).EQ.1 ) THEN
NH1 = NH1 + 1
H(NH1) = obs_bodyElem_r
(lobsSpaceData,OBS_PPP,INDEX_BODY)
AZMV(NH1)= zAzm
ENDIF
ENDDO BODY_2
!C
!C * Apply the observation operator:
!C
IF (LEVELGPSRO.EQ.1) THEN
CALL GPSBNDOPV1
(H , AZMV, NH, PRF, RSTV)
!C CALL GPSBNDOPV1(H+WFGPS, AZMV, NH, PRF, RSTVP)
!C CALL GPSBNDOPV1(H-WFGPS, AZMV, NH, PRF, RSTVM)
!C do nh1 = 1, nh
!C RSTV(nh1)=(RSTVP(nh1)+RSTV(nh1)+RSTVM(nh1))/3.d0
!C enddo
ELSE
CALL GPSREFOPV
(H, NH, PRF, RSTV)
ENDIF
DO NH1=1,NH
vGPSRO_Jacobian(iProfile,NH1,:)= RSTV(NH1)%DVAR(1:2*NGPSLEV+1)
ENDDO
vGPSRO_lJac(iProfile)=.true.
endif
!C
!C * Local error
!C
DO JL = 1, NGPSLEV
DV ( JL) = 1.d0
DV (NGPSLEV+JL) = 1.d0
ENDDO
DV (2*NGPSLEV+1) = 2.d0
!C
!C * Perform the H(xb)DV operation:
!C
NH1 = 0
call obs_set_current_body_list
(lobsSpaceData, INDEX_HEADER)
BODY_3: do
INDEX_BODY = obs_getBodyIndex(lobsSpaceData)
if (INDEX_BODY < 0) exit BODY_3
IF ( obs_bodyElem_i
(lobsSpaceData,OBS_ASS,INDEX_BODY).EQ.1 ) THEN
NH1 = NH1 + 1
!C
!C * Observation jacobian
!C
! JAC = RSTV(NH1)%DVAR
!C
!C * Evaluate sqrt( H(xb)DV **2 )
!C
ZFGE = 0.d0
DO JV = 1, 2*PRF%NGPSLEV+1
ZFGE = ZFGE + (vGPSRO_Jacobian(iProfile,NH1,JV) * DV(JV))**2
ENDDO
ZFGE = SQRT(ZFGE)
ZERR = obs_bodyElem_r
(lobsSpaceData,OBS_OER,INDEX_BODY)
!C
!C * FIRST GUESS ERROR VARIANCE
!C
call obs_bodySet_r
(lobsSpaceData,OBS_HPHT,INDEX_BODY,ZFGE)
IF (FIRSTHEADER) THEN
11 FORMAT(A12,2I5,F12.2,3F16.8)
WRITE(*,11)'SETFGEDIFFGE',NH1,NH,H(NH1),RSTV(NH1)%VAR,ZFGE,ZERR
ENDIF
ENDIF
ENDDO BODY_3
ENDIF
ENDIF
FIRSTHEADER = .FALSE.
ENDDO HEADER
IF (LFIRST) THEN
!C IF (LEVELGPSRO.EQ.1) THEN
!C deallocate( RSTVM )
!C deallocate( RSTVP )
!C ENDIF
deallocate( RSTV )
deallocate( AZMV )
deallocate( H )
deallocate(zVV)
deallocate(zUU)
deallocate(zHU)
deallocate(zTT)
deallocate(zDP)
deallocate(zPP)
ENDIF
WRITE(*,*)'EXIT SETFGEDIFF'
RETURN
END SUBROUTINE SETFGEDIF