8 use,
intrinsic:: iso_c_binding
15 use missing_values_mod
20 use fckit_log_module,
only : fckit_log
40 use fckit_configuration_module,
only: fckit_configuration
43 type(fckit_configuration),
intent(in) :: f_conf
53 real(kind_real),
intent(inout) :: hofx(:)
54 type(c_ptr),
value,
intent(in) :: obss
55 character(len=*),
parameter :: myname =
"ufo_gnssro_bndnbam_simobs"
56 character(max_string) :: err_msg
57 integer :: nrecs, nlocs
58 integer,
parameter :: nlevAdd = 13
59 integer,
parameter :: ngrd = 80
60 integer :: iobs, k, igrd, irec, icount, kk
61 integer :: nlev, nlev1, nlevExt, nlevCheck
62 type(
ufo_geoval),
pointer :: t, q, gph, prs, zs
63 real(kind_real),
allocatable :: gesT(:,:), gesZ(:,:), gesP(:,:), gesQ(:,:), gesTv(:,:), gesZs(:)
64 real(kind_real),
allocatable :: obsLat(:), obsImpP(:),obsLocR(:), obsGeoid(:), obsValue(:)
65 integer(c_size_t),
allocatable :: obsRecnum(:)
66 real(kind_real),
allocatable :: temperature(:)
67 real(kind_real),
allocatable :: humidity(:),refractivity(:),pressure(:)
68 real(kind_real) :: temp, geop
71 real(kind_real) :: grids(ngrd)
72 real(kind_real),
allocatable :: refIndex(:), refXrad(:), geomz(:)
73 real(kind_real),
allocatable :: ref(:), radius(:)
74 real(kind_real) :: sIndx
77 integer,
allocatable :: nlocs_begin(:)
78 integer,
allocatable :: nlocs_end(:)
79 real(c_double) :: missing
80 integer,
allocatable :: super_refraction_flag(:), super(:), obs_max(:)
81 real(kind_real),
allocatable :: toss_max(:)
83 real(kind_real) :: gradRef, obsImpH
84 integer,
allocatable :: LayerIdx(:)
86 write(err_msg,*) myname,
": begin"
87 call fckit_log%info(err_msg)
89 nlocs = obsspace_get_nlocs(obss)
90 nrecs = obsspace_get_nrecs(obss)
91 write(err_msg,*) myname,
': nlocs from gelvals and hofx, nrecs', geovals%nlocs, nlocs, nrecs
92 call fckit_log%info(err_msg)
93 missing = missing_value(missing)
95 allocate(temperature(nlocs))
97 if (trim(self%roconf%output_diags) .eq.
"true")
then
98 allocate(humidity(nlocs))
99 allocate(pressure(nlocs))
100 allocate(refractivity(nlocs))
103 refractivity = missing
105 allocate(super_refraction_flag(nlocs))
106 super_refraction_flag = 0
107 allocate(layeridx(nlocs))
113 if (geovals%nlocs /=
size(hofx))
then
114 write(err_msg,*) myname,
': nlocs inconsistent!', geovals%nlocs,
size(hofx)
115 call abor1_ftn(err_msg)
123 if (self%roconf%vertlayer .eq.
"mass")
then
126 else if (self%roconf%vertlayer .eq.
"full")
then
132 write(err_msg,*) myname,
': vertlayer has to be mass of full, '//new_line(
'a')// &
133 ' will use full layer anyway'
134 call fckit_log%info(err_msg)
140 allocate(gesp(nlev1,nlocs))
141 allocate(gesz(nlev1,nlocs))
142 allocate(gest(nlev,nlocs))
143 allocate(gestv(nlev,nlocs))
144 allocate(gesq(nlev,nlocs))
145 allocate(geszs(nlocs))
149 if (prs%vals(1,1) .lt. prs%vals(prs%nval,1) )
then
151 write(err_msg,
'(a)')
' ufo_gnssro_bndnbam_simobs:'//new_line(
'a')// &
152 ' Model vertical height profile is in descending order,'//new_line(
'a')// &
153 ' but bndNBAM requires it to be ascending order, need flip'
154 call fckit_log%info(err_msg)
156 gest(k,:) = t%vals(nlev-k+1,:)
157 gesq(k,:) = q%vals(nlev-k+1,:)
158 gestv(k,:)= gest(k,:)*(1+gesq(k,:)*(rv_over_rd-1))
161 gesp(k,:) = prs%vals(nlev1-k+1,:)
162 gesz(k,:) = gph%vals(nlev1-k+1,:)
166 gest(k,:) = t%vals(k,:)
167 gesq(k,:) = q%vals(k,:)
168 gestv(k,:) = gest(k,:)*(1+gesq(k,:)*(rv_over_rd-1))
172 gesp(k,:) = prs%vals(k,:)
173 gesz(k,:) = gph%vals(k,:)
176 geszs(:) = zs%vals(1,:)
181 if ( nlev1 /= nlev )
then
183 gesq(k,:) = half* (gesq(k,:) + gesq(k-1,:))
184 gestv(k,:) = half* (gestv(k,:) + gestv(k-1,:))
188 gest(k,:) = gestv(k,:)/(1+ gesq(k,:)*(rv_over_rd-1))
193 allocate(obslat(nlocs))
194 allocate(obsimpp(nlocs))
195 allocate(obslocr(nlocs))
196 allocate(obsgeoid(nlocs))
197 allocate(obsvalue(nlocs))
198 allocate(obsrecnum(nlocs))
199 allocate(nlocs_begin(nrecs))
200 allocate(nlocs_end(nrecs))
202 call obsspace_get_db(obss,
"MetaData",
"latitude", obslat)
203 call obsspace_get_db(obss,
"MetaData",
"impact_parameter", obsimpp)
204 call obsspace_get_db(obss,
"MetaData",
"earth_radius_of_curvature", obslocr)
205 call obsspace_get_db(obss,
"MetaData",
"geoid_height_above_reference_ellipsoid", obsgeoid)
206 call obsspace_get_db(obss,
"ObsValue",
"bending_angle", obsvalue)
207 call obsspace_get_recnum(obss, obsrecnum)
213 if (obsrecnum(iobs+1) /= obsrecnum(iobs))
then
215 nlocs_end(icount-1)= iobs
216 nlocs_begin(icount) = iobs+1
219 nlocs_end(nrecs)= nlocs
220 if (icount /= nrecs)
then
221 write(err_msg,*) myname,
': record number is not consistent :', icount, nrecs
222 call abor1_ftn(err_msg)
225 nlevext = nlev + nlevadd
226 nlevcheck = min(23, nlev)
230 grids(igrd+1) = igrd *
ds
234 allocate(geomz(nlev))
235 allocate(radius(nlev))
236 allocate(ref(nlevext))
237 allocate(refindex(nlev))
238 allocate(refxrad(0:nlevext+1))
240 allocate(super(nlocs))
241 allocate(toss_max(nrecs))
242 allocate(obs_max(nrecs))
250 rec_loop:
do irec = 1, nrecs
252 obs_loop:
do icount = nlocs_begin(irec), nlocs_end(irec)
257 call geop2geometric(obslat(iobs), gesz(k,iobs)-geszs(iobs), geomz(k))
258 radius(k) = geomz(k) + geszs(iobs) + obsgeoid(iobs) + obslocr(iobs)
261 ref(k), self%roconf%use_compress)
262 refindex(k) = one + (
r1em6*ref(k))
263 refxrad(k) = refindex(k) * radius(k)
269 if (sindx < one .or. sindx > float(nlev)) cycle obs_loop
272 layeridx(iobs) = min(max(1, int(sindx)), nlev)
276 wi=min(max(1,indx),nlev)
277 wi2=max(1,min(indx+1,nlev))
279 wf=max(zero,min(wf,one))
280 temperature(iobs)=gestv(wi,iobs)*(one-wf)+gestv(wi2,iobs)*wf
281 if (trim(self%roconf%output_diags) .eq.
"true")
then
282 humidity(iobs)= gesq(wi,iobs)*(one-wf)+gesq(wi2,iobs)*wf
283 temp = gest(wi,iobs)*(one-wf)+gest(wi2,iobs)*wf
284 geop = gesz(wi,iobs)*(one-wf)+gesz(wi2,iobs)*wf
285 pressure(iobs)= gesp(wi,iobs)/exp(two*grav*(geop-gesz(wi,iobs))/(rd*(temperature(iobs)+gestv(wi,iobs))))
287 refractivity(iobs), self%roconf%use_compress)
292 if(
cmp_strings(self%roconf%super_ref_qc,
"NBAM"))
then
294 obsimph = (obsimpp(iobs) - obslocr(iobs)) *
r1em3
296 if (obsimph <=
six)
then
297 do k = nlevcheck, 1, -1
300 gradref = 1000.0 * (ref(k+1)-ref(k))/(radius(k+1)-radius(k))
302 if (abs(gradref) >= 0.75*
crit_gradrefr .and. obsimpp(iobs) <= refxrad(k+2))
then
303 super_refraction_flag(iobs) = 1
310 if (self%roconf%sr_steps > 1 &
311 .and. obsvalue(iobs) >= 0.03 )
then
313 do k = nlevcheck, 1, -1
314 gradref = 1000.0 * (ref(k+1)-ref(k))/(radius(k+1)-radius(k))
316 .and. super(iobs) == 0 &
317 .and. toss_max(irec) <= obsvalue(iobs))
then
319 toss_max(irec)= max(toss_max(irec), obsvalue(iobs))
328 else if(
cmp_strings(self%roconf%super_ref_qc,
"ECMWF"))
then
332 if (refxrad(k) - refxrad(k-1) < 10.0)
THEN
338 if (obsimpp(iobs) < refxrad(sr_hgt_idx))
then
339 super_refraction_flag(iobs) = 1
344 write(err_msg,*) myname,
': super refraction method has to be NBAM or ECMWF!'
345 call abor1_ftn(err_msg)
348 if (super_refraction_flag(iobs) .eq. 0)
then
350 obslat(iobs), obsgeoid(iobs), obslocr(iobs), obsimpp(iobs), &
352 nlev, nlevext, nlevadd, nlevcheck, &
353 radius(1:nlev),ref(1:nlevext),refindex(1:nlev),refxrad(0:nlevext), &
360 if (
cmp_strings(self%roconf%super_ref_qc,
"NBAM") .and. self%roconf%sr_steps > 1 )
then
361 rec_loop2:
do irec = 1, nrecs
363 if (obs_max(irec) > 0 )
then
365 obs_loop2:
do k = nlocs_begin(irec), nlocs_end(irec)
366 obsimph = (obsimpp(k) - obslocr(k)) *
r1em3
367 if (obsimph<=
six .and. obsimpp(k)<=obsimpp(obs_max(irec)) .and. &
368 hofx(k)/=missing .and. super_refraction_flag(k)==0)
then
369 super_refraction_flag(k)=2
393 deallocate(obsrecnum)
394 deallocate(nlocs_begin)
395 deallocate(nlocs_end)
400 write(err_msg,*) myname,
": complete"
401 call fckit_log%info(err_msg)
405 call obsspace_put_db(obss,
"MetaData",
"virtual_temperature", temperature)
407 call obsspace_put_db(obss,
"SRflag",
"bending_angle", super_refraction_flag)
409 call obsspace_put_db(obss,
"LayerIdx",
"bending_angle", layeridx)
410 if (trim(self%roconf%output_diags) .eq.
"true")
then
411 call obsspace_put_db(obss,
"ObsDiag",
"specific_humidity", humidity)
412 call obsspace_put_db(obss,
"ObsDiag",
"refractivity", refractivity)
413 call obsspace_put_db(obss,
"ObsDiag",
"pressure", pressure)
416 deallocate(refractivity)
418 deallocate(super_refraction_flag)
419 deallocate(temperature)
subroutine, public gnssro_conf_setup(roconf, f_conf)
real(kind_real), parameter, public crit_gradrefr
real(kind_real), parameter, public r1em3
real(kind_real), parameter, public six
real(kind_real), parameter, public ds
real(kind_real), parameter, public r1em6
subroutine, public get_coordinate_value(fin, fout, x, nx, flag)
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) nonlinear operator.
subroutine ufo_gnssro_bndnbam_simobs(self, geovals, hofx, obss)
subroutine ufo_gnssro_bndnbam_setup(self, f_conf)
Fortran module of Gnssro NBAM (NCEP's Bending Angle Method) operator.
subroutine, public ufo_gnssro_bndnbam_simobs_single(obsLat, obsGeoid, obsLocR, obsImpP, grids, ngrd, nlev, nlevExt, nlevAdd, nlevCheck, radius, ref, refIndex, refXrad, bendingAngle)
Fortran module with various useful routines.
logical function, public cmp_strings(str1, str2)
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.