FV3 Bundle
test_horiz_interp.F90
Go to the documentation of this file.
1 !***********************************************************************
2 !* GNU Lesser General Public License
3 !*
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
5 !*
6 !* FMS is free software: you can redistribute it and/or modify it under
7 !* the terms of the GNU Lesser General Public License as published by
8 !* the Free Software Foundation, either version 3 of the License, or (at
9 !* your option) any later version.
10 !*
11 !* FMS is distributed in the hope that it will be useful, but WITHOUT
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 !* for more details.
15 !*
16 !* You should have received a copy of the GNU Lesser General Public
17 !* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
18 !***********************************************************************
19 #ifdef TEST_HORIZ_INTERP
20 !z1l: currently only test bilinear interpolation.
21 
22 program test
23 
24  use mpp_mod, only : mpp_error, mpp_pe, mpp_npes, mpp_root_pe
25  use mpp_mod, only : fatal, stdout, stdlog, mpp_chksum
26  use mpp_io_mod, only : mpp_open, mpp_close, mpp_read
27  use mpp_io_mod, only : axistype, fieldtype
28  use mpp_io_mod, only : mpp_get_info, mpp_get_fields, mpp_get_times
29  use mpp_io_mod, only : mpp_get_axes, mpp_get_axis_data, mpp_get_atts
30  use mpp_io_mod, only : mpp_rdonly, mpp_netcdf, mpp_multi, mpp_single, mpp_overwr
31  use mpp_io_mod, only : mpp_get_att_name, mpp_get_att_char, mpp_get_att_type, mpp_get_att_real
32  use mpp_io_mod, only : mpp_write_meta, axistype, fieldtype, mpp_write, mpp_close
35  use mpp_domains_mod, only : mpp_get_domain_components, mpp_define_mosaic, mpp_define_io_domain
36  use mosaic_mod, only : get_mosaic_ntiles
37  use horiz_interp_mod, only : horiz_interp_new, horiz_interp, horiz_interp_end, horiz_interp_type
39  use axis_utils_mod, only : get_axis_cart
40  use fms_io_mod, only : read_data, write_data
42  use fms_mod, only : fms_init, fms_end, open_namelist_file, close_file, file_exist, field_exist
43  use fms_mod, only : check_nml_error, write_version_number, lowercase
44  use constants_mod, only : constants_init, pi
45  use horiz_interp_mod, only : horiz_interp_new, horiz_interp, horiz_interp_end, horiz_interp_type
47 implicit none
48 
49  character(len=256) :: src_file = ""
50  character(len=256) :: dst_grid = "INPUT/grid_spec.nc"
51  character(len=256) :: field_name = ""
52  character(len=256) :: dst_file = "output.nc"
53  logical :: new_missing_handle = .false.
54  character(len=256) :: interp_method = "bilinear"
55  logical :: use_2d_version = .false.
56  logical :: write_remap_index = .false.
57  integer :: layout(2) = (/1,1/)
58  integer :: io_layout(2) = (/1,1/)
59 
60  real, allocatable, dimension(:) :: x_src, y_src
61  real, allocatable, dimension(:,:) :: x_src_2d, y_src_2d
62  real, allocatable, dimension(:,:) :: x_dst, y_dst
63  type(axistype), allocatable, dimension(:) :: axes
64  type(fieldtype), allocatable, dimension(:) :: fields
65  type(domain2d) :: Domain
66  integer :: unit, ierr, io, src_unit, src_field_index, nk
67  integer :: nx_src, ny_src, nx_dst, ny_dst, is, ie, js, je
68  real :: missing_value
69  integer :: n, ntimes
70 
71  namelist /test_horiz_interp_nml/ src_file, field_name, dst_file, dst_grid, new_missing_handle, &
72  interp_method, use_2d_version, layout, write_remap_index
73 
74  call fms_init
75  call horiz_interp_init
76  call constants_init
77 
78 #ifdef INTERNAL_FILE_NML
79  read (input_nml_file, test_horiz_interp_nml, iostat=io)
80  ierr = check_nml_error(io, 'test_horiz_interp_nml')
81 #else
82  if (file_exist('input.nml')) then
83  unit = open_namelist_file( )
84  ierr=1
85  do while (ierr /= 0)
86  read(unit, nml=test_horiz_interp_nml, iostat=io, end=10)
87  ierr = check_nml_error(io, 'test_horiz_interp_nml')
88  enddo
89 10 call close_file (unit)
90  endif
91 #endif
92 
93 
94  if( .not. file_exist(src_file) ) call mpp_error(fatal, &
95  "test_horiz_interp: src_file = "//trim(src_file)//" does not exist")
96  if( .not. field_exist(src_file, field_name) ) call mpp_error(fatal, &
97  "test_horiz_interp: field_name = "//trim(field_name)//" does not exist in file "//trim(src_file) )
98 
99  ! reading the grid information and missing value from src_file
100  call mpp_open(src_unit, trim(src_file), &
101  action=mpp_rdonly, form=mpp_netcdf, threading=mpp_multi, fileset=mpp_single)
102  call read_src_file()
103 
104  ! reading the dst_grid file
105  call read_dst_grid()
106 
107  !--- currently only test for first time level. The following will read the input data,
108  !--- do the remapping and write out data
109  call process_data()
110 
111  call mpp_close(src_unit)
112 
113  call fms_io_exit
114 
115  call fms_end()
116 
117 contains
118 
119 
120  ! read the input data, do the remapping and write out data
121  subroutine process_data()
122  real, allocatable, dimension(:,:,:) :: src_data, dst_data
123  type(horiz_interp_type) :: Interp
124  type(axistype) :: xaxis, yaxis, zaxis, taxis
125  type(domain1D) :: xdom, ydom
126  type(fieldtype) :: field, field_istart,field_iend,field_jstart,field_jend
127  real, allocatable :: mask_src(:,:)
128  real :: D2R
129  integer :: k, i, j
130  character(len=128) :: dst_file2
131 
132  call get_mosaic_tile_file(dst_file, dst_file2, .false., domain=domain)
133 
134  call mpp_get_domain_components( domain, xdom, ydom )
135  !--- set up meta data
136 ! call mpp_open(unit,dst_file,action=MPP_OVERWR,form=MPP_NETCDF,threading=MPP_MULTI, fileset=MPP_MULTI)
137  call mpp_open(unit,dst_file2,action=mpp_overwr,form=mpp_netcdf,domain=domain)
138  call mpp_write_meta( unit, xaxis, 'lon', 'none', 'X index', 'X', domain=xdom, data=(/(i-1.,i=1,nx_dst)/) )
139  call mpp_write_meta( unit, yaxis, 'lat', 'none', 'Y index', 'Y', domain=ydom, data=(/(i-1.,i=1,ny_dst)/) )
140  call mpp_write_meta( unit, zaxis, 'level', 'none', 'Z index', 'Z', data=(/(i-1.,i=1,nk)/) )
141  call mpp_write_meta( unit, taxis, 'time', 'none', 'T index', 'T' )
142  call mpp_write_meta( unit, field, (/xaxis, yaxis, zaxis, taxis/), field_name, 'none', 'none', missing=missing_value)
143  if(write_remap_index) then
144  call mpp_write_meta( unit, field_istart, (/xaxis, yaxis/), "istart", 'none', 'none')
145  call mpp_write_meta( unit, field_iend, (/xaxis, yaxis/), "iend", 'none', 'none')
146  call mpp_write_meta( unit, field_jstart, (/xaxis, yaxis/), "jstart", 'none', 'none')
147  call mpp_write_meta( unit, field_jend, (/xaxis, yaxis/), "jend", 'none', 'none')
148  endif
149 
150  call mpp_write( unit, xaxis )
151  call mpp_write( unit, yaxis )
152  call mpp_write( unit, zaxis )
153 
154 
155  d2r = pi/180.
156 
157  allocate(src_data(nx_src,ny_src,nk))
158  allocate(dst_data(is:ie,js:je,nk))
159 
160  if(trim(interp_method) == 'conservative' ) then
161  ! get the mask_in
162  call mpp_read(src_unit,fields(src_field_index),src_data, tindex=1)
163  allocate(mask_src(nx_src,ny_src))
164  mask_src = 1.0
165  do j = 1, ny_src
166  do i = 1, nx_src
167  if(src_data(i,j,1) == missing_value) mask_src(i,j) = 0.0
168  enddo
169  enddo
170 
171  write(stdout(),*) "use 2-D version of conservative interpolation"
172  call horiz_interp_new(interp, x_src*d2r, y_src*d2r, x_dst*d2r, y_dst*d2r, &
173  interp_method = trim(interp_method), mask_in=mask_src )
174  deallocate(mask_src)
175  else if(trim(interp_method) == "bilinear" .and. use_2d_version) then
176  write(stdout(),*) "use 2-D version of bilinear interpolation"
177  call horiz_interp_new(interp, x_src_2d*d2r, y_src_2d*d2r, x_dst*d2r, y_dst*d2r, &
178  interp_method = trim(interp_method) )
179  else
180  write(stdout(),*) "use 1-D version of interpolation"
181  call horiz_interp_new(interp, x_src*d2r, y_src*d2r, x_dst*d2r, y_dst*d2r, &
182  interp_method = trim(interp_method), grid_at_center = .true. )
183  endif
184 
185  if(write_remap_index) then
186  dst_data(:,:,1) = interp%i_lon(:,:,1)
187  call mpp_write(unit, field_istart, domain, dst_data(:,:,1))
188  dst_data(:,:,1) = interp%i_lon(:,:,2)
189  call mpp_write(unit, field_iend, domain, dst_data(:,:,1))
190  dst_data(:,:,1) = interp%j_lat(:,:,1)
191  call mpp_write(unit, field_jstart, domain, dst_data(:,:,1))
192  dst_data(:,:,1) = interp%j_lat(:,:,2)
193  call mpp_write(unit, field_jend, domain, dst_data(:,:,1))
194  endif
195 
196  dst_data = 0
197  do n = 1, ntimes
198  call mpp_read(src_unit,fields(src_field_index),src_data, tindex=n)
199 
200  do k = 1, nk
201  call horiz_interp(interp, src_data(:,:,k), dst_data(:,:,k), &
202  missing_value=missing_value, new_missing_handle=new_missing_handle)
203  enddo
204  call mpp_write(unit, field, domain, dst_data, n*1.0)
205  write(stdout(),*) "chksum at time = ", n, " = ", mpp_chksum(dst_data)
206  enddo
207 
208  call mpp_close(unit)
209  deallocate(src_data, dst_data)
210 
211  end subroutine process_data
212 
213 
214  subroutine read_dst_grid
215  integer :: start(4), nread(4)
216  character(len=256) :: tile_file
217  integer :: i, j, siz(4), ntiles, mytile, npes_per_tile
218  real, allocatable :: tmp(:,:)
219 
220  ntiles = get_mosaic_ntiles(dst_grid)
221  if(ntiles .NE. 1 .and. ntiles .NE. 6) call mpp_error(fatal, "test_horiz_interp: ntiles should be 1 or 6")
222  npes_per_tile = mpp_npes()/ntiles
223  mytile = mpp_pe()/npes_per_tile + 1
224 
225  if (field_exist(dst_grid, "gridfiles" )) then
226  call read_data(dst_grid, "gridfiles", tile_file, level=mytile)
227  tile_file = 'INPUT/'//trim(tile_file)
228  else
229  call mpp_error(fatal, "test_horiz_interp: field gridfiles does not exist in file "//trim(dst_grid) )
230  endif
231 
232  call field_size(tile_file, "x", siz)
233  nx_dst = (siz(1)-1)/2
234  ny_dst = (siz(2)-1)/2
235 
236  if(layout(1)*layout(2)*ntiles .NE. mpp_npes() ) then
237  call mpp_define_layout( (/1,nx_dst,1,ny_dst/), mpp_npes()/ntiles, layout )
238  end if
239 
240  if(ntiles == 1) then
241  call mpp_define_domains( (/1,nx_dst,1,ny_dst/), layout, domain, name='test_data_override')
242  else
243  call define_cubic_mosaic(domain, nx_dst, ny_dst, layout)
244  endif
245  call mpp_define_io_domain(domain, io_layout)
246 
247  call mpp_get_compute_domain(domain, is, ie, js, je)
248 
249  allocate(tmp(2*is-1:2*ie+1,2*js-1:2*je+1))
250 
251  start = 1; nread = 1
252  start(1) = 2*is-1; nread(1) = 2*(ie-is+1)+1
253  start(2) = 2*js-1; nread(2) = 2*(je-js+1)+1
254 
255  call read_data(tile_file, "x", tmp, start, nread, domain)
256  if(trim(interp_method) == 'conservative' ) then
257  allocate(x_dst(is:ie+1,js:je+1), y_dst(is:ie+1,js:je+1))
258  do j = js, je+1
259  do i = is, ie+1
260  x_dst(i,j) = tmp(2*i-1,2*j-1)
261  enddo
262  enddo
263  else
264  allocate(x_dst(is:ie,js:je), y_dst(is:ie,js:je))
265  do j = js, je
266  do i = is, ie
267  x_dst(i,j) = tmp(2*i,2*j)
268  enddo
269  enddo
270  endif
271  call read_data(tile_file, "y", tmp, start, nread, domain)
272 
273  if(trim(interp_method) == 'conservative' ) then
274  do j = js, je+1
275  do i = is, ie+1
276  y_dst(i,j) = tmp(2*i-1,2*j-1)
277  enddo
278  enddo
279  else
280  do j = js, je
281  do i = is, ie
282  y_dst(i,j) = tmp(2*i,2*j)
283  enddo
284  enddo
285  endif
286 
287  deallocate(tmp)
288 
289  end subroutine read_dst_grid
290 
291  !--- define mosaic domain for cubic grid
292  subroutine define_cubic_mosaic(domain, ni, nj, layout)
293  type(domain2d), intent(inout) :: domain
294  integer, intent(in) :: layout(:)
295  integer, intent(in) :: ni, nj
296  integer :: pe_start(6), pe_end(6)
297  integer :: global_indices(4,6), layout2d(2,6)
298  integer, dimension(12) :: istart1, iend1, jstart1, jend1, tile1
299  integer, dimension(12) :: istart2, iend2, jstart2, jend2, tile2
300  integer :: ntiles, num_contact
301  integer :: p, npes_per_tile, i
302 
303  ntiles = 6
304  num_contact = 12
305  p = 0
306  npes_per_tile = mpp_npes()/ntiles
307  do i = 1, 6
308  layout2d(:,i) = layout(:)
309  global_indices(1,i) = 1
310  global_indices(2,i) = ni
311  global_indices(3,i) = 1
312  global_indices(4,i) = nj
313  pe_start(i) = p
314  p = p + npes_per_tile
315  pe_end(i) = p-1
316  enddo
317 
318 
319  !--- Contact line 1, between tile 1 (EAST) and tile 2 (WEST)
320  tile1(1) = 1; tile2(1) = 2
321  istart1(1) = ni; iend1(1) = ni; jstart1(1) = 1; jend1(1) = nj
322  istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = nj
323  !--- Contact line 2, between tile 1 (NORTH) and tile 3 (WEST)
324  tile1(2) = 1; tile2(2) = 3
325  istart1(2) = 1; iend1(2) = ni; jstart1(2) = nj; jend1(2) = nj
326  istart2(2) = 1; iend2(2) = 1; jstart2(2) = nj; jend2(2) = 1
327  !--- Contact line 3, between tile 1 (WEST) and tile 5 (NORTH)
328  tile1(3) = 1; tile2(3) = 5
329  istart1(3) = 1; iend1(3) = 1; jstart1(3) = 1; jend1(3) = nj
330  istart2(3) = ni; iend2(3) = 1; jstart2(3) = nj; jend2(3) = nj
331  !--- Contact line 4, between tile 1 (SOUTH) and tile 6 (NORTH)
332  tile1(4) = 1; tile2(4) = 6
333  istart1(4) = 1; iend1(4) = ni; jstart1(4) = 1; jend1(4) = 1
334  istart2(4) = 1; iend2(4) = ni; jstart2(4) = nj; jend2(4) = nj
335  !--- Contact line 5, between tile 2 (NORTH) and tile 3 (SOUTH)
336  tile1(5) = 2; tile2(5) = 3
337  istart1(5) = 1; iend1(5) = ni; jstart1(5) = nj; jend1(5) = nj
338  istart2(5) = 1; iend2(5) = ni; jstart2(5) = 1; jend2(5) = 1
339  !--- Contact line 6, between tile 2 (EAST) and tile 4 (SOUTH)
340  tile1(6) = 2; tile2(6) = 4
341  istart1(6) = ni; iend1(6) = ni; jstart1(6) = 1; jend1(6) = nj
342  istart2(6) = ni; iend2(6) = 1; jstart2(6) = 1; jend2(6) = 1
343  !--- Contact line 7, between tile 2 (SOUTH) and tile 6 (EAST)
344  tile1(7) = 2; tile2(7) = 6
345  istart1(7) = 1; iend1(7) = ni; jstart1(7) = 1; jend1(7) = 1
346  istart2(7) = ni; iend2(7) = ni; jstart2(7) = nj; jend2(7) = 1
347  !--- Contact line 8, between tile 3 (EAST) and tile 4 (WEST)
348  tile1(8) = 3; tile2(8) = 4
349  istart1(8) = ni; iend1(8) = ni; jstart1(8) = 1; jend1(8) = nj
350  istart2(8) = 1; iend2(8) = 1; jstart2(8) = 1; jend2(8) = nj
351  !--- Contact line 9, between tile 3 (NORTH) and tile 5 (WEST)
352  tile1(9) = 3; tile2(9) = 5
353  istart1(9) = 1; iend1(9) = ni; jstart1(9) = nj; jend1(9) = nj
354  istart2(9) = 1; iend2(9) = 1; jstart2(9) = nj; jend2(9) = 1
355  !--- Contact line 10, between tile 4 (NORTH) and tile 5 (SOUTH)
356  tile1(10) = 4; tile2(10) = 5
357  istart1(10) = 1; iend1(10) = ni; jstart1(10) = nj; jend1(10) = nj
358  istart2(10) = 1; iend2(10) = ni; jstart2(10) = 1; jend2(10) = 1
359  !--- Contact line 11, between tile 4 (EAST) and tile 6 (SOUTH)
360  tile1(11) = 4; tile2(11) = 6
361  istart1(11) = ni; iend1(11) = ni; jstart1(11) = 1; jend1(11) = nj
362  istart2(11) = ni; iend2(11) = 1; jstart2(11) = 1; jend2(11) = 1
363  !--- Contact line 12, between tile 5 (EAST) and tile 6 (WEST)
364  tile1(12) = 5; tile2(12) = 6
365  istart1(12) = ni; iend1(12) = ni; jstart1(12) = 1; jend1(12) = nj
366  istart2(12) = 1; iend2(12) = 1; jstart2(12) = 1; jend2(12) = nj
367  call mpp_define_mosaic(global_indices, layout2d, domain, ntiles, num_contact, tile1, tile2, &
368  istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
369  pe_start, pe_end, symmetry = .true., name = 'cubic mosaic' )
370 
371  return
372 
373  end subroutine define_cubic_mosaic
374 
375 
376  subroutine read_src_file
377 
378  integer :: ndim, nvar, natt, n
379  integer :: nt, i, j, k, jj, len1
380  character(len=1) :: cart
381  character(len=32) :: name
382  type(axistype) :: axis_bounds(2)
383 
384  call mpp_get_info(src_unit, ndim, nvar, natt, ntimes)
385 
386  allocate(fields(nvar))
387  call mpp_get_fields(src_unit, fields)
388  src_field_index = 0
389  do i=1,nvar
390  call mpp_get_atts(fields(i),name=name)
391  if (lowercase(trim(field_name)) == lowercase(trim(name))) then
392  src_field_index = i
393  endif
394  enddo
395  if(src_field_index == 0) call mpp_error(fatal, 'test_horiz_interp: field '&
396  //trim(field_name)//' is not in the file '//trim(src_file) )
397  !--- get the src grid
398  call mpp_get_atts(fields(src_field_index),ndim=ndim)
399  allocate(axes(ndim))
400  call mpp_get_atts(fields(src_field_index),axes=axes)
401  nx_src=0; ny_src=0; nk=1
402  do j=1,ndim
403  call mpp_get_atts(axes(j),len=len1)
404  call get_axis_cart(axes(j),cart)
405  select case (cart)
406  case ('X')
407  nx_src = len1
408  if(trim(interp_method) == 'conservative' ) then
409  allocate(x_src(nx_src+1))
410  call get_axis_bounds(axes(j),axis_bounds(1), axes)
411  call mpp_get_axis_data(axis_bounds(1), x_src)
412  else
413  allocate(x_src(nx_src))
414  call mpp_get_axis_data(axes(j),x_src)
415  endif
416  case('Y')
417  ny_src = len1
418  if(trim(interp_method) == 'conservative' ) then
419  allocate(y_src(ny_src+1))
420  call get_axis_bounds(axes(j),axis_bounds(2), axes)
421  call mpp_get_axis_data(axis_bounds(2), y_src)
422  else
423  allocate(y_src(ny_src))
424  call mpp_get_axis_data(axes(j),y_src)
425  endif
426  case('Z')
427  nk = len1
428  end select
429  enddo
430 
431  if(nx_src==0) call mpp_error(fatal,'test_horiz_interp: file ' &
432  //trim(src_file)//' does not contain axis with cartesian attributes = "X" ')
433  if(ny_src==0) call mpp_error(fatal,'test_horiz_interp: file '&
434  //trim(src_file)//' does not contain axis with cartesian attributes = "Y" ')
435 
436  if(trim(interp_method) .ne. 'conservative') then
437  allocate(x_src_2d(nx_src,ny_src), y_src_2d(nx_src,ny_src))
438  do i = 1, nx_src
439  x_src_2d(i,:) = x_src(i)
440  enddo
441  do i = 1, ny_src
442  y_src_2d(:,i) = y_src(i)
443  enddo
444  endif
445 
446  !--- get the missing value
447  call mpp_get_atts(fields(src_field_index),missing=missing_value)
448 
449 
450  end subroutine read_src_file
451 
452 
453 end program test
454 
455 #else
457 end module
458 
459 #endif
Definition: fms.F90:20
subroutine, public horiz_interp_end
subroutine define_cubic_mosaic(type, domain, ni, nj, global_indices, layout, pe_start, pe_end)
integer function, public get_mosaic_ntiles(mosaic_file)
Definition: mosaic.F90:214
Definition: mpp.F90:39
integer function, public check_nml_error(IOSTAT, NML_NAME)
Definition: fms.F90:658
int field_exist(const char *file, const char *name)
Definition: read_mosaic.c:69
subroutine, public fms_init(localcomm)
Definition: fms.F90:353
subroutine, public field_size(filename, fieldname, siz, field_found, domain, no_domain)
Definition: fms_io.F90:4941
subroutine, public get_axis_cart(axis, cart)
Definition: axis_utils.F90:79
subroutine, public horiz_interp_init
subroutine, public fms_end()
Definition: fms.F90:476
subroutine, public fms_io_exit()
Definition: fms_io.F90:750
subroutine, public get_axis_bounds(axis, axis_bound, axes, bnd_name, err_msg)
Definition: axis_utils.F90:149
subroutine, public constants_init
dummy routine.
Definition: constants.F90:141
real(fp), parameter, public pi