FV3-JEDI
fv3jedi_interpolation_mod.f90
Go to the documentation of this file.
1 ! (C) Copyright 2019-2020 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 ! fckit
9 use fckit_mpi_module, only: fckit_mpi_comm, fckit_mpi_max, fckit_mpi_min
10 
11 ! oops
12 use unstructured_interpolation_mod, only: unstrc_interp
13 
14 ! fv3jedi
20 use wind_vt_mod, only: d2a, a2d
21 
22 implicit none
23 private
25 
26 ! --------------------------------------------------------------------------------------------------
27 
29 
30  character(len=32) :: interp_type
31  type(fv3jedi_bump_interp) :: bump
32  type(unstrc_interp) :: unsinterp
33  logical :: need_bump, need_bary
34  integer :: nnearest
35  contains
36  procedure :: create
37  procedure :: delete
38  procedure :: apply
39 
40 end type field2field_interp
41 
42 ! --------------------------------------------------------------------------------------------------
43 
44 contains
45 
46 ! --------------------------------------------------------------------------------------------------
47 
48 subroutine create(self, interp_type_in, integer_interp, geom_in, geom_ou)
49 
50 class(field2field_interp), intent(inout) :: self ! field2field_interp
51 character(len=*), intent(in) :: interp_type_in ! bump or barycent
52 logical, intent(in) :: integer_interp ! Need to interpolate integers
53 type(fv3jedi_geom), intent(in) :: geom_in !Geometry of input grid
54 type(fv3jedi_geom), intent(in) :: geom_ou !Geometry of output grid
55 
56 ! Locals
57 integer :: ngrid_ou
58 character(len=32) :: us_interp_type
59 
60 self%need_bump = .false.
61 self%need_bary = .false.
62 
63 self%interp_type = trim(interp_type_in)
64 us_interp_type = ''
65 
66 if (trim(self%interp_type) == 'bump') then
67  self%need_bump = .true.
68 elseif (trim(self%interp_type) == 'barycent') then
69  self%need_bary = .true.
70  us_interp_type = trim(self%interp_type)
71 else
72  call abor1_ftn("In fv3jedi_interpolation_mod.create: interp_type should be bump or barycent")
73 endif
74 
75 if (integer_interp) then
76  self%need_bary = .true.
77  if (us_interp_type == '') us_interp_type = 'barycent'
78 endif
79 
80 ! Initialize bump object
81 ! ----------------------
82 if (self%need_bump) then
83  call self%bump%setup(geom_in%f_comm, geom_in%isc, geom_in%iec, geom_in%jsc, geom_in%jec, geom_in%npz, &
84  geom_in%grid_lon(geom_in%isc:geom_in%iec, geom_in%jsc:geom_in%jec), &
85  geom_in%grid_lat(geom_in%isc:geom_in%iec, geom_in%jsc:geom_in%jec), &
86  geom_ou%ngrid, rad2deg*geom_ou%lon_us, rad2deg*geom_ou%lat_us )
87 endif
88 
89 ! Initialize unstructured interpolation object
90 ! --------------------------------------------
91 self%nnearest = 4
92 if (self%need_bary) then
93  call self%unsinterp%create( geom_in%f_comm, self%nnearest, trim(us_interp_type), &
94  geom_in%ngrid, rad2deg*geom_in%lat_us, rad2deg*geom_in%lon_us, &
95  geom_ou%ngrid, rad2deg*geom_ou%lat_us, rad2deg*geom_ou%lon_us )
96 endif
97 
98 end subroutine create
99 
100 ! --------------------------------------------------------------------------------------------------
101 
102 subroutine delete(self)
103 
104 class(field2field_interp), intent(inout) :: self ! field2field_interp
105 
106 if (self%need_bump) call self%bump%delete()
107 if (self%need_bary) call self%unsinterp%delete()
108 
109 end subroutine delete
110 
111 ! --------------------------------------------------------------------------------------------------
112 
113 subroutine apply(self, nf, geom_in, fields_in, geom_ou, fields_ou)
114 
115 class(field2field_interp), intent(inout) :: self !field2field_interp
116 integer, intent(in) :: nf !Number of fields
117 type(fv3jedi_geom), intent(inout) :: geom_in !Geometry of input grid
118 type(fv3jedi_field), intent(in) :: fields_in(nf) !Input fields
119 type(fv3jedi_geom), intent(inout) :: geom_ou !Geometry of output grid
120 type(fv3jedi_field), intent(inout) :: fields_ou(nf) !Output fields
121 
122 !Locals
123 integer :: var, i, j, k, n
124 real(kind=kind_real), allocatable :: field_in(:), field_ou(:), field_ou_2d(:,:)
125 
126 logical :: do_d2a
127 real(kind=kind_real), allocatable :: ua(:,:,:)
128 real(kind=kind_real), allocatable :: va(:,:,:)
129 real(kind=kind_real), allocatable :: ud(:,:,:)
130 real(kind=kind_real), allocatable :: vd(:,:,:)
131 type(fv3jedi_field), pointer :: u_in
132 type(fv3jedi_field), pointer :: v_in
133 type(fv3jedi_field), pointer :: u_ou
134 type(fv3jedi_field), pointer :: v_ou
135 
136 ! Special case of D-grid winds
137 ! ----------------------------
138 do_d2a = .false.
139 if (has_field(fields_in,'ud')) then
140 
141  do_d2a = .true.
142 
143  call get_field(fields_in, 'ud', u_in)
144  call get_field(fields_in, 'vd', v_in)
145 
146  allocate(ua(geom_in%isc:geom_in%iec,geom_in%jsc:geom_in%jec,geom_in%npz))
147  allocate(va(geom_in%isc:geom_in%iec,geom_in%jsc:geom_in%jec,geom_in%npz))
148 
149  call d2a(geom_in, u_in%array, v_in%array, ua, va)
150 
151  ! Reallocate without staggering
152  deallocate(u_in%array)
153  deallocate(v_in%array)
154  allocate(u_in%array(geom_in%isc:geom_in%iec,geom_in%jsc:geom_in%jec,1:geom_in%npz))
155  allocate(v_in%array(geom_in%isc:geom_in%iec,geom_in%jsc:geom_in%jec,1:geom_in%npz))
156 
157  ! Reallocate output
158  call get_field(fields_ou, 'ud', u_ou)
159  call get_field(fields_ou, 'vd', v_ou)
160  deallocate(u_ou%array)
161  deallocate(v_ou%array)
162  allocate(u_ou%array(geom_ou%isc:geom_ou%iec,geom_ou%jsc:geom_ou%jec,1:geom_ou%npz))
163  allocate(v_ou%array(geom_ou%isc:geom_ou%iec,geom_ou%jsc:geom_ou%jec,1:geom_ou%npz))
164 
165  ! Overwrite field with A-Grid for doing interpolation
166  u_in%array = ua
167  v_in%array = va
168 
169  ! Change field type
170  u_in%space = 'magnitude'
171  v_in%space = 'magnitude'
172 
173  deallocate(ua, va)
174 
175 endif
176 
177 
178 ! Interpolate all fields
179 ! ---------------------
180 do var = 1,nf
181  if (.not. fields_in(var)%integerfield .and. trim(fields_in(var)%space) == 'magnitude' .and. &
182  trim(self%interp_type) == 'bump') then
183 
184  ! Allocation
185  allocate(field_ou_2d(geom_ou%ngrid,1:fields_ou(var)%npz))
186 
187  ! Interpolate
188  call self%bump%apply(fields_ou(var)%npz, fields_in(var)%array, geom_ou%ngrid, field_ou_2d)
189 
190  ! Back to structured
191  n = 0
192  do j = geom_ou%jsc,geom_ou%jec
193  do i = geom_ou%isc,geom_ou%iec
194  n = n + 1
195  fields_ou(var)%array(i,j,1:fields_ou(var)%npz) = field_ou_2d(n,1:fields_ou(var)%npz)
196  enddo
197  enddo
198 
199  ! Release memory
200  deallocate(field_ou_2d)
201 
202  else
203 
204  ! Allocation
205  allocate(field_in(geom_in%ngrid))
206  allocate(field_ou(geom_ou%ngrid))
207 
208  do k = 1, fields_ou(var)%npz
209 
210  ! To unstructured
211  n = 0
212  do j = geom_in%jsc,geom_in%jec
213  do i = geom_in%isc,geom_in%iec
214  n = n + 1
215  field_in(n) = fields_in(var)%array(i,j,k)
216  enddo
217  enddo
218 
219  ! Interpolate
220  if (.not. fields_in(var)%integerfield .and. trim(fields_in(var)%space) == 'magnitude' .and. &
221  trim(self%interp_type) == 'barycent') then
222 
223  call self%unsinterp%apply(field_in, field_ou)
224 
225  elseif (fields_in(var)%integerfield) then
226 
227  call unsinterp_integer_apply(self%unsinterp, field_in, field_ou)
228 
229  elseif (trim(fields_in(var)%space) == 'direction') then
230 
231  call unsinterp_nearest_apply(self%unsinterp, field_in, field_ou)
232 
233  endif
234 
235  ! Back to structured
236  n = 0
237  do j = geom_ou%jsc,geom_ou%jec
238  do i = geom_ou%isc,geom_ou%iec
239  n = n + 1
240  fields_ou(var)%array(i,j,k) = field_ou(n)
241  enddo
242  enddo
243 
244  enddo
245 
246  ! Release memory
247  deallocate(field_in)
248  deallocate(field_ou)
249 
250  endif
251 
252 enddo
253 
254 
255 ! Back to D-Grid
256 ! --------------
257 if (do_d2a) then
258 
259  call get_field(fields_ou, 'ud', u_ou)
260  call get_field(fields_ou, 'vd', v_ou)
261 
262  allocate(ud(geom_ou%isc:geom_ou%iec ,geom_ou%jsc:geom_ou%jec+1,geom_ou%npz))
263  allocate(vd(geom_ou%isc:geom_ou%iec+1,geom_ou%jsc:geom_ou%jec ,geom_ou%npz))
264 
265  call a2d(geom_ou, u_ou%array, v_ou%array, ud, vd)
266 
267  ! Reallocate with staggering
268  deallocate(u_ou%array)
269  deallocate(v_ou%array)
270  allocate(u_ou%array(geom_ou%isc:geom_ou%iec ,geom_ou%jsc:geom_ou%jec+1,1:geom_ou%npz))
271  allocate(v_ou%array(geom_ou%isc:geom_ou%iec+1,geom_ou%jsc:geom_ou%jec ,1:geom_ou%npz))
272 
273  ! Put new D grid back into arrays
274  u_ou%array = ud
275  v_ou%array = vd
276 
277  u_ou%space = 'vector'
278  v_ou%space = 'vector'
279 
280  deallocate(ud, vd)
281 
282 endif
283 
284 end subroutine apply
285 
286 ! --------------------------------------------------------------------------------------------------
287 
288 subroutine unsinterp_integer_apply(unsinterp, field_in, field_ou)
289 
290 type(unstrc_interp), intent(in) :: unsinterp
291 real(kind=kind_real), intent(in) :: field_in(:) !Integer field in
292 real(kind=kind_real), intent(inout) :: field_ou(:) !Integer field out
293 
294 ! Locals
295 integer :: maxtypel, mintypel, maxtype, mintype, ngrid_ou
296 integer :: i, j, k, n, index
297 real(kind=kind_real), allocatable :: interp_w(:,:)
298 real(kind=kind_real), allocatable :: field_ou_tmp(:)
299 real(kind=kind_real), allocatable :: field_neighbours(:,:)
300 real(kind=kind_real), allocatable :: field_types(:)
301 
302 ! Inteprolation of integer fields
303 
304 ! Size of output
305 ! --------------
306 ngrid_ou = size(field_ou)
307 
308 ! Get nearest neighbours
309 ! ----------------------
310 allocate(field_neighbours(unsinterp%nn,ngrid_ou))
311 allocate(field_ou_tmp(ngrid_ou))
312 call unsinterp%apply(field_in, field_ou_tmp, field_neighbours)
313 
314 ! Global min and max integers in field
315 ! ------------------------------------
316 maxtypel = int(maxval(field_in))
317 mintypel = int(minval(field_in))
318 call unsinterp%comm%allreduce(maxtypel,maxtype,fckit_mpi_max())
319 call unsinterp%comm%allreduce(mintypel,mintype,fckit_mpi_min())
320 
321 
322 ! Put weights into field type array and pick max for interpolated value
323 ! ---------------------------------------------------------------------
324 allocate(field_types(mintype:maxtype))
325 
326 field_ou = 0.0_kind_real
327 do i = 1,ngrid_ou
328  field_types = 0.0
329  do n = 1, unsinterp%nn
330  index = int(field_neighbours(n,i))
331  field_types(index) = field_types(index) + unsinterp%interp_w(n,i)
332  enddo
333  field_ou(i) = real(maxloc(field_types,1)+(mintype-1),kind_real)
334 enddo
335 
336 end subroutine unsinterp_integer_apply
337 
338 ! --------------------------------------------------------------------------------------------------
339 
340 subroutine unsinterp_nearest_apply(unsinterp, field_in, field_ou)
341 
342 type(unstrc_interp), intent(in) :: unsinterp
343 real(kind=kind_real), intent(in) :: field_in(:) !Integer field in
344 real(kind=kind_real), intent(inout) :: field_ou(:) !Integer field out
345 
346 integer :: n, ngrid_ou
347 real(kind=kind_real), allocatable :: field_ou_tmp(:)
348 real(kind=kind_real), allocatable :: field_neighbours(:,:)
349 
350 ! Inteprolation using the nearest neighbour
351 
352 ! Size of output
353 ! --------------
354 ngrid_ou = size(field_ou)
355 
356 ! Get nearest neighbours
357 ! ----------------------
358 allocate(field_neighbours(unsinterp%nn,ngrid_ou))
359 allocate(field_ou_tmp(ngrid_ou))
360 call unsinterp%apply(field_in, field_ou_tmp, field_neighbours)
361 
362 ! Find nearest neighbour
363 ! ----------------------
364 do n = 1, ngrid_ou
365  field_ou(n) = field_neighbours(minloc(unsinterp%interp_w(:,n),1),n)
366 enddo
367 
368 
369 end subroutine unsinterp_nearest_apply
370 
371 ! --------------------------------------------------------------------------------------------------
372 
373 end module fv3jedi_interpolation_mod
fv3jedi_field_mod
Definition: fv3jedi_field_mod.f90:6
fv3jedi_field_mod::has_field
logical function, public has_field(fields, field_name, field_index)
Definition: fv3jedi_field_mod.f90:58
fv3jedi_bump_interp_mod::fv3jedi_bump_interp
Definition: fv3jedi_bump_interp_mod.f90:31
fv3jedi_constants_mod::rad2deg
real(kind=kind_real), parameter, public rad2deg
Definition: fv3jedi_constants_mod.f90:13
fv3jedi_interpolation_mod
Definition: fv3jedi_interpolation_mod.f90:6
fv3jedi_geom_mod
Fortran module handling geometry for the FV3 model.
Definition: fv3jedi_geom_mod.f90:8
fv3jedi_interpolation_mod::unsinterp_nearest_apply
subroutine, public unsinterp_nearest_apply(unsinterp, field_in, field_ou)
Definition: fv3jedi_interpolation_mod.f90:341
fv3jedi_field_mod::get_field
Definition: fv3jedi_field_mod.f90:25
fv3jedi_geom_mod::fv3jedi_geom
Fortran derived type to hold geometry data for the FV3JEDI model.
Definition: fv3jedi_geom_mod.f90:46
wind_vt_mod
Definition: wind_variables_mod.f90:6
fv3jedi_interpolation_mod::delete
subroutine delete(self)
Definition: fv3jedi_interpolation_mod.f90:103
fv3jedi_interpolation_mod::apply
subroutine apply(self, nf, geom_in, fields_in, geom_ou, fields_ou)
Definition: fv3jedi_interpolation_mod.f90:114
fv3jedi_constants_mod
Definition: fv3jedi_constants_mod.f90:6
fv3jedi_interpolation_mod::create
subroutine create(self, interp_type_in, integer_interp, geom_in, geom_ou)
Definition: fv3jedi_interpolation_mod.f90:49
fv3jedi_interpolation_mod::unsinterp_integer_apply
subroutine, public unsinterp_integer_apply(unsinterp, field_in, field_ou)
Definition: fv3jedi_interpolation_mod.f90:289
fv3jedi_bump_interp_mod
Definition: fv3jedi_bump_interp_mod.f90:7
fv3jedi_kinds_mod::kind_real
integer, parameter, public kind_real
Definition: fv3jedi_kinds_mod.f90:14
fv3jedi_interpolation_mod::field2field_interp
Definition: fv3jedi_interpolation_mod.f90:28
wind_vt_mod::d2a
subroutine, public d2a(geom, u_comp, v_comp, ua_comp, va_comp)
Definition: wind_variables_mod.f90:1456
wind_vt_mod::a2d
subroutine, public a2d(geom, ua, va, ud, vd)
Definition: wind_variables_mod.f90:1023
fv3jedi_field_mod::fv3jedi_field
Definition: fv3jedi_field_mod.f90:36
fv3jedi_kinds_mod
Definition: fv3jedi_kinds_mod.f90:6