FV3 Bundle
qg_locs_mod.F90
Go to the documentation of this file.
1 ! (C) Copyright 2009-2016 ECMWF.
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 ! In applying this licence, ECMWF does not waive the privileges and immunities
6 ! granted to it by virtue of its status as an intergovernmental organisation nor
7 ! does it submit to any jurisdiction.
8 
9 !> Fortran module handling observation locations
10 
12 
13 use iso_c_binding
15 use kinds
16 
17 implicit none
18 private
19 public :: qg_locs, qg_loc_setup
20 public :: qg_locs_registry
21 
22 ! ------------------------------------------------------------------------------
23 
24 !> Fortran derived type to hold observation locations
25 type :: qg_locs
26  integer :: nloc
27  real(kind=kind_real), allocatable :: xyz(:,:)
28  integer, allocatable :: indx(:)
29 end type qg_locs
30 
31 #define LISTED_TYPE qg_locs
32 
33 !> Linked list interface - defines registry_t type
34 #include "oops/util/linkedList_i.f"
35 
36 !> Global registry
37 type(registry_t) :: qg_locs_registry
38 
39 ! ------------------------------------------------------------------------------
40 contains
41 ! ------------------------------------------------------------------------------
42 !> Linked list implementation
43 #include "oops/util/linkedList_c.f"
44 
45 ! ------------------------------------------------------------------------------
46 
47 subroutine c_qg_loc_create(c_key_locs) bind(c,name='qg_loc_create_f90')
48 
49 implicit none
50 integer(c_int), intent(inout) :: c_key_locs
51 
52 call qg_locs_registry%init()
53 call qg_locs_registry%add(c_key_locs)
54 
55 end subroutine c_qg_loc_create
56 
57 ! ------------------------------------------------------------------------------
58 !> Generate locations for interpolation test
59 !!
60 !! \details **c_qg_loc_test()** generates a list of user-specified and/or
61 !! randomly-generated locations. It was originally intended to be used with the
62 !! test::testStateInterpolation() routine but it may also be adapted for other
63 !! applications. The user can specify a list of specific locations to be tested
64 !! (optional) by setting the "lats" and "lons" items in the "StateTest" section
65 !! of the config file. Alternatively or in addition to these specific locations,
66 !! the user may request that **Nrandom** random locations be generated. If
67 !! neither lats/lons nor Nrandom is specified in the config file, then two
68 !! random locations are generated.
69 !!
70 !! \date April 2, 2018: Created (M. Miesch, JCSDA)
71 !!
72 !! \warning the **lats** and **lons** arrays in the input file are assumed to be
73 !! degrees (for uniformity relative to other models). These are converted to normalized
74 !! x and y coordinates when they are stored in the LocationsQG object as defined here.
75 !! The height specified in the input file is assumed to be normalized already, so
76 !! it will take on a value between 0 and 1.
77 !!
78 !! \warning Since the interpolate() member function of State objects does not
79 !! interpolate in height (z). the z coordinate as recorded in the LocationsQG object
80 !! refers to an integer level of 1 or 2. If the user does not explicitly specify
81 !! the (normalized) height for each latitude and longitude in the config file,
82 !! then the level is set to a default value of 1.
83 !!
84 !! \sa qg::LocationsQG
85 !!
86 subroutine c_qg_loc_test(c_key_locs,config,klocs,klats,klons,kz) bind(c,name='qg_loc_test_f90')
87 use config_mod
88 use fckit_log_module, only : fckit_log
89 
90 implicit none
91 integer(c_int), intent(in) :: c_key_locs !< key to F90 Locations object
92 type(c_ptr) , intent(in) :: config !< Configuration (typically State.StateGenerate)
93 integer(c_int), intent(in) :: klocs !< Number of user-specified locations
94 real(c_double), intent(in) :: klats(klocs) !< user-specified latitudes (degrees)
95 real(c_double), intent(in) :: klons(klocs) !< user-specified longitudes (degrees)
96 real(c_double), intent(in) :: kz(klocs) !< user-specified heights (normalized between 0-1)
97 
98 type(qg_locs), pointer ::locs
99 real(kind_real), allocatable :: xx(:), yy(:), rnum(:)
100 integer :: nrand, nloc, i, jo, nseed
101 integer*4 :: rseed0
102 integer*4, allocatable :: rseed(:)
103 
104 call fckit_log%warning("qg_locs_mod:qg_loc_test generating test locations")
105 
106 if (config_element_exists(config,"Nrandom")) then
107  nrand = config_get_int(config,"Nrandom")
108 else
109  nrand = 0
110 endif
111 
112 if (klocs > 0) then
113  nloc = klocs + nrand
114 else
115  nloc = nrand
116 endif
117 
118 ! pick 2 random locations if no locations are specified
119 if (nloc < 1) then
120  nrand = 2
121  nloc = nrand
122 endif
123 
124 allocate(xx(nloc),yy(nloc))
125 
126 !!
127 !> \warning **qg_loc_test()** latitudes and longitudes are assumed to
128 !! be in normalized coordinates between 0 and 1
129 !!
130 
131 if (klocs > 0) then
132  xx(1:klocs) = klons(:)
133  yy(1:klocs) = klats(:)
134 endif
135 
136 if (config_element_exists(config,"random_seed")) then
137  ! read in the (optional) seed as a real for higher precision
138  ! included for reproducibility
139  rseed0 = config_get_real(config,"random_seed")
140 else
141  ! get the seed from the system clock
142  call system_clock(count=rseed0)
143 endif
144 
145 ! define an optionally reproducible random number seed
146 call random_seed(size=nseed)
147 allocate(rseed(nseed))
148 do i=1,nseed
149  rseed(i) = rseed0 + i**2
150 enddo
151 call random_seed(put=rseed)
152 
153 allocate(rnum(3*nrand))
154 call random_number(rnum)
155 
156 if (nrand > 0) then
157  xx(klocs+1:nloc) = rnum(1:nrand)
158  yy(klocs+1:nloc) = rnum(nrand+1:2*nrand)
159 endif
160 
161 ! Now define the F90 locations object locs. It's assumed that
162 ! this object already exists in the registry.
163 call qg_locs_registry%get(c_key_locs,locs)
164 
165 locs%nloc=nloc
166 
167 ! I think the index is simply the index of the locations array,
168 ! ranging from 1 to nloc
169 allocate(locs%indx(nloc))
170 
171 ! Now initialize the lat and lon
172 allocate(locs%xyz(3,nloc))
173 do jo=1,nloc
174  locs%xyz(1,jo)=xx(jo)
175  locs%xyz(2,jo)=yy(jo)
176  locs%indx(:)=jo
177 enddo
178 
179 ! The QG interpolation does not interpolate in height (z)
180 ! So just define z as the midpoint of the level in question, in meters
181 
182 do jo=1,klocs
183  if (kz(jo) <= 0.5_kind_real) then
184  locs%xyz(3,jo) = 1.0_kind_real
185  else
186  locs%xyz(3,jo) = 2.0_kind_real
187  endif
188 enddo
189 
190 do jo=klocs+1,nloc
191  i=2*nrand+jo-klocs
192  locs%xyz(3,jo) = int(rnum(i)*2.0_kind_real)+1
193 enddo
194 
195 deallocate(xx,yy,rnum)
196 
197 end subroutine c_qg_loc_test
198 
199 ! ------------------------------------------------------------------------------
200 
201 subroutine qg_loc_setup(self, lvec, kobs)
202 implicit none
203 type(qg_locs), intent(inout) :: self
204 type(obs_vect), intent(in) :: lvec
205 integer, intent(in) :: kobs(:)
206 integer :: jc, jo
207 
208 self%nloc=lvec%nobs
209 allocate(self%indx(self%nloc))
210 self%indx(:) = kobs(:)
211 allocate(self%xyz(3,self%nloc))
212 do jo=1,self%nloc
213  do jc=1,3
214  self%xyz(jc,jo)=lvec%values(jc,jo)
215  enddo
216 enddo
217 
218 end subroutine qg_loc_setup
219 
220 ! ------------------------------------------------------------------------------
221 
222 subroutine c_qg_loc_delete(key) bind(c,name='qg_loc_delete_f90')
224 implicit none
225 integer(c_int), intent(inout) :: key
226 type(qg_locs), pointer :: self
227 
228 call qg_locs_registry%get(key,self)
229 if (allocated(self%xyz)) deallocate(self%xyz)
230 call qg_locs_registry%remove(key)
231 
232 end subroutine c_qg_loc_delete
233 
234 ! ------------------------------------------------------------------------------
235 
236 subroutine c_qg_loc_nobs(key, kobs) bind(c,name='qg_loc_nobs_f90')
238 implicit none
239 integer(c_int), intent(in) :: key
240 integer(c_int), intent(inout) :: kobs
241 type(qg_locs), pointer :: self
242 
243 call qg_locs_registry%get(key,self)
244 kobs = self%nloc
245 
246 end subroutine c_qg_loc_nobs
247 
248 ! ------------------------------------------------------------------------------
249 subroutine c_qg_loc_element(key,iloc,xyz) bind(c,name='qg_loc_element_f90')
251 implicit none
252 integer(c_int), intent(in) :: key
253 integer(c_int), intent(in) :: iloc
254 real(c_double), intent(inout) :: xyz(3)
255 type(qg_locs), pointer :: self
256 
257 call qg_locs_registry%get(key,self)
258 
259 xyz(1) = self%xyz(2,iloc+1) ! latitude
260 xyz(2) = self%xyz(1,iloc+1) ! longitude
261 xyz(3) = self%xyz(3,iloc+1) ! height
262 
263 end subroutine c_qg_loc_element
264 
265 ! ------------------------------------------------------------------------------
266 
267 end module qg_locs_mod
subroutine c_qg_loc_create(c_key_locs)
Linked list implementation.
Definition: qg_locs_mod.F90:48
type(registry_t), public qg_locs_registry
Linked list interface - defines registry_t type.
Definition: qg_locs_mod.F90:37
subroutine c_qg_loc_delete(key)
Fortran derived type to hold observation locations.
Definition: qg_locs_mod.F90:25
subroutine c_qg_loc_nobs(key, kobs)
subroutine c_qg_loc_element(key, iloc, xyz)
subroutine c_qg_loc_test(c_key_locs, config, klocs, klats, klons, kz)
Generate locations for interpolation test.
Definition: qg_locs_mod.F90:87
Fortran module handling observation locations.
Definition: qg_locs_mod.F90:11
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************subroutine READ_RECORD_CORE_(unit, field, nwords, data, start, axsiz) integer, intent(in) ::unit type(fieldtype), intent(in) ::field integer, intent(in) ::nwords MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in) ::start(:), axsiz(:) integer(SHORT_KIND) ::i2vals(nwords)!rab used in conjunction with transfer intrinsic to determine size of a variable integer(KIND=1) ::one_byte(8) integer ::word_sz!#ifdef __sgi integer(INT_KIND) ::ivals(nwords) real(FLOAT_KIND) ::rvals(nwords)!#else! integer ::ivals(nwords)! real ::rvals(nwords)!#endif real(DOUBLE_KIND) ::r8vals(nwords) pointer(ptr1, i2vals) pointer(ptr2, ivals) pointer(ptr3, rvals) pointer(ptr4, r8vals) if(mpp_io_stack_size< nwords) call mpp_io_set_stack_size(nwords) call mpp_error(FATAL, 'MPP_READ currently requires use_netCDF option') end subroutine READ_RECORD_CORE_ subroutine READ_RECORD_(unit, field, nwords, data, time_level, domain, position, tile_count, start_in, axsiz_in)!routine that is finally called by all mpp_read routines to perform the read!a non-netCDF record contains:! field ID! a set of 4 coordinates(is:ie, js:je) giving the data subdomain! a timelevel and a timestamp(=NULLTIME if field is static)! 3D real data(stored as 1D)!if you are using direct access I/O, the RECL argument to OPEN must be large enough for the above!in a global direct access file, record position on PE is given by %record.!Treatment of timestamp:! We assume that static fields have been passed without a timestamp.! Here that is converted into a timestamp of NULLTIME.! For non-netCDF fields, field is treated no differently, but is written! with a timestamp of NULLTIME. There is no check in the code to prevent! the user from repeatedly writing a static field. integer, intent(in) ::unit, nwords type(fieldtype), intent(in) ::field MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in), optional ::time_level type(domain2D), intent(in), optional ::domain integer, intent(in), optional ::position, tile_count integer, intent(in), optional ::start_in(:), axsiz_in(:) integer, dimension(size(field%axes(:))) ::start, axsiz integer ::tlevel !, subdomain(4) integer ::i, error, is, ie, js, je, isg, ieg, jsg, jeg type(domain2d), pointer ::io_domain=> tlevel if(PRESENT(start_in) .AND. PRESENT(axsiz_in)) then if(size(start(! the data domain and compute domain must refer to the subdomain being passed ! In this ! since that attempts to gather all data on PE size(field%axes(:)) axsiz(i)
subroutine, public qg_loc_setup(self, lvec, kobs)
Fortran module handling observation vectors.
Fortran derived type to represent an observation vector.