UFO
ufo_atmvertinterplay_tlad_mod.F90
Go to the documentation of this file.
1 ! (C) Copyright 2017-2019 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 
7 
8  use oops_variables_mod
9  use ufo_vars_mod
10  use ufo_geovals_mod
12  use missing_values_mod
13  use, intrinsic :: iso_c_binding
14  use kinds, only: kind_real
15  use missing_values_mod
16 
17 ! ------------------------------------------------------------------------------
18 
19  type, public :: ufo_atmvertinterplay_tlad
20  private
21  type(oops_variables), public :: obsvars
22  type(oops_variables), public :: geovars
23  integer :: nval, nlocs
24  logical :: flip_it
25  real(kind_real), dimension(:), allocatable :: toppressure, botpressure
26  integer, allocatable :: nlevels(:)
27  real, allocatable :: coefficients(:) ! unit conversion from geoval to obs
28  real(kind_real),allocatable :: modelpressures(:,:)
29  contains
30  procedure :: setup => atmvertinterplay_tlad_setup_
31  procedure :: cleanup => atmvertinterplay_tlad_cleanup_
32  procedure :: settraj => atmvertinterplay_tlad_settraj_
33  procedure :: simobs_tl => atmvertinterplay_simobs_tl_
34  procedure :: simobs_ad => atmvertinterplay_simobs_ad_
35  final :: destructor
37 
38 ! ------------------------------------------------------------------------------
39 contains
40 ! ------------------------------------------------------------------------------
41 subroutine atmvertinterplay_tlad_setup_(self, grid_conf)
42  use fckit_configuration_module, only: fckit_configuration
43  implicit none
44  class(ufo_atmvertinterplay_tlad), intent(inout) :: self
45  type(fckit_configuration), intent(in) :: grid_conf
46 
47  character(kind=c_char,len=:), allocatable :: coord_name
48  character(kind=c_char,len=:), allocatable :: gvars(:)
49  real(kind=c_double), allocatable :: coefficients(:)
50  integer(kind=c_int), allocatable :: nlevels(:)
51  !Local Variables
52  integer :: ivar, nlevs=0, nvars=0, ngvars=0, ncoefs=0
53  ! Check configurations
54  if (grid_conf%has("geovals")) then
55  ngvars = grid_conf%get_size("geovals")
56  call grid_conf%get_or_die("geovals", gvars)
57  ! add to geovars list
58  do ivar = 1, ngvars
59  call self%geovars%push_back(gvars(ivar))
60  enddo
61  endif
62  nvars = self%obsvars%nvars()
63  if (ngvars == 0 .and. nvars > 0) then
64  allocate(self%coefficients(nvars))
65  do ivar = 1, nvars
66  call self%geovars%push_back(self%obsvars%variable(ivar))
67  self%coefficients(ivar) = 1.0
68  enddo
69  endif
70  if (grid_conf%has("coefficients")) then
71  ncoefs = grid_conf%get_size("coefficients")
72  call grid_conf%get_or_die("coefficients", coefficients)
73  allocate(self%coefficients(ncoefs))
74  self%coefficients(1:ncoefs) = coefficients(1:ncoefs)
75  endif
76  if (grid_conf%has("nlevels")) then
77  nlevs = grid_conf%get_size("nlevels")
78  call grid_conf%get_or_die("nlevels", nlevels)
79  allocate(self%nlevels(nlevs))
80  self%nlevels(1:nlevs) = nlevels(1:nlevs)
81  endif
82 
83 
84 end subroutine atmvertinterplay_tlad_setup_
85 
86 ! ------------------------------------------------------------------------------
87 
88 subroutine atmvertinterplay_tlad_settraj_(self, geovals_in, obss)
89  use obsspace_mod
90  implicit none
91  class(ufo_atmvertinterplay_tlad), intent(inout) :: self
92  type(ufo_geovals), intent(in) :: geovals_in
93  type(c_ptr), value, intent(in) :: obss
94  integer :: iobs,nlevs,nsig,ilev
95  type(ufo_geovals) :: geovals
96  type(ufo_geoval),pointer :: modelpres
97  type(ufo_geoval),pointer :: p_temp
98  type(ufo_geoval),pointer :: profile
99  character(len=MAXVARLEN) :: var_zdir
100  character(len=MAXVARLEN) :: geovar
101  real(kind_real), dimension(:), allocatable :: airpressure
102  ! Make sure nothing already allocated
103  call self%cleanup()
104 
105  ! Get the observation vertical coordinates
106  self%nlocs = obsspace_get_nlocs(obss)
107  ! Allocate arrays for top and bottom pressures for integral
108  allocate(self%toppressure(self%nlocs))
109  allocate(self%botpressure(self%nlocs))
110  allocate(airpressure(self%nlocs))
111  call ufo_geovals_copy(geovals_in, geovals) ! dont want to change geovals_in
112 
113  call ufo_geovals_get_var(geovals, var_prsi, p_temp)
114  var_zdir = var_prsi ! vertical coordinate variable
115  !if profile direction is top2bottom flip geovals, and make sure tlm and adj follow suit with self%flip_it
116  if( p_temp%vals(1,1) < p_temp%vals(p_temp%nval,1) ) then
117  call ufo_geovals_reorderzdir(geovals, var_zdir, "bottom2top")
118  self%flip_it = .true.
119  else
120  self%flip_it = .false.
121  endif
122 
123  ! Get pressure profiles from geovals [Pa]
124  call ufo_geovals_get_var(geovals, var_prsi, modelpres)
125  nlevs = self%nlevels(1)
126  nsig = modelpres%nval - 1
127  self%nval = modelpres%nval
128  call obsspace_get_db(obss, "MetaData", "air_pressure", airpressure)
129 
130  allocate(self%modelpressures(modelpres%nval,self%nlocs))
131  self%modelpressures(1:nsig+1,1:self%nlocs) = modelpres%vals(1:nsig+1,1:self%nlocs)
132  call get_integral_limits(airpressure(:), self%botpressure(:), self%toppressure(:), self%modelpressures(:,:), nlevs, self%nlocs, nsig)
133 
134 
135  ! Cleanup memory
136  deallocate(airpressure)
137  call ufo_geovals_delete(geovals)
138 end subroutine atmvertinterplay_tlad_settraj_
139 
140 ! ------------------------------------------------------------------------------
141 
142 subroutine atmvertinterplay_simobs_tl_(self, geovals_in, obss, nvars, nlocs, hofx)
143  implicit none
144  class(ufo_atmvertinterplay_tlad), intent(in) :: self
145  type(ufo_geovals), intent(in) :: geovals_in
146  integer, intent(in) :: nvars, nlocs
147  real(c_double), intent(inout) :: hofx(nvars, nlocs)
148  type(c_ptr), value, intent(in) :: obss
149 
150  integer :: iobs, ivar
151  type(ufo_geoval), pointer :: profile
152  type(ufo_geoval), pointer :: pressure
153  character(len=MAXVARLEN) :: geovar
154  character(len=MAXVARLEN) :: var_zdir
155  type(ufo_geovals) :: geovals
156  integer :: nsig
157  call ufo_geovals_copy(geovals_in, geovals) ! dont want to change geovals_in
158  do ivar = 1, nvars
159  ! Get the name of input variable in geovals
160  geovar = self%geovars%variable(ivar)
161  call ufo_geovals_get_var(geovals, geovar, profile)
162  nsig = self%nval-1
163  do iobs = 1, nlocs
164  if(self%flip_it) profile%vals(1:profile%nval,iobs) = profile%vals(profile%nval:1:-1,iobs)
165  call vert_interp_lay_apply_tl(profile%vals(:,iobs), hofx(ivar,iobs), self%coefficients(ivar), self%modelpressures(:,iobs), self%botpressure(iobs), self%toppressure(iobs), nsig)
166  enddo
167  enddo
168  call ufo_geovals_delete(geovals)
169 end subroutine atmvertinterplay_simobs_tl_
170 
171 ! ------------------------------------------------------------------------------
172 
173 subroutine atmvertinterplay_simobs_ad_(self, geovals, obss, nvars, nlocs, hofx)
174  implicit none
175  class(ufo_atmvertinterplay_tlad), intent(in) :: self
176  type(ufo_geovals), intent(inout) :: geovals
177  integer, intent(in) :: nvars, nlocs
178  real(c_double), intent(in) :: hofx(nvars, nlocs)
179  type(c_ptr), value, intent(in) :: obss
180 
181  integer :: iobs, ivar
182  type(ufo_geoval), pointer :: profile
183  type(ufo_geoval), pointer :: pressure
184  character(len=MAXVARLEN) :: geovar
185  character(len=MAXVARLEN) :: var_zdir
186  integer :: nsig
187 
188 
189  do ivar = 1, nvars
190  ! Get the name of input variable in geovals
191  geovar = self%geovars%variable(ivar)
192  call ufo_geovals_get_var(geovals, geovar, profile)
193  nsig = self%nval-1
194  do iobs = 1, nlocs
195  call vert_interp_lay_apply_ad(profile%vals(:,iobs), hofx(ivar,iobs), self%coefficients(ivar), self%modelpressures(:,iobs), self%botpressure(iobs), self%toppressure(iobs), nsig)
196  ! if the geovals come in as top2bottom (logic in traj part of code), make sure to output the adj in the same direction!
197  if(self%flip_it) profile%vals(1:profile%nval,iobs) = profile%vals(profile%nval:1:-1,iobs)
198  enddo
199  enddo
200 
201 
202 end subroutine atmvertinterplay_simobs_ad_
203 
204 ! ------------------------------------------------------------------------------
205 
207  implicit none
208  class(ufo_atmvertinterplay_tlad), intent(inout) :: self
209  self%nval = 0
210  self%nlocs = 0
211  if (allocated(self%toppressure)) deallocate(self%toppressure)
212  if (allocated(self%botpressure)) deallocate(self%botpressure)
213  if (allocated(self%modelpressures)) deallocate(self%modelpressures)
214 end subroutine atmvertinterplay_tlad_cleanup_
215 
216 ! ------------------------------------------------------------------------------
217 
218 subroutine destructor(self)
219  type(ufo_atmvertinterplay_tlad), intent(inout) :: self
220 
221  call self%cleanup()
222 
223 end subroutine destructor
224 
225 ! ------------------------------------------------------------------------------
226 
subroutine atmvertinterplay_simobs_tl_(self, geovals_in, obss, nvars, nlocs, hofx)
subroutine atmvertinterplay_simobs_ad_(self, geovals, obss, nvars, nlocs, hofx)
subroutine atmvertinterplay_tlad_setup_(self, grid_conf)
subroutine atmvertinterplay_tlad_settraj_(self, geovals_in, obss)
subroutine, public ufo_geovals_reorderzdir(self, varname, zdir)
subroutine, public ufo_geovals_copy(self, other)
Copy one GeoVaLs object into another.
subroutine, public ufo_geovals_delete(self)
subroutine, public ufo_geovals_get_var(self, varname, geoval)
character(len=maxvarlen), parameter, public var_prsi
Fortran module to perform linear interpolation.
subroutine vert_interp_lay_apply_tl(modelozoned, layer_ozd, coefficient, modelpressure, botpressure, toppressure, nsig)
subroutine get_integral_limits(airpressure, botpressure, toppressure, modelpressure, nlevs, nlocs, nsig)
subroutine vert_interp_lay_apply_ad(modelozoneb, layer_ozb, coefficient, modelpressure, botpressure, toppressure, nsig)
type to hold interpolated field for one variable, one observation
type to hold interpolated fields required by the obs operators