UFO
ufo_gnssro_bndnbam_tlad_mod.F90
Go to the documentation of this file.
1 ! (C) Copyright 2017-2018 UCAR
2 !
3 ! This software is licensed under the terms of the Apache Licence Version 2.0
4 ! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5 !> Fortran module of Gnssro NBAM (NCEP's Bending Angle Method)
6 !> tlad operator
7 
9 use fckit_configuration_module, only: fckit_configuration
10 use kinds
11 use ufo_vars_mod
14 use obsspace_mod
15 use missing_values_mod
20 use fckit_log_module, only : fckit_log
21 
22 implicit none
23 real(c_double) :: missing
24 
25 !> Fortran derived type for gnssro trajectory
27  private
28  integer :: nlev, nlev1, nlocs, iflip, nrecs
29  real(kind_real), allocatable :: jac_t(:,:), jac_prs(:,:), jac_q(:,:)
30  integer, allocatable :: nlocs_begin(:), nlocs_end(:)
31  type(gnssro_conf) :: roconf
32 
33  contains
34  procedure :: setup => ufo_gnssro_bndnbam_tlad_setup
35  procedure :: delete => ufo_gnssro_bndnbam_tlad_delete
36  procedure :: settraj => ufo_gnssro_bndnbam_tlad_settraj
37  procedure :: simobs_tl => ufo_gnssro_bndnbam_simobs_tl
38  procedure :: simobs_ad => ufo_gnssro_bndnbam_simobs_ad
40 
41 contains
42 ! ------------------------------------------------------------------------------
43 subroutine ufo_gnssro_bndnbam_tlad_setup(self, f_conf)
44  implicit none
45  class(ufo_gnssro_bndnbam_tlad), intent(inout) :: self
46  type(fckit_configuration), intent(in) :: f_conf
47 
48  call gnssro_conf_setup(self%roconf,f_conf)
49 
50 end subroutine ufo_gnssro_bndnbam_tlad_setup
51 
52 ! ------------------------------------------------------------------------------
53 subroutine ufo_gnssro_bndnbam_tlad_settraj(self, geovals, obss)
56  use, intrinsic:: iso_c_binding
57  implicit none
58  class(ufo_gnssro_bndnbam_tlad), intent(inout) :: self
59  type(ufo_geovals), intent(in) :: geovals
60  type(c_ptr), value, intent(in) :: obss
61  character(len=*), parameter :: myname = "ufo_gnssro_bndnbam_tlad_settraj"
62  character(max_string) :: err_msg
63  integer, parameter :: nlevAdd = 13 !num of additional levels on top of exsiting model levels
64  integer, parameter :: newAdd = 20 !num of additional levels on top of extended levels
65  integer, parameter :: ngrd = 80 !num of new veritcal grids for bending angle computation
66  type(ufo_geoval), pointer :: t, q, gph, prs, zs
67  integer :: iobs,k,j, klev, irec, icount
68  integer :: nrecs
69  integer :: nlev, nlev1, nlocs, nlevExt, nlevCheck
70  real(kind_real) :: dw4(4), dw4_tl(4)
71  real(kind_real) :: geomzi
72  real(kind_real), allocatable :: obsLat(:), obsImpP(:), obsLocR(:), obsGeoid(:)
73  integer(c_size_t), allocatable :: obsRecnum(:)
74  real(kind_real) :: d_refXrad, gradRef
75  real(kind_real) :: d_refXrad_tl
76  real(kind_real) :: grids(ngrd)
77  real(kind_real) :: sIndx
78  integer :: indx
79  real(kind_real) :: p_coef, t_coef, q_coef
80  real(kind_real) :: fv, pw
81  real(kind_real) :: dbetaxi, dbetan
82  real(kind_real), allocatable :: lagConst(:,:), lagConst_tl(:,:)
83  real(kind_real), allocatable :: gesT(:,:), gesQ(:,:), gesP(:,:), gesH(:,:), gesZs(:)
84 
85  real(kind_real),allocatable :: radius(:), dzdh(:), refIndex(:)
86  real(kind_real), allocatable :: dhdp(:), dhdt(:)
87  real(kind_real), allocatable :: ref(:)
88  real(kind_real), allocatable :: refXrad(:)
89  real(kind_real), allocatable :: refXrad_s(:)
90  real(kind_real), allocatable :: refXrad_tl(:), ref_tl(:)
91  real(kind_real), allocatable :: dndp(:,:), dndt(:,:), dndq(:,:)
92  real(kind_real), allocatable :: dxidp(:,:), dxidt(:,:), dxidq(:,:)
93  real(kind_real), allocatable :: dbenddxi(:), dbenddn(:)
94  integer, allocatable :: super_refraction_flag(:)
95  integer, allocatable :: obsSRflag(:)
96  integer :: hasSRflag
97 
98  write(err_msg,*) myname, ": begin"
99  call fckit_log%info(err_msg)
100 
101 ! Make sure nothing already allocated
102  call self%delete()
103 
104  missing = missing_value(missing)
105  nlocs = obsspace_get_nlocs(obss) ! number of observations
106  nrecs = obsspace_get_nrecs(obss)
107  write(err_msg,*) myname, ': nlocs from gelvals and hofx, nrecs', nlocs, nrecs
108  call fckit_log%info(err_msg)
109 
110 if (nlocs > 0 ) then
111 ! get variables from geovals
112  call ufo_geovals_get_var(geovals, var_ts, t) ! air temperature
113  call ufo_geovals_get_var(geovals, var_q, q) ! specific humidity
114  call ufo_geovals_get_var(geovals, var_sfc_geomz, zs) ! surface geopotential height/surface altitude
115 
116  if (self%roconf%vertlayer .eq. "mass") then
117  call ufo_geovals_get_var(geovals, var_prs, prs) ! pressure
118  call ufo_geovals_get_var(geovals, var_z, gph) ! geopotential height
119  else
120  call ufo_geovals_get_var(geovals, var_prsi, prs) ! pressure
121  call ufo_geovals_get_var(geovals, var_zi, gph)
122  end if
123 
124  nlev = t%nval ! number of model mass levels
125  nlev1 = prs%nval
126  self%nlev = t%nval ! number of model mass levels
127  self%nlev1 = prs%nval ! number of model pressure/height levels
128  self%nlocs = nlocs
129  self%nrecs = nrecs
130 
131  nlevext = nlev + nlevadd
132  nlevcheck = min(23, nlev) !number of levels to check super refraction
133 
134  allocate(gest(nlev,nlocs))
135  allocate(gesq(nlev,nlocs))
136  allocate(gesp(nlev1,nlocs))
137  allocate(gesh(nlev1,nlocs))
138  allocate(geszs(nlocs))
139 
140 ! copy geovals to local background arrays
141  self%iflip = 0
142  if (prs%vals(1,1) .lt. prs%vals(prs%nval,1) ) then
143  self%iflip = 1
144  write(err_msg,'(a)')' ufo_gnssro_bndnbam_tlad_settraj:'//new_line('a')// &
145  ' Model vertical height profile is in descending order,'//new_line('a')// &
146  ' but NBAM requires it to be ascending order, need flip'
147  call fckit_log%info(err_msg)
148  do k = 1, nlev
149  gest(k,:) = t%vals(nlev-k+1,:)
150  gesq(k,:) = q%vals(nlev-k+1,:)
151  enddo
152  do k = 1, nlev1
153  gesp(k,:) = prs%vals(nlev1-k+1,:)
154  gesh(k,:) = gph%vals(nlev1-k+1,:)
155  enddo
156  else ! not flipping
157  call fckit_log%info(err_msg)
158 
159  do k = 1, nlev
160  gest(k,:) = t%vals(k,:)
161  gesq(k,:) = q%vals(k,:)
162  enddo
163  do k = 1, nlev1
164  gesp(k,:) = prs%vals(k,:)
165  gesh(k,:) = gph%vals(k,:)
166  enddo
167  end if
168 
169 ! if all fields t and q are on mass layers,
170 ! while p and z are on interface layers -- NBAM manner
171  if ( nlev1 /= nlev ) then
172  do k = nlev, 2, -1
173  gest(k,:) = half* (gest(k,:) + gest(k-1,:))
174  gesq(k,:) = half* (gesq(k,:) + gesq(k-1,:))
175  enddo
176  end if
177  geszs(:) = zs%vals(1,:)
178 
179 ! set obs space struture
180  allocate(obslat(nlocs))
181  allocate(obsimpp(nlocs))
182  allocate(obslocr(nlocs))
183  allocate(obsgeoid(nlocs))
184  allocate(obsrecnum(nlocs))
185  allocate(self%nlocs_begin(nrecs))
186  allocate(self%nlocs_end(nrecs))
187 
188  call obsspace_get_db(obss, "MetaData", "latitude", obslat)
189  call obsspace_get_db(obss, "MetaData", "impact_parameter", obsimpp)
190  call obsspace_get_db(obss, "MetaData", "earth_radius_of_curvature", obslocr)
191  call obsspace_get_db(obss, "MetaData", "geoid_height_above_reference_ellipsoid", obsgeoid)
192  call obsspace_get_recnum(obss, obsrecnum)
193 
194  if ( obsspace_has(obss, "SR_flag", "bending_angle") ) then
195  allocate(obssrflag(nlocs))
196  call obsspace_get_db(obss, "SR_flag", "bending_angle", obssrflag)
197  hassrflag = 1 ! SR_flag generated in hofx for real case run
198  else
199  hassrflag = 0 ! SR_flag does not exist in ctest
200  end if
201 
202  self%nlocs_begin=1
203  self%nlocs_end=1
204 
205  icount = 1
206  do iobs = 1, nlocs-1
207  if (obsrecnum(iobs+1) /= obsrecnum(iobs)) then
208  icount = icount +1 !counting number of records
209  self%nlocs_end(icount-1)= iobs
210  self%nlocs_begin(icount) = iobs+1
211  end if
212  end do
213  self%nlocs_end(nrecs)= nlocs
214 
215  if (icount /= nrecs) then
216  write(err_msg,*) "record number is not consistent :", icount, nrecs
217  call fckit_log%info(err_msg)
218  end if
219 
220  allocate(dhdp(nlev))
221  allocate(dhdt(nlev))
222  allocate(dzdh(nlev))
223  allocate(radius(nlev))
224  allocate(refindex(nlev))
225  allocate(ref(nlevext))
226  allocate(ref_tl(nlevext))
227  allocate(refxrad(0:nlevext+1))
228  allocate(refxrad_tl(0:nlevext+1))
229  allocate(refxrad_s(ngrd))
230  allocate(dndp(nlev,nlev))
231  allocate(dndq(nlev,nlev))
232  allocate(dndt(nlev,nlev))
233  allocate(dxidp(nlev,nlev))
234  allocate(dxidt(nlev,nlev))
235  allocate(dxidq(nlev,nlev))
236  allocate(dbenddxi(nlev))
237  allocate(dbenddn(nlev))
238  allocate(lagconst_tl(3,nlevext))
239  allocate(lagconst(3,nlevext))
240  allocate(self%jac_t(nlev,nlocs))
241  allocate(self%jac_q(nlev,nlocs))
242  allocate(self%jac_prs(nlev1,nlocs))
243 
244 ! Inizialize some variables
245  dxidt=zero; dxidp=zero; dxidq=zero
246  dndt=zero; dndq=zero; dndp=zero
247 
248 ! tempprary manner to handle the missing hofx
249  self%jac_t = missing
250 
251  do j = 1, ngrd
252  grids(j) = (j-1) * ds
253  end do
254 
255 ! calculate jacobian
256  call gnssro_ref_constants(self%roconf%use_compress)
257 
258  iobs = 0
259  rec_loop: do irec = 1, nrecs
260  obs_loop: do icount = self%nlocs_begin(irec), self%nlocs_end(irec)
261 
262  iobs = iobs + 1
263 
264  if (hassrflag == 1) then
265  if (obssrflag(iobs) > 0) cycle obs_loop
266  end if
267 
268  dxidt=zero; dxidp=zero; dxidq=zero
269  dndt=zero; dndq=zero; dndp=zero
270 
271  do k = 1, nlev
272 ! geometric height nad dzdh jacobian
273  call geop2geometric( obslat(iobs), gesh(k,iobs)-geszs(iobs), geomzi, dzdh(k))
274 ! guess radius
275  radius(k) = geomzi + geszs(iobs) + obsgeoid(iobs) + obslocr(iobs) ! radius r
276 ! guess refactivity, refactivity index, and impact parameter
277  call compute_refractivity(gest(k,iobs), gesq(k,iobs), gesp(k,iobs), &
278  ref(k),self%roconf%use_compress)
279  refindex(k)= one + (r1em6*ref(k))
280  refxrad(k) = refindex(k) * radius(k)
281  end do
282 
283 ! data rejection based on model background !
284 ! (1) skip data beyond model levels
285  call get_coordinate_value(obsimpp(iobs),sindx,refxrad(1),nlev,"increasing")
286  if (sindx < one .or. sindx > float(nlev)) then
287  cycle obs_loop
288  end if
289 
290  do k = 1, nlev
291 
292 ! jacobian for refractivity(N)
293  fv = rv_over_rd-one
294  pw = rd_over_rv+gesq(k,iobs)*(one-rd_over_rv)
295  q_coef = n_b *gesp(k,iobs)/(gest(k,iobs)**2*pw**2)*rd_over_rv + &
296  n_c *gesp(k,iobs)/(gest(k,iobs)* pw**2)*rd_over_rv
297  p_coef = n_a/gest(k,iobs) + &
298  n_b*gesq(k,iobs)/(gest(k,iobs)**2*pw) + &
299  n_c*gesq(k,iobs)/(gest(k,iobs)*pw)
300  t_coef = -n_a*gesp(k,iobs)/gest(k,iobs)**2 - &
301  n_b*two*gesq(k,iobs)*gesp(k,iobs)/(gest(k,iobs)**3*pw) - &
302  n_c*gesq(k,iobs)*gesp(k,iobs)/(gest(k,iobs)**2*pw)
303 
304  dhdp=zero; dhdt=zero
305  if(k > 1) then
306  do j = 2, k
307  dhdt(j-1)= rd_over_g*(log(gesp(j-1,iobs))-log(gesp(j,iobs)))
308  dhdp(j) = dhdp(j)-rd_over_g*(gest(j-1,iobs)/gesp(j,iobs))
309  dhdp(j-1)= dhdp(j-1)+rd_over_g*(gest(j-1,iobs)/gesp(j-1,iobs))
310  end do
311  end if
312  if(k == 1)then
313  dndt(k,k)=dndt(k,k)+t_coef
314  dndq(k,k)=dndq(k,k)+q_coef
315  dndp(k,k)=dndp(k,k)+p_coef
316  else
317  dndt(k,k)=dndt(k,k)+half*t_coef
318  dndt(k,k-1)=dndt(k,k-1)+half*t_coef
319  dndq(k,k)=dndq(k,k)+half*q_coef
320  dndq(k,k-1)=dndq(k,k-1)+half*q_coef
321  dndp(k,k)=p_coef
322  end if
323  do j = 1, nlev
324  dxidt(k,j)=r1em6*radius(k)*dndt(k,j) + refindex(k)*dzdh(k)*dhdt(j)
325  dxidq(k,j)=r1em6*radius(k)*dndq(k,j)
326  dxidp(k,j)=r1em6*radius(k)*dndp(k,j) + refindex(k)*dzdh(k)*dhdp(j)
327  end do
328  end do !nlev loop
329 
330  d_refxrad=refxrad(nlev)-refxrad(nlev-1)
331 
332  do k = 1, nlevadd
333  refxrad(nlev+k) = refxrad(nlev) + k*d_refxrad
334  ref(nlev+k) = ref(nlev+k-1)**2/ref(nlev+k-2)
335  end do
336 
337  refxrad(0)=refxrad(3)
338  refxrad(nlevext+1)=refxrad(nlevext-2)
339 
340  do klev = 1, nlev
341  refxrad_tl = zero
342  refxrad_tl(klev)= one
343  ref_tl = zero
344  ref_tl(klev) = one
345  lagconst = zero
346  lagconst_tl = zero
347  d_refxrad_tl = refxrad_tl(nlev)-refxrad_tl(nlev-1)
348 
349  do k = 1, nlevadd
350  refxrad_tl(nlev+k) = refxrad_tl(nlev)+ k*d_refxrad_tl
351  ref_tl(nlev+k) = (two*ref(nlev+k-1)*ref_tl(nlev+k-1)/ref(nlev+k-2))-&
352  (ref(nlev+k-1)**2/ref(nlev+k-2)**2)*ref_tl(nlev+k-2)
353  end do
354  refxrad_tl(0)=refxrad_tl(3)
355  refxrad_tl(nlevext+1)=refxrad_tl(nlevext-2)
356 
357  do k=1,nlevext
358  call lag_interp_const_tl(lagconst(:,k),lagconst_tl(:,k),refxrad(k-1:k+1),refxrad_tl(k-1:k+1),3)
359  end do
360 
361  intloop2: do j = 1, ngrd
362  refxrad_s(j) = sqrt(grids(j)**2 + obsimpp(iobs)**2) !x_s^2=s^2+a^2
363  call get_coordinate_value(refxrad_s(j),sindx,refxrad(1:nlevext),nlevext,"increasing")
364  indx=sindx
365  call lag_interp_smthweights_tl(refxrad(indx-1:indx+2),refxrad_tl(indx-1:indx+2), &
366  refxrad_s(j), lagconst(:,indx),lagconst_tl(:,indx),&
367  lagconst(:,indx+1),lagconst_tl(:,indx+1),dw4,dw4_tl,4)
368  if ( indx < nlevext) then
369  if(indx==1) then
370  dw4(4)=dw4(4)+dw4(1);dw4(1:3)=dw4(2:4);dw4(4)=zero
371  dw4_tl(4)=dw4_tl(4)+dw4_tl(1);dw4_tl(1:3)=dw4_tl(2:4);dw4_tl(4)=zero
372  indx=indx+1
373  endif
374  if(indx==nlevext-1) then
375  dw4(1)=dw4(1)+dw4(4); dw4(2:4)=dw4(1:3);dw4(1)=zero
376  dw4_tl(1)=dw4_tl(1)+dw4_tl(4); dw4_tl(2:4)=dw4_tl(1:3);dw4_tl(1)=zero
377  indx=indx-1
378  endif
379 
380  dbetaxi=(r1em6/refxrad_s(j))*dot_product(dw4_tl,ref(indx-1:indx+2))
381  dbetan =(r1em6/refxrad_s(j))*dot_product(dw4,ref_tl(indx-1:indx+2))
382 
383  if(j == 1)then
384  dbenddxi(klev)=dbetaxi
385  dbenddn(klev)=dbetan
386  else
387  dbenddxi(klev)=dbenddxi(klev)+two*dbetaxi
388  dbenddn(klev)=dbenddn(klev)+two*dbetan
389  end if
390  else
391  cycle obs_loop
392  end if ! obs inside the new "s" grids
393  end do intloop2
394  dbenddxi(klev)=-dbenddxi(klev)*ds*obsimpp(iobs)
395  dbenddn(klev)=-dbenddn(klev)*ds*obsimpp(iobs)
396 
397  end do
398 
399  do k = 1, nlev
400  self%jac_t(k,iobs)=zero
401  self%jac_q(k,iobs)=zero
402  self%jac_prs(k,iobs)=zero
403  do j = 1, nlev
404  self%jac_t(k,iobs) = self%jac_t(k,iobs)+dbenddxi(j)*dxidt(j,k)+ &
405  dbenddn(j) * dndt(j,k)
406  self%jac_q(k,iobs) = self%jac_q(k,iobs)+dbenddxi(j)*dxidq(j,k)+ &
407  dbenddn(j) * dndq(j,k)
408  self%jac_prs(k,iobs)= self%jac_prs(k,iobs)+dbenddxi(j)*dxidp(j,k)+ &
409  dbenddn(j) * dndp(j,k)
410  end do
411  end do
412  if ( nlev /= nlev1) self%jac_prs(nlev1,iobs)= 0.
413  end do obs_loop
414  end do rec_loop
415 
416 
417  deallocate(obslat)
418  deallocate(obsimpp)
419  deallocate(obslocr)
420  deallocate(obsgeoid)
421  deallocate(gest)
422  deallocate(gesq)
423  deallocate(gesp)
424  deallocate(gesh)
425  deallocate(geszs)
426  deallocate(dhdp)
427  deallocate(dhdt)
428  deallocate(radius)
429  deallocate(dzdh)
430  deallocate(refindex)
431  deallocate(ref)
432  deallocate(ref_tl)
433  deallocate(refxrad)
434  deallocate(refxrad_tl)
435  deallocate(refxrad_s)
436  deallocate(dndp)
437  deallocate(dndq)
438  deallocate(dndt)
439  deallocate(dxidp)
440  deallocate(dxidt)
441  deallocate(dxidq)
442  deallocate(dbenddxi)
443  deallocate(dbenddn)
444  deallocate(lagconst)
445  deallocate(lagconst_tl)
446  deallocate(obsrecnum)
447  if (allocated(obssrflag)) deallocate(obssrflag)
448 
449 end if
450  self%ltraj = .true.
451  write(err_msg,*) myname, ": complete"
452  call fckit_log%info(err_msg)
453 
454 end subroutine ufo_gnssro_bndnbam_tlad_settraj
455 !----------------------------------------------------------------
456 subroutine ufo_gnssro_bndnbam_simobs_tl(self, geovals, hofx, obss)
458  implicit none
459  class(ufo_gnssro_bndnbam_tlad), intent(in) :: self
460  type(ufo_geovals), intent(in) :: geovals
461  real(kind_real), intent(inout) :: hofx(:)
462  type(c_ptr), value, intent(in) :: obss
463  character(len=*), parameter :: myname = "ufo_gnssro_bndnbam_simobs_tl"
464  character(max_string) :: err_msg
465  integer :: nlev, nlev1, nlocs
466  integer :: iobs, k, irec, icount
467  type(ufo_geoval), pointer :: t_tl, prs_tl, q_tl
468  real(kind_real), allocatable :: gesT_tl(:,:), gesP_tl(:,:), gesQ_tl(:,:)
469  real(kind_real) :: sumIntgl
470 
471  write(err_msg,*) myname, ": begin"
472  call fckit_log%info(err_msg)
473 
474 ! check if trajectory was set
475  if (.not. self%ltraj) then
476  write(err_msg,*) myname, ' trajectory was not set!'
477  call abor1_ftn(err_msg)
478  endif
479 
480 
481 if (geovals%nlocs > 0 ) then
482  hofx = missing_value(missing)
483 
484 ! check if nlocs is consistent in geovals & hofx
485  if (self%nlocs /= size(hofx)) then
486  write(err_msg,*) myname, ' error: nlocs inconsistent!'
487  call abor1_ftn(err_msg)
488  endif
489 
490  call ufo_geovals_get_var(geovals, var_ts, t_tl) ! air temperature
491  call ufo_geovals_get_var(geovals, var_q, q_tl) ! specific humidity
492  if (self%roconf%vertlayer .eq. "mass") then
493  call ufo_geovals_get_var(geovals, var_prs, prs_tl) ! pressure
494  else
495  call ufo_geovals_get_var(geovals, var_prsi, prs_tl) ! pressure
496  end if
497 
498  nlocs = self%nlocs
499  nlev = self%nlev
500  nlev1 = self%nlev1
501  allocate(gest_tl(nlev, nlocs))
502  allocate(gesq_tl(nlev, nlocs))
503  allocate(gesp_tl(nlev1,nlocs))
504 
505  if( self%iflip == 1 ) then
506  do k = 1, nlev
507  gest_tl(k,:) = t_tl%vals(nlev-k+1,:)
508  gesq_tl(k,:) = q_tl%vals(nlev-k+1,:)
509  enddo
510  do k = 1, nlev1
511  gesp_tl(k,:) = prs_tl%vals(nlev1-k+1,:)
512  enddo
513  else ! not flipping
514  do k =1, nlev
515  gest_tl(k,:) = t_tl%vals(k,:)
516  gesq_tl(k,:) = q_tl%vals(k,:)
517  enddo
518  do k =1, nlev1
519  gesp_tl(k,:) = prs_tl%vals(k,:)
520  enddo
521  end if
522 
523 ! if all fields t and q are on mass layers,
524 ! while p and z are on interface layers -- NBAM manner
525  if ( nlev1 /= nlev ) then
526  do k = nlev, 2, -1
527  gest_tl(k,:) = half* (gest_tl(k,:) + gest_tl(k-1,:))
528  gesq_tl(k,:) = half* (gesq_tl(k,:) + gesq_tl(k-1,:))
529  enddo
530  end if
531 
532  iobs = 0
533  rec_loop: do irec = 1, self%nrecs
534  obs_loop: do icount = self%nlocs_begin(irec), self%nlocs_end(irec)
535  iobs = iobs + 1
536  if (self%jac_t(1,iobs) /= missing ) then
537  sumintgl = 0.0
538  do k = 1, nlev
539  sumintgl = sumintgl + self%jac_t(k,iobs)*gest_tl(k,iobs) &
540  + self%jac_q(k,iobs)*gesq_tl(k,iobs) &
541  + self%jac_prs(k,iobs)*gesp_tl(k,iobs)
542 
543  end do
544  hofx(iobs)=sumintgl
545  end if
546  end do obs_loop
547  end do rec_loop
548 
549  deallocate(gest_tl)
550  deallocate(gesp_tl)
551  deallocate(gesq_tl)
552 
553 end if
554 
555  write(err_msg,*) "TRACE: ufo_gnssro_bndnbam_simobs_tl: begin"
556  call fckit_log%info(err_msg)
557 
558 end subroutine ufo_gnssro_bndnbam_simobs_tl
559 
560 !----------------------------------------------------------------
561 subroutine ufo_gnssro_bndnbam_simobs_ad(self, geovals, hofx, obss)
562  implicit none
563  class(ufo_gnssro_bndnbam_tlad), intent(in) :: self
564  type(ufo_geovals), intent(inout) :: geovals
565  real(kind_real), intent(in) :: hofx(:)
566  type(c_ptr), value, intent(in) :: obss
567  type(ufo_geoval), pointer :: t_ad, q_ad, prs_ad
568  real(kind_real), allocatable :: gesT_ad(:,:), gesP_ad(:,:), gesQ_ad(:,:)
569  character(len=*), parameter :: myname = "ufo_gnssro_bndnbam_simobs_ad"
570  character(max_string) :: err_msg
571  integer :: nlocs, iobs, k, nlev,nlev1, icount, irec
572 
573  write(err_msg,*) myname,": begin"
574  call fckit_log%info(err_msg)
575 
576 ! check if trajectory was set
577  if (.not. self%ltraj) then
578  write(err_msg,*) myname, ' trajectory wasnt set!'
579  call abor1_ftn(err_msg)
580  endif
581 
582 if (self%nlocs > 0 ) then
583 
584 ! check if nlocs is consistent in geovals & hofx
585  if (geovals%nlocs /= size(hofx)) then
586  write(err_msg,*) myname, ' error: nlocs inconsistent!'
587  call abor1_ftn(err_msg)
588  endif
589 
590  call ufo_geovals_get_var(geovals, var_ts, t_ad) ! air temperature
591  call ufo_geovals_get_var(geovals, var_q, q_ad) ! specific humidity
592 
593  if (self%roconf%vertlayer .eq. "mass") then
594  call ufo_geovals_get_var(geovals, var_prs, prs_ad) ! pressure
595  else
596  call ufo_geovals_get_var(geovals, var_prsi, prs_ad) ! pressure
597  end if
598 
599  nlocs = self%nlocs
600  nlev = self%nlev
601  nlev1 = self%nlev1
602  allocate(gest_ad(nlev,nlocs))
603  allocate(gesq_ad(nlev,nlocs))
604  allocate(gesp_ad(nlev1,nlocs))
605 
606  gest_ad = 0.0_kind_real
607  gesq_ad = 0.0_kind_real
608  gesp_ad = 0.0_kind_real
609 
610  iobs = 0
611  rec_loop: do irec = 1, self%nrecs
612  obs_loop: do icount = self%nlocs_begin(irec), self%nlocs_end(irec)
613  iobs = iobs + 1
614  if (self%jac_t(1,iobs) /= missing .and. hofx(iobs) /= missing) then
615 
616  do k = 1,nlev1
617  if (k == nlev + 1) then
618  gesp_ad(k,iobs) = gesp_ad(k,iobs) + hofx(iobs)*self%jac_prs(k,iobs)
619  else
620  gest_ad(k,iobs) = gest_ad(k,iobs) + hofx(iobs)*self%jac_t(k,iobs)
621  gesq_ad(k,iobs) = gesq_ad(k,iobs) + hofx(iobs)*self%jac_q(k,iobs)
622  gesp_ad(k,iobs) = gesp_ad(k,iobs) + hofx(iobs)*self%jac_prs(k,iobs)
623  end if
624  end do
625 
626  if ( nlev1 /= nlev ) then
627  do k = 2, nlev
628  gest_ad(k-1,iobs) = half*gest_ad(k,iobs) + gest_ad(k-1,iobs)
629  gest_ad(k,iobs) = half*gest_ad(k,iobs)
630  gesq_ad(k-1,iobs) = half*gesq_ad(k,iobs) + gesq_ad(k-1,iobs)
631  gesq_ad(k,iobs) = half*gesq_ad(k,iobs)
632  enddo
633  end if
634 
635  end if
636  end do obs_loop
637  end do rec_loop
638 
639  if( self%iflip == 1 ) then
640  do k = 1, nlev
641  t_ad%vals(nlev-k+1,:) = gest_ad(k,:)
642  q_ad%vals(nlev-k+1,:) = gesq_ad(k,:)
643  enddo
644  do k = 1, nlev1
645  prs_ad%vals(nlev1-k+1,:) = gesp_ad(k,:)
646  enddo
647  else ! not flipping
648  do k =1, nlev
649  t_ad%vals(k,:) = gest_ad(k,:)
650  q_ad%vals(k,:) = gesq_ad(k,:)
651  enddo
652  do k =1, nlev1
653  prs_ad%vals(k,:) = gesp_ad(k,:)
654  enddo
655  end if
656 
657  deallocate(gest_ad)
658  deallocate(gesp_ad)
659  deallocate(gesq_ad)
660 end if
661  write(err_msg,*) "TRACE: ufo_gnssro_bndnbam_simobs_ad: begin"
662  call fckit_log%info(err_msg)
663 
664 end subroutine ufo_gnssro_bndnbam_simobs_ad
665 ! ------------------------------------------------------------------------------
666 
668  implicit none
669  class(ufo_gnssro_bndnbam_tlad), intent(inout) :: self
670  character(len=*), parameter :: myname="ufo_gnssro_bndnbam_tlad_delete"
671 
672  self%nlocs = 0
673  self%nrecs = 0
674  self%nlev = 0
675  self%nlev1 = 0
676  if (allocated(self%nlocs_begin)) deallocate(self%nlocs_begin)
677  if (allocated(self%nlocs_end)) deallocate(self%nlocs_end)
678  if (allocated(self%jac_t)) deallocate(self%jac_t)
679  if (allocated(self%jac_prs)) deallocate(self%jac_prs)
680  if (allocated(self%jac_q)) deallocate(self%jac_q)
681 
682  self%ltraj = .false.
683 
684 end subroutine ufo_gnssro_bndnbam_tlad_delete
685 
686 ! ------------------------------------------------------------------------------
subroutine, public gnssro_conf_setup(roconf, f_conf)
subroutine, public gnssro_ref_constants(use_compress)
real(kind_real), public n_a
real(kind_real), public n_b
real(kind_real), parameter, public ds
real(kind_real), parameter, public r1em6
real(kind_real), public n_c
subroutine, public get_coordinate_value(fin, fout, x, nx, flag)
subroutine geop2geometric(latitude, geopotentialH, geometricZ, dzdh_jac)
subroutine compute_refractivity(temperature, specH, pressure, refr, use_compress)
Fortran module to prepare for Lagrange polynomial interpolation. based on GSI: lagmod....
Definition: lag_interp.F90:4
subroutine, public lag_interp_smthweights_tl(x, x_TL, xt, aq, aq_TL, bq, bq_TL, dw, dw_TL, n)
Definition: lag_interp.F90:226
subroutine, public lag_interp_const_tl(q, q_TL, x, x_TL, n)
Definition: lag_interp.F90:52
type(registry_t), public ufo_geovals_registry
Linked list interface - defines registry_t type.
subroutine, public ufo_geovals_get_var(self, varname, geoval)
Fortran module of Gnssro NBAM (NCEP's Bending Angle Method) tlad operator.
subroutine ufo_gnssro_bndnbam_tlad_settraj(self, geovals, obss)
subroutine ufo_gnssro_bndnbam_tlad_setup(self, f_conf)
subroutine ufo_gnssro_bndnbam_simobs_tl(self, geovals, hofx, obss)
subroutine ufo_gnssro_bndnbam_simobs_ad(self, geovals, hofx, obss)
character(len=maxvarlen), parameter, public var_prsi
character(len=maxvarlen), parameter, public var_prs
character(len=maxvarlen), parameter, public var_q
character(len=maxvarlen), parameter, public var_zi
character(len=maxvarlen), parameter, public var_sfc_geomz
character(len=maxvarlen), parameter, public var_z
character(len=maxvarlen), parameter, public var_ts
type to hold interpolated field for one variable, one observation
type to hold interpolated fields required by the obs operators