FV3 Bundle
test_xgrid.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 
20 #ifdef TEST_XGRID
21 ! Now only test some simple test, will test cubic grid mosaic in the future.
22 
23 program xgrid_test
24 
25  use mpp_mod, only : mpp_pe, mpp_npes, mpp_error, fatal, mpp_chksum, mpp_min, mpp_max
26  use mpp_mod, only : mpp_set_current_pelist, mpp_declare_pelist, mpp_sync
27  use mpp_mod, only : mpp_root_pe, mpp_broadcast, stdout, note, mpp_sync_self
28  use mpp_domains_mod, only : mpp_define_domains, mpp_define_layout, mpp_domains_exit
29  use mpp_domains_mod, only : mpp_get_compute_domain, domain2d, mpp_domains_init
30  use mpp_domains_mod, only : mpp_define_mosaic_pelist, mpp_define_mosaic, mpp_global_sum
32  use mpp_domains_mod, only : domainug, mpp_define_unstruct_domain, mpp_get_ug_compute_domain
34  use mpp_io_mod, only : mpp_open, mpp_rdonly,mpp_netcdf, mpp_multi, mpp_single, mpp_close
35  use mpp_io_mod, only : mpp_get_att_value
36  use fms_mod, only : fms_init, file_exist, field_exist, field_size, open_namelist_file
37  use fms_mod, only : check_nml_error, close_file, read_data, stdout, fms_end
38  use fms_mod, only : get_mosaic_tile_grid, write_data, set_domain
40  use constants_mod, only : deg_to_rad
47  use grid_mod, only : get_grid_comp_area
51 
52 implicit none
53 #include <fms_platform.h>
54 
55  real, parameter :: EPSLN = 1.0e-10
56  character(len=256) :: atm_input_file = "INPUT/atmos_input.nc"
57  character(len=256) :: atm_output_file = "atmos_output.nc"
58  character(len=256) :: lnd_output_file = "land_output.nc"
59  character(len=256) :: ice_output_file = "ocean_output.nc"
60  character(len=256) :: atm_field_name = "none"
61 
62  character(len=256) :: runoff_input_file = "INPUT/land_runoff.nc"
63  character(len=256) :: runoff_output_file = "land_runoff.nc"
64  character(len=256) :: runoff_field_name = "none"
65  integer :: num_iter = 0
66  integer :: nk_lnd = 1, nk_ice = 1
67  integer :: atm_layout(2) = (/0,0/)
68  integer :: lnd_layout(2) = (/0,0/)
69  integer :: ice_layout(2) = (/0,0/)
70  integer :: atm_nest_layout(2) = (/0,0/)
71  integer :: atm_npes = 0
72  integer :: lnd_npes = 0
73  integer :: ice_npes = 0
74  integer :: ocn_npes = 0
75  integer :: atm_nest_npes = 0
76  logical :: concurrent = .false.
77  logical :: test_unstruct = .false.
78 
79  namelist /xgrid_test_nml/ atm_input_file, atm_field_name, runoff_input_file, runoff_field_name, num_iter, &
80  nk_lnd, nk_ice, atm_layout, ice_layout, lnd_layout, atm_nest_layout, &
81  atm_nest_npes, atm_npes, lnd_npes, ice_npes, test_unstruct
82 
83  integer :: remap_method
84  integer :: pe, npes, ierr, nml_unit, io, n
85  integer :: siz(4), ntile_lnd, ntile_atm, ntile_ice, ncontact
86  integer, allocatable :: layout(:,:), global_indices(:,:)
87  integer, allocatable :: atm_nx(:), atm_ny(:), ice_nx(:), ice_ny(:), lnd_nx(:), lnd_ny(:)
88  integer, allocatable :: pe_start(:), pe_end(:), dummy(:)
89  integer, allocatable :: istart1(:), iend1(:), jstart1(:), jend1(:), tile1(:)
90  integer, allocatable :: istart2(:), iend2(:), jstart2(:), jend2(:), tile2(:)
91  character(len=256) :: grid_file = "INPUT/grid_spec.nc"
92  character(len=256) :: atm_mosaic, ocn_mosaic, lnd_mosaic
93  character(len=256) :: atm_mosaic_file, ocn_mosaic_file, lnd_mosaic_file
94  character(len=256) :: grid_descriptor, tile_file
95  integer :: isc_atm, iec_atm, jsc_atm, jec_atm, nxc_atm, nyc_atm
96  integer :: isc_lnd, iec_lnd, jsc_lnd, jec_lnd
97  integer :: isc_ice, iec_ice, jsc_ice, jec_ice
98  integer :: isd_atm, ied_atm, jsd_atm, jed_atm
99  integer :: unit, i, j, nxa, nya, nxgrid, nxl, nyl, out_unit, k
100  type(domain2d) :: Atm_domain, Ice_domain, Lnd_domain
101  type(xmap_type) :: Xmap, Xmap_runoff
102  type(grid_box_type) :: atm_grid
103  real, allocatable :: xt(:,:), yt(:,:) ! on T-cell data domain
104  real, allocatable :: xc(:,:), yc(:,:) ! on C-cell compute domain
105  real, allocatable :: tmpx(:,:), tmpy(:,:)
106  real, allocatable :: atm_data_in(:,:), atm_data_out(:,:)
107  real, allocatable :: atm_data_out_1(:,:), atm_data_out_2(:,:), atm_data_out_3(:,:)
108  real, allocatable :: lnd_data_out(:,:,:), ice_data_out(:,:,:)
109  real, allocatable :: runoff_data_in(:,:), runoff_data_out(:,:,:)
110  real, allocatable :: atm_area(:,:), lnd_area(:,:), ice_area(:,:)
111  real, allocatable :: lnd_frac(:,:,:), ice_frac(:,:,:)
112  real, allocatable :: x_1(:), x_2(:), x_3(:), x_4(:)
113  real :: sum_atm_in, sum_ice_out, sum_lnd_out, sum_atm_out
114  real :: sum_runoff_in, sum_runoff_out, tot
115  real :: min_atm_in, max_atm_in, min_atm_out, max_atm_out
116  real :: min_x, max_x
117  logical :: atm_input_file_exist, runoff_input_file_exist
118  integer :: npes_per_tile
119  integer :: id_put_side1_to_xgrid, id_get_side1_from_xgrid
120  integer :: id_put_side2_to_xgrid, id_get_side2_from_xgrid
121  integer :: ens_siz(6), ensemble_size
122  integer :: atm_root_pe, lnd_root_pe, ocn_root_pe, ice_root_pe, atm_nest_root_pe
123  integer :: atm_global_npes, ntile_atm_global, ncontact_global
124  integer :: atm_nest_nx, atm_nest_ny, ntile_atm_nest
125  logical :: atm_pe, lnd_pe, ice_pe, ocn_pe, atm_global_pe, atm_nest_pe
126  integer, allocatable :: atm_pelist(:), ocn_pelist(:), ice_pelist(:), lnd_pelist(:)
127  integer, allocatable :: atm_global_pelist(:), atm_nest_pelist(:)
128  integer, allocatable :: tile_id(:)
129 
130  call fms_init
131 
132  call mpp_domains_init
133 
134  call xgrid_init(remap_method)
135  call ensemble_manager_init()
136 
137  npes = mpp_npes()
138  pe = mpp_pe()
139  out_unit = stdout()
140 
141 #ifdef INTERNAL_FILE_NML
142  read (input_nml_file, xgrid_test_nml, iostat=io)
143  ierr = check_nml_error(io, 'xgrid_test_nml')
144 #else
145  if (file_exist('input.nml')) then
146  ierr=1
147  nml_unit = open_namelist_file()
148  do while (ierr /= 0)
149  read(nml_unit, nml=xgrid_test_nml, iostat=io, end=10)
150  ierr = check_nml_error(io, 'xgrid_test_nml')
151  enddo
152 10 call close_file(nml_unit)
153  endif
154 #endif
155 
156  !--- get ensemble size
157  ens_siz = get_ensemble_size()
158  ensemble_size = ens_siz(1)
159  npes = ens_siz(2)
160 
161  if( atm_npes == 0 ) atm_npes = mpp_npes()
162  if( lnd_npes == 0 ) lnd_npes = atm_npes
163  if( ocn_npes == 0 ) ocn_npes = atm_npes
164  if( ice_npes == 0 ) ice_npes = atm_npes
165  if(lnd_npes > atm_npes) call mpp_error(fatal, 'xgrid_test: lnd_npes > atm_npes')
166  if(ocn_npes > atm_npes) call mpp_error(fatal, 'xgrid_test: ocn_npes > atm_npes')
167 
168  write(out_unit, *) "NOTE from test_xgrid: atm_npes = ", atm_npes
169  write(out_unit, *) "NOTE from test_xgrid: atm_nest_npes = ", atm_nest_npes
170  write(out_unit, *) "NOTE from test_xgrid: lnd_npes = ", lnd_npes
171  write(out_unit, *) "NOTE from test_xgrid: ice_npes = ", ice_npes
172  write(out_unit, *) "NOTE from test_xgrid: ocn_npes = ", ocn_npes
173 
174  allocate(atm_pelist(atm_npes))
175  allocate(ice_pelist(ice_npes))
176  allocate(lnd_pelist(lnd_npes))
177  allocate(ocn_pelist(ocn_npes))
178  concurrent = .false.
179 
180  call ensemble_pelist_setup(concurrent, atm_npes, ocn_npes, lnd_npes, ice_npes, &
181  atm_pelist, ocn_pelist, lnd_pelist, ice_pelist)
182 
183  if(atm_nest_npes > 0) then
184  atm_global_npes = atm_npes - atm_nest_npes
185  allocate(atm_global_pelist(atm_global_npes))
186  allocate(atm_nest_pelist(atm_nest_npes))
187  atm_global_pelist(1:atm_global_npes) = atm_pelist(1:atm_global_npes)
188  atm_nest_pelist(1:atm_nest_npes) = atm_pelist(atm_global_npes+1:atm_npes)
189  atm_global_pe = any(atm_global_pelist == mpp_pe())
190  atm_nest_pe = any(atm_nest_pelist == mpp_pe())
191  atm_nest_root_pe = atm_nest_pelist(1)
192  call mpp_declare_pelist(atm_global_pelist, "atm global pelist")
193  call mpp_declare_pelist(atm_nest_pelist, "atm nest pelist")
194  else
195  atm_global_npes = atm_npes
196  allocate(atm_global_pelist(atm_global_npes))
197  atm_global_pelist(1:atm_global_npes) = atm_pelist(1:atm_global_npes)
198  atm_global_pe = any(atm_global_pelist == mpp_pe())
199  atm_nest_pe = .false.
200  endif
201 
202  atm_pe = any(atm_pelist .EQ. mpp_pe())
203  lnd_pe = any(lnd_pelist .EQ. mpp_pe())
204  ocn_pe = any(ocn_pelist .EQ. mpp_pe())
205  ice_pe = any(ice_pelist .EQ. mpp_pe())
206  atm_root_pe = atm_pelist(1)
207  lnd_root_pe = lnd_pelist(1)
208  ice_root_pe = ice_pelist(1)
209  ocn_root_pe = ocn_pelist(1)
210 
211  ntile_atm = 1
212  ntile_ice = 1
213  ntile_lnd = 1
214 
215  if(field_exist(grid_file, "AREA_ATM" ) ) then
216  if( atm_nest_npes > 0 ) call mpp_error(fatal, &
217  'xgrid_test: nested atmosphere model is only supported for mosaic grid')
218  allocate(atm_nx(1), atm_ny(1))
219  allocate(lnd_nx(1), lnd_ny(1))
220  allocate(ice_nx(1), ice_ny(1))
221  call field_size(grid_file, "AREA_ATM", siz )
222  atm_nx = siz(1); atm_ny = siz(2)
223  call field_size(grid_file, "AREA_OCN", siz )
224  ice_nx = siz(1); ice_ny = siz(2)
225  call field_size(grid_file, "AREA_LND", siz )
226  lnd_nx = siz(1); lnd_ny = siz(2)
227  if( atm_layout(1)*atm_layout(2) .NE. npes ) then
228  call mpp_define_layout( (/1,atm_nx,1,atm_ny/), npes, atm_layout)
229  endif
230  call mpp_define_domains( (/1,atm_nx,1,atm_ny/), atm_layout, atm_domain, name="atmosphere")
231  if( lnd_layout(1)*lnd_layout(2) .NE. npes ) then
232  call mpp_define_layout( (/1,lnd_nx,1,lnd_ny/), npes, lnd_layout)
233  endif
234  call mpp_define_domains( (/1,lnd_nx,1,lnd_ny/), lnd_layout, lnd_domain, name="land")
235  if( ice_layout(1)*ice_layout(2) .NE. npes ) then
236  call mpp_define_layout( (/1,ice_nx,1,ice_ny/), npes, ice_layout)
237  endif
238  call mpp_define_domains( (/1,ice_nx,1,ice_ny/), ice_layout, ice_domain, name="Ice")
239  else if (field_exist(grid_file, "atm_mosaic" ) ) then
240  !--- Get the mosaic data of each component model
241  call read_data(grid_file, 'atm_mosaic', atm_mosaic)
242  call read_data(grid_file, 'lnd_mosaic', lnd_mosaic)
243  call read_data(grid_file, 'ocn_mosaic', ocn_mosaic)
244  atm_mosaic_file = 'INPUT/'//trim(atm_mosaic)//'.nc'
245  lnd_mosaic_file = 'INPUT/'//trim(lnd_mosaic)//'.nc'
246  ocn_mosaic_file = 'INPUT/'//trim(ocn_mosaic)//'.nc'
247 
248  ntile_lnd = get_mosaic_ntiles(lnd_mosaic_file);
249  ntile_ice = get_mosaic_ntiles(ocn_mosaic_file);
250  ntile_atm = get_mosaic_ntiles(atm_mosaic_file);
251 
252  if(ntile_ice > 1) call mpp_error(fatal, &
253  'xgrid_test: there is more than one tile in ocn_mosaic, which is not implemented yet')
254 
255  write(out_unit,*)" There is ", ntile_atm, " tiles in atmos mosaic"
256  write(out_unit,*)" There is ", ntile_lnd, " tiles in land mosaic"
257  write(out_unit,*)" There is ", ntile_ice, " tiles in ocean mosaic"
258  allocate(atm_nx(ntile_atm), atm_ny(ntile_atm))
259  allocate(lnd_nx(ntile_lnd), lnd_ny(ntile_lnd))
260  allocate(ice_nx(ntile_ice), ice_ny(ntile_ice))
261 
262  call get_mosaic_grid_sizes(atm_mosaic_file, atm_nx, atm_ny)
263  call get_mosaic_grid_sizes(lnd_mosaic_file, lnd_nx, lnd_ny)
264  call get_mosaic_grid_sizes(ocn_mosaic_file, ice_nx, ice_ny)
265 
266  ncontact = get_mosaic_ncontacts(atm_mosaic_file)
267 
268  if(ncontact > 0) then
269  allocate(tile1(ncontact), tile2(ncontact) )
270  allocate(istart1(ncontact), iend1(ncontact) )
271  allocate(jstart1(ncontact), jend1(ncontact) )
272  allocate(istart2(ncontact), iend2(ncontact) )
273  allocate(jstart2(ncontact), jend2(ncontact) )
274  call get_mosaic_contact( atm_mosaic_file, tile1, tile2, istart1, iend1, jstart1, jend1, &
275  istart2, iend2, jstart2, jend2)
276  endif
277 
278  ntile_atm_global = ntile_atm
279  ncontact_global = ncontact
280  if( atm_nest_npes > 0 ) then
281  if(ntile_atm .NE. 7) call mpp_error(fatal, &
282  'xgrid_test: ntile_atm should be 7 when atmos_nest_npes > 0')
283  if(ncontact .NE. 13 ) call mpp_error(fatal, &
284  'xgrid_test: ncontact_atm should be 13 when atmos_nest_npes > 0')
285  ntile_atm_global = ntile_atm_global - 1
286  ncontact_global = ncontact_global - 1
287  endif
288 
289  if(atm_global_pe) then
290  call mpp_set_current_pelist(atm_global_pelist)
291  if(mod(atm_global_npes, ntile_atm_global) .NE. 0 ) call mpp_error(fatal, &
292  "atm_npes_global should be divided by ntile_atm_global")
293 
294  allocate(pe_start(ntile_atm_global), pe_end(ntile_atm_global) )
295  allocate(global_indices(4, ntile_atm_global), layout(2,ntile_atm_global))
296  npes_per_tile = atm_global_npes/ntile_atm_global
297  do n = 1, ntile_atm_global
298  pe_start(n) = atm_root_pe + (n-1)*npes_per_tile
299  pe_end(n) = atm_root_pe + n*npes_per_tile - 1
300  global_indices(:,n) = (/1, atm_nx(n), 1, atm_ny(n)/)
301  if(atm_layout(1)*atm_layout(2) == npes_per_tile ) then
302  layout(:,n) = atm_layout(:)
303  else
304  call mpp_define_layout( global_indices(:,n), pe_end(n)-pe_start(n)+1, layout(:,n))
305  endif
306  end do
307 
308  allocate(tile_id(ntile_atm_global))
309  do n = 1, ntile_atm_global
310  tile_id(n) = n
311  enddo
312 
313  call mpp_define_mosaic(global_indices, layout, atm_domain, ntile_atm_global, ncontact_global, &
314  tile1(1:ncontact_global), tile2(1:ncontact_global), &
315  istart1(1:ncontact_global), iend1(1:ncontact_global), &
316  jstart1(1:ncontact_global), jend1(1:ncontact_global), &
317  istart2(1:ncontact_global), iend2(1:ncontact_global), &
318  jstart2(1:ncontact_global), jend2(1:ncontact_global), &
319  pe_start, pe_end, whalo=1, ehalo=1, shalo=1, nhalo=1, &
320  tile_id=tile_id, name="atmosphere")
321  deallocate( pe_start, pe_end, global_indices, layout, tile_id )
322  endif
323  if( atm_nest_pe ) then
324  atm_nest_nx = atm_nx(ntile_atm)
325  atm_nest_ny = atm_ny(ntile_atm)
326  call mpp_set_current_pelist(atm_nest_pelist)
327  ntile_atm_nest = 1
328  ncontact = 0
329  allocate(pe_start(1), pe_end(1) )
330  allocate(global_indices(4, 1), layout(2,1))
331  pe_start(1) = atm_nest_root_pe
332  pe_end(1) = atm_nest_root_pe + atm_nest_npes - 1
333  global_indices(:,1) = (/1, atm_nest_nx, 1, atm_nest_ny/) !-- the last tile is the nested tile
334  if(atm_nest_layout(1)*atm_nest_layout(2) == atm_nest_npes ) then
335  layout(:,1) = atm_nest_layout(:)
336  else
337  call mpp_define_layout( global_indices(:,1), atm_nest_npes, layout(:,1))
338  endif
339  allocate(tile_id(1))
340  tile_id(1) = ntile_atm
341  call mpp_define_mosaic(global_indices, layout, atm_domain, ntile_atm_nest, ncontact, dummy, dummy, &
342  dummy, dummy, dummy, dummy, dummy, dummy, dummy, dummy, pe_start, pe_end, &
343  whalo=1, ehalo=1, shalo=1, nhalo=1, tile_id=tile_id, name="atmos nest")
344  deallocate( pe_start, pe_end, global_indices, layout, tile_id )
345  endif
346 
347  if( lnd_pe ) then
348  call mpp_set_current_pelist(lnd_pelist)
349  ncontact = 0 ! no update is needed for land model.
350  allocate(pe_start(ntile_lnd), pe_end(ntile_lnd) )
351  allocate(global_indices(4,ntile_lnd), layout(2,ntile_lnd))
352  if(mod(lnd_npes, ntile_lnd) .NE. 0 ) call mpp_error(fatal,"lnd_npes should be divided by ntile_lnd")
353  npes_per_tile = lnd_npes/ntile_lnd
354  do n = 1, ntile_lnd
355  pe_start(n) = lnd_root_pe + (n-1)*npes_per_tile
356  pe_end(n) = lnd_root_pe + n*npes_per_tile - 1
357  global_indices(:,n) = (/1, lnd_nx(n), 1, lnd_ny(n)/)
358  if(lnd_layout(1)*lnd_layout(2) == npes_per_tile ) then
359  layout(:,n) = lnd_layout(:)
360  else
361  call mpp_define_layout( global_indices(:,n), npes_per_tile, layout(:,n))
362  endif
363  end do
364 
365  ncontact = 0 ! no update is needed for land and ocean model.
366 
367  allocate(tile_id(ntile_lnd))
368  do n = 1, ntile_lnd
369  tile_id(n) = n
370  enddo
371 
372  call mpp_define_mosaic(global_indices, layout, lnd_domain, ntile_lnd, ncontact, dummy, dummy, &
373  dummy, dummy, dummy, dummy, dummy, dummy, dummy, dummy, pe_start, pe_end, tile_id=tile_id, name="land")
374  deallocate( pe_start, pe_end, global_indices, layout, tile_id )
375  endif
376 
377  if( ice_pe ) then
378  call mpp_set_current_pelist(ice_pelist)
379  ncontact = 0 ! no update is needed for ocn model.
380  allocate(pe_start(ntile_ice), pe_end(ntile_ice) )
381  allocate(global_indices(4, ntile_ice), layout(2, ntile_ice))
382  npes_per_tile = ice_npes/ntile_ice
383  do n = 1, ntile_ice
384  pe_start(n) = ice_root_pe + (n-1)*npes_per_tile
385  pe_end(n) = ice_root_pe + n*npes_per_tile - 1
386  global_indices(:,n) = (/1, ice_nx(n), 1, ice_ny(n)/)
387  if(ice_layout(1)*ice_layout(2) == npes_per_tile ) then
388  layout(:,n) = ice_layout(:)
389  else
390  call mpp_define_layout( global_indices(:,n), ice_npes, layout(:,n))
391  endif
392  end do
393  allocate(tile_id(ntile_ice))
394  do n = 1, ntile_ice
395  tile_id(n) = n
396  enddo
397 
398  call mpp_define_mosaic(global_indices, layout, ice_domain, ntile_ice, ncontact, dummy, dummy, &
399  dummy, dummy, dummy, dummy, dummy, dummy, dummy, dummy, pe_start, pe_end, tile_id=tile_id, name="Ice")
400  deallocate( pe_start, pe_end, global_indices, layout, tile_id )
401  endif
402  else
403  call mpp_error(fatal, 'test_xgrid:both AREA_ATM and atm_mosaic does not exist in '//trim(grid_file))
404  end if
405 
406  if( atm_pe ) then
407  call mpp_get_compute_domain(atm_domain, isc_atm, iec_atm, jsc_atm, jec_atm)
408  call mpp_get_data_domain(atm_domain, isd_atm, ied_atm, jsd_atm, jed_atm)
409  call mpp_get_global_domain(atm_domain, xsize = nxa, ysize = nya)
410  nxc_atm = iec_atm - isc_atm + 1
411  nyc_atm = jec_atm - jsc_atm + 1
412  endif
413  if( lnd_pe ) then
414  call mpp_get_compute_domain(lnd_domain, isc_lnd, iec_lnd, jsc_lnd, jec_lnd)
415  call mpp_get_global_domain(lnd_domain, xsize = nxl, ysize = nyl)
416  endif
417  if( ice_pe ) then
418  call mpp_get_compute_domain(ice_domain, isc_ice, iec_ice, jsc_ice, jec_ice)
419  endif
420 
421  ! set up atm_grid for second order conservative interpolation and atm grid is cubic grid.
422  if(remap_method == second_order ) then
423  if( atm_nest_npes > 0 ) call mpp_error(fatal, &
424  'test_xgrid: remap_method could not be SECOND_ORDER when atmos_nest_npes > 0')
425  if(ntile_atm == 6) then ! 6 tile for cubic grid
426  allocate(xt(isd_atm:ied_atm,jsd_atm:jed_atm), yt(isd_atm:ied_atm,jsd_atm:jed_atm) )
427  allocate(xc(isc_atm:ied_atm,jsc_atm:jed_atm), yc(isc_atm:ied_atm,jsc_atm:jed_atm) )
428  allocate(atm_grid%dx(isc_atm:iec_atm,jsc_atm:jed_atm), atm_grid%dy(isc_atm:iec_atm+1,jsc_atm:jec_atm) )
429  allocate(atm_grid%edge_w(jsc_atm:jed_atm), atm_grid%edge_e(jsc_atm:jed_atm))
430  allocate(atm_grid%edge_s(isc_atm:ied_atm), atm_grid%edge_n(isc_atm:ied_atm))
431  allocate(atm_grid%en1 (3,isc_atm:iec_atm,jsc_atm:jed_atm), atm_grid%en2 (3,isc_atm:ied_atm,jsc_atm:jec_atm) )
432  allocate(atm_grid%vlon(3,isc_atm:iec_atm,jsc_atm:jec_atm), atm_grid%vlat(3,isc_atm:iec_atm,jsc_atm:jec_atm) )
433  allocate(atm_grid%area(isc_atm:iec_atm,jsc_atm:jec_atm) )
434 
435  ! first get grid from grid file
436  call get_mosaic_tile_grid(tile_file, atm_mosaic_file, atm_domain)
437  allocate(tmpx(nxa*2+1, nya*2+1), tmpy(nxa*2+1, nya*2+1))
438  call read_data( tile_file, 'x', tmpx, no_domain=.true.)
439  call read_data( tile_file, 'y', tmpy, no_domain=.true.)
440  xt = 0; yt = 0;
441  do j = jsc_atm, jec_atm
442  do i = isc_atm, iec_atm
443  xt(i,j) = tmpx(2*i, 2*j)*deg_to_rad
444  yt(i,j) = tmpy(2*i, 2*j)*deg_to_rad
445  end do
446  end do
447  do j = jsc_atm, jed_atm
448  do i = isc_atm, ied_atm
449  xc(i,j) = tmpx(2*i-1, 2*j-1)*deg_to_rad
450  yc(i,j) = tmpy(2*i-1, 2*j-1)*deg_to_rad
451  end do
452  end do
453  call mpp_update_domains(xt, atm_domain)
454  call mpp_update_domains(yt, atm_domain)
455 
456  call calc_cubic_grid_info(xt, yt, xc, yc, atm_grid%dx, atm_grid%dy, atm_grid%area, atm_grid%edge_w, &
457  atm_grid%edge_e, atm_grid%edge_s, atm_grid%edge_n, atm_grid%en1, &
458  atm_grid%en2, atm_grid%vlon, atm_grid%vlat, isc_atm==1, iec_atm==nxa, &
459  jsc_atm==1, jec_atm==nya )
460  end if
461  end if
462 
463  call mpp_set_current_pelist()
464 
465  !--- conservation check is done in setup_xmap.
466  call setup_xmap(xmap, (/ 'ATM', 'OCN', 'LND' /), (/ atm_domain, ice_domain, lnd_domain /), grid_file, atm_grid)
467  call setup_xmap(xmap_runoff, (/ 'LND', 'OCN'/), (/ lnd_domain, ice_domain/), grid_file )
468  !--- set frac area if nk_lnd or nk_ocn is greater than 1.
469  if(nk_lnd > 0 .AND. lnd_pe) then
470  allocate(lnd_frac(isc_lnd:iec_lnd, jsc_lnd:jec_lnd, nk_lnd))
471  call random_number(lnd_frac)
472  lnd_frac = lnd_frac + 0.5
473  do j = jsc_lnd, jec_lnd
474  do i = isc_lnd, iec_lnd
475  tot = sum(lnd_frac(i,j,:))
476  do k = 1, nk_lnd
477  lnd_frac(i,j,k)=lnd_frac(i,j,k)/tot
478  enddo
479  enddo
480  enddo
481  call set_frac_area(lnd_frac, 'LND', xmap)
482  endif
483  if(nk_ice > 0 ) then
484  if( ice_pe ) then
485  allocate(ice_frac(isc_ice:iec_ice, jsc_ice:jec_ice, nk_ice))
486  call random_number(ice_frac)
487  ice_frac = ice_frac + 0.5
488  do j = jsc_ice, jec_ice
489  do i = isc_ice, iec_ice
490  tot = sum(ice_frac(i,j,:))
491  do k = 1, nk_ice
492  ice_frac(i,j,k)=ice_frac(i,j,k)/tot
493  enddo
494  enddo
495  enddo
496  endif
497  call set_frac_area(ice_frac, 'OCN', xmap)
498  endif
499 
500  if(test_unstruct) call test_unstruct_exchange()
501 
502  deallocate(atm_nx, atm_ny, lnd_nx, lnd_ny, ice_nx, ice_ny)
503 
504  !--- remap realistic data and write the output file when atmos_input_file does exist
505  atm_input_file_exist = file_exist(atm_input_file, domain=atm_domain)
506  if( atm_input_file_exist ) then
507  if(trim(atm_input_file) == trim(atm_output_file) ) call mpp_error(fatal, &
508  "test_xgrid: atm_input_file should have a different name from atm_output_file")
509  call field_size(atm_input_file, atm_field_name, siz, domain=atm_domain )
510  if(siz(1) .NE. nxa .OR. siz(2) .NE. nya ) call mpp_error(fatal,"test_xgrid: x- and y-size of field "//trim(atm_field_name) &
511  //" in file "//trim(atm_input_file) //" does not compabile with the grid size" )
512  if(siz(3) > 1) call mpp_error(fatal,"test_xgrid: number of vertical level of field "//trim(atm_field_name) &
513  //" in file "//trim(atm_input_file) //" should be no larger than 1")
514 
515  allocate(atm_data_in(isc_atm:iec_atm, jsc_atm:jec_atm ) )
516  allocate(atm_data_out(isc_atm:iec_atm, jsc_atm:jec_atm ) )
517  allocate(lnd_data_out(isc_lnd:iec_lnd, jsc_lnd:jec_lnd, nk_lnd) )
518  allocate(ice_data_out(isc_ice:iec_ice, jsc_ice:jec_ice, nk_ice) )
519  allocate(atm_data_out_1(isc_atm:iec_atm, jsc_atm:jec_atm ) )
520  allocate(atm_data_out_2(isc_atm:iec_atm, jsc_atm:jec_atm ) )
521  allocate(atm_data_out_3(isc_atm:iec_atm, jsc_atm:jec_atm ) )
522  nxgrid = max(xgrid_count(xmap), 1)
523  allocate(x_1(nxgrid), x_2(nxgrid))
524  allocate(x_3(nxgrid), x_4(nxgrid))
525  x_1 = 0
526  x_2 = 0
527  x_3 = 0
528  x_4 = 0
529 
530  atm_data_in = 0
531  atm_data_out = 0
532  lnd_data_out = 0
533  ice_data_out = 0
534  atm_data_out_1 = 0
535  atm_data_out_2 = 0
536  atm_data_out_3 = 0
537  ! test one time level should be sufficient
538  call read_data(atm_input_file, atm_field_name, atm_data_in, atm_domain)
539  call put_to_xgrid(atm_data_in, 'ATM', x_1, xmap, remap_method=remap_method)
540  call put_to_xgrid(atm_data_in, 'ATM', x_2, xmap, remap_method=remap_method, complete=.false.)
541  call put_to_xgrid(atm_data_in, 'ATM', x_3, xmap, remap_method=remap_method, complete=.false.)
542  call put_to_xgrid(atm_data_in, 'ATM', x_4, xmap, remap_method=remap_method, complete=.true.)
543  min_x = minval(x_1)
544  max_x = maxval(x_1)
545  !--- check make sure x_2, x_3 and x_4 are the same as x_1
546  if(any(x_1 .NE. x_2)) call mpp_error(fatal,"test_xgrid: x_1 and x_2 are not equal")
547  if(any(x_1 .NE. x_3)) call mpp_error(fatal,"test_xgrid: x_1 and x_3 are not equal")
548  if(any(x_1 .NE. x_4)) call mpp_error(fatal,"test_xgrid: x_1 and x_4 are not equal")
549 
550  deallocate(x_3,x_4)
551  x_2 = 0
552  call get_from_xgrid(lnd_data_out, 'LND', x_1, xmap)
553  call get_from_xgrid(ice_data_out, 'OCN', x_1, xmap)
554  call put_to_xgrid(lnd_data_out, 'LND', x_2, xmap)
555  call put_to_xgrid(ice_data_out, 'OCN', x_2, xmap)
556  call get_from_xgrid(atm_data_out, 'ATM', x_2, xmap)
557  call get_from_xgrid(atm_data_out_1, 'ATM', x_2, xmap, complete=.false.)
558  call get_from_xgrid(atm_data_out_2, 'ATM', x_2, xmap, complete=.false.)
559  call get_from_xgrid(atm_data_out_3, 'ATM', x_2, xmap, complete=.true.)
560  if(any(atm_data_out .NE. atm_data_out_1)) &
561  call mpp_error(fatal,"test_xgrid: atm_data_out and atm_data_out_1 are not equal")
562  if(any(atm_data_out .NE. atm_data_out_2)) &
563  call mpp_error(fatal,"test_xgrid: atm_data_out and atm_data_out_2 are not equal")
564  if(any(atm_data_out .NE. atm_data_out_3)) &
565  call mpp_error(fatal,"test_xgrid: atm_data_out and atm_data_out_3 are not equal")
566 
567  call write_data( atm_output_file, atm_field_name, atm_data_out, atm_domain)
568  call write_data( lnd_output_file, atm_field_name, lnd_data_out, lnd_domain)
569  call write_data( ice_output_file, atm_field_name, ice_data_out, ice_domain)
570  !--- print out checksum
571  write(out_unit,*) "chksum for atm_data_in", mpp_chksum(atm_data_in)
572  write(out_unit,*) "chksum for lnd_data_out", mpp_chksum(lnd_data_out)
573  write(out_unit,*) "chksum for ice_data_out", mpp_chksum(ice_data_out)
574  write(out_unit,*) "chksum for atm_data_out", mpp_chksum(atm_data_out)
575 
576  ! conservation check
577  allocate(atm_area(isc_atm:iec_atm, jsc_atm:jec_atm ) )
578  allocate(lnd_area(isc_lnd:iec_lnd, jsc_lnd:jec_lnd ) )
579  allocate(ice_area(isc_ice:iec_ice, jsc_ice:jec_ice ) )
580  call get_xmap_grid_area("ATM", xmap, atm_area)
581  call get_xmap_grid_area("LND", xmap, lnd_area)
582  call get_xmap_grid_area("OCN", xmap, ice_area)
583 
584  min_atm_in = minval(atm_data_in)
585  max_atm_in = maxval(atm_data_in)
586  min_atm_out = minval(atm_data_out)
587  max_atm_out = maxval(atm_data_out)
588  call mpp_min(min_atm_in)
589  call mpp_max(max_atm_in)
590  call mpp_min(min_atm_out)
591  call mpp_max(max_atm_out)
592  call mpp_min(min_x)
593  call mpp_max(max_x)
594 
595  sum_atm_in = mpp_global_sum(atm_domain, atm_area * atm_data_in)
596  sum_lnd_out = 0
597  do k = 1, nk_lnd
598  sum_lnd_out = sum_lnd_out + mpp_global_sum(lnd_domain, lnd_area * lnd_data_out(:,:,k))
599  enddo
600  sum_ice_out = 0
601  do k = 1, nk_ice
602  sum_ice_out = sum_ice_out + mpp_global_sum(ice_domain, ice_area * ice_data_out(:,:,k))
603  enddo
604  sum_atm_out = mpp_global_sum(atm_domain, atm_area * atm_data_out)
605  write(out_unit,*) "********************** check conservation *********************** "
606  write(out_unit,*) "the global area sum of atmos input data is : ", sum_atm_in
607  write(out_unit,*) "the global area sum of atmos output data is : ", sum_atm_out
608  write(out_unit,*) "the global area sum of land output data + ocean output data is: ", sum_lnd_out+sum_ice_out
609  write(out_unit,*) "The min of atmos input data is ", min_atm_in
610  write(out_unit,*) "The min of xgrid data is ", min_x
611  write(out_unit,*) "The min of atmos output data is ", min_atm_out
612  write(out_unit,*) "The max of atmos input data is ", max_atm_in
613  write(out_unit,*) "The max of xgrid data is ", max_x
614  write(out_unit,*) "The max of atmos output data is ", max_atm_out
615 
616 
617  deallocate(atm_area, lnd_area, ice_area, atm_data_in, atm_data_out, lnd_data_out, ice_data_out)
618  deallocate(atm_data_out_1, atm_data_out_2, atm_data_out_3)
619  deallocate(x_1, x_2)
620  else
621  write(out_unit,*) "NOTE from test_xgrid ==> file "//trim(atm_input_file)//" does not exist, no check is done for real data sets."
622  end if
623 
624  runoff_input_file_exist = file_exist(runoff_input_file, domain=atm_domain)
625  if( runoff_input_file_exist ) then
626  if( atm_nest_npes > 0 ) call mpp_error(fatal, &
627  "test_xgrid: runoff_input_file_exist should be false when atmos_nest_npes > 0")
628  if(trim(runoff_input_file) == trim(runoff_output_file) ) call mpp_error(fatal, &
629  "test_xgrid: runoff_input_file should have a different name from runoff_output_file")
630  call field_size(runoff_input_file, runoff_field_name, siz )
631  if(siz(1) .NE. nxl .OR. siz(2) .NE. nyl ) call mpp_error(fatal,"test_xgrid: x- and y-size of field "//trim(runoff_field_name) &
632  //" in file "//trim(runoff_input_file) //" does not compabile with the grid size" )
633  if(siz(3) > 1) call mpp_error(fatal,"test_xgrid: number of vertical level of field "//trim(runoff_field_name) &
634  //" in file "//trim(runoff_input_file) //" should be no larger than 1")
635 
636  allocate(runoff_data_in(isc_lnd:iec_lnd, jsc_lnd:jec_lnd ) )
637  allocate(runoff_data_out(isc_ice:iec_ice, jsc_ice:jec_ice, 1) )
638  nxgrid = max(xgrid_count(xmap_runoff), 1)
639  allocate(x_1(nxgrid), x_2(nxgrid))
640 
641  runoff_data_in = 0
642  runoff_data_out = 0
643  ! test one time level should be sufficient
644  call read_data(runoff_input_file, runoff_field_name, runoff_data_in, lnd_domain)
645  call put_to_xgrid(runoff_data_in, 'LND', x_1, xmap_runoff)
646  call get_from_xgrid(runoff_data_out, 'OCN', x_1, xmap_runoff)
647  call write_data( runoff_output_file, runoff_field_name, runoff_data_out, ice_domain)
648  ! conservation check
649  allocate(lnd_area(isc_lnd:iec_lnd, jsc_lnd:jec_lnd ) )
650  allocate(ice_area(isc_ice:iec_ice, jsc_ice:jec_ice ) )
651  call get_xmap_grid_area("LND", xmap_runoff, lnd_area)
652  call get_xmap_grid_area("OCN", xmap_runoff, ice_area)
653 
654  sum_runoff_in = mpp_global_sum(lnd_domain, lnd_area * runoff_data_in)
655  sum_runoff_out = mpp_global_sum(ice_domain, ice_area * runoff_data_out(:,:,1))
656  write(out_unit,*) "********************** check conservation *********************** "
657  write(out_unit,*) "the global area sum of runoff input data is : ", sum_runoff_in
658  write(out_unit,*) "the global area sum of runoff output data is : ", sum_runoff_out
659  else
660  write(out_unit,*) "NOTE from test_xgrid ==> file "//trim(runoff_input_file)//" does not exist, no check is done for real data sets."
661  end if
662 
663  ! when num_iter is greater than 0, create random number as input to test the performance of xgrid_mod.
664  if(num_iter > 0) then
665  if( atm_nest_npes > 0 ) call mpp_error(fatal, &
666  "test_xgrid: num_iter > 0 when atm_nest_npes > 0")
667 
668  allocate(atm_data_in(isc_atm:iec_atm, jsc_atm:jec_atm ) )
669  allocate(atm_data_out(isc_atm:iec_atm, jsc_atm:jec_atm ) )
670  allocate(lnd_data_out(isc_lnd:iec_lnd, jsc_lnd:jec_lnd, nk_lnd) )
671  allocate(ice_data_out(isc_ice:iec_ice, jsc_ice:jec_ice, nk_ice) )
672  nxgrid = max(xgrid_count(xmap), 1)
673  allocate(x_1(nxgrid), x_2(nxgrid))
674  atm_data_in = 0
675  atm_data_out = 0
676  lnd_data_out = 0
677  ice_data_out = 0
678  allocate(atm_area(isc_atm:iec_atm, jsc_atm:jec_atm ) )
679  allocate(lnd_area(isc_lnd:iec_lnd, jsc_lnd:jec_lnd ) )
680  allocate(ice_area(isc_ice:iec_ice, jsc_ice:jec_ice ) )
681  call get_xmap_grid_area("ATM", xmap, atm_area)
682  call get_xmap_grid_area("LND", xmap, lnd_area)
683  call get_xmap_grid_area("OCN", xmap, ice_area)
684  do n = 1, num_iter
685  call random_number(atm_data_in)
686  call put_to_xgrid(atm_data_in, 'ATM', x_1, xmap, remap_method=remap_method)
687 
688  call get_from_xgrid(lnd_data_out, 'LND', x_1, xmap)
689  call get_from_xgrid(ice_data_out, 'OCN', x_1, xmap)
690 
691  call put_to_xgrid(lnd_data_out, 'LND', x_2, xmap)
692  call put_to_xgrid(ice_data_out, 'OCN', x_2, xmap)
693 
694  call get_from_xgrid(atm_data_out, 'ATM', x_2, xmap)
695  sum_atm_in = mpp_global_sum(atm_domain, atm_area * atm_data_in)
696  sum_lnd_out = 0
697  do k = 1, nk_lnd
698  sum_lnd_out = sum_lnd_out + mpp_global_sum(lnd_domain, lnd_area * lnd_data_out(:,:,k))
699  enddo
700  sum_ice_out = 0
701  do k = 1, nk_ice
702  sum_ice_out = sum_ice_out + mpp_global_sum(ice_domain, ice_area * ice_data_out(:,:,k))
703  enddo
704  sum_atm_out = mpp_global_sum(atm_domain, atm_area * atm_data_out)
705  write(out_unit,*) "********************** check conservation *********************** "
706  write(out_unit,*) "the global area sum of atmos input data is : ", sum_atm_in
707  write(out_unit,*) "the global area sum of atmos output data is : ", sum_atm_out
708  write(out_unit,*) "the global area sum of land output data + ocean output data is: ", sum_lnd_out+sum_ice_out
709  enddo
710  deallocate(atm_area, lnd_area, ice_area, atm_data_in, atm_data_out, lnd_data_out, ice_data_out)
711  deallocate(x_1, x_2)
712  endif
713 
714  write(out_unit,*) "************************************************************************"
715  write(out_unit,*) "*********** Finish running program test_xgrid *************"
716  write(out_unit,*) "************************************************************************"
717 
718  call fms_io_exit
719  call fms_end
720 
721 contains
722 
723  subroutine test_unstruct_exchange()
724 
725  real, allocatable :: atm_data_in(:,:), atm_data_sg(:,:)
726  real, allocatable :: atm_data_sg_1(:,:), atm_data_sg_2(:,:), atm_data_sg_3(:,:)
727  real, allocatable :: lnd_data_sg(:,:,:), ice_data_sg(:,:,:)
728  real, allocatable :: atm_data_ug(:,:), tmp_sg(:,:,:)
729  real, allocatable :: atm_data_ug_1(:,:), atm_data_ug_2(:,:), atm_data_ug_3(:,:)
730  real, allocatable :: lnd_data_ug(:,:), ice_data_ug(:,:,:)
731  real, allocatable :: x_1(:), x_2(:), x_3(:), x_4(:)
732  real, allocatable :: y_1(:), y_2(:), y_3(:), y_4(:)
733  real, allocatable, dimension(:,:) :: rmask, tmp2d
734  logical, allocatable, dimension(:,:,:) :: lmask
735  integer, allocatable, dimension(:) :: npts_tile, grid_index, ntiles_grid
736  integer :: ntiles, nx, ny, ntotal_land, l, is_ug, ie_ug
737  type(domainUG) :: ug_domain
738  type(xmap_type) :: Xmap_ug, Xmap_runoff_ug
739 
740  if(ntile_lnd .NE. 6) call mpp_error(fatal, &
741  "test_xgrid: when test_unstruct is true, ntile_lnd must be 6")
742 
743  !--- define unstructured grid domain
744  ntiles = ntile_lnd
745  nx = lnd_nx(1)
746  ny = lnd_ny(1)
747  allocate(lmask(nx,ny,ntiles))
748  allocate(npts_tile(ntiles))
749  lmask = .false.
750  if(mpp_pe() == mpp_root_pe() ) then
751  allocate(rmask(nx,ny))
752  !--- construct gmask.
753  call set_domain(lnd_domain)
754  do n = 1, ntiles
755  rmask = 0
756  call get_grid_comp_area('LND', n, rmask)
757  do j = 1, ny
758  do i = 1, nx
759  if(rmask(i,j) > 0) then
760  lmask(i,j,n) = .true.
761  endif
762  enddo
763  enddo
764  npts_tile(n) = count(lmask(:,:,n))
765  enddo
766  call nullify_domain()
767  ntotal_land = sum(npts_tile)
768  allocate(grid_index(ntotal_land))
769  l = 0
770  do n = 1, ntiles
771  do j = 1, ny
772  do i = 1, nx
773  if(lmask(i,j,n)) then
774  l = l + 1
775  grid_index(l) = (j-1)*nx+i
776  endif
777  enddo
778  enddo
779  enddo
780  deallocate(rmask)
781  endif
782  call mpp_broadcast(npts_tile, ntiles, mpp_root_pe())
783  if(mpp_pe() .NE. mpp_root_pe()) then
784  ntotal_land = sum(npts_tile)
785  allocate(grid_index(ntotal_land))
786  endif
787  call mpp_broadcast(grid_index, ntotal_land, mpp_root_pe())
788  allocate(ntiles_grid(ntotal_land))
789  ntiles_grid = 1
790  !--- define the unstructured grid domain
791  if(lnd_pe) then
792  call mpp_set_current_pelist(lnd_pelist)
793  call mpp_define_unstruct_domain(ug_domain, lnd_domain, npts_tile, ntiles_grid, mpp_npes(), &
794  1, grid_index, name="LAND unstruct")
795  call mpp_get_ug_compute_domain(ug_domain, is_ug, ie_ug)
796  endif
797  call mpp_set_current_pelist()
798 
799  call setup_xmap(xmap_ug, (/ 'ATM', 'OCN', 'LND' /), (/ atm_domain, ice_domain, lnd_domain /), &
800  grid_file, atm_grid, lnd_ug_domain=ug_domain)
801 
802  !--- set frac area if nk_lnd or nk_ocn is greater than 1.
803  if(nk_lnd > 0 .AND. lnd_pe) then
804  allocate(tmp2d(is_ug:ie_ug,nk_lnd))
805  call mpp_pass_sg_to_ug(ug_domain, lnd_frac, tmp2d)
806  call set_frac_area(tmp2d, 'LND', xmap_ug)
807  deallocate(tmp2d)
808  endif
809 
810  if(nk_ice > 0 ) then
811  call set_frac_area(ice_frac, 'OCN', xmap_ug)
812  endif
813 
814 ! call setup_xmap(Xmap_runoff_ug, (/ 'LND', 'OCN'/), (/ Lnd_domain, Ice_domain/), grid_file, lnd_ug_domain=UG_domain )
815  allocate(atm_data_ug(isc_atm:iec_atm, jsc_atm:jec_atm ) )
816  allocate(atm_data_ug_1(isc_atm:iec_atm, jsc_atm:jec_atm ) )
817  allocate(atm_data_ug_2(isc_atm:iec_atm, jsc_atm:jec_atm ) )
818  allocate(atm_data_ug_3(isc_atm:iec_atm, jsc_atm:jec_atm ) )
819 
820  allocate(atm_data_in(isc_atm:iec_atm, jsc_atm:jec_atm ) )
821  allocate(atm_data_sg(isc_atm:iec_atm, jsc_atm:jec_atm ) )
822  allocate(atm_data_sg_1(isc_atm:iec_atm, jsc_atm:jec_atm ) )
823  allocate(atm_data_sg_2(isc_atm:iec_atm, jsc_atm:jec_atm ) )
824  allocate(atm_data_sg_3(isc_atm:iec_atm, jsc_atm:jec_atm ) )
825  atm_data_in = 0
826  atm_data_sg = 0
827  atm_data_sg_1 = 0
828  atm_data_sg_2 = 0
829  atm_data_sg_3 = 0
830  atm_data_ug = 0
831  atm_data_ug_1 = 0
832  atm_data_ug_2 = 0
833  atm_data_ug_3 = 0
834 
835 
836  if(lnd_pe) then
837  allocate(lnd_data_ug(is_ug:ie_ug, nk_lnd) )
838  allocate(lnd_data_sg(isc_lnd:iec_lnd, jsc_lnd:jec_lnd, nk_lnd) )
839  lnd_data_sg = 0
840  lnd_data_ug = 0
841  endif
842  if(ice_pe) then
843  allocate(ice_data_ug(isc_ice:iec_ice, jsc_ice:jec_ice, nk_ice) )
844  allocate(ice_data_sg(isc_ice:iec_ice, jsc_ice:jec_ice, nk_ice) )
845  ice_data_sg = 0
846  ice_data_ug = 0
847  endif
848 
849  nxgrid = max(xgrid_count(xmap), 1)
850  allocate(x_1(nxgrid), x_2(nxgrid))
851  allocate(x_3(nxgrid), x_4(nxgrid))
852  x_1 = 0
853  x_2 = 0
854  x_3 = 0
855  x_4 = 0
856 
857  call random_number(atm_data_in)
858  call put_to_xgrid(atm_data_in, 'ATM', x_1, xmap, remap_method=remap_method)
859  call put_to_xgrid(atm_data_in+1, 'ATM', x_2, xmap, remap_method=remap_method, complete=.false.)
860  call put_to_xgrid(atm_data_in+2, 'ATM', x_3, xmap, remap_method=remap_method, complete=.false.)
861  call put_to_xgrid(atm_data_in+3, 'ATM', x_4, xmap, remap_method=remap_method, complete=.true.)
862  call get_from_xgrid(lnd_data_sg, 'LND', x_1, xmap)
863  call get_from_xgrid(ice_data_sg, 'OCN', x_1, xmap)
864  call put_to_xgrid(lnd_data_sg, 'LND', x_2, xmap)
865  call put_to_xgrid(ice_data_sg, 'OCN', x_2, xmap)
866  call get_from_xgrid(atm_data_sg, 'ATM', x_2, xmap)
867  call get_from_xgrid(atm_data_sg_1, 'ATM', x_2, xmap, complete=.false.)
868  call get_from_xgrid(atm_data_sg_2, 'ATM', x_2, xmap, complete=.false.)
869  call get_from_xgrid(atm_data_sg_3, 'ATM', x_2, xmap, complete=.true.)
870 
871  nxgrid = max(xgrid_count(xmap_ug), 1)
872  allocate(y_1(nxgrid), y_2(nxgrid))
873  allocate(y_3(nxgrid), y_4(nxgrid))
874  y_1 = 0
875  y_2 = 0
876  y_3 = 0
877  y_4 = 0
878 
879  call put_to_xgrid(atm_data_in, 'ATM', y_1, xmap_ug, remap_method=remap_method)
880  call put_to_xgrid(atm_data_in+1, 'ATM', y_2, xmap_ug, remap_method=remap_method, complete=.false.)
881  call put_to_xgrid(atm_data_in+2, 'ATM', y_3, xmap_ug, remap_method=remap_method, complete=.false.)
882  call put_to_xgrid(atm_data_in+3, 'ATM', y_4, xmap_ug, remap_method=remap_method, complete=.true.)
883  call get_from_xgrid_ug(lnd_data_ug, 'LND', y_1, xmap_ug)
884  call get_from_xgrid(ice_data_ug, 'OCN', y_1, xmap_ug)
885  call put_to_xgrid_ug(lnd_data_ug, 'LND', y_2, xmap_ug)
886  call put_to_xgrid(ice_data_ug, 'OCN', y_2, xmap_ug)
887  call get_from_xgrid(atm_data_ug, 'ATM', y_1, xmap_ug)
888  call get_from_xgrid(atm_data_ug_1, 'ATM', y_2, xmap_ug, complete=.false.)
889  call get_from_xgrid(atm_data_ug_2, 'ATM', y_2, xmap_ug, complete=.false.)
890  call get_from_xgrid(atm_data_ug_3, 'ATM', y_2, xmap_ug, complete=.true.)
891 
892  !--- comparing data ---------------------
893  call compare_chksum(ice_data_ug, ice_data_sg, "ice_data_out")
894  call compare_chksum_2d(atm_data_ug, atm_data_ug, "atm_data_out")
895  call compare_chksum_2d(atm_data_ug_1, atm_data_ug_1, "atm_data_out_1")
896  call compare_chksum_2d(atm_data_ug_2, atm_data_ug_2, "atm_data_out_2")
897  call compare_chksum_2d(atm_data_ug_3, atm_data_ug_3, "atm_data_out_3")
898  allocate(tmp_sg(isc_lnd:iec_lnd,jsc_lnd:jec_lnd,nk_lnd))
899  tmp_sg = 0
900  if(lnd_pe) then
901  call mpp_set_current_pelist(lnd_pelist)
902  call mpp_pass_ug_to_sg(ug_domain, lnd_data_ug, tmp_sg)
903  call compare_chksum(tmp_sg, lnd_data_sg, "lnd_data_out")
904  deallocate(lnd_data_sg,lnd_data_ug)
905  endif
906  call mpp_set_current_pelist()
907 
908  if(ice_pe) deallocate(ice_data_sg, ice_data_ug)
909  deallocate(tmp_sg, x_1, x_2, x_3, x_4, y_1, y_2, y_3, y_4)
910  deallocate(atm_data_in, atm_data_sg)
911  deallocate(atm_data_sg_1, atm_data_sg_2, atm_data_sg_3)
912  deallocate(atm_data_ug)
913  deallocate(atm_data_ug_1, atm_data_ug_2, atm_data_ug_3)
914 
915  end subroutine test_unstruct_exchange
916 
917  !###########################################################################
918  subroutine compare_chksum_2d( a, b, string )
919  real, intent(in), dimension(:,:) :: a, b
920  character(len=*), intent(in) :: string
921  integer(LONG_KIND) :: sum1, sum2
922  integer :: i, j
923 
924  call mpp_sync_self()
925 
926  if(size(a,1) .ne. size(b,1) .or. size(a,2) .ne. size(b,2) ) &
927  call mpp_error(fatal,'compare_chksum_2D: size of a and b does not match')
928 
929  do j = 1, size(a,2)
930  do i = 1, size(a,1)
931  if(a(i,j) .ne. b(i,j)) then
932  write(*,'(a,i3,a,i3,a,i3,a,f20.9,a,f20.9)')"at pe ", mpp_pe(), &
933  ", at point (",i,", ", j, "),a=", a(i,j), ",b=", b(i,j)
934  call mpp_error(fatal, trim(string)//': point by point comparison are not OK.')
935  endif
936  enddo
937  enddo
938 
939  sum1 = mpp_chksum( a, (/pe/) )
940  sum2 = mpp_chksum( b, (/pe/) )
941  if( sum1.EQ.sum2 )then
942  if( pe.EQ.mpp_root_pe() )call mpp_error( note, trim(string)//': OK.' )
943  !--- in some case, even though checksum agree, the two arrays
944  ! actually are different, like comparing (1.1,-1.2) with (-1.1,1.2)
945  !--- hence we need to check the value point by point.
946  else
947  call mpp_error( fatal, trim(string)//': chksums are not OK.' )
948  end if
949  end subroutine compare_chksum_2d
950 
951 
952  !###########################################################################
953 
954 
955  subroutine compare_chksum( a, b, string )
956  real, intent(in), dimension(:,:,:) :: a, b
957  character(len=*), intent(in) :: string
958  integer(LONG_KIND) :: sum1, sum2
959  integer :: i, j, k
960 
961  ! z1l can not call mpp_sync here since there might be different number of tiles on each pe.
962  ! mpp_sync()
963  call mpp_sync_self()
964 
965  if(size(a,1) .ne. size(b,1) .or. size(a,2) .ne. size(b,2) .or. size(a,3) .ne. size(b,3) ) &
966  call mpp_error(fatal,'compare_chksum: size of a and b does not match')
967 
968  do k = 1, size(a,3)
969  do j = 1, size(a,2)
970  do i = 1, size(a,1)
971  if(a(i,j,k) .ne. b(i,j,k)) then
972  print*, "a,b=", a(i,j,k), b(i,j,k), i,j,k
973  write(*, '(a,i3,a,i3,a,i3,a,i3,a,f20.9,a,f20.9)')" at pe ", mpp_pe(), &
974  ", at point (",i,", ", j, ", ", k, "), a = ", a(i,j,k), ", b = ", b(i,j,k)
975  call mpp_error(fatal, trim(string)//': point by point comparison are not OK.')
976  endif
977  enddo
978  enddo
979  enddo
980 
981  call mpp_sync()
982  sum1 = mpp_chksum( a, (/pe/) )
983  sum2 = mpp_chksum( b, (/pe/) )
984 
985  if( sum1.EQ.sum2 )then
986  if( pe.EQ.mpp_root_pe() )call mpp_error( note, trim(string)//': OK.' )
987  !--- in some case, even though checksum agree, the two arrays
988  ! actually are different, like comparing (1.1,-1.2) with (-1.1,1.2)
989  !--- hence we need to check the value point by point.
990  else
991  call mpp_error( fatal, trim(string)//': chksums are not OK.' )
992  end if
993  end subroutine compare_chksum
994 
995 end program xgrid_test
996 
997 #else
999 end module
1000 
1001 #endif /* test_mpp */
Definition: fms.F90:20
subroutine, public get_mosaic_contact(mosaic_file, tile1, tile2, istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2)
Definition: mosaic.F90:352
subroutine, public set_domain(Domain2)
Definition: fms_io.F90:7401
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
subroutine, public get_mosaic_grid_sizes(mosaic_file, nx, ny)
Definition: mosaic.F90:279
integer, parameter, public second_order
Definition: xgrid.F90:180
int field_exist(const char *file, const char *name)
Definition: read_mosaic.c:69
subroutine, public fms_init(localcomm)
Definition: fms.F90:353
integer function, dimension(6), public get_ensemble_size()
subroutine, public nullify_domain()
Definition: fms_io.F90:7421
ensemble_manager_mod
integer function, public get_mosaic_ncontacts(mosaic_file)
Definition: mosaic.F90:239
subroutine, public setup_xmap(xmap, grid_ids, grid_domains, grid_file, atm_grid, lnd_ug_domain)
Definition: xgrid.F90:1514
subroutine, public fms_end()
Definition: fms.F90:476
subroutine, public fms_io_exit()
Definition: fms_io.F90:750
#define max(a, b)
Definition: mosaic_util.h:33
real, parameter, public deg_to_rad
Radians per degree [rad/deg].
Definition: constants.F90:120
subroutine, public calc_cubic_grid_info(xt, yt, xc, yc, dx, dy, area, edge_w, edge_e, edge_s, edge_n, en_n, en_e, vlon, vlat, on_west_edge, on_east_edge, on_south_edge, on_north_edge)
Definition: gradient.F90:109
integer function, public xgrid_count(xmap)
Definition: xgrid.F90:3151
subroutine, public ensemble_manager_init()
ensemble_manager_init
subroutine, public xgrid_init(remap_method)
Definition: xgrid.F90:532
subroutine, public get_xmap_grid_area(id, xmap, area)
Definition: xgrid.F90:4347
subroutine, public ensemble_pelist_setup(concurrent, atmos_npes, ocean_npes, land_npes, ice_npes, Atm_pelist, Ocean_pelist, Land_pelist, Ice_pelist)
ensemble_pelist_setup