37       class(ufo_gnssro_bndGSI), 
intent(in)    :: self
    38       type(ufo_geovals),        
intent(in)    :: geovals
    39       real(kind_real),          
intent(inout) :: hofx(:)
    40       type(c_ptr), 
value,       
intent(in)    :: obss
    42       character(len=*), 
parameter     :: myname_ =
"ufo_gnssro_bndgsi_simobs"    43       logical, 
parameter              :: use_compress = .true.
    44       real(kind_real), 
parameter      :: r1em6 = 1.0e-6_kind_real
    45       real(kind_real), 
parameter      :: r1em3 = 1.0e-3_kind_real
    46       real(kind_real), 
parameter      :: six   = 6.0_kind_real
    47       real(kind_real), 
parameter      :: ds    = 10000.0_kind_real
    48       integer, 
parameter              :: nlevAdd = 13 
    49       integer, 
parameter              :: newAdd  = 20 
    50       integer, 
parameter              :: ngrd    = 80 
    51       integer, 
parameter              :: max_string    = 800
    52       real(kind_real), 
parameter      :: miss_values   = -99999.00
    53       real(kind_real), 
parameter      :: crit_gradRefr = 157.0_kind_real 
    55       character(max_string)           :: err_msg
    56       integer                         :: iobs, ilev, igrd, klev
    57       integer                         :: nlev, nlev1, nobs, nlevExt, nlevCheck
    58       real(kind_real)                 :: rnlevExt
    59       real(kind_real)                 :: w4(4), dw4(4)
    61       type(ufo_geoval), 
pointer       :: t, gphi, prsi, q
    62       real(kind_real), 
allocatable    :: gesT(:,:), gesZi(:,:), gesPi(:,:), gesQ(:,:)
    63       real(kind_real), 
allocatable    :: refr(:,:), radius(:,:)
    64       real(kind_real), 
allocatable    :: refrIndex(:), refrXrad(:), geomzi(:), refrXrad_new(:)
    65       real(kind_real), 
allocatable    :: lagConst(:,:)
    66       real(kind_real), 
allocatable    :: obsLat(:), obsImpP(:), obsLocR(:), obsGeoid(:)
    67       real(kind_real)                 :: specHmean, tmean
    68       real(kind_real)                 :: d_refrXrad
    69       real(kind_real)                 :: derivRefr_s(ngrd),grids(ngrd),refrXrad_s(ngrd)
    70       real(kind_real)                 :: sIndx, sIndxExt
    72       real(kind_real)                 :: bndIntgd, bendingAngle, obsImpH, gradRefr
    73       logical                         :: obs_check, qc_layer_SR
    74       integer                         :: nobs_outIntgl
    75       integer                         :: count_SR, top_layer_SP, top_layer_SR, bot_layer_SR 
    76       integer                         :: count_rejection
    77        real(kind_real)                 :: jacob    
    86       if (geovals%nobs /= 
size(hofx)) 
then    87         write(err_msg,*) myname_, 
' error: nobs inconsistent!'    88         call abor1_ftn(err_msg)
    93          write(err_msg,*) myname_, trim(
var_prsi), 
' doesnt exist'    94          call abor1_ftn(err_msg)
    99          write(err_msg,*) myname_, trim(
var_t), 
' doesnt exist'   100          call abor1_ftn(err_msg)
   105          write(err_msg,*) myname_, trim(
var_q), 
' doesnt exist'   106          call abor1_ftn(err_msg)
   111          write(err_msg,*) myname_, trim(
var_zi), 
' doesnt exist'   112          call abor1_ftn(err_msg)
   118       if (nlev1 /= nlev+1) 
then   119          write(err_msg,*) myname_, 
' Numbers of vertical profiles, nlev1 and nlev, dont match'   120          call abor1_ftn(err_msg)
   122       nlevext = nlev + nlevadd
   123       nlevcheck = 
min(23, nlev) 
   126       allocate(gespi(nlev1,nobs)) 
   127       allocate(geszi(nlev1,nobs)) 
   128       allocate(gest(nlev,nobs)) 
   129       allocate(gesq(nlev,nobs)) 
   133          gest(ilev,:) = t%vals(nlev-ilev+1,:)
   134          gesq(ilev,:) = q%vals(nlev-ilev+1,:)
   138          gespi(ilev,:) = prsi%vals(nlev1-ilev+1,:)
   139          geszi(ilev,:) = gphi%vals(nlev1-ilev+1,:)
   143           grids(igrd+1) = igrd * ds
   146       allocate(geomzi(nlev))      
   147       allocate(radius(nlev,nobs)) 
   149       allocate(refr(nlevext,nobs))    
   150       allocate(refrindex(nlev))       
   151       allocate(refrxrad(0:nlevext+1)) 
   152       allocate(lagconst(3,nlevext))   
   153       allocate(refrxrad_new(nlevext+newadd))
   155       allocate(obslat(nobs))
   156       allocate(obsimpp(nobs))
   157       allocate(obslocr(nobs))
   158       allocate(obsgeoid(nobs))
   168       obs_loop: 
do iobs = 1, nobs 
   172             call geop2geometric( obslat(iobs), geszi(ilev,iobs), geomzi(ilev), jacob)
   175             radius(ilev,iobs) = geomzi(ilev) + obsgeoid(iobs) + obslocr(iobs)   
   179                spechmean = (gesq(ilev,iobs) + gesq(ilev-1,iobs))/
two   180                tmean = (gest(ilev,iobs) + gest(ilev-1,iobs) )/
two   182                spechmean = gesq(1,iobs)
   186             refrindex(ilev) = 
one + (r1em6*refr(ilev,iobs))         
   187             refrxrad(ilev)  = refrindex(ilev) * radius(ilev,iobs)   
   194          if (sindx < 
one .or. sindx > float(nlev)) 
then    195              count_rejection = count_rejection + 1
   204          obsimph = (obsimpp(iobs) - obslocr(iobs)) * r1em3 
   205          if (obsimph <= six) 
then   206             do klev=nlevcheck,1,-1
   209                gradrefr = 1000.0_kind_real * (refr(klev+1,iobs)-refr(klev,iobs)) / (radius(klev+1,iobs)-radius(klev,iobs))
   211                if (abs(gradrefr)>= 
half*crit_gradrefr) 
then     216                if (abs(gradrefr) >= 0.75_kind_real*crit_gradrefr) 
then     219                   if (count_sr > 1 ) 
then   224                      bot_layer_sr=top_layer_sr
   229             if (top_layer_sr >= 1 .and. obsimpp(iobs) <= refrxrad(top_layer_sr+2)) 
then    230                count_rejection = count_rejection + 1
   237          d_refrxrad = refrxrad(nlev) - refrxrad(nlev-1)
   239             refrxrad(nlev+ilev)=refrxrad(nlev)+ ilev*d_refrxrad 
   240             refr(nlev+ilev,iobs)=refr(nlev+ilev-1,iobs)**2/refr(nlev+ilev-2,iobs) 
   243          refrxrad(0)=refrxrad(3)
   244          refrxrad(nlevext+1)=refrxrad(nlevext-2)
   253          grids_loop: 
do igrd =1,ngrd
   255            refrxrad_s(igrd)=sqrt(grids(igrd)**2 + obsimpp(iobs)**2) 
   259            rnlevext = float(nlevext)
   261            if (sindx < rnlevext) 
then     267                    lagconst(:,indx),lagconst(:,indx+1),&
   270                  w4(4)=w4(4)+w4(1); w4(1:3)=w4(2:4);w4(4)=
zero   271                  dw4(4)=dw4(4)+dw4(1);dw4(1:3)=dw4(2:4);dw4(4)=
zero   274               if(indx==nlevext-1) 
then   275                  w4(1)=w4(1)+w4(4); w4(2:4)=w4(1:3);w4(1)=
zero   276                  dw4(1)=dw4(1)+dw4(4); dw4(2:4)=dw4(1:3);dw4(1)=
zero   280               derivrefr_s(igrd)=dot_product(dw4,refr(indx-1:indx+2,iobs)) 
   281               derivrefr_s(igrd)=
max(
zero,abs(derivrefr_s(igrd)))
   285               nobs_outintgl=nobs_outintgl+1
   286               d_refrxrad=refrxrad(nlev)-refrxrad(nlev-1)
   288                  refrxrad_new(nlevext+klev)=refrxrad(nlevext)+ klev*d_refrxrad 
   291                  refrxrad_new(klev)=refrxrad(klev)
   293               call get_coordinate_value(refrxrad_s(igrd), sindx,refrxrad_new(1:nlevext+newadd),nlevext+newadd,
"increasing")
   294               sindxext=
max(sindx,sindxext)
   299          bendingangle = ds*derivrefr_s(1)/refrxrad_s(1)
   301             bndintgd     = ds*derivrefr_s(igrd)/refrxrad_s(igrd)
   302             bendingangle = bendingangle + 
two*bndintgd
   304          bendingangle=r1em6 * obsimpp(iobs) * bendingangle
   305          hofx(iobs) = bendingangle
   309       write(6,*) 
'bndGSI: hofx ', &
   310                  'min = ', minval(hofx, mask=hofx > miss_values), 
'min index = ', minloc(hofx), &
   311                  'max = ', maxval(hofx, mask=hofx > miss_values), 
'max index = ', maxloc(hofx)
   312       write(6,*) 
'bndGSI: ', count_rejection, 
' out of ', nobs, 
' rejected due to model vertical range and super refraction'   315       if (nobs_outintgl>=1) 
then   316          write(6,*)
'bndGSI: Warning',nobs_outintgl,
'obs outside integration grid. Increase nlevExt to',&
   330       deallocate(refrindex) 
   335       deallocate(refrxrad_new) 
 subroutine, public ufo_geovals_get_var(self, varname, geoval, status)
real(fp), parameter, public zero
character(len=maxvarlen), public var_prsi
subroutine, public lag_interp_smthweights(x, xt, aq, bq, w, dw, n)
real(kind_real), parameter, public half
subroutine, public get_coordinate_value(fin, fout, x, nx, flag)
Fortran module to prepare for Lagrange polynomial interpolation. based on GSI: lagmod.f90. 
Fortran module to perform linear interpolation. 
real(fp), parameter, public one
character(len=maxvarlen), public var_q
real(fp), parameter, public two
subroutine ufo_gnssro_bndgsi_simobs(self, geovals, hofx, obss)
type(registry_t), public ufo_geovals_registry
Linked list interface - defines registry_t type. 
subroutine, public lag_interp_const(q, x, n)
Fortran module to handle gnssro bending angle observations following the NCEP/GSI (2018 Aug) implemen...
character(len=maxvarlen), public var_zi
character(len=maxvarlen), public var_t
Fortran interface to ObsSpace. 
Fortran derived type for gnssro trajectory.