20 use missing_values_mod
22 use fckit_log_module,
only : fckit_log
38 logical :: vert_interp_ops
40 real(kind_real) :: min_temp_grad
65 logical(c_bool),
intent(in) :: vert_interp_ops
66 logical(c_bool),
intent(in) :: pseudo_ops
67 real(c_float),
intent(in) :: min_temp_grad
69 self % vert_interp_ops = vert_interp_ops
70 self % pseudo_ops = pseudo_ops
71 self % min_temp_grad = min_temp_grad
93 real(kind_real),
intent(inout) :: hofx(:)
94 type(c_ptr),
value,
intent(in) :: obss
97 character(len=*),
parameter :: myname_ =
"ufo_gnssro_refmetoffice_simobs"
98 integer,
parameter :: max_string = 800
100 character(max_string) :: err_msg
101 character(max_string) :: message
109 real(kind_real),
allocatable :: obsLat(:)
110 real(kind_real),
allocatable :: obsLon(:)
111 real(kind_real),
allocatable :: obs_height(:)
114 real(kind_real),
allocatable :: refractivity(:)
115 real(kind_real),
allocatable :: model_heights(:)
119 write(err_msg,*)
"TRACE: ufo_gnssro_refmetoffice_simobs: begin"
120 call fckit_log%info(err_msg)
125 DO ivar = 1, obs_diags % nvar
126 IF (obs_diags % variables(ivar) ==
"refractivity" .OR. &
127 obs_diags % variables(ivar) ==
"model_heights")
THEN
128 write(err_msg,*)
"TRACE: ufo_gnssro_refmetoffice_simobs: initialising obs_diags for " // &
129 obs_diags % variables(ivar)
130 call fckit_log%info(err_msg)
131 obs_diags % geovals(ivar) % nval = 0
136 if (geovals_in%nlocs /=
size(hofx))
then
137 write(err_msg,*) myname_,
' error: nlocs inconsistent!'
138 call abor1_ftn(err_msg)
145 write(message, *) myname_,
' Running Met Office GNSS-RO forward operator with:'
146 call fckit_log%info(message)
147 write(message, *)
'vert_interp_ops =', self % vert_interp_ops, &
148 'pseudo_ops =', self % pseudo_ops,
'min_temp_grad =', self % min_temp_grad
149 call fckit_log%info(message)
157 write(message,
'(A,10I6)')
'Q: ', q%nval, q%nlocs, shape(q%vals)
158 call fckit_log%info(message)
159 write(message,
'(A,10I6)')
'Pressure: ', prs%nval, prs%nlocs, shape(prs%vals)
160 call fckit_log%info(message)
162 nobs = obsspace_get_nlocs(obss)
165 allocate(obslon(nobs))
166 allocate(obslat(nobs))
167 allocate(obs_height(nobs))
169 call obsspace_get_db(obss,
"MetaData",
"longitude", obslon)
170 call obsspace_get_db(obss,
"MetaData",
"latitude", obslat)
171 call obsspace_get_db(obss,
"MetaData",
"obs_height", obs_height)
173 obs_loop:
do iobs = 1, nobs
177 rho_heights % vals(:,iobs), &
178 theta_heights % vals(:,iobs), &
179 prs % vals(:,iobs), &
182 self % vert_interp_ops, &
183 self % min_temp_grad, &
185 obs_height(iobs:iobs), &
193 write(err_msg,*)
"Error with observation processing ", iobs
194 call fckit_log % info(err_msg)
199 DO ivar = 1, obs_diags % nvar
200 IF (obs_diags % variables(ivar) ==
"refractivity")
THEN
202 obs_diags % geovals(ivar) % nval =
SIZE(refractivity)
203 ALLOCATE(obs_diags % geovals(ivar) % vals(
SIZE(refractivity), obs_diags % nlocs))
207 obs_diags % geovals(ivar) % vals(:,iobs) = missing_value(obs_diags % geovals(ivar) % vals(1,1))
209 obs_diags % geovals(ivar) % vals(:,iobs) = refractivity(:)
213 IF (obs_diags % variables(ivar) ==
"model_heights")
THEN
215 obs_diags % geovals(ivar) % nval =
SIZE(model_heights)
216 ALLOCATE(obs_diags % geovals(ivar) % vals(
SIZE(model_heights), obs_diags % nlocs))
220 obs_diags % geovals(ivar) % vals(:,iobs) = missing_value(obs_diags % geovals(ivar) % vals(1,1))
222 obs_diags % geovals(ivar) % vals(:,iobs) = model_heights(:)
230 deallocate(obs_height)
233 write(err_msg,*)
"TRACE: ufo_gnssro_refmetoffice_simobs: completed"
234 call fckit_log%info(err_msg)
257 GPSRO_vert_interp_ops, &
258 GPSRO_min_temp_grad, &
267 INTEGER,
INTENT(IN) :: nlevp
268 INTEGER,
INTENT(IN) :: nlevq
269 REAL(kind_real),
INTENT(IN) :: za(1:nlevp)
270 REAL(kind_real),
INTENT(IN) :: zb(1:nlevq)
271 REAL(kind_real),
INTENT(IN) :: pressure(1:nlevp)
272 REAL(kind_real),
INTENT(IN) :: humidity(1:nlevq)
273 LOGICAL,
INTENT(IN) :: GPSRO_pseudo_ops
274 LOGICAL,
INTENT(IN) :: GPSRO_vert_interp_ops
275 REAL(kind_real),
INTENT(IN) :: GPSRO_min_temp_grad
276 INTEGER,
INTENT(IN) :: nobs
277 REAL(kind_real),
INTENT(IN) :: zobs(1:nobs)
278 REAL(kind_real),
INTENT(IN) :: Latitude
279 REAL(kind_real),
INTENT(INOUT) :: ycalc(1:nobs)
280 LOGICAL,
INTENT(OUT) :: BAErr
281 REAL(kind_real),
INTENT(INOUT),
ALLOCATABLE :: refractivity(:)
282 REAL(kind_real),
INTENT(INOUT),
ALLOCATABLE :: model_heights(:)
286 INTEGER :: nRefLevels
287 REAL(kind_real),
ALLOCATABLE :: nr(:)
291 integer,
parameter :: max_string = 800
292 character(len=*),
parameter :: myname_ =
"Ops_GPSRO_ForwardModel"
296 INTEGER :: num_pseudo
297 REAL(kind_real) :: x(1:nlevp+nlevq)
298 character(max_string) :: err_msg
301 REAL(kind_real) :: temperature(nlevq)
302 REAL(kind_real) :: Pb(nlevq)
303 REAL(kind_real) :: humidity_ob
304 REAL(kind_real) :: T_ob
305 REAL(kind_real) :: P_ob
306 REAL(kind_real) :: log_humid
307 REAL(kind_real) :: temperature_grad
308 REAL(kind_real) :: pressure_coeff
309 REAL(kind_real) :: alpha_interp
310 REAL(kind_real) :: beta_interp
311 REAL(kind_real) :: model_height_diff
312 REAL(kind_real) :: obs_height_diff
315 IF (nlevp /= nlevq + 1)
THEN
316 write(err_msg,*) myname_ //
':' //
' Data must be on a staggered grid nlevp, nlevq = ', nlevp, nlevq
317 call fckit_log % warning(err_msg)
318 write(err_msg,*) myname_ //
':' //
' error: number of levels inconsistent!'
319 call abor1_ftn(err_msg)
323 ycalc(:) = missing_value(ycalc(1))
333 gpsro_vert_interp_ops, &
334 gpsro_min_temp_grad, &
348 IF (gpsro_pseudo_ops)
THEN
349 IF (zb(nlevq) > zobs(iobs) .AND. zb(1) < zobs(iobs))
THEN
353 IF (zobs(iobs) < zb(ilevel + 1))
EXIT
357 model_height_diff = zb(ilevel + 1) - zb(ilevel)
358 obs_height_diff = zobs(iobs) - zb(ilevel)
361 IF (min(humidity(ilevel - 1), humidity(ilevel)) > 0.0)
THEN
363 log_humid = log(humidity(ilevel) / humidity(ilevel + 1)) / model_height_diff
364 humidity_ob = humidity(ilevel) * exp(-log_humid * obs_height_diff)
367 humidity_ob = humidity(ilevel) + (humidity(ilevel + 1) - humidity(ilevel)) / &
368 model_height_diff * obs_height_diff
372 temperature_grad = (temperature(ilevel + 1) - temperature(ilevel)) / &
374 t_ob = temperature(ilevel) + temperature_grad * obs_height_diff
377 IF (abs(temperature(ilevel + 1) - temperature(ilevel)) > gpsro_min_temp_grad)
THEN
378 pressure_coeff = ((pb(ilevel + 1) / pb(ilevel)) * (temperature(ilevel + 1) / temperature(ilevel)) ** &
379 (grav / (
rd * temperature_grad)) - 1.0) / model_height_diff
380 p_ob = (pb(ilevel) * (t_ob / temperature(ilevel)) ** (-grav / (
rd * temperature_grad))) * &
381 (1.0 + pressure_coeff * obs_height_diff)
385 p_ob = pb(ilevel) * exp(log(pb(ilevel + 1) / pb(ilevel)) * &
386 obs_height_diff / model_height_diff)
392 ycalc(iobs) = n_alpha * p_ob / t_ob + n_beta * p_ob * humidity_ob / (t_ob ** 2 * &
393 (mw_ratio + (1.0 - mw_ratio) * humidity_ob))
398 IF (model_heights(nreflevels) > zobs(iobs) .AND. model_heights(1) < zobs(iobs))
THEN
402 IF (zobs(iobs) < model_heights(ilevel + 1))
EXIT
407 alpha_interp = (model_heights(ilevel + 1) - zobs(iobs)) / &
408 (model_heights(ilevel + 1) - model_heights(ilevel))
409 beta_interp = 1.0 - alpha_interp
410 ycalc(iobs) = exp(alpha_interp * log(refractivity(ilevel)) + &
411 beta_interp * log(refractivity(ilevel + 1)))
412 ELSE IF (zobs(iobs) /= missing_value(zobs(iobs)))
THEN
413 print*,
'Height out of range', iobs, nreflevels, model_heights(nreflevels), zobs(iobs)
Fortran module to prepare for Lagrange polynomial interpolation. based on GSI: lagmod....
subroutine, public lag_interp_const(q, x, n)
subroutine, public lag_interp_smthweights(x, xt, aq, bq, w, dw, n)
real(kind_real), parameter, public rd
type(registry_t), public ufo_geovals_registry
Linked list interface - defines registry_t type.
subroutine, public ufo_geovals_reorderzdir(self, varname, zdir)
subroutine, public ufo_geovals_copy(self, other)
Copy one GeoVaLs object into another.
subroutine, public ufo_geovals_delete(self)
subroutine, public ufo_geovals_get_var(self, varname, geoval)
Fortran module for gnssro refractivity Met Office forward operator.
subroutine ufo_gnssro_refmetoffice_setup(self, vert_interp_ops, pseudo_ops, min_temp_grad)
Set up the Met Office GNSS-RO refractivity operator.
subroutine ufo_gnssro_refmetoffice_simobs(self, geovals_in, obss, hofx, obs_diags)
Calculate the model forecast of the observations.
subroutine refmetoffice_forwardmodel(nlevp, nlevq, za, zb, pressure, humidity, GPSRO_pseudo_ops, GPSRO_vert_interp_ops, GPSRO_min_temp_grad, nobs, zobs, Latitude, ycalc, BAErr, refractivity, model_heights)
Interface routine for the GNSS-RO refractivity forward operator.
Module for containing a general refractivity forward operator and its K-matrix.
subroutine, public ufo_calculate_refractivity(nlevP, nlevq, za, zb, P, q, vert_interp_ops, pseudo_ops, min_temp_grad, refracerr, nRefLevels, refractivity, model_heights, temperature, interp_pressure)
Calculation of the refractivity from the pressure and specific humidity.
character(len=maxvarlen), parameter, public var_prsi
character(len=maxvarlen), parameter, public var_q
character(len=maxvarlen), parameter, public var_zi
character(len=maxvarlen), parameter, public var_z
Fortran module to perform linear interpolation.
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.