UFO
ufo_rttovonedvarcheck_minimize_utils_mod.f90
Go to the documentation of this file.
1 ! (C) Copyright 2020 Met Office
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 
6 !> Fortran module containing subroutines used by both minimizers.
7 
9 
10 use fckit_log_module, only : fckit_log
11 use iso_c_binding
12 use kinds
13 use oops_variables_mod
14 use ufo_constants_mod, only: grav, zero, t0c, half, one, two, min_q
21 use ufo_vars_mod
23 
24 implicit none
25 private
26 
27 ! subroutines - public
36 
37 character(len=max_string) :: message
38 
39 contains
40 
41 !-------------------------------------------------------------------------------
42 !> Copy geovals data (and ob) to profile.
43 !!
44 !! \details Heritage: Ops_SatRad_RTprof2Vec_RTTOV12.f90
45 !!
46 !! Convert profile data from the GeoVaLs format (and ob) into the minimisation
47 !! format vector profile. We only copy fields that are being retrieved, as indicated by
48 !! the profindex structure.
49 !!
50 !! \author Met Office
51 !!
52 !! \date 09/06/2020: Created
53 !!
54 subroutine ufo_rttovonedvarcheck_geovals2profvec( geovals, & ! in
55  profindex, & ! in
56  ob, & ! in
57  prof_x ) ! out
58 
59 implicit none
60 
61 ! subroutine arguments:
62 type(ufo_geovals), intent(in) :: geovals !< model data at obs location
63 type(ufo_rttovonedvarcheck_profindex), intent(in) :: profindex !< index array for x vector
64 type(ufo_rttovonedvarcheck_ob), intent(in) :: ob !< satellite metadata
65 real(kind_real), intent(out) :: prof_x(:) !< x vector
66 
67 ! Local arguments:
68 character(len=*), parameter :: routinename = "ufo_rttovonedvarcheck_GeoVaLs2ProfVec"
69 character(len=max_string) :: varname
70 
71 type(ufo_geoval), pointer :: geoval
72 integer :: nlevels
73 integer :: ii
74 real(kind_real), allocatable :: humidity_total(:)
75 real(kind_real), allocatable :: emiss_pc(:)
76 real(kind_real) :: u, v ! components for windspeed calculation
77 
78 !-------------------------------------------------------------------------------
79 
80 prof_x(:) = zero
81 nlevels = profindex % nlevels
82 
83 !------------------------------
84 ! 2. Set multi-level variables
85 !------------------------------
86 
87 ! Note: GeoVaLs are surface -> TOA; prof_x is TOA -> surface
88 
89 ! Note that if number of profile levels is less than number of pressure levels
90 ! we assume the levels are from the surface upwards (remember that RTTOV levels
91 ! are upside-down)
92 
93 ! var_ts - air_temperature - K
94 if (profindex % t(1) > 0) then
95  call ufo_geovals_get_var(geovals, var_ts, geoval)
96  prof_x(profindex % t(1):profindex % t(2)) = geoval%vals(nlevels:1:-1, 1) ! K
97 end if
98 
99 ! var_q - specific_humidity - kg/kg
100 ! for retrieval is ln(g/kg)
101 if (profindex % q(1) > 0) then
102  call ufo_geovals_get_var(geovals, var_q, geoval)
103  prof_x(profindex % q(1):profindex % q(2)) = &
104  log(geoval%vals(nlevels:1:-1, 1) * 1000.0_kind_real) ! ln(g/kg)
105 end if
106 
107 ! var_q - specific_humidity - kg/kg
108 ! var_clw = "mass_content_of_cloud_liquid_water_in_atmosphere_layer" - kg/kg
109 ! var_cli = "mass_content_of_cloud_ice_in_atmosphere_layer" - kg/kg
110 ! for retrieval is ln(g/kg)
111 if (profindex % qt(1) > 0) then
112  allocate(humidity_total(nlevels))
113  humidity_total(:) = zero
114 
115  ! Get humidity data from geovals
116  call ufo_geovals_get_var(geovals, var_q, geoval)
117  humidity_total(:) = humidity_total(:) + geoval%vals(nlevels:1:-1, 1)
118  call ufo_geovals_get_var(geovals, var_clw, geoval)
119  humidity_total(:) = humidity_total(:) + geoval%vals(nlevels:1:-1, 1)
120  call ufo_geovals_get_var(geovals, var_cli, geoval)
121  humidity_total(:) = humidity_total(:) + geoval%vals(nlevels:1:-1, 1)
122 
123  ! Convert from kg/kg to ln(g/kg)
124  prof_x(profindex % qt(1):profindex % qt(2)) = log(humidity_total * 1000.0_kind_real) ! ln(g/kg)
125 
126  deallocate(humidity_total)
127 end if
128 
129 !----------------------------
130 ! 3. Single-valued variables
131 !----------------------------
132 
133 ! var_sfc_t2m = "surface_temperature"
134 if (profindex % t2 > 0) then
135  call ufo_geovals_get_var(geovals, var_sfc_t2m, geoval)
136  prof_x(profindex % t2) = geoval%vals(1, 1)
137 end if
138 
139 ! var_sfc_q2m = "specific_humidity_at_two_meters_above_surface" (kg/kg)
140 ! for retrieval is ln(g/kg)
141 if (profindex % q2 > 0) then
142  call ufo_geovals_get_var(geovals, var_sfc_q2m, geoval)
143  prof_x(profindex % q2) = log(geoval%vals(1, 1) * 1000.0_kind_real) ! ln(g/kg)
144 end if
145 
146 ! var_sfc_p2m = "air_pressure_at_two_meters_above_surface" ! (Pa)
147 if (profindex % pstar > 0) then
148  call ufo_geovals_get_var(geovals, var_sfc_p2m, geoval)
149  prof_x(profindex % pstar) = geoval%vals(1, 1) / 100.0_kind_real ! Pa to hPa
150 end if
151 
152 ! var_sfc_tskin = "skin_temperature" ! (K)
153 if (profindex % tstar > 0) then
154  call ufo_geovals_get_var(geovals, var_sfc_tskin, geoval)
155  prof_x(profindex % tstar) = geoval%vals(1, 1)
156 end if
157 
158 ! This has been left in for future development
159 ! cloud top pressure
160 !if (profindex % cloudtopp > 0) then
161 ! prof_x(profindex % cloudtopp) = ob % cloudtopp ! carried around as hPa
162 !end if
163 
164 ! This has been left in for future development
165 ! cloud fraction
166 !if (profindex % cloudfrac > 0) then
167 ! prof_x(profindex % cloudfrac) = ob % cloudfrac
168 !end if
169 
170 ! Windspeed - var_sfc_u10 = "uwind_at_10m"
171 ! - var_sfc_v10 = "vwind_at_10m"
172 ! - windsp = sqrt (u*u + v*v)
173 if (profindex % windspeed > 0) then
174  call ufo_geovals_get_var(geovals, trim(var_sfc_u10), geoval)
175  u = geoval % vals(1, 1)
176  call ufo_geovals_get_var(geovals, trim(var_sfc_v10), geoval)
177  v = geoval % vals(1, 1)
178  prof_x(profindex % windspeed) = sqrt(u ** 2 + v ** 2)
179 end if
180 
181 !----------------------------
182 ! 4. Emissivities
183 ! This has been left in for future development
184 !----------------------------
185 
186 ! Microwave Emissivity
187 !if (profindex % mwemiss(1) > 0) then
188 ! ! Check that emissivity map is the correct size for the profile
189 ! if ((profindex % mwemiss(2) - profindex % mwemiss(1) + 1) /= size(EmissMap)) then
190 ! call abor1_ftn("mwemiss size differs from emissivity map")
191 ! end if
192 ! ! Copy microwave emissivity to profile
193 ! prof_x(profindex % mwemiss(1):profindex % mwemiss(2)) = ob % emiss(EmissMap)
194 !end if
195 
196 ! Retrieval of emissivity principal components
197 !if (profindex % emisspc(1) > 0) THEN
198 ! ! convert ob % emiss to emiss pc
199 ! allocate(emiss_pc(profindex % emisspc(2)-profindex % emisspc(1)+1))
200 ! call ob % pcemis % emistoPC(ob % channels_used(:), ob % emiss(:), emiss_pc(:))
201 ! prof_x(profindex % emisspc(1):profindex % emisspc(2)) = emiss_pc
202 ! deallocate(emiss_pc)
203 !end if
204 
206 
207 !-------------------------------------------------------------------------------
208 !> Copy profile data to geovals (and ob).
209 !!
210 !! \details Heritage: Ops_SatRad_Vec2RTprof_RTTOV12.f90
211 !!
212 !! Convert profile data to the GeoVaLs (and ob) format. We only copy fields
213 !! that are being retrieved, as indicated by the profindex structure.
214 !!
215 !! \author Met Office
216 !!
217 !! \date 09/06/2020: Created
218 !!
219 subroutine ufo_rttovonedvarcheck_profvec2geovals(geovals, & ! inout
220  profindex, & ! in
221  ob, & ! inout
222  prof_x, & ! in
223  UseQtsplitRain) ! in
224 
225 implicit none
226 
227 ! subroutine arguments:
228 type(ufo_geovals), intent(inout) :: geovals !< model data at obs location
229 type(ufo_rttovonedvarcheck_profindex), intent(in) :: profindex !< index array for x vector
230 type(ufo_rttovonedvarcheck_ob), intent(inout) :: ob !< satellite metadata
231 real(kind_real), intent(in) :: prof_x(:) !< x vector
232 logical, intent(in) :: useqtsplitrain !< flag to choose whether to split rain in qt
233 
234 ! Local arguments:
235 character(len=*), parameter :: routinename = "ufo_rttovonedvarcheck_ProfVec2GeoVaLs"
236 character(len=max_string) :: varname
237 integer :: gv_index, i, ii
238 integer :: nlevels
239 integer :: emisselement
240 type(ufo_geoval), pointer :: geoval
241 real(kind_real), allocatable :: pressure(:)
242 real(kind_real), allocatable :: humidity_total(:)
243 real(kind_real), allocatable :: q(:)
244 real(kind_real), allocatable :: ql(:)
245 real(kind_real), allocatable :: qi(:)
246 real(kind_real), allocatable :: emiss_pc(:)
247 real(kind_real) :: u, v, windsp ! variable needed for the windspeed calculation
248 
249 !-------------------------------------------------------------------------------
250 
251 nlevels = profindex % nlevels
252 
253 !------------------------------
254 ! 2. Set multi-level variables
255 !------------------------------
256 
257 ! Note GeoVaLs are surface -> TOA ; profile is TOA -> surface
258 
259 ! Note that if number of profile levels is less than number of pressure levels
260 ! we assume the levels are from the surface upwards (remember that RTTOV levels
261 ! are upside-down)
262 
263 ! var_ts - air_temperature - K
264 if (profindex % t(1) > 0) then
265  gv_index = 0
266  do i=1,geovals%nvar
267  if (cmp_strings(var_ts, geovals%variables(i))) gv_index = i
268  end do
269  geovals%geovals(gv_index)%vals(nlevels:1:-1,1) = prof_x(profindex % t(1):profindex % t(2)) ! K
270 end if
271 
272 ! var_q = "specific_humidity" ! kg/kg
273 ! for retrieval is ln(g/kg)
274 if (profindex % q(1) > 0) then
275  gv_index = 0
276  do i=1,geovals%nvar
277  if (cmp_strings(var_q, geovals%variables(i))) gv_index = i
278  end do
279  geovals%geovals(gv_index)%vals(nlevels:1:-1,1) = exp(prof_x(profindex % q(1):profindex % q(2))) / &
280  1000.0_kind_real ! ln(g/kg) => kg/kg
281 end if
282 
283 ! var_q = "specific_humidity" ! kg/kg
284 ! var_clw = "mass_content_of_cloud_liquid_water_in_atmosphere_layer" - kg/kg
285 ! var_cli = "mass_content_of_cloud_ice_in_atmosphere_layer" - kg/kg
286 ! for retrieval is ln(g/kg)
287 if (profindex % qt(1) > 0) then
288  nlevels = profindex % nlevels
289  allocate(pressure(nlevels))
290  allocate(humidity_total(nlevels))
291  allocate(q(nlevels))
292  allocate(ql(nlevels))
293  allocate(qi(nlevels))
294 
295  ! Convert from ln(g/kg) to kg/kg
296  humidity_total(nlevels:1:-1) = exp(prof_x(profindex % qt(1):profindex % qt(2))) / &
297  1000.0_kind_real ! ln(g/kg) => kg/kg
298 
299  ! var_prs = "air_pressure" Pa
300  call ufo_geovals_get_var(geovals, var_prs, geoval)
301  pressure(:) = geoval%vals(:, 1) ! Pa
302 
303  ! Split qtotal to q(water_vapour), q(liquid), q(ice)
304  call ops_satrad_qsplit ( 1, &
305  pressure(:), &
306  ob % background_T(:), &
307  humidity_total, &
308  q(:), &
309  ql(:), &
310  qi(:), &
311  useqtsplitrain)
312 
313  ! Assign values to geovals
314  gv_index = 0
315  do i=1,geovals%nvar
316  if (cmp_strings(var_q, geovals%variables(i))) gv_index = i
317  end do
318  geovals%geovals(gv_index)%vals(:,1) = q(:)
319 
320  gv_index = 0
321  do i=1,geovals%nvar
322  if (cmp_strings(var_clw, geovals%variables(i))) gv_index = i
323  end do
324  geovals%geovals(gv_index)%vals(:,1) = ql(:)
325 
326  gv_index = 0
327  do i=1,geovals%nvar
328  if (cmp_strings(var_cli, geovals%variables(i))) gv_index = i
329  end do
330  geovals%geovals(gv_index)%vals(:,1) = qi(:)
331 
332  deallocate(pressure)
333  deallocate(humidity_total)
334  deallocate(q)
335  deallocate(ql)
336  deallocate(qi)
337 
338 end if
339 
340 !----------------------------
341 ! 3. Single-valued variables
342 !----------------------------
343 
344 ! var_sfc_t2m = "surface_temperature"
345 if (profindex % t2 > 0) then
346  gv_index = 0
347  do i=1,geovals%nvar
348  if (cmp_strings(var_sfc_t2m, geovals%variables(i))) gv_index = i
349  end do
350  geovals%geovals(gv_index)%vals(1,1) = prof_x(profindex % t2) ! K
351 end if
352 
353 ! var_sfc_q2m = "specific_humidity_at_two_meters_above_surface" ! (kg/kg)
354 ! for retrieval is ln(g/kg)
355 if (profindex % q2 > 0) then
356  gv_index = 0
357  do i=1,geovals%nvar
358  if (cmp_strings(var_sfc_q2m, geovals%variables(i))) gv_index = i
359  end do
360  geovals%geovals(gv_index)%vals(1,1) = exp(prof_x(profindex % q2)) / 1000.0_kind_real ! ln(g/kg) => kg/kg
361 end if
362 
363 ! var_sfc_p2m = "air_pressure_at_two_meters_above_surface" ! (Pa)
364 if (profindex % pstar > 0) then
365  gv_index = 0
366  do i=1,geovals%nvar
367  if (cmp_strings(var_sfc_p2m, geovals%variables(i))) gv_index = i
368  end do
369  geovals%geovals(gv_index)%vals(1,1) = prof_x(profindex % pstar) * 100.0_kind_real
370 end if
371 
372 ! var_sfc_tskin = "skin_temperature" ! (K)
373 if (profindex % tstar > 0) then
374  gv_index = 0
375  do i=1,geovals%nvar
376  if (cmp_strings(var_sfc_tskin, geovals%variables(i))) gv_index = i
377  end do
378  geovals%geovals(gv_index)%vals(1,1) = prof_x(profindex % tstar)
379 end if
380 
381 ! This has been left in for future development
382 ! cloud top pressure - passed through via the ob
383 !if (profindex % cloudtopp > 0) then
384 ! ob % cloudtopp = prof_x(profindex % cloudtopp) ! stored in ob as hPa
385 !end if
386 
387 ! This has been left in for future development
388 ! cloud fraction - passed through via the ob
389 !if (profindex % cloudfrac > 0) then
390 ! ob % cloudfrac = prof_x(profindex % cloudfrac)
391 !end if
392 
393 ! windspeed
394 if (profindex % windspeed > 0) then
395  call ufo_geovals_get_var(geovals, trim(var_sfc_u10), geoval)
396  u = geoval % vals(1, 1)
397  call ufo_geovals_get_var(geovals, trim(var_sfc_v10), geoval)
398  v = geoval % vals(1, 1)
399  windsp = sqrt(u ** 2 + v ** 2)
400 
401  ! The ratio of new windsp to old windsp gives the fractional change.
402  ! This is then applied to each component of the wind.
403  if (windsp > zero) then
404  u = u * (prof_x(profindex % windspeed) / windsp)
405  v = v * (prof_x(profindex % windspeed) / windsp)
406  else
407  u = zero
408  v = zero
409  end if
410 
411  ! Write back updated u component
412  gv_index = 0
413  do i=1,geovals%nvar
414  if (trim(var_sfc_u10) == trim(geovals%variables(i))) gv_index = i
415  end do
416  geovals%geovals(gv_index)%vals(1,1) = u
417 
418  ! Write back updated v component
419  gv_index = 0
420  do i=1,geovals%nvar
421  if (trim(var_sfc_v10) == trim(geovals%variables(i))) gv_index = i
422  end do
423  geovals%geovals(gv_index)%vals(1,1) = v
424 end if
425 
426 !----------------------------
427 ! 4. Emissivities
428 ! This has been left in for future development
429 !------------------------
430 
431 ! Retrieval of microwave emissivity directly
432 !if (profindex % mwemiss(1) > 0) THEN
433 ! do ii = 1, size(ob % channels_used)
434 ! EmissElement = EmissElements(ob % channels_used(ii))
435 ! ob % emiss(ii) = prof_x(profindex % mwemiss(1) + EmissElement - 1)
436 ! end do
437 !end if
438 
439 ! Retrieval of emissivity principal components
440 !if (profindex % emisspc(1) > 0) THEN
441 ! allocate(emiss_pc(profindex % emisspc(2)-profindex % emisspc(1)+1))
442 ! emiss_pc = prof_x(profindex % emisspc(1):profindex % emisspc(2))
443 ! ! convert emiss_pc to ob % emissivity using
444 ! call ob % pcemis % pctoemis(size(ob % channels_used), ob % channels_used, &
445 ! size(emiss_pc), emiss_pc(:), ob % emiss(:))
446 ! deallocate(emiss_pc)
447 !end if
448 
450 
451 !-------------------------------------------------------------------------------
452 !> Check the geovals are ready for the first iteration
453 !!
454 !! \details Heritage: Ops_SatRad_SetUpRTprofBg_RTTOV12.f90
455 !!
456 !! Check the geovals profile is ready for the first iteration. The
457 !! only check included at the moment if the first calculation for
458 !! q total.
459 !!
460 !! \author Met Office
461 !!
462 !! \date 09/06/2020: Created
463 !!
464 subroutine ufo_rttovonedvarcheck_check_geovals(self, geovals, profindex, surface_type)
465 
466 implicit none
467 
468 ! subroutine arguments:
469 type(ufo_rttovonedvarcheck), intent(in) :: self
470 type(ufo_geovals), intent(inout) :: geovals !< model data at obs location
471 type(ufo_rttovonedvarcheck_profindex), intent(in) :: profindex !< index array for x vector
472 integer, intent(in) :: surface_type !< surface type for cold surface check
473 
474 character(len=*), parameter :: routinename = "ufo_rttovonedvarcheck_check_geovals"
475 character(len=max_string) :: varname
476 type(ufo_geoval), pointer :: geoval
477 integer :: gv_index, i ! counters
478 integer :: nlevels
479 real(kind_real), allocatable :: temperature(:) ! temperature (K)
480 real(kind_real), allocatable :: pressure(:) ! pressure (Pa)
481 real(kind_real), allocatable :: qsaturated(:)
482 real(kind_real), allocatable :: humidity_total(:)
483 real(kind_real), allocatable :: q(:) ! specific humidity (kg/kg)
484 real(kind_real), allocatable :: ql(:)
485 real(kind_real), allocatable :: qi(:)
486 real(kind_real) :: skin_t, pressure_2m, temperature_2m, newt
487 integer :: level_1000hpa, level_950hpa
488 
489 write(message, *) routinename, " : started"
490 call fckit_log % debug(message)
491 
492 ! -------------------------------------------
493 ! Load variables needed by multiple routines
494 ! -------------------------------------------
495 
496 nlevels = profindex % nlevels
497 allocate(temperature(nlevels))
498 allocate(pressure(nlevels))
499 call ufo_geovals_get_var(geovals, trim(var_ts), geoval)
500 temperature(:) = geoval%vals(:, 1) ! K
501 call ufo_geovals_get_var(geovals, trim(var_prs), geoval)
502 pressure(:) = geoval%vals(:, 1) ! Pa
503 
504 !---------------------------------------------------
505 ! 1. Make sure q and q2m does not exceed saturation
506 !---------------------------------------------------
507 if (profindex % q(1) > 0 .or. profindex % qt(1) > 0) then
508  allocate(q(nlevels))
509  allocate(qsaturated(nlevels))
510 
511  ! Get humidity - kg/kg
512  varname = trim(var_q)
513  call ufo_geovals_get_var(geovals, varname, geoval)
514  q(:) = geoval%vals(:, 1)
515 
516  ! Calculated saturation humidity
517  if (self % UseRHwaterForQC) then
518  call ops_qsatwat (qsaturated(:), & ! out
519  temperature(:), & ! in
520  pressure(:), & ! in
521  nlevels) ! in
522  else
523  call ops_qsat (qsaturated(:), & ! out
524  temperature(:), & ! in
525  pressure(:), & ! in
526  nlevels) ! in
527  end if
528 
529  ! Limit q
530  where (q > qsaturated)
531  q = qsaturated
532  end where
533  where (q < min_q)
534  q = min_q
535  end where
536 
537  ! Assign values to geovals q
538  gv_index = 0
539  do i=1,geovals%nvar
540  if (cmp_strings(varname, geovals%variables(i))) gv_index = i
541  end do
542  geovals%geovals(gv_index) % vals(:,1) = q(:)
543 
544  deallocate(q)
545  deallocate(qsaturated)
546 end if
547 
548 if (profindex % q2 > 0) then
549  allocate(q(1))
550  allocate(qsaturated(1))
551 
552  ! Get humidity - kg/kg
553  varname = trim(var_sfc_q2m)
554  call ufo_geovals_get_var(geovals, varname, geoval)
555  q(1) = geoval%vals(1, 1)
556 
557  ! Calculated saturation humidity
558  if (self % UseRHwaterForQC) then
559  call ops_qsatwat (qsaturated(1:1), & ! out
560  temperature(1:1), & ! in
561  pressure(1:1), & ! in
562  1) ! in
563  else
564  call ops_qsat (qsaturated(1:1), & ! out
565  temperature(1:1), & ! in
566  pressure(1:1), & ! in
567  1) ! in
568  end if
569 
570  ! Limit q
571  if (q(1) > qsaturated(1)) q(1) = qsaturated(1)
572  if (q(1) < min_q) q(1) = min_q
573 
574  ! Assign values to geovals q
575  gv_index = 0
576  do i=1,geovals%nvar
577  if (cmp_strings(varname, geovals%variables(i))) gv_index = i
578  end do
579  geovals%geovals(gv_index) % vals(1,1) = q(1)
580 
581  deallocate(q)
582  deallocate(qsaturated)
583 end if
584 
585 !-------------------------
586 ! 2. Specific humidity total
587 !-------------------------
588 
589 if (profindex % qt(1) > 0) then
590 
591  allocate(humidity_total(nlevels))
592  allocate(q(nlevels))
593  allocate(ql(nlevels))
594  allocate(qi(nlevels))
595 
596  humidity_total(:) = 0.0
597  ! Water vapour
598  call ufo_geovals_get_var(geovals, trim(var_q), geoval)
599  humidity_total(:) = humidity_total(:) + geoval%vals(:, 1)
600 
601  ! Cloud liquid water
602  call ufo_geovals_get_var(geovals, trim(var_clw), geoval)
603  where (geoval%vals(:, 1) < 0.0) geoval%vals(:, 1) = 0.0
604  humidity_total(:) = humidity_total(:) + geoval%vals(:, 1)
605 
606  ! Split qtotal to q(water_vapour), q(liquid), q(ice)
607  call ops_satrad_qsplit ( 1, &
608  pressure(:), &
609  temperature(:), &
610  humidity_total, &
611  q(:), &
612  ql(:), &
613  qi(:), &
614  self % UseQtsplitRain)
615 
616  ! Assign values to geovals q
617  varname = trim(var_q) ! kg/kg
618  gv_index = 0
619  do i=1,geovals%nvar
620  if (cmp_strings(varname, geovals%variables(i))) gv_index = i
621  end do
622  geovals%geovals(gv_index) % vals(:,1) = q(:)
623 
624  ! Assign values to geovals q clw
625  varname = trim(var_clw) ! kg/kg
626  gv_index = 0
627  do i=1,geovals%nvar
628  if (cmp_strings(varname, geovals%variables(i))) gv_index = i
629  end do
630  geovals%geovals(gv_index) % vals(:,1) = ql(:)
631 
632  ! Assign values to geovals ciw
633  varname = trim(var_cli) ! kg/kg
634  gv_index = 0
635  do i=1,geovals%nvar
636  if (cmp_strings(varname, geovals%variables(i))) gv_index = i
637  end do
638  geovals%geovals(gv_index)%vals(:,1) = qi(:)
639 
640  deallocate(humidity_total)
641  deallocate(q)
642  deallocate(ql)
643  deallocate(qi)
644 
645 end if
646 
647 !----
648 ! Legacy Ops_SatRad_SetUpRTprofBg_RTTOV12.f90 - done here to make sure geovals are updated
649 ! Reset low level temperatures over seaice and cold, low land as per Ops_SatRad_SetUpRTprofBg.F90
650 ! N.B. I think this should be flagged so it's clear that the background has been modified
651 !----
652 if(surface_type /= rtsea .and. self % UseColdSurfaceCheck) then
653 
654  ! Get skin temperature
655  call ufo_geovals_get_var(geovals, var_sfc_tskin, geoval)
656  skin_t = geoval%vals(1, 1)
657 
658  ! Get 2m pressure
659  call ufo_geovals_get_var(geovals, var_sfc_p2m, geoval)
660  pressure_2m = geoval%vals(1, 1)
661 
662  ! Get 2m temperature
663  call ufo_geovals_get_var(geovals, var_sfc_t2m, geoval)
664  temperature_2m = geoval%vals(1, 1)
665 
666  if(skin_t < 271.4_kind_real .and. &
667  pressure_2m > 95000.0_kind_real) then
668 
669  level_1000hpa = minloc(abs(pressure - 100000.0_kind_real),dim=1)
670  level_950hpa = minloc(abs(pressure - 95000.0_kind_real),dim=1)
671 
672  newt = temperature(level_950hpa)
673  if(pressure_2m > 100000.0_kind_real) then
674  newt = max(newt, temperature(level_1000hpa))
675  end if
676  newt = min(newt, 271.4_kind_real)
677 
678  temperature(level_1000hpa) = max(temperature(level_1000hpa), newt)
679  temperature_2m = max(temperature_2m, newt)
680  skin_t = max(skin_t, newt)
681 
682  ! Put updated values back into geovals
683  ! Temperature
684  gv_index = 0
685  varname = trim(var_ts)
686  do i=1,geovals%nvar
687  if (cmp_strings(varname, geovals%variables(i))) gv_index = i
688  end do
689  geovals%geovals(gv_index) % vals(level_1000hpa,1) = temperature(level_1000hpa)
690 
691  ! 2m Temperature
692  gv_index = 0
693  varname = trim(var_sfc_t2m)
694  do i=1,geovals%nvar
695  if (cmp_strings(varname, geovals%variables(i))) gv_index = i
696  end do
697  geovals%geovals(gv_index) % vals(1,1) = temperature_2m
698 
699  ! Skin Temperature
700  gv_index = 0
701  varname = trim(var_sfc_tskin)
702  do i=1,geovals%nvar
703  if (cmp_strings(varname, geovals%variables(i))) gv_index = i
704  end do
705  geovals%geovals(gv_index) % vals(1,1) = skin_t
706 
707  endif
708 
709 endif
710 
711 ! Tidy up
712 if (allocated(temperature)) deallocate(temperature)
713 if (allocated(pressure)) deallocate(pressure)
714 if (allocated(qsaturated)) deallocate(qsaturated)
715 if (allocated(humidity_total)) deallocate(humidity_total)
716 if (allocated(q)) deallocate(q)
717 if (allocated(ql)) deallocate(ql)
718 if (allocated(qi)) deallocate(qi)
719 
720 write(message, *) routinename, " : ended"
721 call fckit_log % debug(message)
722 
724 
725 !-------------------------------------------------------------------------------
726 !> Calculate the cost function.
727 !!
728 !! \details Heritage: Ops_SatRad_CostFunction.f90
729 !!
730 !! Calculate the cost function from the input delta's and error
731 !! covariances.
732 !!
733 !! \author Met Office
734 !!
735 !! \date 09/06/2020: Created
736 !!
737 subroutine ufo_rttovonedvarcheck_costfunction(DeltaProf, b_inv, &
738  DeltaObs, r_matrix, &
739  Jcost)
740 
741 implicit none
742 
743 ! subroutine arguments:
744 real(kind_real), intent(in) :: deltaprof(:)
745 real(kind_real), intent(in) :: b_inv(:,:)
746 real(kind_real), intent(in) :: deltaobs(:)
747 type(ufo_rttovonedvarcheck_rsubmatrix), intent(in) :: r_matrix
748 real(kind_real), intent(out) :: jcost(3)
749 
750 ! Local arguments:
751 character(len=*), parameter :: routinename = "ufo_rttovonedvarcheck_CostFunction"
752 integer :: y_size
753 real(kind_real) :: jb, jo, jcurrent
754 real(kind_real), allocatable :: rinvdeltay(:)
755 
756 !-------------------------------------------------------------------------------
757 
758 allocate(rinvdeltay, source=deltaobs)
759 
760 y_size = size(deltaobs)
761 jcost(:) = zero
762 call r_matrix % multiply_inverse_vector(deltaobs, rinvdeltay)
763 
764 jo = half * dot_product(deltaobs, rinvdeltay)
765 jb = half * dot_product(deltaprof, (matmul(b_inv, deltaprof)))
766 jcurrent = jb + jo
767 
768 jcost(1) = (jo + jb) * two / real(y_size, kind_real) ! Normalize cost by nchans
769 jcost(2) = jb * two / real(y_size, kind_real) ! Normalize cost by nchans
770 jcost(3) = jo * two / real(y_size, kind_real) ! Normalize cost by nchans
771 
772 write(message,*) "Jo, Jb, Jcurrent = ", jo, jb, jcost(1)
773 call fckit_log % debug(message)
774 
775 deallocate(rinvdeltay)
776 
778 
779 !-------------------------------------------------------------------------------
780 !> Constrain profile humidity and check temperature values are okay
781 !!
782 !! \details Heritage: Ops_SatRad_CheckIteration.f90
783 !!
784 !! Check humidity and temperature profiles.
785 !!
786 !! \author Met Office
787 !!
788 !! \date 09/06/2020: Created
789 !!
791  geovals, &
792  profindex, &
793  profile, &
794  OutOfRange)
795 
796 implicit none
797 
798 ! subroutine arguments:
799 type(ufo_rttovonedvarcheck), intent(in) :: self
800 type(ufo_geovals), intent(in) :: geovals
801 type(ufo_rttovonedvarcheck_profindex), intent(in) :: profindex
802 real(kind_real), intent(inout) :: profile(:)
803 logical, intent(out) :: outofrange
804 
805 ! Local declarations:
806 real(kind_real), allocatable :: qsaturated(:)
807 real(kind_real), allocatable :: scaled_qsaturated(:)
808 real(kind_real) :: q2_sat(1)
809 real(kind_real), allocatable :: plevels_1dvar(:)
810 real(kind_real) :: pstar_pa(1)
811 real(kind_real), allocatable :: temp(:)
812 real(kind_real) :: temp2(1)
813 real(kind_real) :: rtbase
814 integer :: nlevels_q
815 integer :: toplevel_q
816 character(len=*), parameter :: routinename = "ufo_rttovonedvarcheck_CheckIteration"
817 type(ufo_geoval), pointer :: geoval
818 character(len=max_string) :: varname
819 integer :: ii
820 integer :: nlevels_1dvar
821 
822 ! Setup
823 outofrange = .false.
824 nlevels_1dvar = self % nlevels
825 allocate(temp(nlevels_1dvar))
826 
827 !---------------------
828 ! 1. Check Temperatures
829 !---------------------
830 
831 !----
832 ! 1.1) levels
833 !----
834 
835 if (profindex % t(1) > 0) then
836  temp = profile(profindex % t(1):profindex % t(2))
837  if (any(temp < mintemperature) .or. any(temp > maxtemperature)) then
838  outofrange = .true.
839  end if
840 else
841  varname = var_ts
842  call ufo_geovals_get_var(geovals, varname, geoval)
843  ! Note: profile is TOA -> surface
844  temp = geoval%vals(nlevels_1dvar:1:-1, 1) ! K
845 end if
846 
847 !----
848 ! 1.2) surface air
849 !----
850 
851 if (profindex % t2 > 0) then
852  temp2 = profile(profindex % t2)
853  if (temp2(1) < mintemperature .or. temp2(1) > maxtemperature) then
854  outofrange = .true.
855  end if
856 else
857  varname = var_sfc_t2m
858  call ufo_geovals_get_var(geovals, varname, geoval)
859  temp2 = geoval%vals(1, 1) ! K
860 end if
861 
862 !----
863 ! 1.3) surface skin
864 !----
865 
866 if (profindex % tstar > 0) then
867  if (profile(profindex % tstar) < mintemperature .or. &
868  profile(profindex % tstar) > maxtemperature) then
869  outofrange = .true.
870  end if
871 end if
872 
873 !---------------------
874 ! 2. Constrain humidity
875 !---------------------
876 
877 constrain: if (.not. outofrange) then
878 
879  ! Work out the number of humidity levels and allocate size to arrays
880 
881  if (profindex % q(1) > 0) then
882  nlevels_q = profindex % q(2) - profindex % q(1) + 1
883  else if (profindex % qt(1) > 0) then
884  nlevels_q = profindex % qt(2) - profindex % qt(1) + 1
885  allocate (scaled_qsaturated(nlevels_q))
886  else
887  nlevels_q = nlevels_1dvar
888  end if
889  toplevel_q = nlevels_1dvar - nlevels_q + 1
890  allocate (qsaturated(nlevels_q))
891 
892 
893  ! Get pressure
894  varname = var_prs
895  call ufo_geovals_get_var(geovals, varname, geoval)
896  if (.not. allocated(plevels_1dvar)) allocate(plevels_1dvar(nlevels_q))
897  ! Note: profile is TOA -> surface
898  plevels_1dvar(:) = geoval%vals(nlevels_1dvar:1:-1, 1) ! K
899 
900  !----
901  ! 2.1) Levels
902  !----
903 
904  ! Note that if number of profile levels is less than number of pressure levels
905  ! we assume the levels are from the surface upwards (remember that RTTOV levels
906  ! are upside-down)
907 
908  if (profindex % q(1) > 0) then
909 
910  if (self % useRHwaterForQC) then
911  call ops_qsatwat(qsaturated(1:nlevels_q), & ! out (qsat levels)
912  temp(1:nlevels_q), & ! in (t levels)
913  plevels_1dvar(1:nlevels_q), & ! in (p levels)
914  nlevels_q) ! in
915  else
916  call ops_qsat(qsaturated(1:nlevels_q), & ! out
917  temp(1:nlevels_q), & ! in
918  plevels_1dvar(1:nlevels_q), & ! in
919  nlevels_q) ! in
920  end if
921 
922  qsaturated(1:nlevels_q) = log(qsaturated(1:nlevels_q) * 1000.0_kind_real)
923  where (profile(profindex % q(1):profindex % q(2)) > qsaturated(1:nlevels_q))
924  profile(profindex % q(1):profindex % q(2)) = qsaturated(1:nlevels_q)
925  end where
926 
927  end if
928 
929  if (profindex % qt(1) > 0) then
930 
931  ! Qtotal is not included in the relative humidity quality control changes
932  call ops_qsat (qsaturated(1:nlevels_q), & ! out
933  temp(1:nlevels_q), & ! in
934  plevels_1dvar(1:nlevels_q), & ! in
935  nlevels_q) ! in
936 
937  ! scaled_qsaturated is generated as an upper limit on the value of qtot , and
938  ! is set to 2*qsat.
939  scaled_qsaturated(1:nlevels_q) = log(two * qsaturated(1:nlevels_q) * 1000.0_kind_real)
940  where (profile(profindex % qt(1):profindex % qt(2)) > scaled_qsaturated(1:nlevels_q))
941  profile(profindex % qt(1):profindex % qt(2)) = scaled_qsaturated(1:nlevels_q)
942  end where
943 
944  end if
945 
946  !----
947  ! 2.2) Surface
948  !----
949 
950  if (profindex % q2 > 0) then
951  varname = var_sfc_p2m
952  call ufo_geovals_get_var(geovals, varname, geoval)
953  pstar_pa(1) = geoval%vals(1, 1)
954  if (self % useRHwaterForQC) then
955  call ops_qsatwat (q2_sat(1:1), & ! out
956  temp2, & ! in
957  pstar_pa(1:1), & ! in
958  1) ! in
959  else
960  call ops_qsat (q2_sat(1:1), & ! out
961  temp2, & ! in
962  pstar_pa(1:1), & ! in
963  1) ! in
964  end if
965  q2_sat(1) = log(q2_sat(1) * 1000.0_kind_real)
966  if (profile(profindex % q2) > q2_sat(1)) then
967  profile(profindex % q2) = q2_sat(1)
968  end if
969  end if
970 
971 ! This has been left in for future development
972 ! !----
973 ! ! 2.3) Grey cloud
974 ! !----
975 !
976 ! if (profindex % cloudtopp > 0) then
977 ! profile(profindex % CloudFrac) = min (profile(profindex % CloudFrac), 1.0)
978 ! profile(profindex % CloudFrac) = max (profile(profindex % CloudFrac), 0.0)
979 ! profile(profindex % CloudTopP) = max (profile(profindex % CloudTopP), 100.0)
980 ! if (LimitCTPtorTBase) then
981 ! rtbase = maxval (Plevels_RTModel(:))
982 ! profile(profindex % CloudTopP) = min (profile(profindex % CloudTopP), Pstar_mb, rtbase)
983 ! else
984 ! profile(profindex % CloudTopP) = min (profile(profindex % CloudTopP), Pstar_mb)
985 ! end if
986 ! end if
987 !
988 ! This has been left in for future development
989 ! !----
990 ! ! 2.4) Surface emissivity PCs
991 ! !----
992 !
993 ! if (profindex % emisspc(1) > 0) then
994 ! where (profile(profindex % emisspc(1):profindex % emisspc(2)) > EmisEigenVec % PCmax(1:nemisspc))
995 ! profile(profindex % emisspc(1):profindex % emisspc(2)) = EmisEigenVec % PCmax(1:nemisspc)
996 ! end where
997 ! where (profile(profindex % emisspc(1):profindex % emisspc(2)) < EmisEigenVec % PCmin(1:nemisspc))
998 ! profile(profindex % emisspc(1):profindex % emisspc(2)) = EmisEigenVec % PCmin(1:nemisspc)
999 ! end where
1000 ! end if
1001 !
1002 ! This has been left in for future development
1003 ! !--------
1004 ! ! 2.5) Cloud profiles
1005 ! !--------
1006 !
1007 ! if (profindex % cf(1) > 0) then
1008 ! where (profile(profindex % cf(1):profindex % cf(2)) <= 0.001)
1009 ! profile(profindex % cf(1):profindex % cf(2)) = 0.001
1010 ! end where
1011 ! where (profile(profindex % cf(1):profindex % cf(2)) >= 1.0)
1012 ! profile(profindex % cf(1):profindex % cf(2)) = 0.999
1013 ! end where
1014 ! end if
1015 !
1016 ! if (profindex % ql(1) > 0 .AND. .not. useLogForCloud) then
1017 ! where (profile(profindex % ql(1):profindex % ql(2)) < 0)
1018 ! profile(profindex % ql(1):profindex % ql(2)) = 0
1019 ! end where
1020 ! end if
1021 !
1022 ! if (profindex % qi(1) > 0 .AND. .not. useLogForCloud) then
1023 ! where (profile(profindex % qi(1):profindex % qi(2)) < 0)
1024 ! profile(profindex % qi(1):profindex % qi(2)) = 0
1025 ! end where
1026 ! end if
1027 
1028 end if constrain
1029 
1030 ! --------
1031 ! Tidy up
1032 ! --------
1033 if (allocated(qsaturated)) deallocate(qsaturated)
1034 if (allocated(scaled_qsaturated)) deallocate(scaled_qsaturated)
1035 if (allocated(plevels_1dvar)) deallocate(plevels_1dvar)
1036 if (allocated(temp)) deallocate(temp)
1037 
1039 
1040 !-------------------------------------------------------------------------------
1041 !> Check cloud during iteration.
1042 !!
1043 !! \details Heritage: Ops_SatRad_CheckCloudyIteration.f90
1044 !!
1045 !! For a 1dvar profile using cloud variables, check that the liquid water path
1046 !! and the ice water path are sensible. if they are beyond sensible values stop
1047 !! 1dvar and reject profile
1048 !!
1049 !! \author Met Office
1050 !!
1051 !! \date 09/06/2020: Created
1052 !!
1054  geovals, & ! in
1055  profindex, & ! in
1056  nlevels_1dvar, & ! in
1057  OutOfRange, & ! out
1058  OutLWP ) ! out
1059 
1060 implicit none
1061 
1062 type(ufo_geovals), intent(in) :: geovals
1063 type(ufo_rttovonedvarcheck_profindex), intent(in) :: profindex
1064 integer, intent(in) :: nlevels_1dvar
1065 logical, intent(out) :: outofrange
1066 real(kind_real), optional, intent(out) :: outlwp
1067 
1068 ! Local variables:
1069 real(kind_real) :: lwp
1070 real(kind_real) :: iwp
1071 real(kind_real) :: dp
1072 real(kind_real) :: meanql
1073 real(kind_real) :: meanqi
1074 integer :: i
1075 integer :: nlevels_q, toplevel_q
1076 character(len=*), parameter :: routinename = "ufo_rttovonedvarcheck_CheckCloudyIteration"
1077 
1078 real(kind_real), parameter :: maxlwp = two
1079 real(kind_real), parameter :: maxiwp = 3.0_kind_real
1080 real(kind_real) :: plevels_1dvar(nlevels_1dvar)
1081 type(ufo_geoval), pointer :: geoval
1082 real(kind_real) :: clw(nlevels_1dvar)
1083 real(kind_real) :: ciw(nlevels_1dvar)
1084 character(len=max_string) :: varname
1085 
1086 !-------------------------------------------------------------------------------
1087 
1088 !initialise
1089 outofrange = .false.
1090 iwp = zero
1091 lwp = zero
1092 
1093 ! Get pressure from geovals
1094 varname = var_prs
1095 call ufo_geovals_get_var(geovals, varname, geoval)
1096 plevels_1dvar(:) = geoval%vals(:, 1) ! K
1097 
1098 ! Get clw from geovals
1099 varname = var_clw
1100 call ufo_geovals_get_var(geovals, varname, geoval)
1101 clw = geoval%vals(:, 1)
1102 
1103 ! Get ciw from geovals
1104 varname = var_cli
1105 call ufo_geovals_get_var(geovals, varname, geoval)
1106 ciw = geoval%vals(:, 1)
1107 
1108 ! Work out the number of humidity levels
1109 if ( profindex % q(1) > 0 ) then
1110  nlevels_q = profindex % q(2) - profindex % q(1) + 1
1111 else if ( profindex % qt(1) > 0 ) then
1112  nlevels_q = profindex % qt(2) - profindex % qt(1) + 1
1113 else if ( profindex % ql(1) > 0 ) then
1114  nlevels_q = profindex % ql(2) - profindex % ql(1) + 1
1115 else if ( profindex % qi(1) > 0 ) then
1116  nlevels_q = profindex % qi(2) - profindex % qi(1) + 1
1117 else
1118  nlevels_q = nlevels_1dvar
1119 end if
1120 toplevel_q = nlevels_1dvar - nlevels_q + 1
1121 
1122 !is the profile cloudy?
1123 !if it is do the test
1124 
1125 if (any(ciw(:) > zero) .or. &
1126  any(clw(:) > zero)) then
1127 
1128 !1.1 compute iwp, lwp
1129 
1130  do i=1, nlevels_1dvar-1
1131 
1132  dp = plevels_1dvar(i) - plevels_1dvar(i+1)
1133 
1134  ! Calculate layer mean from CloudIce on levels
1135  meanqi = half * &
1136  (ciw(i) + ciw(i+1))
1137  if (meanqi > zero) then
1138  iwp = iwp + dp * meanqi
1139  end if
1140 
1141  ! Calculate layer mean from CLW on levels
1142  meanql = half * (clw(i) + clw(i+1))
1143  if (meanql > zero) then
1144  lwp = lwp + dp * meanql
1145  end if
1146 
1147  end do
1148 
1149  iwp = iwp / grav
1150  lwp = lwp / grav
1151 
1152 
1153 !2.1 test if lwp iwp exceeds thresholds
1154 
1155  if ((iwp > maxiwp) .or. (lwp > maxlwp)) then
1156  call fckit_log % debug("lwp or iwp exceeds thresholds")
1157  outofrange = .true.
1158  write(message,*) "lwp and iwp = ",lwp,iwp
1159  call fckit_log % debug(message)
1160  else
1161  call fckit_log % debug("lwp and iwp less than thresholds")
1162  write(message,*) "lwp and iwp = ",lwp,iwp
1163  call fckit_log % debug(message)
1164  end if
1165 
1166 end if
1167 
1168 if (present(outlwp)) outlwp = lwp
1169 
1171 
1172 !-----------------------------------------------------------
1173 !> Print detailed information for each iteration for diagnostics
1174 !!
1175 !! \author Met Office
1176 !!
1177 !! \date 29/03/2021: Created
1178 !!
1179 subroutine ufo_rttovonedvarcheck_printiterinfo(yob, hofx, channels, &
1180  guessprofile, backprofile, &
1181  diffprofile, binv, hmatrix)
1182 
1183 implicit none
1184 
1185 real(kind_real), intent(in) :: yob(:)
1186 real(kind_real), intent(in) :: hofx(:)
1187 integer, intent(in) :: channels(:)
1188 real(kind_real), intent(in) :: guessprofile(:)
1189 real(kind_real), intent(in) :: backprofile(:)
1190 real(kind_real), intent(in) :: diffprofile(:)
1191 real(kind_real), intent(in) :: binv(:,:) ! (nprofelements,nprofelements)
1192 real(kind_real), intent(in) :: hmatrix(:,:) ! (nchans,nprofelements)
1193 
1194 integer :: obs_size, profile_size, ii, jj
1195 character(len=12) :: chans_fmt, prof_fmt
1196 character(len=3) :: txt_nchans, txt_nprof
1197 character(len=10) :: int_fmt
1198 
1199 obs_size = size(yob)
1200 write( unit=txt_nchans,fmt='(i3)' ) obs_size
1201 write( unit=chans_fmt,fmt='(a)' ) '(' // trim(txt_nchans) // 'E30.16)'
1202 write( unit=int_fmt,fmt='(a)' ) '(' // trim(txt_nchans) // 'I30)'
1203 
1204 profile_size = size(guessprofile)
1205 write( unit=txt_nprof,fmt='(i3)' ) profile_size
1206 write( unit=prof_fmt,fmt='(a)' ) '(' // trim(txt_nprof) // 'E30.16)'
1207 
1208 write(*,*) "Start print iter info"
1209 
1210 ! Print obs info
1211 write(*,"(2A30)") "yob", "hofx"
1212 do ii = 1, obs_size
1213  write(*,"(2E30.16)") yob(ii),hofx(ii)
1214 end do
1215 
1216 ! Print profile info
1217 write(*,"(3A30)") "guessprofile", "backprofile", "diffprofile"
1218 do ii = 1, profile_size
1219  write(*,"(3E30.16)") guessprofile(ii),backprofile(ii), diffprofile(ii)
1220 end do
1221 
1222 ! Print b inv
1223 write(*,"(2A30)") "B inverse"
1224 do ii = 1, profile_size
1225  write(*,prof_fmt) binv(:,ii)
1226 end do
1227 
1228 ! Print hmatrix
1229 write(*,"(2A30)") "hmatrix"
1230 write(*, int_fmt) channels(:)
1231 do ii = 1, profile_size
1232  write(*,chans_fmt) hmatrix(:,ii)
1233 end do
1234 
1235 write(*,*) "Finished print iter info"
1236 
1238 
1239 ! ----------------------------------------------------------
1240 
1241 subroutine ufo_rttovonedvarcheck_hofxdiags_levels(retrieval_vars, nlevels, ret_nlevs)
1242 
1243 implicit none
1244 
1245 type(oops_variables), intent(in) :: retrieval_vars !< retrieval variables for 1D-Var
1246 integer, intent(in) :: nlevels
1247 integer(c_size_t), intent(inout) :: ret_nlevs(:) !< number of levels for each retreival val
1248 
1249 character(MAXVARLEN), allocatable :: varlist(:)
1250 character(MAXVARLEN) :: varname, message
1251 integer :: i, ss, ee
1252 
1253 ret_nlevs(:) = zero
1254 varlist = retrieval_vars % varlist()
1255 do i = 1, size(varlist)
1256  ss = index(varlist(i), "jacobian_", .false.) + 9
1257  ee = index(varlist(i), "_", .true.) - 1
1258  varname = varlist(i)(ss:ee)
1259  if (trim(varname) == trim(var_ts) .or. &
1260  trim(varname) == trim(var_q) .or. &
1261  trim(varname) == trim(var_clw) .or. &
1262  trim(varname) == trim(var_cli)) then
1263  ret_nlevs(i) = nlevels
1264  else if (trim(varname) == trim(var_sfc_t2m) .or. &
1265  trim(varname) == trim(var_sfc_q2m) .or. &
1266  trim(varname) == trim(var_sfc_p2m) .or. &
1267  trim(varname) == trim(var_sfc_tskin) .or. &
1268  trim(varname) == trim(var_sfc_u10) .or. &
1269  trim(varname) == trim(var_sfc_v10)) then
1270  ret_nlevs(i) = 1
1271  else
1272  write(message, *) trim(varlist(i)), " not setup for retrieval yet: aborting"
1273  call abor1_ftn(message)
1274  end if
1275 end do
1276 
1278 
1279 ! ----------------------------------------------------------
1280 
real(kind_real), parameter, public min_q
real(kind_real), parameter, public one
real(kind_real), parameter, public grav
real(kind_real), parameter, public t0c
real(kind_real), parameter, public zero
real(kind_real), parameter, public two
real(kind_real), parameter, public half
subroutine, public ufo_geovals_get_var(self, varname, geoval)
Fortran module constants used throughout the rttovonedvarcheck filter.
integer, parameter, public rtsea
integer for sea surface type
real(kind_real), parameter, public maxtemperature
Maximum temperature ( K )
real(kind_real), parameter, public mintemperature
Minimum temperature ( K )
Fortran module containing subroutines used by both minimizers.
subroutine, public ufo_rttovonedvarcheck_geovals2profvec(geovals, profindex, ob, prof_x)
Copy geovals data (and ob) to profile.
subroutine, public ufo_rttovonedvarcheck_check_geovals(self, geovals, profindex, surface_type)
Check the geovals are ready for the first iteration.
subroutine, public ufo_rttovonedvarcheck_checkiteration(self, geovals, profindex, profile, OutOfRange)
Constrain profile humidity and check temperature values are okay.
subroutine, public ufo_rttovonedvarcheck_profvec2geovals(geovals, profindex, ob, prof_x, UseQtsplitRain)
Copy profile data to geovals (and ob).
subroutine, public ufo_rttovonedvarcheck_printiterinfo(yob, hofx, channels, guessprofile, backprofile, diffprofile, binv, hmatrix)
Print detailed information for each iteration for diagnostics.
subroutine, public ufo_rttovonedvarcheck_checkcloudyiteration(geovals, profindex, nlevels_1dvar, OutOfRange, OutLWP)
Check cloud during iteration.
subroutine, public ufo_rttovonedvarcheck_costfunction(DeltaProf, b_inv, DeltaObs, r_matrix, Jcost)
Calculate the cost function.
subroutine, public ufo_rttovonedvarcheck_hofxdiags_levels(retrieval_vars, nlevels, ret_nlevs)
Fortran module which contains the observation metadata for a single observation.
Fortran module containing profile index.
Fortran derived type to hold data for the observation covariance.
Fortran module containing main type, setup and utilities for the main rttovonedvarcheck object.
Fortran module with various useful routines.
subroutine, public ops_satrad_qsplit(output_type, p, t, qtotal, q, ql, qi, UseQtSplitRain)
Split the humidity into water vapour, liquid water and ice.
subroutine, public ops_qsat(QS, T, P, npnts)
Calculate the Saturation Specific Humidity Scheme (Qsat): Vapour to Liquid/Ice.
subroutine, public ops_qsatwat(QS, T, P, npnts)
Saturation Specific Humidity Scheme: Vapour to Liquid.
logical function, public cmp_strings(str1, str2)
character(len=maxvarlen), parameter, public var_clw
character(len=maxvarlen), parameter, public var_sfc_v10
character(len=maxvarlen), parameter, public var_prs
character(len=maxvarlen), parameter, public var_q
character(len=maxvarlen), parameter, public var_sfc_u10
character(len=maxvarlen), parameter, public var_sfc_q2m
character(len=maxvarlen), parameter, public var_sfc_tskin
character(len=maxvarlen), parameter, public var_sfc_p2m
character(len=maxvarlen), parameter, public var_ts
character(len=maxvarlen), parameter, public var_cli
character(len=maxvarlen), parameter, public var_sfc_t2m
type to hold interpolated field for one variable, one observation
type to hold interpolated fields required by the obs operators