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