26 use mpp_mod,
only : mpp_set_current_pelist, mpp_declare_pelist, mpp_sync
34 use mpp_io_mod,
only : mpp_open, mpp_rdonly,mpp_netcdf, mpp_multi, mpp_single, mpp_close
53 #include <fms_platform.h> 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" 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.
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
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(:,:)
104 real,
allocatable :: xc(:,:), yc(:,:)
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
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(:)
132 call mpp_domains_init
134 call xgrid_init(remap_method)
135 call ensemble_manager_init()
141 #ifdef INTERNAL_FILE_NML 142 read (input_nml_file, xgrid_test_nml, iostat=io)
143 ierr = check_nml_error(io,
'xgrid_test_nml')
145 if (file_exist(
'input.nml'))
then 147 nml_unit = open_namelist_file()
149 read(nml_unit, nml=xgrid_test_nml, iostat=io, end=10)
150 ierr = check_nml_error(io,
'xgrid_test_nml')
152 10
call close_file(nml_unit)
158 ensemble_size = ens_siz(1)
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')
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
174 allocate(atm_pelist(atm_npes))
175 allocate(ice_pelist(ice_npes))
176 allocate(lnd_pelist(lnd_npes))
177 allocate(ocn_pelist(ocn_npes))
180 call ensemble_pelist_setup(concurrent, atm_npes, ocn_npes, lnd_npes, ice_npes, &
181 atm_pelist, ocn_pelist, lnd_pelist, ice_pelist)
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")
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.
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)
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 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 235 if( ice_layout(1)*ice_layout(2) .NE. npes )
then 239 else if (
field_exist(grid_file,
"atm_mosaic" ) )
then 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' 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);
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')
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))
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)
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)
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
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")
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(:)
304 call mpp_define_layout( global_indices(:,n), pe_end(n)-pe_start(n)+1, layout(:,n))
308 allocate(tile_id(ntile_atm_global))
309 do n = 1, ntile_atm_global
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 )
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)
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/)
334 if(atm_nest_layout(1)*atm_nest_layout(2) == atm_nest_npes )
then 335 layout(:,1) = atm_nest_layout(:)
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 )
348 call mpp_set_current_pelist(lnd_pelist)
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
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(:)
367 allocate(tile_id(ntile_lnd))
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 )
378 call mpp_set_current_pelist(ice_pelist)
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
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(:)
393 allocate(tile_id(ntile_ice))
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 )
403 call mpp_error(fatal,
'test_xgrid:both AREA_ATM and atm_mosaic does not exist in '//trim(grid_file))
410 nxc_atm = iec_atm - isc_atm + 1
411 nyc_atm = jec_atm - jsc_atm + 1
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 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) )
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.)
441 do j = jsc_atm, jec_atm
442 do i = isc_atm, iec_atm
447 do j = jsc_atm, jed_atm
448 do i = isc_atm, ied_atm
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 )
463 call mpp_set_current_pelist()
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 )
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,:))
477 lnd_frac(i,j,k)=lnd_frac(i,j,k)/tot
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,:))
492 ice_frac(i,j,k)=ice_frac(i,j,k)/tot
500 if(test_unstruct)
call test_unstruct_exchange()
502 deallocate(atm_nx, atm_ny, lnd_nx, lnd_ny, ice_nx, ice_ny)
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")
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))
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.)
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")
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")
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)
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)
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)
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)
598 sum_lnd_out = sum_lnd_out +
mpp_global_sum(lnd_domain, lnd_area * lnd_data_out(:,:,k))
602 sum_ice_out = sum_ice_out +
mpp_global_sum(ice_domain, ice_area * ice_data_out(:,:,k))
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
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)
621 write(out_unit,*)
"NOTE from test_xgrid ==> file "//trim(atm_input_file)//
" does not exist, no check is done for real data sets." 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")
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))
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)
647 call write_data( runoff_output_file, runoff_field_name, runoff_data_out, ice_domain)
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)
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
660 write(out_unit,*)
"NOTE from test_xgrid ==> file "//trim(runoff_input_file)//
" does not exist, no check is done for real data sets." 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")
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))
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)
685 call random_number(atm_data_in)
686 call put_to_xgrid(atm_data_in,
'ATM', x_1, xmap, remap_method=remap_method)
698 sum_lnd_out = sum_lnd_out +
mpp_global_sum(lnd_domain, lnd_area * lnd_data_out(:,:,k))
702 sum_ice_out = sum_ice_out +
mpp_global_sum(ice_domain, ice_area * ice_data_out(:,:,k))
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
710 deallocate(atm_area, lnd_area, ice_area, atm_data_in, atm_data_out, lnd_data_out, ice_data_out)
714 write(out_unit,*)
"************************************************************************" 715 write(out_unit,*)
"*********** Finish running program test_xgrid *************" 716 write(out_unit,*)
"************************************************************************" 723 subroutine test_unstruct_exchange()
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
740 if(ntile_lnd .NE. 6)
call mpp_error(fatal, &
741 "test_xgrid: when test_unstruct is true, ntile_lnd must be 6")
747 allocate(lmask(nx,ny,ntiles))
748 allocate(npts_tile(ntiles))
750 if(mpp_pe() == mpp_root_pe() )
then 751 allocate(rmask(nx,ny))
759 if(rmask(i,j) > 0)
then 760 lmask(i,j,n) = .true.
764 npts_tile(n) = count(lmask(:,:,n))
767 ntotal_land = sum(npts_tile)
768 allocate(grid_index(ntotal_land))
773 if(lmask(i,j,n))
then 775 grid_index(l) = (j-1)*nx+i
783 if(mpp_pe() .NE. mpp_root_pe())
then 784 ntotal_land = sum(npts_tile)
785 allocate(grid_index(ntotal_land))
788 allocate(ntiles_grid(ntotal_land))
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)
797 call mpp_set_current_pelist()
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)
803 if(nk_lnd > 0 .AND. lnd_pe)
then 804 allocate(tmp2d(is_ug:ie_ug,nk_lnd))
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 ) )
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 ) )
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) )
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) )
849 nxgrid =
max(xgrid_count(xmap), 1)
850 allocate(x_1(nxgrid), x_2(nxgrid))
851 allocate(x_3(nxgrid), x_4(nxgrid))
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.)
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.)
871 nxgrid =
max(xgrid_count(xmap_ug), 1)
872 allocate(y_1(nxgrid), y_2(nxgrid))
873 allocate(y_3(nxgrid), y_4(nxgrid))
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.)
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.)
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))
901 call mpp_set_current_pelist(lnd_pelist)
903 call compare_chksum(tmp_sg, lnd_data_sg,
"lnd_data_out")
904 deallocate(lnd_data_sg,lnd_data_ug)
906 call mpp_set_current_pelist()
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)
915 end subroutine test_unstruct_exchange
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
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')
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.')
941 if( sum1.EQ.sum2 )
then 949 end subroutine compare_chksum_2d
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
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')
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.')
985 if( sum1.EQ.sum2 )
then 993 end subroutine compare_chksum
995 end program xgrid_test
1001 #endif /* test_mpp */
subroutine, public get_mosaic_contact(mosaic_file, tile1, tile2, istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2)
subroutine, public set_domain(Domain2)
integer function, public get_mosaic_ntiles(mosaic_file)
integer function, public check_nml_error(IOSTAT, NML_NAME)
subroutine, public get_mosaic_grid_sizes(mosaic_file, nx, ny)
integer, parameter, public second_order
int field_exist(const char *file, const char *name)
subroutine, public fms_init(localcomm)
integer function, dimension(6), public get_ensemble_size()
subroutine, public nullify_domain()
integer function, public get_mosaic_ncontacts(mosaic_file)
subroutine, public setup_xmap(xmap, grid_ids, grid_domains, grid_file, atm_grid, lnd_ug_domain)
subroutine, public fms_end()
subroutine, public fms_io_exit()
real, parameter, public deg_to_rad
Radians per degree [rad/deg].
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)
integer function, public xgrid_count(xmap)
subroutine, public ensemble_manager_init()
ensemble_manager_init
subroutine, public xgrid_init(remap_method)
subroutine, public get_xmap_grid_area(id, xmap, area)
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