UFO
ufo_gnssro_ropp1d_utils_mod.F90
Go to the documentation of this file.
1 ! (C) Copyright 2017-2018 UCAR
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 to handle gnssro bending angle observations following
7 !> the ROPP (2018 Aug) implementation
8 
10 
11 !use iso_c_binding
12 use fckit_log_module, only: fckit_log
13 use kinds, only: kind_real
14 
15 ! ROPP data type and library subroutines
16 use typesizes, only: wp => eightbytereal
17 use datetimetypes, only: dp
18 use ropp_fm_types, only: state1dfm, obs1dbangle
19 use geodesy, only: gravity, r_eff, geometric2geopotential
20 use arrays, only: callocate
21 
22 implicit none
23 public :: init_ropp_1d_statevec
25 public :: init_ropp_1d_obvec
27 public :: ropp_tidy_up_1d
28 public :: ropp_tidy_up_tlad_1d
29 private
30 
31 contains
32 
33 ! ------------------------------------------------------------------------------------
34 ! ------------------------------------------------------------------------------------
35 
36 subroutine init_ropp_1d_statevec(step_time,rlon,rlat, temp,shum,pres,phi,lm,phi_sfc,x, iflip)
37 ! Description:
38 ! subroutine to fill a ROPP state vector structure with
39 ! model background fields: Temperature, pressure, specific
40 ! humidity at full-levels, and surface geopotential height.
41 !
42 ! Inputs:
43 ! temp background temperature
44 ! shum background specific humidity
45 ! pres background pressure
46 ! phi geopotential height
47 ! phi_sfc terrain geopotential of background field
48 ! lm number of vertical levels in the background
49 !
50 ! Outputs:
51 ! x Forward model state vector
52 ! ------------------------------------------------------------------------------------
53  implicit none
54 
55  type(state1dfm), intent(out) :: x
56  real(kind=dp), intent(in) :: step_time
57  real(kind=kind_real), intent(in) :: rlat, rlon
58  real(kind=kind_real), intent(in) :: phi_sfc
59  integer, intent(in) :: lm
60  real(kind=kind_real), dimension(lm), intent(in) :: temp,shum,pres,phi
61 
62 ! Local variables
63  character(len=250) :: record
64  real(kind=kind_real) :: rlon_local
65  integer :: n,i,j,k
66  integer, optional, intent(in) :: iflip
67  x%non_ideal = .false.
68  x%direct_ion = .false.
69  x%state_ok = .true.
70  x%new_bangle_op = .true. ! activate ROPP v8 new interpolation scheme
71 
72 ! ROPP Longitude value is -180.0 to 180.0
73  x%lat = real(rlat,kind=wp)
74  rlon_local = rlon
75  if (rlon_local .gt. 180) rlon_local = rlon_local - 360.
76  x%lon = real(rlon_local,kind=wp)
77  x%time = real(step_time, kind=wp)
78 
79 
80 ! Number of levels in background profile. What about (lm+1) field ?
81  x%n_lev = lm
82 
83 !--------------------------------------------------------------
84 ! allocate arrays for temperature, specific humidity, pressure
85 ! and geopotential height data
86 !--------------------------------------------------------------
87  if (associated(x%temp)) deallocate(x%temp)
88  if (associated(x%shum)) deallocate(x%shum)
89  if (associated(x%pres)) deallocate(x%pres)
90  if (associated(x%geop)) deallocate(x%geop)
91 
92  allocate(x%temp(x%n_lev))
93  allocate(x%shum(x%n_lev))
94  allocate(x%pres(x%n_lev))
95  allocate(x%geop(x%n_lev))
96 !----------------------------------------------------
97 ! ROPP FM requires vertical height profile to be of the ascending order.
98 ! (see ropp_io_ascend ( ROdata )). So we need to flip the data.
99 !----------------------------------------------------
100  write(record,'(4a9,a11)') 'lvl','temp','shum','pres','geop'
101 
102  n = lm
103  if ( present(iflip) .and. iflip .eq. 1) then
104  do k = 1, lm
105  x%temp(n) = real(temp(k),kind=wp)
106  x%shum(n) = real(shum(k),kind=wp)
107  x%pres(n) = real(pres(k),kind=wp)
108  x%geop(n) = real(phi(k),kind=wp)
109  n = n - 1
110  end do
111 else
112  do k = 1, lm
113  x%temp(k) = real(temp(k),kind=wp)
114  x%shum(k) = real(shum(k),kind=wp)
115  x%pres(k) = real(pres(k),kind=wp)
116  x%geop(k) = real(phi(k),kind=wp)
117  end do
118 end if
119 
120 ! sufrace geopotential height value
121  x%geop_sfc = real(phi_sfc,kind=wp)
122  write(record,'("geop_sfc",f15.2)') x%geop_sfc
123 !------------------------------------------------
124 ! covariance matrix, is this used by ROPP FM?
125 !------------------------------------------------
126  x%cov_ok = .true.
127 
128 ! Allocate memory
129 ! For ECMWF example, Covariance matrix for temperature sigma and
130 ! specific humidity sigma, and surface pressure. There the
131 ! size of covariance matrix is 2 * nlevel + 1.
132 
133  n = (2*x%n_lev)+1 ! Number of elements in the state vector
134 
135  if (associated(x%cov%d)) deallocate(x%cov%d)
136  call callocate(x%cov%d, n*(n+1)/2) ! From ROPP utility library
137 
138  do i = 1, x%n_lev
139  x%cov%d(i + i*(i-1)/2) = 1.0_wp
140  end do
141 
142  do i = 1, x%n_lev
143  j = x%n_lev + i
144  x%cov%d(j + j*(j-1)/2) = 1.0_wp
145  enddo
146 
147  x%cov%d(n + n*(n-1)/2) = 1.0_wp
148 
149 !------------------------------
150 ! Rest of the covariance marix
151 !------------------------------
152  if (associated(x%cov%e)) deallocate(x%cov%e)
153  if (associated(x%cov%f)) deallocate(x%cov%f)
154  if (associated(x%cov%s)) deallocate(x%cov%s)
155 
156  x%cov%fact_chol = .false.
157  x%cov%equi_chol = 'N'
158 
159  return
160 end subroutine init_ropp_1d_statevec
161 
162 !------------------------------------------------------------------------------------
163 !------------------------------------------------------------------------------------
164 
165 subroutine init_ropp_1d_statevec_ad(temp_d,shum_d,pres_d,phi_d,lm,x_ad, iflip)
166 
167 ! Description:
168 ! subroutine to fill a ROPP state vector structure with
169 ! model background fields: Temperature, pressure, specific
170 ! humidity at full-levels, and surface geopotential height.
171 !
172 ! Inputs:
173 ! temp background temperature
174 ! shum background specific humidity
175 ! pres background pressure
176 ! phi geopotential height
177 ! phi_sfc terrain geopotential of background field
178 ! lm number of vertical levels in the background
179 !
180 ! Outputs:
181 ! x Forward model state vector
182 !
183 ! ###############################################################
184  type(state1dfm), intent(inout) :: x_ad
185  integer, intent(in) :: lm
186  real(kind=kind_real), dimension(lm), intent(inout) :: temp_d,shum_d,pres_d,phi_d
187 
188 ! Local variables
189  integer :: n,k
190  integer, optional, intent(in) :: iflip
191 !-------------------------------------------------------------------------
192 
193  n = lm
194 
195  if ( present(iflip) .and. iflip .eq. 1) then
196  do k = 1, lm
197 
198 !! x_tl%temp(n,:) = real(temp_d(k),kind=wp)
199  temp_d(k) = temp_d(k) + real(x_ad%temp(n),kind=kind_real)
200  x_ad%temp(n) = 0.0_wp
201 
202 !! x_tl%shum(n,:) = real(shum_d(k),kind=wp)
203  shum_d(k) = shum_d(k) + real(x_ad%shum(n),kind=kind_real)
204  x_ad%shum(n) = 0.0_wp
205 
206 !! x_tl%pres(n,:) = real(pres_d(k),kind=wp)
207  pres_d(k) = pres_d(k) + real(x_ad%pres(n),kind=kind_real)
208  x_ad%pres(n) = 0.0_wp
209 
210 !! x_tl%geop(n,:) = real(phi_d(k),kind=wp)
211  phi_d(k) = phi_d(k) + real(x_ad%geop(n),kind=kind_real)
212  x_ad%geop(n) = 0.0_wp
213 
214  n = n -1
215  end do
216  else
217  do k = 1, lm
218  temp_d(k) = temp_d(k) + real(x_ad%temp(k),kind=kind_real)
219  x_ad%temp(k) = 0.0_wp
220  shum_d(k) = shum_d(k) + real(x_ad%shum(k),kind=kind_real)
221  x_ad%shum(k) = 0.0_wp
222  pres_d(k) = pres_d(k) + real(x_ad%pres(k),kind=kind_real)
223  x_ad%pres(k) = 0.0_wp
224  phi_d(k) = phi_d(k) + real(x_ad%geop(k),kind=kind_real)
225  x_ad%geop(k) = 0.0_wp
226  end do
227 
228  end if
229  return
230 
231 end subroutine init_ropp_1d_statevec_ad
232 
233 !------------------------------------------------------------------------------------
234 !------------------------------------------------------------------------------------
235 
236 subroutine init_ropp_1d_obvec(nvprof,obs_impact,ichk,ob_time,rlat,rlon,roc,undulat,y)
237 
238 ! Description:
239 ! subroutine to fill a ROPP observation vector structure
240 ! observation provides the inputs of:
241 ! impact parameter, lat, lon, time, radius of curvature
242 !
243 ! forward model will provide the simulation of bending angle
244 !
245 ! Inputs:
246 ! obs_impact impact parameter
247 ! ob_time time of the observation
248 ! rlat latitude
249 ! rlon longitude
250 ! roc radius of curvature
251 ! undulat undulation correction for radius of curvature
252 !
253 ! Outputs:
254 ! y: Partially filled Forward model observation vector
255 !-----------------------------------------------------------------------------------
256  implicit none
257 ! Output state vector
258  type(obs1dbangle), intent(out) :: y
259 
260  integer, intent(in) :: nvprof
261  integer, dimension(nvprof), intent(in) :: ichk
262  real(kind=kind_real), dimension(nvprof), intent(in) :: obs_impact
263  real(kind=kind_real), intent(in) :: rlat, rlon
264  real(kind=kind_real), intent(in) :: roc, undulat
265  real(kind=dp), intent(in) :: ob_time
266 ! Local variables
267  real(kind=wp) :: r8lat
268  real(kind=kind_real) :: rlon_local
269  character(len=250) :: record
270  integer :: i
271 
272  y%time = real(ob_time,kind=wp)
273  r8lat = real(rlat,kind=wp)
274  y%lat = r8lat
275  rlon_local = rlon
276  if (rlon_local .gt. 180) rlon_local = rlon_local - 360.
277  y%lon = real(rlon_local,kind=wp)
278  y%nobs = nvprof
279  y%g_sfc = gravity(r8lat, 0.0_wp) ! 2nd argument is height(m) above the sfc
280  y%r_curve = real(roc,kind=wp) ! ROPP rad of curve (m)
281  y%undulation = real(undulat,kind=wp) ! ROPP undulation corr for rad of curve (m)
282  y%r_earth = r_eff(r8lat)
283 
284 !----------------------------------------------------
285 ! allocate bending angle, impact parameter & weights
286 !----------------------------------------------------
287  if (associated(y%bangle)) then
288  deallocate(y%bangle)
289  deallocate(y%impact)
290  deallocate(y%weights)
291  nullify(y%bangle)
292  nullify(y%impact)
293  nullify(y%weights)
294  end if
295 
296  allocate(y%bangle(1:nvprof)) ! value computed in fwd model
297  allocate(y%impact(1:nvprof))
298  allocate(y%weights(1:nvprof)) ! value set in fwd model
299 
300  do i=1,nvprof
301  y%impact(i) = real(obs_impact(i),kind=wp) ! ROPP expects impact parameter in meters
302  if (ichk(i) .le. 0) then
303  y%weights(i) = 1.0_wp ! following t_fascod example
304  else
305  y%weights(i) = 0.0_wp
306  end if
307  end do
308 
309  y%bangle(:) = 0.0_wp ! following t_fascod example
310 
311  write(record,'(a9,2a11,3a15)') 'ROPPyvec:','lat', 'lon', 'g_sfc', 'roc', 'r_earth_eff'
312  write(record,'(9x,2f11.2,f15.6,2f15.2)') y%lat, y%lon, y%g_sfc, y%r_curve, y%r_earth
313 
314 !---------------------------------------------
315 ! covariance matrix, is this used by ROPP FM?
316 !--------------------------------------------
317  y%obs_ok = .true.
318  return
319 
320 end subroutine init_ropp_1d_obvec
321 
322 !-------------------------------------------------------------------------
323 !-------------------------------------------------------------------------
324 subroutine init_ropp_1d_obvec_tlad(iloop,nvprof,obs_impact, &
325  rlat,rlon,roc,undulat,y,y_p)
326  implicit none
327 ! Output state vector
328  type(obs1dbangle), intent(out) :: y,y_p
329 
330  integer, intent(in) :: iloop
331  integer, intent(in) :: nvprof
332  real(kind=kind_real), dimension(nvprof), intent(in) :: obs_impact
333  real(kind=kind_real), intent(in) :: rlat,rlon
334  real(kind=kind_real), intent(in) :: roc, undulat
335  real(kind=wp) :: r8lat
336  integer :: i
337  real(kind=kind_real) :: rlon_local
338 
339 !-------------------------------------------------------------------------
340  y%time = real(0.0, kind=wp)!)real(ob_time,kind=wp)
341  r8lat = real(rlat,kind=wp)
342  y%lat = real(rlat,kind=wp)
343  rlon_local = rlon
344  if (rlon_local .gt. 180) rlon_local = rlon_local - 360.
345  y%lon = real(rlon_local,kind=wp)
346  y%nobs = nvprof
347  y%g_sfc = gravity(r8lat, 0.0_wp) ! 2nd argument is height(m) above the sfc
348  y%r_curve = real(roc,kind=wp) ! ROPP rad of curve (m)
349  y%undulation = real(undulat,kind=wp) ! ROPP undulation corr for rad of curve (m)
350  y%r_earth = r_eff(r8lat)
351 
352 ! allocate bending angle, impact parameter & weights
353 !---------------------------------------------------------
354  allocate(y%bangle(1:nvprof)) ! value computed in fwd model
355  allocate(y%impact(1:nvprof))
356  allocate(y%weights(1:nvprof))
357  allocate(y_p%bangle(1:nvprof)) ! value computed in fwd model
358  allocate(y_p%impact(1:nvprof))
359  allocate(y_p%weights(1:nvprof))
360 
361 ! number of points in profile
362  y%nobs = nvprof
363  y_p%nobs = nvprof
364 
365  do i=1,nvprof
366  y_p%impact(i) = real(obs_impact(i),kind=wp)
367  y%impact(i) = real(obs_impact(i),kind=wp)
368  y%weights(i) = 1.0
369  y_p%weights(i) = 1.0
370  y%bangle(i) = 0.0
371  y_p%bangle(i) = 0.0
372  end do
373 
374  y%obs_ok = .true.
375  return
376 
377 end subroutine init_ropp_1d_obvec_tlad
378 
379 !-------------------------------------------------------------------------
380 !-------------------------------------------------------------------------
381 subroutine ropp_tidy_up_1d(x,y)
382  implicit none
383  type(state1dfm), intent(inout) :: x
384  type(obs1dbangle), intent(inout) :: y
385 ! x
386  if (associated(x%temp)) deallocate(x%temp)
387  if (associated(x%shum)) deallocate(x%shum)
388  if (associated(x%pres)) deallocate(x%pres)
389  if (associated(x%geop)) deallocate(x%geop)
390 ! y
391  if (associated(y%impact)) deallocate(y%impact)
392  if (associated(y%bangle)) deallocate(y%bangle)
393 
394 end subroutine ropp_tidy_up_1d
395 
396 !-------------------------------------------------------------------------
397 !-------------------------------------------------------------------------
398 subroutine ropp_tidy_up_tlad_1d(x,x_p,y,y_p)
399  implicit none
400  type(state1dfm), intent(inout) :: x,x_p ! x_p can be either x_tl or x_ad
401  type(obs1dbangle), intent(inout) :: y,y_p ! y_p can be either y_tl or y_ad
402 ! x
403  deallocate(x%temp)
404  deallocate(x%shum)
405  deallocate(x%pres)
406  deallocate(x%geop)
407 
408  deallocate(x_p%temp)
409  deallocate(x_p%shum)
410  deallocate(x_p%pres)
411  deallocate(x_p%geop)
412 ! y
413  deallocate(y%impact)
414  deallocate(y%bangle)
415  deallocate(y_p%impact)
416  deallocate(y_p%bangle)
417 
418  deallocate(y%weights)
419  deallocate(y_p%weights)
420 
421  return
422 
423 end subroutine ropp_tidy_up_tlad_1d
424 
425 !-------------------------------------------------------------------------
426 
Fortran module to handle gnssro bending angle observations following the ROPP (2018 Aug) implementati...
subroutine, public init_ropp_1d_statevec_ad(temp_d, shum_d, pres_d, phi_d, lm, x_ad, iflip)
subroutine, public init_ropp_1d_statevec(step_time, rlon, rlat, temp, shum, pres, phi, lm, phi_sfc, x, iflip)
subroutine, public ropp_tidy_up_tlad_1d(x, x_p, y, y_p)
subroutine, public init_ropp_1d_obvec_tlad(iloop, nvprof, obs_impact, rlat, rlon, roc, undulat, y, y_p)
subroutine, public init_ropp_1d_obvec(nvprof, obs_impact, ichk, ob_time, rlat, rlon, roc, undulat, y)