FV3 Bundle
ufo_gnssro_ref_tlad_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 for gnssro refractivity tangent linear and adjoint
7 
9  use iso_c_binding
10  use kinds
11  use ufo_vars_mod
12  use ufo_geovals_mod
14  use vert_interp_mod
16  use obsspace_mod
17 
18  integer, parameter :: max_string=800
19 
20  !> Fortran derived type for gnssro trajectory
22  private
23  integer :: nval, nobs
24  real(kind_real), allocatable :: wf(:)
25  integer, allocatable :: wi(:)
26  real(kind_real), allocatable :: prs(:), t(:), q(:)
27  real(kind_real), allocatable :: obsh(:)
28  contains
30  procedure :: settraj => ufo_gnssro_ref_tlad_settraj
31  procedure :: simobs_tl => ufo_gnssro_ref_simobs_tl
32  procedure :: simobs_ad => ufo_gnssro_ref_simobs_ad
33  end type ufo_gnssro_ref_tlad
34 
35 contains
36 ! ------------------------------------------------------------------------------
37 
38  subroutine ufo_gnssro_ref_tlad_settraj(self, geovals, obss)
41 
42  implicit none
43  class(ufo_gnssro_Ref_tlad), intent(inout) :: self
44  type(ufo_geovals), intent(in) :: geovals
45  type(c_ptr), value, intent(in) :: obss
46 
47  character(len=*), parameter :: myname_="ufo_gnssro_ref_tlad_settraj"
48  character(max_string) :: err_msg
49 
50  type(ufo_geoval), pointer :: t,q,prs,gph
51  integer :: iobs, ierr
52  real(kind_real), allocatable :: obsZ(:), obsLat(:) ! observation vector
53  real(kind_real) :: Tv, Tv0
54  integer :: wi0
55 
56  !Check if variables are in geovals and get them
57  call ufo_geovals_get_var(geovals, var_prs, prs, status=ierr)
58  if (ierr/=0) then
59  write(err_msg,*) myname_, trim(var_prs), ' doesnt exist'
60  call abor1_ftn(err_msg)
61  endif
62  call ufo_geovals_get_var(geovals, var_t, t, status=ierr)
63  if (ierr/=0) then
64  write(err_msg,*) myname_, trim(var_t), ' doesnt exist'
65  call abor1_ftn(err_msg)
66  endif
67  call ufo_geovals_get_var(geovals, var_q, q, status=ierr)
68  if (ierr/=0) then
69  write(err_msg,*) myname_, trim(var_q), ' doesnt exist'
70  call abor1_ftn(err_msg)
71  endif
72  call ufo_geovals_get_var(geovals, var_z, gph,status=ierr)
73  if (ierr/=0) then
74  write(err_msg,*) myname_, trim(var_z), ' doesnt exist'
75  call abor1_ftn(err_msg)
76  endif
77 
78  !Make sure nothing already allocated
79  call self%delete()
80 
81  !Keep copy of dimensions
82  self%nval = prs%nval
83  self%nobs = obsspace_get_nobs(obss)
84 
85  allocate(self%wi(self%nobs))
86  allocate(self%wf(self%nobs))
87  allocate(self%t(self%nobs))
88  allocate(self%q(self%nobs))
89  allocate(self%prs(self%nobs))
90  allocate(self%obsH(self%nobs))
91 
92  allocate(obsz(self%nobs))
93  allocate(obslat(self%nobs))
94 
95  ! observation of altitude (MSL) (for vertical interpolation)
96  call obsspace_get_db(obss, "Metadata", "altitude", obsz)
97  ! observation of Latitude (degree) (for geometric to geopotential height transform)
98  call obsspace_get_db(obss, "Metadata", "latitude", obslat)
99 
100  do iobs = 1, self%nobs
101 
102  ! calculate observation geopotential height using MJ Mahoney's (2001)
103  call geometric2geop(obslat(iobs), obsz(iobs), self%obsH(iobs))
104  call vert_interp_weights(self%nval, self%obsH(iobs), gph%vals(:,iobs),self%wi(iobs),self%wf(iobs))
105  wi0 = self%wi(iobs)
106  call vert_interp_apply(t%nval, t%vals(:,iobs), self%t(iobs), self%wi(iobs),self%wf(iobs))
107  call vert_interp_apply(q%nval, q%vals(:,iobs), self%q(iobs), self%wi(iobs),self%wf(iobs))
108  ! use hypsometric equation to calculate pressure
109  tv = 0.0
110  tv0 = 0.0
111  tv = self%t(iobs)*(one + (rv_over_rd-one)*self%q(iobs)/(1.0-self%q(iobs)) )
112  tv0 = t%vals(wi0,iobs)*(one + (rv_over_rd-one)*q%vals(wi0,iobs)/(1.0-q%vals(wi0,iobs) ))
113  self%prs(iobs) = prs%vals(wi0,iobs)/exp(two*grav*(self%obsH(iobs)-gph%vals(wi0,iobs))/(rd*(tv+tv0)))
114 
115  enddo
116 
117  self%ltraj = .true.
118  ! cleanup
119  deallocate(obsz)
120  deallocate(obslat)
121  end subroutine ufo_gnssro_ref_tlad_settraj
122 
123 ! ------------------------------------------------------------------------------
124 
125  subroutine ufo_gnssro_ref_simobs_tl(self, geovals, hofx, obss)
127  implicit none
128  class(ufo_gnssro_Ref_tlad), intent(in) :: self
129  type(ufo_geovals), intent(in) :: geovals
130  real(kind_real), intent(inout) :: hofx(:)
131  type(c_ptr), value, intent(in) :: obss
132  logical, parameter :: use_compress=.true.
133 
134  character(len=*), parameter :: myname_="ufo_gnssro_ref_tlad_tl"
135  character(max_string) :: err_msg
136 
137  integer :: iobs,ierr
138  type(ufo_geoval), pointer :: t_d, q_d !, prs_d
139  real(kind_real) :: t_coeff, q_coeff !, prs_coeff
140  real(kind_real) :: gesT_d, gesQ_d, gesTv_d, gesTv0_d !, gesP_d
141  integer :: wi0
142  ! check if trajectory was set
143  if (.not. self%ltraj) then
144  write(err_msg,*) myname_, ' trajectory wasnt set!'
145  call abor1_ftn(err_msg)
146  endif
147 
148  ! check if nobs is consistent in geovals & hofx
149  if (geovals%nobs /= size(hofx)) then
150  write(err_msg,*) myname_, ' error: nobs inconsistent!'
151  call abor1_ftn(err_msg)
152  endif
153 
154  ! check if variables are in geovals and get them
155  call ufo_geovals_get_var(geovals, var_t, t_d,status=ierr)
156  if (ierr/=0) then
157  write(err_msg,*) myname_, trim(var_t), ' doesnt exist'
158  call abor1_ftn(err_msg)
159  endif
160  call ufo_geovals_get_var(geovals, var_q, q_d,status=ierr)
161  if (ierr/=0) then
162  write(err_msg,*) myname_, trim(var_q), ' doesnt exist'
163  call abor1_ftn(err_msg)
164  endif
165 
166 
167  call gnssro_ref_constants(use_compress)
168 
169  ! tangent linear obs operator (linear)
170  do iobs = 1, geovals%nobs
171  wi0 = self%wi(iobs)
172  call vert_interp_apply_tl( t_d%nval, t_d%vals(:,iobs), gest_d, self%wi(iobs),self%wf(iobs))
173  call vert_interp_apply_tl( q_d%nval, q_d%vals(:,iobs), gesq_d, self%wi(iobs),self%wf(iobs))
174 
175 ! pressure does not change during minimization
176 
177  t_coeff = - n_a*self%prs(iobs)/self%t(iobs)**2 &
178  - n_b*two*self%prs(iobs)*self%q(iobs)/ &
179  ( ((1-rd_over_rv)*self%q(iobs)+rd_over_rv)*self%t(iobs)**3 ) &
180  - n_c*self%prs(iobs)*self%q(iobs)/ &
181  ( ((1-rd_over_rv)*self%q(iobs)+rd_over_rv)*self%t(iobs)**2 )
182  q_coeff = n_b*self%prs(iobs)/( self%t(iobs)**2*( (1-rd_over_rv)*self%q(iobs)+rd_over_rv)**2 ) * &
183  rd_over_rv &
184  + n_c*self%prs(iobs)/( self%t(iobs) *( (1-rd_over_rv)*self%q(iobs)+rd_over_rv)**2 ) * &
185  rd_over_rv
186  hofx(iobs) = t_coeff*gest_d + q_coeff*gesq_d !+ prs_coeff*gesP_d
187 
188  enddo
189 
190  end subroutine ufo_gnssro_ref_simobs_tl
191 
192 ! ------------------------------------------------------------------------------
193 
194  subroutine ufo_gnssro_ref_simobs_ad(self, geovals, hofx, obss)
196  implicit none
197  class(ufo_gnssro_Ref_tlad), intent(in) :: self
198  type(ufo_geovals), intent(inout) :: geovals
199  real(kind_real), intent(in) :: hofx(:)
200  type(c_ptr), value, intent(in) :: obss
201  logical, parameter :: use_compress=.true.
202 
203  character(len=*), parameter :: myname_="ufo_gnssro_ref_tlad_ad"
204  character(max_string) :: err_msg
205 
206  integer :: iobs,ierr
207  type(ufo_geoval), pointer :: t_d, q_d, prs_d, gph_d
208  real(kind_real) :: t_coeff, q_coeff !, prs_coeff
209  real(kind_real) :: gesT_d, gesQ_d !, gesTv_d,gesTv0_d !, gesP_d
210 
211  ! check if trajectory was set
212  if (.not. self%ltraj) then
213  write(err_msg,*) myname_, ' trajectory wasnt set!'
214  call abor1_ftn(err_msg)
215  endif
216 
217  ! check if nobs is consistent in geovals & hofx
218  if (geovals%nobs /= size(hofx)) then
219  write(err_msg,*) myname_, ' error: nobs inconsistent!'
220  call abor1_ftn(err_msg)
221  endif
222 
223  ! check if variables are in geovals and get them
224  call ufo_geovals_get_var(geovals, var_prs, prs_d, status=ierr)
225  if (ierr/=0) then
226  write(err_msg,*) myname_, trim(var_prs), ' doesnt exist'
227  call abor1_ftn(err_msg)
228  endif
229 
230  call ufo_geovals_get_var(geovals, var_t, t_d, status=ierr)
231  if (ierr/=0) then
232  write(err_msg,*) myname_, trim(var_t), ' doesnt exist'
233  call abor1_ftn(err_msg)
234  endif
235 
236  call ufo_geovals_get_var(geovals, var_q, q_d, status=ierr)
237  if (ierr/=0) then
238  write(err_msg,*) myname_, trim(var_q), ' doesnt exist'
239  call abor1_ftn(err_msg)
240  endif
241  call ufo_geovals_get_var(geovals, var_z, gph_d, status=ierr)
242  if (ierr/=0) then
243  write(err_msg,*) myname_, trim(var_z), ' doesnt exist'
244  call abor1_ftn(err_msg)
245  endif
246  ! allocate if not yet allocated
247  if (.not. allocated(t_d%vals)) then
248  t_d%nobs = self%nobs
249  t_d%nval = self%nval
250  allocate(t_d%vals(t_d%nval,t_d%nobs))
251  endif
252  t_d%vals = 0.0_kind_real
253 
254  if (.not. allocated(prs_d%vals)) then
255  prs_d%nobs = self%nobs
256  prs_d%nval = self%nval
257  allocate(prs_d%vals(prs_d%nval,prs_d%nobs))
258  endif
259  prs_d%vals = 0.0_kind_real
260 
261  if (.not. allocated(q_d%vals)) then
262  q_d%nobs = self%nobs
263  q_d%nval = self%nval
264  allocate(q_d%vals(q_d%nval,q_d%nobs))
265  endif
266  q_d%vals = 0.0_kind_real
267 
268  if (.not. allocated(gph_d%vals)) then
269  gph_d%nobs = self%nobs
270  gph_d%nval = self%nval
271  allocate(gph_d%vals(gph_d%nval,gph_d%nobs))
272  endif
273  gph_d%vals = 0.0_kind_real
274 
275  if (.not. geovals%linit ) geovals%linit=.true.
276 
277  call gnssro_ref_constants(use_compress)
278 
279 
280  do iobs = 1, geovals%nobs
281 
282 ! zero impct on pressure during minimization
283  t_coeff = - n_a*self%prs(iobs)/self%t(iobs)**2 &
284  - n_b*two*self%prs(iobs)*self%q(iobs)/ &
285  ( ((1-rd_over_rv)*self%q(iobs)+rd_over_rv)*self%t(iobs)**3 ) &
286  - n_c*self%prs(iobs)*self%q(iobs)/ &
287  ( ((1-rd_over_rv)*self%q(iobs)+rd_over_rv)*self%t(iobs)**2 )
288  q_coeff = n_b*self%prs(iobs)/( self%t(iobs)**2*( (1-rd_over_rv)*self%q(iobs)+rd_over_rv)**2 ) * &
289  rd_over_rv &
290  + n_c*self%prs(iobs)/( self%t(iobs) *( (1-rd_over_rv)*self%q(iobs)+rd_over_rv)**2 ) * &
291  rd_over_rv
292 
293  gest_d = 0.0_kind_real
294  gesq_d = 0.0_kind_real
295  gest_d = gest_d + hofx(iobs)*t_coeff
296  gesq_d = gesq_d + hofx(iobs)*q_coeff
297  call vert_interp_apply_ad( t_d%nval, t_d%vals(:,iobs), gest_d, self%wi(iobs), self%wf(iobs))
298  call vert_interp_apply_ad( q_d%nval, q_d%vals(:,iobs), gesq_d, self%wi(iobs), self%wf(iobs))
299 
300  enddo
301 
302  end subroutine ufo_gnssro_ref_simobs_ad
303 
304 ! ------------------------------------------------------------------------------
305 
306  subroutine ufo_gnssro_ref_tlad_delete(self)
307  implicit none
308  class(ufo_gnssro_Ref_tlad), intent(inout) :: self
309  character(len=*), parameter :: myname_="ufo_gnssro_ref_tlad_delete"
310 
311  self%nval = 0
312  if (allocated(self%wi)) deallocate(self%wi)
313  if (allocated(self%wf)) deallocate(self%wf)
314  if (allocated(self%prs)) deallocate(self%prs)
315  if (allocated(self%t)) deallocate(self%t)
316  if (allocated(self%q)) deallocate(self%q)
317  if (allocated(self%obsH))deallocate(self%obsH)
318  self%ltraj = .false.
319  end subroutine ufo_gnssro_ref_tlad_delete
320 
321 ! ------------------------------------------------------------------------------
322 
323 end module ufo_gnssro_ref_tlad_mod
subroutine, public ufo_geovals_get_var(self, varname, geoval, status)
subroutine vert_interp_apply(nlev, fvec, f, wi, wf)
Definition: vert_interp.F90:67
integer, parameter max_string
subroutine vert_interp_apply_ad(nlev, fvec_ad, f_ad, wi, wf)
Definition: vert_interp.F90:97
integer function, public obsspace_get_nobs(c_dom)
Return the number of observations.
real(kind_real), parameter, public rd
Fortran module for gnssro refractivity tangent linear and adjoint.
real(kind_real), parameter, public rd_over_rv
subroutine vert_interp_apply_tl(nlev, fvec_tl, f_tl, wi, wf)
Definition: vert_interp.F90:82
real(kind_real), parameter, public rv_over_rd
subroutine geometric2geop(Latitude, geometricZ, geopotentialH)
character(len=maxvarlen), public var_z
Fortran module to perform linear interpolation.
Definition: vert_interp.F90:8
real(fp), parameter, public one
character(len=maxvarlen), public var_q
real(kind_real), public n_c
subroutine, public gnssro_ref_constants(use_compress)
real(fp), parameter, public two
character(len=maxvarlen), public var_prs
subroutine ufo_gnssro_ref_simobs_tl(self, geovals, hofx, obss)
type(registry_t), public ufo_geovals_registry
Linked list interface - defines registry_t type.
subroutine ufo_gnssro_ref_tlad_delete(self)
Fortran derived type for gnssro trajectory.
real(kind_real), parameter, public grav
real(kind_real), public n_b
character(len=maxvarlen), public var_t
Fortran interface to ObsSpace.
Definition: obsspace_mod.F90:9
subroutine vert_interp_weights(nlev, obl, vec, wi, wf)
Definition: vert_interp.F90:20
real(kind_real), public n_a
subroutine ufo_gnssro_ref_tlad_settraj(self, geovals, obss)
subroutine ufo_gnssro_ref_simobs_ad(self, geovals, hofx, obss)
subroutine, public delete(self)
Definition: qg_fields.F90:136