UFO
ufo_gnssroonedvarcheck_do1dvar_mod.f90
Go to the documentation of this file.
1 !-------------------------------------------------------------------------------
2 ! (C) British Crown Copyright 2020 Met Office
3 !
4 ! This software is licensed under the terms of the Apache Licence Version 2.0
5 ! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6 !-------------------------------------------------------------------------------
7 
8 !> Fortran module for gnssro bending angle Met Office forward operator
9 
11 
12 use kinds, only: kind_real
13 use missing_values_mod, only: missing_value
14 use fckit_log_module, only: fckit_log
15 
16 private
17 public :: ops_gpsro_do1dvar_ba
18 
19 contains
20 
21 !-------------------------------------------------------------------------------
22 ! Find a solution to the satellite sounding inverse problem
23 !-------------------------------------------------------------------------------
24 SUBROUTINE ops_gpsro_do1dvar_ba (nlevp, &
25  nlevq, &
26  BM1, &
27  Bsig, &
28  Back, &
29  Ob, &
30  GPSRO_pseudo_ops, &
31  GPSRO_vert_interp_ops, &
32  GPSRO_min_temp_grad, &
33  GPSRO_cost_funct_test, & ! Threshold value for the cost function convergence test
34  GPSRO_y_test, & ! Threshold value for the yobs-ysol tes
35  GPSRO_n_iteration_test, & ! Maximum number of iterations
36  GPSRO_Delta_factor, & ! Delta
37  GPSRO_Delta_ct2, & ! Delta observations
38  GPSRO_OB_test, & ! Threshold value for the O-B test
39  capsupersat, &
40  BAerr, &
41  Tb, &
42  Ts, &
43  O_Bdiff, &
44  DFS)
45 
47  singlebg_type, &
49 
52 
55 
56 IMPLICIT NONE
57 
58 ! Subroutine arguments:
59 INTEGER, INTENT(IN) :: nlevp
60 INTEGER, INTENT(IN) :: nlevq
61 REAL(kind_real), INTENT(IN) :: bm1(:,:)
62 REAL(kind_real), INTENT(IN) :: bsig(:)
63 TYPE (singlebg_type), INTENT(INOUT) :: back
64 TYPE (singleob_type), INTENT(INOUT) :: ob
65 LOGICAL, INTENT(IN) :: gpsro_pseudo_ops
66 LOGICAL, INTENT(IN) :: gpsro_vert_interp_ops
67 REAL(kind_real), INTENT(IN) :: gpsro_min_temp_grad
68 REAL(kind_real), INTENT(IN) :: gpsro_cost_funct_test
69 REAL(kind_real), INTENT(IN) :: gpsro_y_test
70 INTEGER, INTENT(IN) :: gpsro_n_iteration_test
71 REAL(kind_real), INTENT(IN) :: gpsro_delta_ct2
72 REAL(kind_real), INTENT(IN) :: gpsro_delta_factor
73 REAL(kind_real), INTENT(IN) :: gpsro_ob_test
74 LOGICAL, INTENT(IN) :: capsupersat
75 LOGICAL, INTENT(OUT) :: baerr
76 REAL(kind_real), INTENT(INOUT) :: tb(nlevq)
77 REAL(kind_real), INTENT(INOUT) :: ts(nlevq)
78 REAL(kind_real), INTENT(INOUT) :: o_bdiff ! measure of O-B for whole profile
79 REAL(kind_real), INTENT(INOUT) :: dfs ! measure of degrees of freedom of signal for whole profile
80 
81 ! Local parameters
82 CHARACTER(len=*), PARAMETER :: routinename = "Ops_GPSRO_Do1DVar_BA"
83 INTEGER, PARAMETER :: max_string = 800
84 
85 ! Local variables
86 INTEGER :: nobs ! size of the 1DVar observation vector
87 INTEGER :: i
88 INTEGER :: j
89 INTEGER :: it
90 LOGICAL :: om1_error
91 LOGICAL :: converged
92 LOGICAL :: do1dvar_error
93 LOGICAL :: ran_iteration
94 REAL(kind_real) :: j_pen
95 REAL(kind_real) :: xb(nlevp+nlevq) ! background profile used in the 1D-Var
96 REAL(kind_real) :: x(nlevp+nlevq) ! 1Dvar solution profile
97 REAL(kind_real) :: amat(nlevp+nlevq,nlevp+nlevq) ! solultion error cov matrix
98 REAL(kind_real), ALLOCATABLE :: zobs(:)
99 REAL(kind_real), ALLOCATABLE :: yobs(:)
100 REAL(kind_real), ALLOCATABLE :: yb(:)
101 REAL(kind_real), ALLOCATABLE :: ycalc(:)
102 REAL(kind_real), ALLOCATABLE :: om1(:,:)
103 INTEGER, ALLOCATABLE :: index_packed(:)
104 REAL(kind_real), ALLOCATABLE :: model_heights(:) ! Heights of model and pseudo-levels
105 REAL(kind_real), ALLOCATABLE :: refractivity(:) ! Refractivity on model and pseudo_levels
106 INTEGER :: nreflevels ! Number of levs to calculate ref on
107 CHARACTER(LEN=max_string) :: message
108 
109 REAL(kind_real) :: temp_rad_curv ! Temporary store of the earth's radius of curvature
110 REAL(kind_real) :: temp_latitude ! Temporary store of the observation's latitude
111 REAL(kind_real) :: temp_undulation ! Temporary store of the undulation
112 
113 !--------------
114 ! 1. Initialise
115 !--------------
116 
117 do1dvar_error = .false.
118 baerr = .false.
119 ran_iteration = .false.
120 om1_error = .false.
121 
122 ! Set all the PGE values to gross error
123 
124 ob % BendingAngle(:) % PGEFinal = 1.0
125 
126 ! Calculate refractivity on theta levels, to find appropriate
127 ! impact height vertical range
128 
129 CALL ufo_calculate_refractivity (nlevp, &
130  nlevq, &
131  back % za, &
132  back % zb, &
133  back % p, &
134  back % q, &
135  gpsro_pseudo_ops, &
136  gpsro_vert_interp_ops, &
137  gpsro_min_temp_grad, &
138  baerr, &
139  nreflevels, &
140  refractivity, &
141  model_heights)
142 
143 ! Set the background vector
144 xb(1:nlevp) = 1.0e-2 * back % p(:) ! in hPa
145 xb(nlevp + 1:nlevp+nlevq) = 1.0e3 * back % q(:) ! in g/kg
146 
147 ! Set size of obs vector used in 1D- Var
148 
149 nobs = count(ob % BendingAngle(:) % value /= missing_value(ob % BendingAngle(1) % value) .AND. & ! not missing bending angle
150  ob % ImpactParam(:) % value /= missing_value(ob % ImpactParam(1) % value) .AND. & ! not missing impact parameter
151  ob % qc_flags(:) == 0)
152 
153 WRITE (message, '(A,I0)') 'size of input obs vector ', SIZE (ob % BendingAngle(:) % value)
154 CALL fckit_log % info(message)
155 WRITE (message, '(A,I0)') 'size of packed obs vector ', nobs
156 CALL fckit_log % info(message)
157 
158 ! Only continue if we have some observations to process
159 IF (nobs > 0) THEN
160 
161  ! calculate an array of indices of the packed elements
162 
163  ALLOCATE (index_packed(nobs)) ! allocate the packed index vector
164  index_packed = missing_value(index_packed(1)) ! initialise
165 
166  ! Allocate arrays used in 1D-Var after test to stop allocating size nobs=0
167  ALLOCATE (om1(nobs,nobs))
168  ALLOCATE (yobs(nobs))
169  ALLOCATE (zobs(nobs))
170  ALLOCATE (yb(nobs))
171  ALLOCATE (ycalc(nobs))
172 
173  ! Pack observation arrays for valid values
174  ! Note: This hard-codes the R-matrix to be diagonal, since that is all that
175  ! is currently available in JEDI. This will need to be revisted once the
176  ! full capability is available.
177 
178  om1 = 0
179  j = 1
180  DO i = 1, SIZE (ob % BendingAngle(:) % Value)
181  IF (ob % BendingAngle(i) % Value /= missing_value(ob % BendingAngle(i) % Value) .AND. &
182  ob % ImpactParam(i) % value /= missing_value(ob % ImpactParam(i) % value) .AND. &
183  ob % qc_flags(i) == 0) THEN
184  index_packed(j) = i
185  zobs(j) = ob % ImpactParam(i) % value
186  yobs(j) = ob % BendingAngle(i) % Value
187  om1(j,j) = (ob % BendingAngle(i) % oberr)**(-2)
188  j = j + 1
189  END IF
190  END DO
191 
192  !-----------------------------------------------
193  ! 2. If no errors so far, call the 1DVar routine
194  !-----------------------------------------------
195 
196  IF (all(zobs(:) /= missing_value(zobs(1))) .AND. &
197  all(yobs(:) /= missing_value(yobs(1))) .AND. &
198  .NOT. om1_error) THEN
199 
200  temp_rad_curv = ob % RO_Rad_Curv % Value
201  temp_latitude = ob % Latitude
202  temp_undulation = ob % RO_geoid_und % value
203  CALL ops_gpsro_rootsolv_ba (nlevp+nlevq, & ! size of state vector
204  nlevp, & ! no. of press. levels
205  nlevq, & ! no. of theta levels
206  nlevq, & ! no. of q levels
207  nobs, & ! no of obs
208  back % za, & ! height of rho levels
209  back % zb, & ! height of theta levels
210  xb, & ! background vector
211  yobs, & ! ob. vector
212  zobs, & ! ob. impact parameters
213  bsig, & ! standard dev. of B errors
214  bm1, & ! Inverse Back. cov matrix
215  om1, & ! Inverse Ob cov matrix
216  it, & ! no of iterations
217  x, & ! solution vector
218  yb, & ! obs at first guess
219  ycalc, & ! obs at solution
220  j_pen, & ! penalty value
221  amat, & ! solution cov. matrix
222  converged, & ! convergence flag
223  baerr, & ! error flag
224  do1dvar_error, & ! error flag
225  gpsro_n_iteration_test, & !
226  gpsro_delta_factor, & !
227  gpsro_delta_ct2, & !
228  gpsro_pseudo_ops, &
229  gpsro_vert_interp_ops, &
230  gpsro_min_temp_grad, &
231  capsupersat, &
232  o_bdiff, & ! observed -background BA value
233  temp_rad_curv, & ! Radius of curvature of ellipsoid
234  temp_latitude, & ! Latitude of occ
235  temp_undulation, & ! geoid undulation
236  tb, &
237  ts, &
238  dfs)
239  ran_iteration = .true.
240  ELSE
241 
242  do1dvar_error = .true.
243 
244  ob % BendingAngle(:) % PGEFinal = 0.99
245 
246  END IF
247 
248  IF (.NOT. do1dvar_error) THEN
249 
250  ! store iteration and cost
251 
252  ob % Niter = it
253 
254  ob % Jcost = 2.0_kind_real * j_pen / real(nobs)
255 
256  ! map the retrieval information back into the ob structures
257 
258  ob % p(:) % Value = 1.0e2 * x(1:nlevp)
259 
260  DO i = 1, nlevp
261 
262  ob % p(i) % ObErr = 1.0e2 * sqrt(amat(i,i)) ! error. est. from cov
263 
264  END DO
265 
266  ob % q(:) % Value = 1.0e-3 * x(nlevp + 1:nlevp+nlevq)
267 
268  DO i = 1, nlevq
269 
270  j = i + nlevp
271 
272  ob % q(i) % ObErr = 1.0e-3 * sqrt(amat(j,j)) ! error est. from cov
273 
274  END DO
275 
276  ! Bending angle calculated with solution
277 
278  ob % SolutBendingAngle(index_packed) = ycalc(1:nobs)
279 
280 ! ! store the bending angle calculated from the background
281 
282 ! Back % BendingAngle(index_packed) = yb(1:nobs)
283 
284  ! PROBABILTY OF GROSS ERROR. Use the cost function value.
285 
286  IF (j_pen > gpsro_cost_funct_test * real(nobs, kind=kind_real)) THEN
287 
288  ! the cost function for profile is too high - GROSS ERROR -
289  ! set all pge's in profile to 0.8
290 
291  ob % BendingAngle(:) % PGEFinal = 0.8
292 
293  ELSE
294 
295  ! For each value in profile, estimate probability of gross error
296  ! from difference between solution and observed value
297 
298  DO i = 1,nobs
299 
300  IF (abs(ob % BendingAngle(index_packed(i)) % Value - ob % SolutBendingAngle(index_packed(i))) < &
301  (gpsro_y_test * ob % BendingAngle(index_packed(i)) % ObErr)) THEN
302  ob % BendingAngle(index_packed(i)) % PGEFinal = 0.1
303  ELSE
304  ob % BendingAngle(index_packed(i)) % PGEFinal = 0.7
305  END IF
306 
307  END DO
308 
309  END IF
310 
311  ! if the initial 2J/m value exceeds read-in value then flag
312  IF (o_bdiff > gpsro_ob_test) THEN
313  ob % BendingAngle(:) % PGEFinal = 0.6
314  END IF
315 
316  ! check for the BAerr being set
317  IF (baerr) THEN
318  ob % BendingAngle(:) % PGEFinal = 0.58 ! flag BAerr
319  END IF
320 
321  ELSE ! Do 1D-Var_error
322 
323  IF (ran_iteration) THEN
324  ob % BendingAngle(:) % PGEFinal = 0.9 ! flag lack of convergence
325 
326  ! Bending angle calculated with solution
327  ob % SolutBendingAngle(index_packed) = ycalc(1:nobs)
328 
329  ! map the retrieval information back into the ob structures
330  ob % p(:) % Value = 1.0e2 * x(1:nlevp)
331  ob % q(:) % Value = 1.0e-3 * x(nlevp + 1:nlevp+nlevq)
332 
333  ! store iterations and cost
334  ob % Niter = it
335  ob % Jcost = 2.0_kind_real * j_pen / nobs
336 
337  ELSE IF (om1_error) THEN
338 
339  ob % BendingAngle(:) % PGEFinal = 0.85 ! Flag error in getting
340  ! observation error inverse
341  END IF
342 
343  END IF
344 
345 ELSE
346  IF (nobs <= 10) THEN
347  WRITE (message, '(A)') 'nobs is less than 10: exit Ops_GPSRO_Do1DVar_BA'
348  CALL fckit_log % info(message)
349  ob % BendingAngle(:) % PGEFinal = 0.55 ! flag lack of observation data
350  END IF
351 
352  IF (baerr) THEN
353  WRITE (message, '(A)') 'Error in Ops_Refractivity: exit Ops_GPSRO_Do1DVar_BA'
354  CALL fckit_log % info(message)
355  ob % BendingAngle(:) % PGEFinal = 0.58 ! flag BAerr
356  END IF
357 END IF
358 
359 END SUBROUTINE ops_gpsro_do1dvar_ba
360 
Fortran module for gnssro bending angle Met Office forward operator.
subroutine, public ops_gpsro_do1dvar_ba(nlevp, nlevq, BM1, Bsig, Back, Ob, GPSRO_pseudo_ops, GPSRO_vert_interp_ops, GPSRO_min_temp_grad, GPSRO_cost_funct_test, GPSRO_y_test, GPSRO_n_iteration_test, GPSRO_Delta_factor, GPSRO_Delta_ct2, GPSRO_OB_test, capsupersat, BAerr, Tb, Ts, O_Bdiff, DFS)
Fortran module for gnssro bending angle Met Office forward operator.
subroutine, public ops_gpsro_rootsolv_ba(nstate, nlevp, nb, nlevq, Nobs, za, zb, xb, yobs, zobs, Bsig, Bm1, Om1, it, x, yb, ycalc, J_pen, Amat, converged, BAerr, Do1DVar_error, Iter_max, Delta, Delta_ct2, GPSRO_pseudo_ops, GPSRO_vert_interp_ops, GPSRO_min_temp_grad, capsupersat, O_Bdiff, RO_Rad_Curv, Latitude, RO_geoid_und, Tb, Ts, DFS)
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.