UFO
ufo_insitutemperature_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 insitutemperature module for tl/ad observation operator
7 
9 
10  use fckit_configuration_module, only: fckit_configuration
11  use iso_c_binding
12  use kinds
13 
16  use ufo_vars_mod
17  use obsspace_mod
18  use missing_values_mod
19 
20  implicit none
21  private
22 
23  integer, parameter :: max_string=800
24 
25  !> Fortran derived type for the tl/ad observation operator
26  type, extends(ufo_basis_tlad), public :: ufo_insitutemperature_tlad
27  private
28  integer :: nlocs !< Number of observations
29  integer :: nval !< Number of level in model's profiles
30  type(ufo_geoval) :: temp !< Temperature (traj) ] Model vertical
31  type(ufo_geoval) :: salt !< Salinity (traj) ] profile at
32  type(ufo_geoval) :: h !< Layer thickness (traj) ] obs locations
33  real (kind=kind_real), allocatable :: depth(:,:) !< Depth [nval x nlocs]
34  real (kind=kind_real), allocatable :: lono(:) !< Observation location
35  real (kind=kind_real), allocatable :: lato(:) !< Observation location
36  real (kind=kind_real), allocatable :: deptho(:) !< Observation location
37  real (kind=kind_real), allocatable :: tempo(:) !< temp interpolated at observation location
38  real (kind=kind_real), allocatable :: salto(:) !< salt interpolated at observation location
39  real(kind_real), allocatable :: wf(:) !< Vertical interpolation weights
40  integer, allocatable :: wi(:) !< Vertical interpolation indices
41  real (kind=kind_real), allocatable :: jac(:,:) !< Jacobian [2 x nlocs]
42  contains
43  procedure :: setup => ufo_insitutemperature_tlad_setup
44  procedure :: delete => ufo_insitutemperature_tlad_delete
45  procedure :: settraj => ufo_insitutemperature_tlad_settraj
46  procedure :: simobs_tl => ufo_insitutemperature_simobs_tl
47  procedure :: simobs_ad => ufo_insitutemperature_simobs_ad
49 
50 contains
51 
52 ! ------------------------------------------------------------------------------
53 subroutine ufo_insitutemperature_tlad_setup(self, f_conf)
54 implicit none
55 class(ufo_insitutemperature_tlad), intent(inout) :: self
56 type(fckit_configuration), intent(in) :: f_conf
57 
59 
60 ! ------------------------------------------------------------------------------
62 implicit none
63 class(ufo_insitutemperature_tlad), intent(inout) :: self
64 
65  if (allocated(self%jac)) deallocate(self%jac)
66  if (allocated(self%wi)) deallocate(self%wi)
67  if (allocated(self%wf)) deallocate(self%wf)
68  if (allocated(self%deptho)) deallocate(self%deptho)
69  if (allocated(self%lato)) deallocate(self%lato)
70  if (allocated(self%lono)) deallocate(self%lono)
71  if (allocated(self%depth)) deallocate(self%depth)
72  if (allocated(self%temp%vals)) deallocate(self%temp%vals)
73  if (allocated(self%salt%vals)) deallocate(self%salt%vals)
74  if (allocated(self%h%vals)) deallocate(self%h%vals)
75  if (allocated(self%tempo)) deallocate(self%tempo)
76  if (allocated(self%salto)) deallocate(self%salto)
77  self%ltraj = .false.
78 
80 
81 ! ------------------------------------------------------------------------------
82 subroutine ufo_insitutemperature_tlad_settraj(self, geovals, obss)
83  use vert_interp_mod
84  use ufo_tpsp2ti_mod
85 
86  implicit none
87  class(ufo_insitutemperature_tlad), intent(inout) :: self !< Complete trajectory needed by the operator
88  type(ufo_geovals), intent(in) :: geovals !< Model background
89  type(c_ptr), value, intent(in) :: obss !< Insitu temperature observations
90 
91  character(len=*), parameter :: myname_="ufo_insitutemperature_tlad_settraj"
92  character(max_string) :: err_msg
93 
94  type(ufo_geoval), pointer :: temp, salt, h
95  integer :: nlocs, nlev, iobs, ilev
96 
97  real(kind_real), allocatable :: obs_lat(:)
98  real(kind_real), allocatable :: obs_lon(:)
99  real(kind_real), allocatable :: obs_depth(:)
100  integer :: obss_nlocs
101 
102  ! check if sea temperature profile variable is in geovals and get it
103  call ufo_geovals_get_var(geovals, var_ocn_pot_temp, temp)
104 
105  ! check if sea salinity profile variable is in geovals and get it
106  call ufo_geovals_get_var(geovals, var_ocn_salt, salt)
107 
108  ! check if ocean layer thickness variable is in geovals and get it
109  call ufo_geovals_get_var(geovals, var_ocn_lay_thick, h)
110 
112 
113  nlocs = h%nlocs
114  nlev = h%nval
115 
116  self%nlocs = nlocs
117  self%nval = nlev
118 
119  self%temp = temp
120  self%salt = salt
121  self%h = h
122 
123  allocate(self%lono(nlocs))
124  allocate(self%lato(nlocs))
125  allocate(self%deptho(nlocs))
126 
127  obss_nlocs = obsspace_get_nlocs(obss)
128  allocate(obs_lat(obss_nlocs))
129  allocate(obs_lon(obss_nlocs))
130  allocate(obs_depth(obss_nlocs))
131 
132  call obsspace_get_db(obss, "MetaData", "longitude", obs_lon)
133  call obsspace_get_db(obss, "MetaData", "latitude", obs_lat)
134  call obsspace_get_db(obss, "MetaData", "depth", obs_depth)
135 
136  self%lono = obs_lon
137  self%lato = obs_lat
138  self%deptho = obs_depth
139 
140  !< Depth from layer thickness
141  allocate(self%depth(nlev,nlocs))
142  do iobs = 1, nlocs
143  self%depth(1,iobs)=0.5*self%h%vals(1,iobs)
144  do ilev = 2, nlev
145  self%depth(ilev,iobs)=sum(self%h%vals(1:ilev-1,iobs))+0.5*self%h%vals(ilev,iobs)
146  end do
147  end do
148 
149  !< Interpolation weight
150  allocate(self%wi(nlocs),self%wf(nlocs))
151  do iobs = 1, nlocs
152  call vert_interp_weights(nlev,self%deptho(iobs),self%depth(:,iobs),self%wi(iobs),self%wf(iobs))
153  if (self%deptho(iobs).ge.maxval(self%depth(:,iobs))) then
154  self%wi(iobs)=nlev-1
155  self%wf(iobs)=0.0
156  end if
157  end do
158  self%ltraj = .true.
159 
160  !< Jacobian
161  allocate(self%jac(2,nlocs),self%tempo(nlocs),self%salto(nlocs))
162  do iobs = 1, nlocs
163  ! Interpolate background do obs depth and save in traj
164  call vert_interp_apply(nlev, self%temp%vals(:,iobs), self%tempo(iobs), self%wi(iobs), self%wf(iobs))
165  call vert_interp_apply(nlev, self%salt%vals(:,iobs), self%salto(iobs), self%wi(iobs), self%wf(iobs))
166 
167  ! Compute jacobian
168  call insitu_t_jac(self%jac(:,iobs), self%tempo(iobs), self%salto(iobs), self%lono(iobs), self%lato(iobs), self%deptho(iobs))
169  end do
170 
171  deallocate(obs_lat)
172  deallocate(obs_lon)
173  deallocate(obs_depth)
174 
176 
177 ! ------------------------------------------------------------------------------
178 subroutine ufo_insitutemperature_simobs_tl(self, geovals, hofx, obss)
179  use ufo_tpsp2ti_mod
181  use vert_interp_mod
182  implicit none
183  class(ufo_insitutemperature_tlad), intent(in) :: self
184  type(ufo_geovals), intent(in) :: geovals
185  real(c_double), intent(inout) :: hofx(:)
186  type(c_ptr), value, intent(in) :: obss
187 
188  character(len=*), parameter :: myname_="ufo_insitutemperature_simobs_tl"
189  character(max_string) :: err_msg
190 
191  integer :: iobs, ilev, nlev, nlocs
192 
193  type(ufo_geoval), pointer :: temp_d, salt_d, dlayerthick !< Increments from geovals
194  real (kind=kind_real) :: lono, lato, deptho !< Observation location
195 
196  ! Vertical interpolation
197  real(kind_real) :: dtp, dsp
198 
199  ! check if trajectory was set
200  if (.not. self%ltraj) then
201  write(err_msg,*) myname_, ' trajectory wasnt set!'
202  call abor1_ftn(err_msg)
203  endif
204 
205  ! check if nlocs is consistent in geovals & hofx
206  if (geovals%nlocs /= size(hofx,1)) then
207  write(err_msg,*) myname_, ' error: nlocs inconsistent!'
208  call abor1_ftn(err_msg)
209  endif
210 
211  ! check if sea temperature profile variable is in geovals and get it
212  call ufo_geovals_get_var(geovals, var_ocn_pot_temp, temp_d)
213 
214  ! check if sea salinity profile variable is in geovals and get it
215  call ufo_geovals_get_var(geovals, var_ocn_salt, salt_d)
216 
217  ! check if sea layer thickness variable is in geovals get it and zero it out
218  call ufo_geovals_get_var(geovals, var_ocn_lay_thick, dlayerthick)
219  ! Make sure thickness is not perturbed
220  dlayerthick%vals=0.0
221 
222  nlev = temp_d%nval
223  nlocs = temp_d%nlocs
224 
225  ! linear sea temperature profile obs operator
226  hofx = 0.0
227  do iobs = 1,nlocs
228 
229  lono = self%lono(iobs)
230  lato = self%lato(iobs)
231  deptho = self%deptho(iobs)
232 
233  ! Interpolate increment
234  call vert_interp_apply(nlev, temp_d%vals(:,iobs), dtp, self%wi(iobs), self%wf(iobs))
235  call vert_interp_apply(nlev, salt_d%vals(:,iobs), dsp, self%wi(iobs), self%wf(iobs))
236 
237  ! Get insitu temp at model levels and obs location (lono, lato, zo)
238  call insitu_t_tl(hofx(iobs),dtp,dsp,self%tempo(iobs),self%salto(iobs),lono,lato,deptho,self%jac(:,iobs))
239 
240  enddo
241 
242 end subroutine ufo_insitutemperature_simobs_tl
243 
244 ! ------------------------------------------------------------------------------
245 subroutine ufo_insitutemperature_simobs_ad(self, geovals, hofx, obss)
246  use ufo_tpsp2ti_mod
248  use vert_interp_mod
249  implicit none
250  class(ufo_insitutemperature_tlad), intent(in) :: self
251  type(ufo_geovals), intent(inout) :: geovals
252  real(c_double), intent(in) :: hofx(:)
253  type(c_ptr), value, intent(in) :: obss
254 
255  character(len=*), parameter :: myname_="ufo_insitutemperature_simobs_ad"
256  character(max_string) :: err_msg
257 
258  real (kind=kind_real) :: lono, lato, deptho !< Observation location
259 
260  integer :: iobs, nlocs, ilev, nlev
261  type(ufo_geoval), pointer :: dtemp, dsalt, dlayerthick
262  real (kind_real) :: dtp, dsp
263  real(c_double) :: missing
264 
265  !> Set missing value
266  missing = missing_value(missing)
267 
268  ! check if trajectory was set
269  if (.not. self%ltraj) then
270  write(err_msg,*) myname_, ' trajectory wasnt set!'
271  call abor1_ftn(err_msg)
272  endif
273 
274  ! check if nlocs is consistent in geovals & hofx
275  if (geovals%nlocs /= size(hofx,1)) then
276  write(err_msg,*) myname_, ' error: nlocs inconsistent!'
277  call abor1_ftn(err_msg)
278  endif
279 
280  if (.not. geovals%linit ) geovals%linit=.true.
281 
282  ! check if sea temperature profile variable is in geovals and get it
283  call ufo_geovals_get_var(geovals, var_ocn_pot_temp, dtemp)
284 
285  ! check if sea salinity profile variable is in geovals and get it
286  call ufo_geovals_get_var(geovals, var_ocn_salt, dsalt)
287 
288  ! check if sea layer thickness variable is in geovals get it and zero it out
289  call ufo_geovals_get_var(geovals, var_ocn_lay_thick, dlayerthick)
290 
291  nlev = self%nval
292  nlocs = self%nlocs
293 
294  ! backward sea temperature profile obs operator
295  do iobs = 1, size(hofx,1)
296 
297  if (hofx(iobs) /= missing) then
298  lono = self%lono(iobs)
299  lato = self%lato(iobs)
300  deptho = self%deptho(iobs)
301 
302  ! Adjoint obs operator
303  dtp = 0.0
304  dsp = 0.0
305  call insitu_t_tlad(hofx(iobs),dtp,dsp,self%tempo(iobs),self%salto(iobs),lono,lato,deptho,self%jac(:,iobs))
306 
307  ! Backward interpolate
308  call vert_interp_apply_ad(nlev, dtemp%vals(:,iobs), dtp, self%wi(iobs), self%wf(iobs))
309  call vert_interp_apply_ad(nlev, dsalt%vals(:,iobs), dsp, self%wi(iobs), self%wf(iobs))
310 
311  end if
312  enddo
313 
314 end subroutine ufo_insitutemperature_simobs_ad
315 
subroutine, public ufo_geovals_get_var(self, varname, geoval)
Fortran insitutemperature module for tl/ad observation operator.
subroutine ufo_insitutemperature_simobs_tl(self, geovals, hofx, obss)
subroutine ufo_insitutemperature_simobs_ad(self, geovals, hofx, obss)
subroutine ufo_insitutemperature_tlad_settraj(self, geovals, obss)
subroutine ufo_insitutemperature_tlad_setup(self, f_conf)
subroutine, public insitu_t_tlad(dtemp_i, dtemp_p, dsalt_p, temp_p, salt_p, lono, lato, deptho, Jacobian)
subroutine, public insitu_t_tl(dtemp_i, dtemp_p, dsalt_p, temp_p, salt_p, lono, lato, deptho, Jacobian)
subroutine, public insitu_t_jac(jac, temp_p, salt_p, lono, lato, deptho)
character(len=maxvarlen), public var_ocn_pot_temp
character(len=maxvarlen), public var_ocn_salt
character(len=maxvarlen), public var_ocn_lay_thick
Fortran module to perform linear interpolation.
Definition: vert_interp.F90:8
subroutine vert_interp_apply_ad(nlev, fvec_ad, f_ad, wi, wf)
subroutine vert_interp_weights(nlev, obl, vec, wi, wf)
Definition: vert_interp.F90:22
subroutine vert_interp_apply(nlev, fvec, f, wi, wf)
Definition: vert_interp.F90:73
type to hold interpolated field for one variable, one observation
type to hold interpolated fields required by the obs operators
Fortran derived type for the tl/ad observation operator.