9 use fckit_configuration_module,
only: fckit_configuration
15 use missing_values_mod
20 use fckit_log_module,
only : fckit_log
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(:)
46 type(fckit_configuration),
intent(in) :: f_conf
56 use,
intrinsic:: iso_c_binding
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
64 integer,
parameter :: newAdd = 20
65 integer,
parameter :: ngrd = 80
66 type(
ufo_geoval),
pointer :: t, q, gph, prs, zs
67 integer :: iobs,k,j, klev, irec, icount
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
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(:)
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(:)
98 write(err_msg,*) myname,
": begin"
99 call fckit_log%info(err_msg)
105 nlocs = obsspace_get_nlocs(obss)
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)
116 if (self%roconf%vertlayer .eq.
"mass")
then
127 self%nlev1 = prs%nval
131 nlevext = nlev + nlevadd
132 nlevcheck = min(23, nlev)
134 allocate(gest(nlev,nlocs))
135 allocate(gesq(nlev,nlocs))
136 allocate(gesp(nlev1,nlocs))
137 allocate(gesh(nlev1,nlocs))
138 allocate(geszs(nlocs))
142 if (prs%vals(1,1) .lt. prs%vals(prs%nval,1) )
then
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)
149 gest(k,:) = t%vals(nlev-k+1,:)
150 gesq(k,:) = q%vals(nlev-k+1,:)
153 gesp(k,:) = prs%vals(nlev1-k+1,:)
154 gesh(k,:) = gph%vals(nlev1-k+1,:)
157 call fckit_log%info(err_msg)
160 gest(k,:) = t%vals(k,:)
161 gesq(k,:) = q%vals(k,:)
164 gesp(k,:) = prs%vals(k,:)
165 gesh(k,:) = gph%vals(k,:)
171 if ( nlev1 /= nlev )
then
173 gest(k,:) = half* (gest(k,:) + gest(k-1,:))
174 gesq(k,:) = half* (gesq(k,:) + gesq(k-1,:))
177 geszs(:) = zs%vals(1,:)
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))
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)
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)
207 if (obsrecnum(iobs+1) /= obsrecnum(iobs))
then
209 self%nlocs_end(icount-1)= iobs
210 self%nlocs_begin(icount) = iobs+1
213 self%nlocs_end(nrecs)= nlocs
215 if (icount /= nrecs)
then
216 write(err_msg,*)
"record number is not consistent :", icount, nrecs
217 call fckit_log%info(err_msg)
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))
245 dxidt=zero; dxidp=zero; dxidq=zero
246 dndt=zero; dndq=zero; dndp=zero
252 grids(j) = (j-1) *
ds
259 rec_loop:
do irec = 1, nrecs
260 obs_loop:
do icount = self%nlocs_begin(irec), self%nlocs_end(irec)
264 if (hassrflag == 1)
then
265 if (obssrflag(iobs) > 0) cycle obs_loop
268 dxidt=zero; dxidp=zero; dxidq=zero
269 dndt=zero; dndq=zero; dndp=zero
273 call geop2geometric( obslat(iobs), gesh(k,iobs)-geszs(iobs), geomzi, dzdh(k))
275 radius(k) = geomzi + geszs(iobs) + obsgeoid(iobs) + obslocr(iobs)
278 ref(k),self%roconf%use_compress)
279 refindex(k)= one + (
r1em6*ref(k))
280 refxrad(k) = refindex(k) * radius(k)
286 if (sindx < one .or. sindx > float(nlev))
then
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)
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))
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
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
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)
330 d_refxrad=refxrad(nlev)-refxrad(nlev-1)
333 refxrad(nlev+k) = refxrad(nlev) + k*d_refxrad
334 ref(nlev+k) = ref(nlev+k-1)**2/ref(nlev+k-2)
337 refxrad(0)=refxrad(3)
338 refxrad(nlevext+1)=refxrad(nlevext-2)
342 refxrad_tl(klev)= one
347 d_refxrad_tl = refxrad_tl(nlev)-refxrad_tl(nlev-1)
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)
354 refxrad_tl(0)=refxrad_tl(3)
355 refxrad_tl(nlevext+1)=refxrad_tl(nlevext-2)
358 call lag_interp_const_tl(lagconst(:,k),lagconst_tl(:,k),refxrad(k-1:k+1),refxrad_tl(k-1:k+1),3)
361 intloop2:
do j = 1, ngrd
362 refxrad_s(j) = sqrt(grids(j)**2 + obsimpp(iobs)**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
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
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
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))
384 dbenddxi(klev)=dbetaxi
387 dbenddxi(klev)=dbenddxi(klev)+two*dbetaxi
388 dbenddn(klev)=dbenddn(klev)+two*dbetan
394 dbenddxi(klev)=-dbenddxi(klev)*
ds*obsimpp(iobs)
395 dbenddn(klev)=-dbenddn(klev)*
ds*obsimpp(iobs)
400 self%jac_t(k,iobs)=zero
401 self%jac_q(k,iobs)=zero
402 self%jac_prs(k,iobs)=zero
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)
412 if ( nlev /= nlev1) self%jac_prs(nlev1,iobs)= 0.
434 deallocate(refxrad_tl)
435 deallocate(refxrad_s)
445 deallocate(lagconst_tl)
446 deallocate(obsrecnum)
447 if (
allocated(obssrflag))
deallocate(obssrflag)
451 write(err_msg,*) myname,
": complete"
452 call fckit_log%info(err_msg)
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
471 write(err_msg,*) myname,
": begin"
472 call fckit_log%info(err_msg)
475 if (.not. self%ltraj)
then
476 write(err_msg,*) myname,
' trajectory was not set!'
477 call abor1_ftn(err_msg)
481 if (geovals%nlocs > 0 )
then
485 if (self%nlocs /=
size(hofx))
then
486 write(err_msg,*) myname,
' error: nlocs inconsistent!'
487 call abor1_ftn(err_msg)
492 if (self%roconf%vertlayer .eq.
"mass")
then
501 allocate(gest_tl(nlev, nlocs))
502 allocate(gesq_tl(nlev, nlocs))
503 allocate(gesp_tl(nlev1,nlocs))
505 if( self%iflip == 1 )
then
507 gest_tl(k,:) = t_tl%vals(nlev-k+1,:)
508 gesq_tl(k,:) = q_tl%vals(nlev-k+1,:)
511 gesp_tl(k,:) = prs_tl%vals(nlev1-k+1,:)
515 gest_tl(k,:) = t_tl%vals(k,:)
516 gesq_tl(k,:) = q_tl%vals(k,:)
519 gesp_tl(k,:) = prs_tl%vals(k,:)
525 if ( nlev1 /= nlev )
then
527 gest_tl(k,:) = half* (gest_tl(k,:) + gest_tl(k-1,:))
528 gesq_tl(k,:) = half* (gesq_tl(k,:) + gesq_tl(k-1,:))
533 rec_loop:
do irec = 1, self%nrecs
534 obs_loop:
do icount = self%nlocs_begin(irec), self%nlocs_end(irec)
536 if (self%jac_t(1,iobs) /=
missing )
then
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)
555 write(err_msg,*)
"TRACE: ufo_gnssro_bndnbam_simobs_tl: begin"
556 call fckit_log%info(err_msg)
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
573 write(err_msg,*) myname,
": begin"
574 call fckit_log%info(err_msg)
577 if (.not. self%ltraj)
then
578 write(err_msg,*) myname,
' trajectory wasnt set!'
579 call abor1_ftn(err_msg)
582 if (self%nlocs > 0 )
then
585 if (geovals%nlocs /=
size(hofx))
then
586 write(err_msg,*) myname,
' error: nlocs inconsistent!'
587 call abor1_ftn(err_msg)
593 if (self%roconf%vertlayer .eq.
"mass")
then
602 allocate(gest_ad(nlev,nlocs))
603 allocate(gesq_ad(nlev,nlocs))
604 allocate(gesp_ad(nlev1,nlocs))
606 gest_ad = 0.0_kind_real
607 gesq_ad = 0.0_kind_real
608 gesp_ad = 0.0_kind_real
611 rec_loop:
do irec = 1, self%nrecs
612 obs_loop:
do icount = self%nlocs_begin(irec), self%nlocs_end(irec)
614 if (self%jac_t(1,iobs) /=
missing .and. hofx(iobs) /=
missing)
then
617 if (k == nlev + 1)
then
618 gesp_ad(k,iobs) = gesp_ad(k,iobs) + hofx(iobs)*self%jac_prs(k,iobs)
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)
626 if ( nlev1 /= nlev )
then
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)
639 if( self%iflip == 1 )
then
641 t_ad%vals(nlev-k+1,:) = gest_ad(k,:)
642 q_ad%vals(nlev-k+1,:) = gesq_ad(k,:)
645 prs_ad%vals(nlev1-k+1,:) = gesp_ad(k,:)
649 t_ad%vals(k,:) = gest_ad(k,:)
650 q_ad%vals(k,:) = gesq_ad(k,:)
653 prs_ad%vals(k,:) = gesp_ad(k,:)
661 write(err_msg,*)
"TRACE: ufo_gnssro_bndnbam_simobs_ad: begin"
662 call fckit_log%info(err_msg)
670 character(len=*),
parameter :: myname=
"ufo_gnssro_bndnbam_tlad_delete"
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)
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)
Fortran module to prepare for Lagrange polynomial interpolation. based on GSI: lagmod....
subroutine, public lag_interp_smthweights_tl(x, x_TL, xt, aq, aq_TL, bq, bq_TL, dw, dw_TL, n)
subroutine, public lag_interp_const_tl(q, q_TL, x, x_TL, n)
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_tlad_delete(self)
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
Fortran derived type for gnssro trajectory.