FMS  2026.01.01-dev
Flexible Modeling System
xgrid.F90
1 !***********************************************************************
2 !* Apache License 2.0
3 !*
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
5 !*
6 !* Licensed under the Apache License, Version 2.0 (the "License");
7 !* you may not use this file except in compliance with the License.
8 !* You may obtain a copy of the License at
9 !*
10 !* http://www.apache.org/licenses/LICENSE-2.0
11 !*
12 !* FMS is distributed in the hope that it will be useful, but WITHOUT
13 !* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied;
14 !* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
15 !* PARTICULAR PURPOSE. See the License for the specific language
16 !* governing permissions and limitations under the License.
17 !***********************************************************************
18 !> @defgroup xgrid_mod xgrid_mod
19 !> @ingroup exchange
20 !> @brief Implements exchange grids for coupled models running on multiple processors
21 !> @author Michael Winton, Zhi Liang
22 !!
23 !! An exchange grid is formed from the union of
24 !! the bounding lines of the two (logically rectangular) participating
25 !! grids. The exchange grid is therefore the coarsest grid that is a
26 !! refinement of both participating grids. Exchange grids are used for
27 !! two purposes by coupled models:
28 !! 1. conservative interpolation of fields
29 !! between models uses the exchange grid cell areas as weights and
30 !! 2. the surface flux calculation takes place on the exchange grid thereby
31 !! using the finest scale data available.
32 !! <TT>xgrid_mod</TT> uses a NetCDF grid
33 !! specification file containing the grid cell overlaps in combination with
34 !! the @link ftp://ftp.gfdl.gov/pub/vb/mpp/mpp_domains.F90 @endlink domain
35 !! decomposition information to determine
36 !! the grid and processor connectivities.
37 !!
38 !!
39 !! xgrid_mod - implements exchange grids. An exchange grid is the grid whose
40 !! boundary set is the union of the boundaries of the participating
41 !! grids. The exchange grid is the coarsest grid that is a
42 !! refinement of each of the participating grids. Every exchange
43 !! grid cell is a subarea of one and only one cell in each of the
44 !! participating grids. The exchange grid has two purposes:
45 !!
46 !! (1) The exchange cell areas are used as weights for
47 !! conservative interpolation between model grids.
48 !!
49 !! (2) Computation of surface fluxes takes place on it,
50 !! thereby using the finest scale data obtainable.
51 !!
52 !! The exchange cells are the 2D intersections between cells of the
53 !! participating grids. They are computed elsewhere and are
54 !! read here from a NetCDF grid file as a sequence of quintuples
55 !! (i and j on each of two grids and the cell area).
56 !!
57 !! Each processing element (PE) computes a subdomain of each of the
58 !! participating grids as well as a subset of the exchange cells.
59 !! The geographic regions corresponding to these subdomains will,
60 !! in general, not be the same so communication must occur between
61 !! the PEs. The scheme for doing this is as follows. A distinction
62 !! is drawn between the participating grids. There is a single
63 !! "side 1" grid and it does not have partitions (sub-grid surface
64 !! types). There are one or more "side 2" grids and they may have
65 !! more than 1 partition. In standard usage, the atmosphere grid is
66 !! on side 1 and the land and sea ice grids are on side 2. The set
67 !! of exchange cells computed on a PE corresponds to its side 2
68 !! geographic region(s). Communication between the PEs takes place
69 !! on the side 1 grid. Note: this scheme does not generally allow
70 !! reproduction of answers across varying PE counts. This is
71 !! because, in the side 1 "get", exchange cells are first summed
72 !! locally onto a side 1 grid, then these side 1 contributions are
73 !! further summed after they have been communicated to their target
74 !! PE. For the make_exchange_reproduce option, a special side 1 get
75 !! is used. This get communicates individual exchange cells. The
76 !! cells are summed in the order they appear in the grid spec. file.
77 !!
78 !! <TT>xgrid_mod</TT> reads a NetCDF grid specification file to determine the
79 !! grid and processor connectivities. The exchange grids are defined
80 !! by a sequence of quintuples: the <TT>i/j</TT> indices of the intersecting
81 !! cells of the two participating grids and their areal overlap.
82 !! The names of the five fields are generated automatically from the
83 !! three character ids of the participating grids. For example, if
84 !! the side one grid id is "ATM" and the side two grid id is "OCN",
85 !! <TT>xgrid_mod</TT> expects to find the following five fields in the grid
86 !! specification file: <TT>I_ATM_ATMxOCN, J_ATM_ATMxOCN, I_OCN_ATMxOCN,
87 !! J_OCN_ATMxOCN, and AREA_ATMxOCN</TT>. These fields may be generated
88 !! by the <TT>make_xgrids</TT> utility.
89 
90 !> @addtogroup xgrid_mod
91 !> @{
92 module xgrid_mod
93 
94 
95 use fms_mod, only: check_nml_error, &
96  error_mesg, fatal, note, stdlog, &
97  write_version_number, lowercase, string
98 use mpp_mod, only: mpp_npes, mpp_pe, mpp_root_pe, mpp_send, mpp_recv, &
99  mpp_sync_self, stdout, mpp_max, event_recv, &
101  mpp_alltoall, &
102  mpp_clock_begin, mpp_clock_end, mpp_clock_sync, &
103  comm_tag_1, comm_tag_2, comm_tag_3, comm_tag_4, &
104  comm_tag_5, comm_tag_6, comm_tag_7, comm_tag_8, &
105  comm_tag_9, comm_tag_10
106 use mpp_mod, only: input_nml_file, mpp_set_current_pelist, mpp_sum, mpp_sync
107 use mpp_domains_mod, only: mpp_get_compute_domain, mpp_get_compute_domains, &
117  domainug, mpp_get_ug_compute_domains, &
118  mpp_get_ug_domains_index, mpp_get_ug_domain_grid_index, &
119  mpp_get_ug_domain_tile_list, mpp_pass_sg_to_ug
120 use constants_mod, only: pi, radius
121 use mosaic2_mod, only: get_mosaic_xgrid, get_mosaic_xgrid_size, &
125 use stock_constants_mod, only: istock_top, istock_bottom, istock_side, stock_names, &
126  stock_units, nelems, stocks_file, stock_type
127 use gradient_mod, only: gradient_cubic
128 use fms2_io_mod, only: fmsnetcdffile_t, open_file, variable_exists, close_file
129 use fms2_io_mod, only: fmsnetcdfdomainfile_t, read_data, get_dimension_size
130 use fms2_io_mod, only: get_variable_units, dimension_exists
131 use platform_mod, only: r8_kind, i8_kind, fms_file_len
132 
133 implicit none
134 private
135 
138  area_atm_sphere, area_ocn_sphere, &
139  area_atm_model, area_ocn_model, &
143 
144 !--- parameters that determine the remapping method
145 integer, parameter :: FIRST_ORDER = 1
146 integer, parameter :: SECOND_ORDER = 2
147 integer, parameter :: version1 = 1 !< grid spec file
148 integer, parameter :: version2 = 2 !< mosaic grid file
149 integer, parameter :: max_fields = 100
150 
151 logical :: make_exchange_reproduce = .false. !< Set to .true. to make <TT>xgrid_mod</TT> reproduce answers on different
152  !! numbers of PEs. This option has a considerable performance impact.
153 !< exactly same on different # PEs
154 character(len=64) :: interp_method = 'first_order' !< Exchange grid interpolation method.
155  !! It has two options: "first_order", "second_order".
156 logical :: debug_stocks = .false.
157 logical :: xgrid_clocks_on = .false.
158 logical :: monotonic_exchange = .false.
159 integer :: nsubset = 0 !< Number of processors to read exchange grid information. Those processors
160  !! that read the exchange grid information will send data to other processors
161  !! to prepare for flux exchange. Default value is 0. When nsubset is 0, each
162  !! processor will read part of the exchange grid information. The purpose of
163  !! this namelist is to improve performance of setup_xmap when running on
164  !! higher processor count and solve receiving size mismatch issue on high
165  !! processor count. Try to set nsubset = mpp_npes/MPI_rank_per_node.
166 logical :: do_alltoall = .true.
167 logical :: do_alltoallv = .false.
168 !> @brief xgrid nml
169 namelist /xgrid_nml/ make_exchange_reproduce, interp_method, debug_stocks, xgrid_clocks_on, &
170  monotonic_exchange, nsubset, do_alltoall, do_alltoallv
171 
173 
174 !> Area elements used inside each model
175 real(r8_kind), allocatable, dimension(:,:) :: area_atm_model, area_lnd_model, area_ocn_model
176 !> Area elements based on a the spherical model used by the ICE layer
177 real(r8_kind), allocatable, dimension(:,:) :: area_atm_sphere, area_lnd_sphere, area_ocn_sphere
178 
179 !> @}
180 
181 !> @brief Scatters data from model grid onto exchange grid.
182 !!
183 !> Example usage:
184 !! @code{.F90}
185 !! call put_to_xgrid(d, grid_id, x, xmap, remap_order)
186 !! @endcode
187 !!
188 !> @ingroup xgrid_mod
189 interface put_to_xgrid
190  module procedure put_side1_to_xgrid
191  module procedure put_side2_to_xgrid
192 end interface
193 
194 !> @brief Sums data from exchange grid to model grid.
195 !!
196 !> <br>Example usage:
197 !! @code{.F90}
198 !! call get_from_xgrid(d, grid_id, x, xmap)
199 !! @endcode
200 !> @ingroup xgrid_mod
201 interface get_from_xgrid
202  module procedure get_side1_from_xgrid
203  module procedure get_side2_from_xgrid
204 end interface
205 
206 !> @brief @ref put_to_xgrid for unstructured grids.
207 !!
208 !> Scatters data from unstructured grid onto exchange grid.
209 !> @ingroup xgrid_mod
211  module procedure put_side1_to_xgrid_ug
212  module procedure put_side2_to_xgrid_ug
213 end interface
214 
215 !> @brief @ref get_from_xgrid for unstructured grids.
216 !!
217 !> Sums data from exchange grid to model grid.
218 !> @ingroup xgrid_mod
220  module procedure get_side2_from_xgrid_ug
221  module procedure get_side1_from_xgrid_ug
222 end interface
223 
224 !> @brief Sets sub-grid area and numbering in the given exchange grid.
225 !> @ingroup xgrid_mod
226 interface set_frac_area
227  module procedure set_frac_area_sg
228  module procedure set_frac_area_ug
229 end interface
230 
231 !> @brief Returns three numbers which are the global sum of a variable.
232 !! @details Returns three numbers which are the global sum of a
233 !! variable (1) on its home model grid, (2) after interpolation to the other
234 !! side grid(s), and (3) after re_interpolation back onto its home side grid(s).
235 !! Conservation_check must be called by all PEs to work properly.
236 !!
237 !! @param d real(r8_kind) data
238 !! @param grid_id 3 character grid ID
239 !! @param[inout] xmap exchange grid
240 !! @param[out] global sum of a variable on home model grid, after side grid interpolation and after
241 !! reinterpolation
242 !!
243 !! <br>Example usage:
244 !! @code{.F90}
245 !! call conservation_check(d, grid_id, xmap,remap_order)
246 !! @endcode
247 !> @ingroup xgrid_mod
249  module procedure conservation_check_side1
250  module procedure conservation_check_side2
251 end interface
252 
253 !> For an unstructured grid, returns three numbers which are the global sum of a
254 !! variable (1) on its home model grid, (2) after interpolation to the other
255 !! side grid(s), and (3) after re_interpolation back onto its home side grid(s).
256 !> @ingroup xgrid_mod
258  module procedure conservation_check_ug_side1
259  module procedure conservation_check_ug_side2
260 end interface
261 
262 
263 !> Private type for cell indices and data in the exchange grid
264 !> @ingroup xgrid_mod
266  integer :: i1 !< indices of cell in model arrays on both sides
267  integer :: j1 !< indices of cell in model arrays on both sides
268  integer :: i2 !< indices of cell in model arrays on both sides
269  integer :: j2 !< indices of cell in model arrays on both sides
270  integer :: l1, l2
271  integer :: recv_pos !< position in the receive buffer.
272  integer :: pe !< other side pe that has this cell
273  integer :: tile !< tile index of side 1 mosaic.
274  real(r8_kind) :: area !< geographic area of exchange cell
275 ! real(r8_kind) :: area1_ratio !(= x_area/grid1_area), will be added in the future to improve efficiency
276 ! real(r8_kind) :: area2_ratio !(= x_area/grid2_area), will be added in the future to improve efficiency
277  real(r8_kind) :: di !< Weight for the gradient of flux
278  real(r8_kind) :: dj !< Weight for the gradient of flux
279  real(r8_kind) :: scale
280 end type xcell_type
281 
282 !> Type to hold pointers for grid boxes
283 !> @ingroup xgrid_mod
285  real(r8_kind), dimension(:,:), pointer :: dx => null()
286  real(r8_kind), dimension(:,:), pointer :: dy => null()
287  real(r8_kind), dimension(:,:), pointer :: area => null()
288  real(r8_kind), dimension(:), pointer :: edge_w => null()
289  real(r8_kind), dimension(:), pointer :: edge_e => null()
290  real(r8_kind), dimension(:), pointer :: edge_s => null()
291  real(r8_kind), dimension(:), pointer :: edge_n => null()
292  real(r8_kind), dimension(:,:,:), pointer :: en1 => null()
293  real(r8_kind), dimension(:,:,:), pointer :: en2 => null()
294  real(r8_kind), dimension(:,:,:), pointer :: vlon => null()
295  real(r8_kind), dimension(:,:,:), pointer :: vlat => null()
296 end type grid_box_type
297 
298 !> Private type to hold all data needed from given grid for an exchange grid
299 !> @ingroup xgrid_mod
301  character(len=3) :: id !< grid identifier
302  integer :: npes !< number of processor on this grid.
303  logical :: on_this_pe !< indicate the domain is defined on this pe
304  integer :: root_pe !< indicate the root pe of the domain
305  integer, pointer, dimension(:) :: pelist !< pelist of the domain
306  integer :: ntile !< number of tiles in mosaic
307  integer :: ni !< max of global size of all the tiles
308  integer :: nj !< max of global size of all the tiles
309  integer, pointer, dimension(:) :: tile =>null() !< tile id ( pe index )
310  integer, pointer, dimension(:) :: is =>null() !< domain - i-range (pe index)
311  integer, pointer, dimension(:) :: ie =>null() !< domain - i-range (pe index)
312  integer, pointer, dimension(:) :: js =>null() !< domain - j-range (pe index)
313  integer, pointer, dimension(:) :: je =>null() !< domain - j-range (pe index)
314  integer, pointer :: is_me =>null() !< my domain - i-range
315  integer, pointer :: ie_me =>null() !< my domain - i-range
316  integer, pointer :: js_me =>null() !< my domain - j-range
317  integer, pointer :: je_me =>null() !< my domain - j-range
318  integer :: isd_me !< my data domain - i-range
319  integer :: ied_me !< my data domain - i-range
320  integer :: jsd_me !< my data domain - j-range
321  integer :: jed_me !< my data domain - j-range
322  integer :: nxd_me !< data domain size
323  integer :: nyd_me !< data domain size
324  integer :: nxc_me !< compute domain size
325  integer :: nyc_me !< compute domain size
326  integer, pointer :: tile_me !< my tile id
327  integer :: im !< global domain range
328  integer :: jm !< global domain range
329  integer :: km !< global domain range
330  real(r8_kind), pointer, dimension(:) :: lon =>null() !< center of global grids
331  real(r8_kind), pointer, dimension(:) :: lat =>null() !< center of global grids
332  real(r8_kind), pointer, dimension(:,:) :: geolon=>null() !< geographical grid center
333  real(r8_kind), pointer, dimension(:,:) :: geolat=>null() !< geographical grid center
334  real(r8_kind), pointer, dimension(:,:,:) :: frac_area =>null() !< partition fractions
335  real(r8_kind), pointer, dimension(:,:) :: area =>null() !< cell area
336  real(r8_kind), pointer, dimension(:,:) :: area_inv =>null() !< 1 / area for normalization
337  integer :: first !< xgrid index range
338  integer :: last !< xgrid index range
339  integer :: first_get !< xgrid index range for get_2_from_xgrid
340  integer :: last_get !< xgrid index range for get_2_from_xgrid
341  integer :: size !< # xcell patterns
342  type(xcell_type), pointer :: x(:) =>null() !< xcell patterns
343  integer :: size_repro !< # side 1 patterns for repro
344  type(xcell_type), pointer :: x_repro(:) =>null() !< side 1 patterns for repro
345  type(domain2d) :: domain !< used for conservation checks
346  type(domain2d) :: domain_with_halo !< used for second order remapping
347  logical :: is_latlon !< indicate if the grid is lat-lon grid or not.
348  type(grid_box_type) :: box !< used for second order remapping.
349  !--- The following is for land unstruct domain
350  logical :: is_ug
351  integer :: nxl_me
352  integer, pointer :: ls_me =>null() !< unstruct domain
353  integer, pointer :: le_me =>null() !< unstruct domain
354  integer, pointer, dimension(:) :: ls =>null(), le =>null()
355  integer, pointer :: gs_me =>null(), ge_me =>null()
356  integer, pointer, dimension(:) :: gs =>null(), ge =>null()
357  integer, pointer, dimension(:) :: l_index =>null()
358  type(domainug) :: ug_domain
359 
360 end type grid_type
361 
362 !> Private type for exchange grid data
363 !> @ingroup xgrid_mod
365  integer :: i, j
366  real(r8_kind) :: area !< (= geographic area * frac_area)
367 ! real(r8_kind) :: area_ratio !(= x1_area/grid1_area) ! will be added in the future to improve efficiency
368  real(r8_kind) :: di !< weight for the gradient of flux
369  real(r8_kind) :: dj !< weight for the gradient of flux
370  integer :: tile !< tile index of side 1 mosaic.
371  integer :: pos
372 end type x1_type
373 
374 !> Private type for exchange grid data
375 !> @ingroup xgrid_mod
377  integer :: i, j, l, k, pos
378  real(r8_kind) :: area !< geographic area of exchange cell
379 ! real(r8_kind) :: area_ratio !(=x2_area/grid2_area ) ! will be added in the future to improve efficiency
380 end type x2_type
381 
382 !> Private type for overlap exchange grid data
383 !> @ingroup xgrid_mod
385  integer :: count
386  integer :: pe
387  integer :: buffer_pos
388  integer, allocatable :: i(:)
389  integer, allocatable :: j(:)
390  integer, allocatable :: g(:)
391  integer, allocatable :: xLoc(:)
392  integer, allocatable :: tile(:)
393  real(r8_kind), allocatable :: di(:)
394  real(r8_kind), allocatable :: dj(:)
395 end type overlap_type
396 
397 !> Private type used for exchange grid communication
398 !> @ingroup xgrid_mod
400  integer :: nsend, nrecv
401  integer :: sendsize, recvsize
402  integer, pointer, dimension(:) :: unpack_ind=>null()
403  type(overlap_type), pointer, dimension(:) :: send=>null()
404  type(overlap_type), pointer, dimension(:) :: recv=>null()
405 end type comm_type
406 
407 !> @brief Type for an exchange grid, holds pointers to included grids and any necessary data.
408 !> @ingroup xgrid_mod
410  private
411  integer :: size !< # of exchange grid cells with area > 0 on this pe
412  integer :: size_put1 !< # of exchange grid cells for put_1_to_xgrid
413  integer :: size_get2 !< # of exchange grid cells for get_2_to_xgrid
414  integer :: me, npes, root_pe
415  logical, pointer, dimension(:) :: your1my2 =>null()!< true if side 1 domain on
416  !! indexed pe overlaps side 2
417  !! domain on this pe
418  logical, pointer, dimension(:) :: your2my1 =>null() !< true if a side 2 domain on
419  !! indexed pe overlaps side 1
420  !! domain on this pe
421  integer, pointer, dimension(:) :: your2my1_size=>null() !< number of exchange grid of
422  !! a side 2 domain on
423  !! indexed pe overlaps side 1
424  !! domain on this pe
425 
426  type (grid_type), pointer, dimension(:) :: grids =>null() !< 1st grid is side 1;
427  !! rest on side 2
428  !
429  ! Description of the individual exchange grid cells (index is cell #)
430  !
431  type(x1_type), pointer, dimension(:) :: x1 =>null() !< side 1 info
432  type(x1_type), pointer, dimension(:) :: x1_put =>null() !< side 1 info
433  type(x2_type), pointer, dimension(:) :: x2 =>null() !< side 2 info
434  type(x2_type), pointer, dimension(:) :: x2_get =>null() !< side 2 info
435 
436  integer, pointer, dimension(:) :: send_count_repro =>null()
437  integer, pointer, dimension(:) :: recv_count_repro =>null()
438  integer :: send_count_repro_tot !< sum(send_count_repro)
439  integer :: recv_count_repro_tot !< sum(recv_count_repro)
440  integer :: version !< version of xgrids. version=VERSION! is for grid_spec file
441  !! and version=VERSION2 is for mosaic grid.
442  integer, pointer, dimension(:) :: ind_get1 =>null() !< indx for side1 get and side2 put.
443  integer, pointer, dimension(:) :: ind_put1 =>null() !< indx for side1 put and side 2get.
444  type(comm_type), pointer :: put1 =>null() !< for put_1_to_xgrid
445  type(comm_type), pointer :: get1 =>null() !< for get_1_from_xgrid
446  type(comm_type), pointer :: get1_repro =>null()!< for get_1_from_xgrid_repro
447 end type xmap_type
448 
449 !> @addtogroup stock_constants_mod
450 !> @{
451 !-----------------------------------------------------------------------
452 ! Include variable "version" to be written to log file.
453 #include<file_version.h>
454 
455  real(r8_kind), parameter :: eps = 1.0e-10_r8_kind
456  real(r8_kind), parameter :: large_number = 1.e20_r8_kind
457  logical :: module_is_initialized = .false.
458  integer :: id_put_1_to_xgrid_order_1 = 0
459  integer :: id_put_1_to_xgrid_order_2 = 0
460  integer :: id_get_1_from_xgrid = 0
461  integer :: id_get_1_from_xgrid_repro = 0
462  integer :: id_get_2_from_xgrid = 0
463  integer :: id_put_2_to_xgrid = 0
464  integer :: id_setup_xmap = 0
465  integer :: id_load_xgrid1, id_load_xgrid2, id_load_xgrid3
466  integer :: id_load_xgrid4, id_load_xgrid5
467  integer :: id_load_xgrid, id_set_comm, id_regen, id_conservation_check
468 
469 
470  ! The following is for nested model
471  integer :: nnest=0, tile_nest, tile_parent
472  integer :: is_nest=0, ie_nest=0, js_nest=0, je_nest=0
473  integer :: is_parent=0, ie_parent=0, js_parent=0, je_parent=0
474 
475 !> @}
476  ! The following is required to compute stocks of water, heat, ...
477 
478  !> @ingroup xgrid_mod
479  interface stock_move
480  module procedure stock_move_3d, stock_move_2d
481  end interface
482 
483  !> @ingroup xgrid_mod
484  interface stock_move_ug
485  module procedure stock_move_ug_3d
486  end interface
487 
488  public stock_move, stock_type, stock_print, get_index_range, stock_integrate_2d
489  public first_order, second_order, stock_move_ug
490 
491  !> @ingroup xgrid_mod
493  module procedure get_area_elements_fms2_io
494  end interface
495  !> @ingroup xgrid_mod
497  module procedure get_nest_contact_fms2_io
498  end interface
499 
500 contains
501 
502 !> @addtogroup xgrid_mod
503 !> @{
504 
505 !#######################################################################
506 !> @return logical in_box
507 logical function in_box(i, j, is, ie, js, je)
508  integer, intent(in) :: i, j, is, ie, js, je
509 
510  in_box = (i>=is) .and. (i<=ie) .and. (j>=js) .and. (j<=je)
511 end function in_box
512 
513 !#######################################################################
514 
515 !> @brief Initialize the xgrid_mod.
516 !! @details Initialization routine for the xgrid module. It reads the xgrid_nml,
517 !! writes the version information and xgrid_nml to the log file.
518 subroutine xgrid_init(remap_method)
519  integer, intent(out) :: remap_method !< exchange grid interpolation method. It has four possible values:
520  !! FIRST_ORDER (=1), SECOND_ORDER(=2).
521 
522  integer :: iunit, ierr, io, out_unit
523 
524  if (module_is_initialized) return
525  module_is_initialized = .true.
526 
527  read (input_nml_file, xgrid_nml, iostat=io)
528  ierr = check_nml_error( io, 'xgrid_nml' )
529 
530 !--------- write version number and namelist ------------------
531  call write_version_number("XGRID_MOD", version)
532 
533  iunit = stdlog( )
534  out_unit = stdout()
535  if ( mpp_pe() == mpp_root_pe() ) write (iunit,nml=xgrid_nml)
536 
537 !--------- check interp_method has suitable value
538 !--- when monotonic_exchange is true, interp_method must be second order.
539 
540  select case(trim(interp_method))
541  case('first_order')
542  remap_method = first_order
543  if( monotonic_exchange ) call error_mesg('xgrid_mod', &
544  'xgrid_nml monotonic_exchange must be .false. when interp_method = first_order', fatal)
545  write(out_unit,*)"NOTE from xgrid_mod: use first_order conservative exchange"
546  case('second_order')
547  if(monotonic_exchange) then
548  write(out_unit,*)"NOTE from xgrid_mod: use monotonic second_order conservative exchange"
549  else
550  write(out_unit,*)"NOTE from xgrid_mod: use second_order conservative exchange"
551  endif
552  remap_method = second_order
553  case default
554  call error_mesg('xgrid_mod', ' nml interp_method = ' //trim(interp_method)// &
555  ' is not a valid namelist option', fatal)
556  end select
557 
558  if(xgrid_clocks_on) then
559  id_put_1_to_xgrid_order_1 = mpp_clock_id("put_1_to_xgrid_order_1", flags=mpp_clock_sync)
560  id_put_1_to_xgrid_order_2 = mpp_clock_id("put_1_to_xgrid_order_2", flags=mpp_clock_sync)
561  id_get_1_from_xgrid = mpp_clock_id("get_1_from_xgrid", flags=mpp_clock_sync)
562  id_get_1_from_xgrid_repro = mpp_clock_id("get_1_from_xgrid_repro", flags=mpp_clock_sync)
563  id_get_2_from_xgrid = mpp_clock_id("get_2_from_xgrid", flags=mpp_clock_sync)
564  id_put_2_to_xgrid = mpp_clock_id("put_2_to_xgrid", flags=mpp_clock_sync)
565  id_setup_xmap = mpp_clock_id("setup_xmap", flags=mpp_clock_sync)
566  id_set_comm = mpp_clock_id("set_comm")
567  id_regen = mpp_clock_id("regen")
568  id_conservation_check = mpp_clock_id("conservation_check")
569  id_load_xgrid = mpp_clock_id("load_xgrid")
570  id_load_xgrid1 = mpp_clock_id("load_xgrid1")
571  id_load_xgrid2 = mpp_clock_id("load_xgrid2")
572  id_load_xgrid3 = mpp_clock_id("load_xgrid3")
573  id_load_xgrid4 = mpp_clock_id("load_xgrid4")
574  id_load_xgrid5 = mpp_clock_id("load_xgrid5")
575  endif
576 
577  remapping_method = remap_method
578 
579 end subroutine xgrid_init
580 
581 !#######################################################################
582 
583 subroutine load_xgrid (xmap, grid, grid_file, grid1_id, grid_id, tile1, tile2, use_higher_order)
584 type(xmap_type), intent(inout) :: xmap
585 type(grid_type), intent(inout) :: grid
586 character(len=*), intent(in) :: grid_file
587 character(len=3), intent(in) :: grid1_id, grid_id
588 integer, intent(in) :: tile1, tile2
589 logical, intent(in) :: use_higher_order
590 
591  integer, pointer, dimension(:) :: i1=>null(), j1=>null()
592  integer, pointer, dimension(:) :: i2=>null(), j2=>null()
593  real(r8_kind), pointer, dimension(:) :: di=>null(), dj=>null()
594  real(r8_kind), pointer, dimension(:) :: area =>null()
595  integer, pointer, dimension(:) :: i1_tmp=>null(), j1_tmp=>null()
596  integer, pointer, dimension(:) :: i2_tmp=>null(), j2_tmp=>null()
597  real(r8_kind), pointer, dimension(:) :: di_tmp=>null(), dj_tmp=>null()
598  real(r8_kind), pointer, dimension(:) :: area_tmp =>null()
599  integer, pointer, dimension(:) :: i1_side1=>null(), j1_side1=>null()
600  integer, pointer, dimension(:) :: i2_side1=>null(), j2_side1=>null()
601  real(r8_kind), pointer, dimension(:) :: di_side1=>null(), dj_side1=>null()
602  real(r8_kind), pointer, dimension(:) :: area_side1 =>null()
603 
604  real(r8_kind), allocatable, dimension(:,:) :: tmp
605  real(r8_kind), allocatable, dimension(:) :: send_buffer, recv_buffer
606  type (grid_type), pointer, save :: grid1 =>null()
607  integer :: l, ll, ll_repro, p, nxgrid, size_prev
608  type(xcell_type), allocatable :: x_local(:)
609  integer :: size_repro, out_unit
610  logical :: scale_exist = .false.
611  logical :: is_distribute = .false.
612  real(r8_kind), allocatable, dimension(:) :: scale
613  real(r8_kind) :: garea
614  integer :: npes, isc, iec, nxgrid_local, pe, nxgrid_local_orig
615  integer :: nxgrid1, nxgrid2, nset1, nset2, ndivs, cur_ind
616  integer :: pos, nsend, nrecv, l1, l2, n, mypos
617  integer :: start(4), nread(4)
618  logical :: found
619  character(len=128) :: attvalue
620  integer, dimension(0:xmap%npes-1) :: pelist
621  logical, dimension(0:xmap%npes-1) :: subset_rootpe
622  integer, dimension(0:xmap%npes-1) :: nsend1, nsend2, nrecv1, nrecv2
623  integer, dimension(0:xmap%npes-1) :: send_cnt, recv_cnt
624  integer, dimension(0:xmap%npes-1) :: send_buffer_pos, recv_buffer_pos
625  integer, dimension(0:xmap%npes-1) :: ibegin, iend, pebegin, peend
626  integer, dimension(2*xmap%npes) :: ibuf1, ibuf2
627  integer, dimension(0:xmap%npes-1) :: pos_x, y2m1_size
628  integer, allocatable, dimension(:) :: y2m1_pe
629  integer, pointer, save :: iarray(:), jarray(:)
630  integer, allocatable, save :: pos_s(:)
631  integer, pointer, dimension(:) :: iarray2(:)=>null(), jarray2(:)=>null()
632  logical :: last_grid
633  integer :: nxgrid1_old
634  integer :: lll
635  type(fmsnetcdffile_t) :: fileobj
636 
637  if(.not. open_file(fileobj, grid_file, 'read' )) then
638  call error_mesg('xgrid_mod(load_xgrid)', 'Error in opening file '//trim(grid_file), fatal)
639  endif
640 
641  scale_exist = .false.
642  grid1 => xmap%grids(1)
643  out_unit = stdout()
644  npes = xmap%npes
645  pe = mpp_pe()
646  mypos = mpp_pe()-mpp_root_pe()
647 
648  call mpp_get_current_pelist(pelist)
649  !--- make sure npes = pelist(npes-1) - pelist(0) + 1
650  if( npes .NE. pelist(npes-1) - pelist(0) + 1 ) then
651  print*, "npes =", npes, ", pelist(npes-1)=", pelist(npes-1), ", pelist(0)=", pelist(0)
652  call error_mesg('xgrid_mod', .NE.'npes pelist(npes-1) - pelist(0)', fatal)
653  endif
654 
655  select case(xmap%version)
656  case(version1)
657  nxgrid = 0
658  if (dimension_exists(fileobj, 'i_'//lowercase(grid1_id)//'X'//lowercase(grid_id))) then
659  call get_dimension_size(fileobj, 'i_'//lowercase(grid1_id)//'X'//lowercase(grid_id), nxgrid)
660  endif
661  if(nxgrid .LE. 0) return
662  case(version2)
663  !--- max_size is the exchange grid size between super grid.
664  nxgrid = get_mosaic_xgrid_size(fileobj)
665  if(nxgrid .LE. 0) return
666  end select
667 
668  !--- define a domain to read exchange grid.
669  if(nxgrid > npes) then
670  ndivs = npes
671  if(nsubset >0 .AND. nsubset < npes) ndivs = nsubset
672  call mpp_compute_extent( 1, nxgrid, ndivs, ibegin, iend)
673  if(npes == ndivs) then
674  p = mpp_pe()-mpp_root_pe()
675  isc = ibegin(p)
676  iec = iend(p)
677  subset_rootpe(:) = .true.
678  else
679  isc = 0; iec = -1
680  call mpp_compute_extent(pelist(0), pelist(npes-1), ndivs, pebegin, peend)
681  do n = 0, ndivs-1
682  if(pe == pebegin(n)) then
683  isc = ibegin(n)
684  iec = iend(n)
685  exit
686  endif
687  enddo
688  cur_ind = 0
689  subset_rootpe(:) = .false.
690 
691  do n = 0, npes-1
692  if(pelist(n) == pebegin(cur_ind)) then
693  subset_rootpe(n) = .true.
694  cur_ind = cur_ind+1
695  if(cur_ind == ndivs) exit
696  endif
697  enddo
698  endif
699  is_distribute = .true.
700  else
701  is_distribute = .false.
702  isc = 1; iec = nxgrid
703  endif
704 
705  nset1 = 5
706  nset2 = 5
707  if(use_higher_order) then
708  nset1 = nset1 + 2
709  nset2 = nset2 + 2
710  end if
711  if(scale_exist) nset2 = nset1 + 1
712 
713  call mpp_clock_begin(id_load_xgrid1)
714  if(iec .GE. isc) then
715  nxgrid_local = iec - isc + 1
716  allocate(i1_tmp(isc:iec), j1_tmp(isc:iec), i2_tmp(isc:iec), j2_tmp(isc:iec), area_tmp(isc:iec) )
717  if(use_higher_order) allocate(di_tmp(isc:iec), dj_tmp(isc:iec))
718 
719  start = 1; nread = 1
720 
721  select case(xmap%version)
722  case(version1)
723  start(1) = isc; nread(1) = nxgrid_local
724  allocate(tmp(nxgrid_local,1))
725  call read_data(fileobj, 'I_'//grid1_id//'_'//grid1_id//'x'//grid_id, tmp, corner=start, edge_lengths=nread)
726  i1_tmp = int(tmp(:,1))
727  call read_data(fileobj, 'J_'//grid1_id//'_'//grid1_id//'x'//grid_id, tmp, corner=start, edge_lengths=nread)
728  j1_tmp = int(tmp(:,1))
729  call read_data(fileobj, 'I_'//grid_id//'_'//grid1_id//'x'//grid_id, tmp, corner=start, edge_lengths=nread)
730  i2_tmp = int(tmp(:,1))
731  call read_data(fileobj, 'J_'//grid_id//'_'//grid1_id//'x'//grid_id, tmp, corner=start, edge_lengths=nread)
732  j2_tmp = int(tmp(:,1))
733  call read_data(fileobj, 'AREA_'//grid1_id//'x'//grid_id, tmp, corner=start, edge_lengths=nread)
734  area_tmp = tmp(:,1)
735  if(use_higher_order) then
736  call read_data(fileobj, 'DI_'//grid1_id//'x'//grid_id, tmp, corner=start, edge_lengths=nread)
737  di_tmp = tmp(:,1)
738  call read_data(fileobj, 'DJ_'//grid1_id//'x'//grid_id, tmp, corner=start, edge_lengths=nread)
739  dj_tmp = tmp(:,1)
740  end if
741  deallocate(tmp)
742  case(version2)
743  nread(1) = 2; start(2) = isc; nread(2) = nxgrid_local
744  allocate(tmp(2, isc:iec))
745  call read_data(fileobj, "tile1_cell", tmp, corner=start, edge_lengths=nread)
746  i1_tmp(isc:iec) = int(tmp(1, isc:iec))
747  j1_tmp(isc:iec) = int(tmp(2, isc:iec))
748  call read_data(fileobj, "tile2_cell", tmp, corner=start, edge_lengths=nread)
749  i2_tmp(isc:iec) = int(tmp(1, isc:iec))
750  j2_tmp(isc:iec) = int(tmp(2, isc:iec))
751  if(use_higher_order) then
752  call read_data(fileobj, "tile1_distance", tmp, corner=start, edge_lengths=nread)
753  di_tmp(isc:iec) = tmp(1, isc:iec)
754  dj_tmp(isc:iec) = tmp(2, isc:iec)
755  end if
756  start = 1; nread = 1
757  start(1) = isc; nread(1) = nxgrid_local
758  deallocate(tmp)
759  allocate(tmp(isc:iec,1) )
760 
761  call read_data(fileobj, "xgrid_area", tmp(:,1:1), corner=start, edge_lengths=nread)
762  ! check the units of "xgrid_area
763  call get_variable_units(fileobj, "xgrid_area", attvalue)
764 
765  if( trim(attvalue) == 'm2' ) then
766  garea = 4.0_r8_kind * pi * radius * radius;
767  area_tmp = tmp(:,1)/garea
768  else if( trim(attvalue) == 'none' ) then
769  area_tmp = tmp(:,1)
770  else
771  call error_mesg('xgrid_mod', 'In file '//trim(grid_file)//', xgrid_area units = '// &
772  trim(attvalue)//' should be "m2" or "none"', fatal)
773  endif
774 
775  !--- if field "scale" exist, read this field. Normally this
776  !--- field only exist in landXocean exchange grid cell.
777  if(grid1_id == 'LND' .AND. grid_id == 'OCN') then
778  if(variable_exists(fileobj, "scale")) then
779  allocate(scale(isc:iec))
780  write(out_unit, *)"NOTE from load_xgrid(xgrid_mod): field 'scale' exist in the file "// &
781  & trim(grid_file)//", this field will be read and the exchange grid cell area will be"// &
782  & " multiplied by scale"
783  call read_data(fileobj, "scale", tmp, corner=start, edge_lengths=nread)
784  scale = tmp(:,1)
785  scale_exist = .true.
786  endif
787  endif
788  deallocate(tmp)
789  end select
790 
791  !---z1l: The following change is for the situation that some processor is masked out.
792  !---loop through all the pe to see if side 1 and side of each exchange grid is on some processor
793  nxgrid_local_orig = nxgrid_local
794  allocate(i1(isc:iec), j1(isc:iec), i2(isc:iec), j2(isc:iec), area(isc:iec) )
795  if(use_higher_order) allocate(di(isc:iec), dj(isc:iec))
796  pos = isc-1
797  do l = isc, iec
798  found = .false.
799  !--- first check if the exchange grid is on one of side 1 processor
800  do p = 0, npes - 1
801  if(grid1%tile(p) == tile1) then
802  if(in_box_nbr(i1_tmp(l), j1_tmp(l), grid1, p)) then
803  found = .true.
804  exit
805  endif
806  endif
807  enddo
808  !--- Then check if the exchange grid is on one of side 2 processor
809  if( found ) then
810  do p = 0, npes - 1
811  if(grid%tile(p) == tile2) then
812  if (in_box_nbr(i2_tmp(l), j2_tmp(l), grid, p)) then
813  pos = pos+1
814  i1(pos) = i1_tmp(l)
815  j1(pos) = j1_tmp(l)
816  i2(pos) = i2_tmp(l)
817  j2(pos) = j2_tmp(l)
818  area(pos) = area_tmp(l)
819  if(use_higher_order) then
820  di(pos) = di_tmp(l)
821  dj(pos) = dj_tmp(l)
822  endif
823  exit
824  endif
825  endif
826  enddo
827  endif
828  enddo
829 
830  deallocate(i1_tmp, i2_tmp, j1_tmp, j2_tmp, area_tmp)
831  if(use_higher_order) deallocate( di_tmp, dj_tmp)
832  iec = pos
833  if(iec .GE. isc) then
834  nxgrid_local = iec - isc + 1
835  else
836  nxgrid_local = 0
837  endif
838  else
839  nxgrid_local = 0
840  nxgrid_local_orig = 0
841  endif
842 
843  call close_file(fileobj)
844 
845  call mpp_clock_end(id_load_xgrid1)
846 
847  if(is_distribute) then
848  !--- Since the xgrid is distributed according to side 2 grid. Send all the xgrid to its own side 2.
849  !--- Also need to send the xgrid to its own side 1 for the reproducing ability between processor count.
850  !--- first find out number of points need to send to other pe and fill the send buffer.
851  nsend1(:) = 0; nrecv1(:) = 0
852  nsend2(:) = 0; nrecv2(:) = 0
853  ibuf1(:)= 0; ibuf2(:)= 0
854 
855  call mpp_clock_begin(id_load_xgrid2)
856  if(nxgrid_local>0) then
857  allocate( send_buffer(nxgrid_local * (nset1+nset2)) )
858  pos = 0
859  do p = 0, npes - 1
860  send_buffer_pos(p) = pos
861  if(grid%tile(p) == tile2) then
862  do l = isc, iec
863  if(in_box_nbr(i2(l), j2(l), grid, p) ) then
864  nsend2(p) = nsend2(p) + 1
865  send_buffer(pos+1) = real(i1(l), r8_kind)
866  send_buffer(pos+2) = real(j1(l), r8_kind)
867  send_buffer(pos+3) = real(i2(l), r8_kind)
868  send_buffer(pos+4) = real(j2(l), r8_kind)
869  send_buffer(pos+5) = area(l)
870  if(use_higher_order) then
871  send_buffer(pos+6) = di(l)
872  send_buffer(pos+7) = dj(l)
873  endif
874  if(scale_exist) send_buffer(pos+nset2) = scale(l)
875  pos = pos + nset2
876  endif
877  enddo
878  endif
879  if(grid1%tile(p) == tile1) then
880  do l = isc, iec
881  if(in_box_nbr(i1(l), j1(l), grid1, p)) then
882  nsend1(p) = nsend1(p) + 1
883  send_buffer(pos+1) = real(i1(l), r8_kind)
884  send_buffer(pos+2) = real(j1(l), r8_kind)
885  send_buffer(pos+3) = real(i2(l), r8_kind)
886  send_buffer(pos+4) = real(j2(l), r8_kind)
887  send_buffer(pos+5) = area(l)
888  if(use_higher_order) then
889  send_buffer(pos+6) = di(l)
890  send_buffer(pos+7) = dj(l)
891  endif
892  pos = pos + nset1
893  endif
894  enddo
895  endif
896  enddo
897  endif
898  call mpp_clock_end(id_load_xgrid2)
899 
900  !--- send the size of the data on side 1 to be sent over.
901  call mpp_clock_begin(id_load_xgrid3)
902 
903  if (do_alltoall) then
904  do p = 0, npes-1
905  ibuf1(2*p+1) = nsend1(p)
906  ibuf1(2*p+2) = nsend2(p)
907  enddo
908  call mpp_alltoall(ibuf1, 2, ibuf2, 2)
909  else
910  do n = 0, npes-1
911  p = mod(mypos+npes-n, npes)
912  if(.not. subset_rootpe(p)) cycle
913  call mpp_recv( ibuf2(2*p+1), glen=2, from_pe=pelist(p), block=.false., tag=comm_tag_1)
914  enddo
915 
916  if(nxgrid_local_orig>0) then
917  do n = 0, npes-1
918  p = mod(mypos+n, npes)
919  ibuf1(2*p+1) = nsend1(p)
920  ibuf1(2*p+2) = nsend2(p)
921  call mpp_send( ibuf1(2*p+1), plen=2, to_pe=pelist(p), tag=comm_tag_1)
922  enddo
923  endif
924  call mpp_sync_self(check=event_recv)
925  endif
926  do p = 0, npes-1
927  nrecv1(p) = ibuf2(2*p+1)
928  nrecv2(p) = ibuf2(2*p+2)
929  enddo
930 
931  if(.not. do_alltoall) call mpp_sync_self()
932  call mpp_clock_end(id_load_xgrid3)
933  call mpp_clock_begin(id_load_xgrid4)
934  pos = 0
935  do p = 0, npes - 1
936  recv_buffer_pos(p) = pos
937  pos = pos + nrecv1(p) * nset1 + nrecv2(p) * nset2
938  end do
939 
940  !--- now get the data
941  nxgrid1 = sum(nrecv1)
942  nxgrid2 = sum(nrecv2)
943  if(nxgrid1>0 .OR. nxgrid2>0) allocate(recv_buffer(nxgrid1*nset1+nxgrid2*nset2))
944 
945  if (do_alltoallv) then
946  ! Construct the send and receive counters
947  send_cnt(:) = nset1 * nsend1(:) + nset2 * nsend2(:)
948  recv_cnt(:) = nset1 * nrecv1(:) + nset2 * nrecv2(:)
949 
950  call mpp_alltoall(send_buffer, send_cnt, send_buffer_pos, &
951  recv_buffer, recv_cnt, recv_buffer_pos)
952  else
953  do n = 0, npes-1
954  p = mod(mypos+npes-n, npes)
955  nrecv = nrecv1(p)*nset1+nrecv2(p)*nset2
956  if(nrecv==0) cycle
957  pos = recv_buffer_pos(p)
958  call mpp_recv(recv_buffer(pos+1), glen=nrecv, from_pe=pelist(p), &
959  block=.false., tag=comm_tag_2)
960  end do
961 
962  do n = 0, npes-1
963  p = mod(mypos+n, npes)
964  nsend = nsend1(p)*nset1 + nsend2(p)*nset2
965  if(nsend==0) cycle
966  pos = send_buffer_pos(p)
967  call mpp_send(send_buffer(pos+1), plen=nsend, to_pe=pelist(p), &
968  tag=comm_tag_2)
969  end do
970  call mpp_sync_self(check=event_recv)
971  end if
972  call mpp_clock_end(id_load_xgrid4)
973  !--- unpack buffer.
974  if( nxgrid_local>0) then
975  deallocate(i1,j1,i2,j2,area)
976  endif
977 
978  allocate(i1(nxgrid2), j1(nxgrid2))
979  allocate(i2(nxgrid2), j2(nxgrid2))
980  allocate(area(nxgrid2))
981  allocate(i1_side1(nxgrid1), j1_side1(nxgrid1))
982  allocate(i2_side1(nxgrid1), j2_side1(nxgrid1))
983  allocate(area_side1(nxgrid1))
984  if(use_higher_order) then
985  if(nxgrid_local>0) deallocate(di,dj)
986  allocate(di(nxgrid2), dj(nxgrid2))
987  allocate(di_side1(nxgrid1), dj_side1(nxgrid1))
988  endif
989  if(scale_exist) then
990  if(nxgrid_local>0)deallocate(scale)
991  allocate(scale(nxgrid2))
992  endif
993  pos = 0
994  l1 = 0; l2 = 0
995  do p = 0,npes-1
996  do n = 1, nrecv2(p)
997  l2 = l2+1
998  i1(l2) = int(recv_buffer(pos+1))
999  j1(l2) = int(recv_buffer(pos+2))
1000  i2(l2) = int(recv_buffer(pos+3))
1001  j2(l2) = int(recv_buffer(pos+4))
1002  area(l2) = recv_buffer(pos+5)
1003  if(use_higher_order) then
1004  di(l2) = recv_buffer(pos+6)
1005  dj(l2) = recv_buffer(pos+7)
1006  endif
1007  if(scale_exist)scale(l2) = recv_buffer(pos+nset2)
1008  pos = pos + nset2
1009  enddo
1010  do n = 1, nrecv1(p)
1011  l1 = l1+1
1012  i1_side1(l1) = int(recv_buffer(pos+1))
1013  j1_side1(l1) = int(recv_buffer(pos+2))
1014  i2_side1(l1) = int(recv_buffer(pos+3))
1015  j2_side1(l1) = int(recv_buffer(pos+4))
1016  area_side1(l1) = recv_buffer(pos+5)
1017  if(use_higher_order) then
1018  di_side1(l1) = recv_buffer(pos+6)
1019  dj_side1(l1) = recv_buffer(pos+7)
1020  endif
1021  pos = pos + nset1
1022  enddo
1023  enddo
1024  call mpp_sync_self()
1025  if(allocated(send_buffer)) deallocate(send_buffer)
1026  if(allocated(recv_buffer)) deallocate(recv_buffer)
1027 
1028  else
1029  nxgrid1 = nxgrid
1030  nxgrid2 = nxgrid
1031  i1_side1 => i1; j1_side1 => j1
1032  i2_side1 => i2; j2_side1 => j2
1033  area_side1 => area
1034  if(use_higher_order) then
1035  di_side1 => di
1036  dj_side1 => dj
1037  endif
1038  endif
1039 
1040  call mpp_clock_begin(id_load_xgrid5)
1041 
1042 
1043  size_prev = grid%size
1044 
1045  if(grid%tile_me == tile2) then
1046  do l=1,nxgrid2
1047  if (in_box_me(i2(l), j2(l), grid) ) then
1048  grid%size = grid%size + 1
1049  ! exclude the area overlapped with parent grid
1050  if( grid1_id .NE. "ATM" .OR. tile1 .NE. tile_parent .OR. &
1051  .NOT. in_box(i1(l), j1(l), is_parent, ie_parent, js_parent, je_parent) ) then
1052  if(grid%is_ug) then
1053  lll = grid%l_index((j2(l)-1)*grid%im+i2(l))
1054  grid%area(lll,1) = grid%area(lll,1)+area(l)
1055  else
1056  grid%area(i2(l),j2(l)) = grid%area(i2(l),j2(l))+area(l)
1057  endif
1058  endif
1059  do p=0,xmap%npes-1
1060  if(grid1%tile(p) == tile1) then
1061  if (in_box_nbr(i1(l), j1(l), grid1, p)) then
1062  xmap%your1my2(p) = .true.
1063  end if
1064  end if
1065  end do
1066  end if
1067  end do
1068  end if
1069 
1070  if(grid%size > size_prev) then
1071  if(size_prev > 0) then ! need to extend data
1072  allocate(x_local(size_prev))
1073  x_local = grid%x
1074  if(ASSOCIATED(grid%x)) deallocate(grid%x)
1075  allocate( grid%x( grid%size ) )
1076  grid%x(1:size_prev) = x_local
1077  deallocate(x_local)
1078  else
1079  if(ASSOCIATED(grid%x)) deallocate(grid%x) !< Check if allocated
1080  allocate( grid%x( grid%size ) )
1081  grid%x%di = 0.0_r8_kind; grid%x%dj = 0.0_r8_kind
1082  end if
1083  end if
1084 
1085  ll = size_prev
1086  if( grid%tile_me == tile2 ) then ! me is tile2
1087  do l=1,nxgrid2
1088  if (in_box_me(i2(l), j2(l), grid)) then
1089  ! insert in this grids cell pattern list and add area to side 2 area
1090  ll = ll + 1
1091  grid%x(ll)%i1 = i1(l); grid%x(ll)%i2 = i2(l)
1092  grid%x(ll)%j1 = j1(l); grid%x(ll)%j2 = j2(l)
1093  if(grid%is_ug) then
1094  grid%x(ll)%l2 = grid%l_index((j2(l)-1)*grid%im + i2(l))
1095  endif
1096 ! if(grid1%is_ug) then
1097 ! grid1%x(ll)%l1 = grid1%l_index((j1(l)-1)*grid1%im + i1(l))
1098 ! endif
1099  grid%x(ll)%tile = tile1
1100  grid%x(ll)%area = area(l)
1101  if(scale_exist) then
1102  grid%x(ll)%scale = scale(l)
1103  else
1104  grid%x(ll)%scale = 1.0_r8_kind
1105  endif
1106  if(use_higher_order) then
1107  grid%x(ll)%di = di(l)
1108  grid%x(ll)%dj = dj(l)
1109  end if
1110 
1111  if (make_exchange_reproduce) then
1112  do p=0,xmap%npes-1
1113  if(grid1%tile(p) == tile1) then
1114  if (in_box_nbr(i1(l), j1(l), grid1, p)) then
1115  grid%x(ll)%pe = p + xmap%root_pe
1116  end if
1117  end if
1118  end do
1119  end if ! make_exchange reproduce
1120  end if
1121  end do
1122  end if
1123 
1124  if(grid%id == xmap%grids(size(xmap%grids(:)))%id) then
1125  last_grid = .true.
1126  else
1127  last_grid = .false.
1128  endif
1129 
1130  size_repro = 0
1131  if(grid1%tile_me == tile1) then
1132  if(associated(iarray)) then
1133  nxgrid1_old = size(iarray(:))
1134  else
1135  nxgrid1_old = 0
1136  endif
1137 
1138  allocate(y2m1_pe(nxgrid1))
1139  if(.not. last_grid ) allocate(pos_s(0:xmap%npes-1))
1140  y2m1_pe = -1
1141  if(nxgrid1_old > 0) then
1142  do p=0,xmap%npes-1
1143  y2m1_size(p) = xmap%your2my1_size(p)
1144  enddo
1145  else
1146  y2m1_size = 0
1147  endif
1148 
1149  do l=1,nxgrid1
1150  if (in_box_me(i1_side1(l), j1_side1(l), grid1) ) then
1151  if(grid1%is_ug) then
1152  lll = grid1%l_index((j1_side1(l)-1)*grid1%im+i1_side1(l))
1153  grid1%area(lll,1) = grid1%area(lll,1) + area_side1(l)
1154  else
1155  grid1%area(i1_side1(l),j1_side1(l)) = grid1%area(i1_side1(l),j1_side1(l))+area_side1(l)
1156  endif
1157  do p=0,xmap%npes-1
1158  if (grid%tile(p) == tile2) then
1159  if (in_box_nbr(i2_side1(l), j2_side1(l), grid, p)) then
1160  xmap%your2my1(p) = .true.
1161  y2m1_pe(l) = p
1162  y2m1_size(p) = y2m1_size(p) + 1
1163  endif
1164  endif
1165  enddo
1166  size_repro = size_repro + 1
1167  endif
1168  enddo
1169  pos_x = 0
1170  do p = 1, npes-1
1171  pos_x(p) = pos_x(p-1) + y2m1_size(p-1)
1172  enddo
1173 
1174  if(.not. last_grid) pos_s(:) = pos_x(:)
1175 
1176  if(nxgrid1_old > 0) then
1177  y2m1_size(:) = xmap%your2my1_size(:)
1178  iarray2 => iarray
1179  jarray2 => jarray
1180  allocate(iarray(nxgrid1+nxgrid1_old), jarray(nxgrid1+nxgrid1_old))
1181  ! copy the i-j index
1182  do p=0,xmap%npes-1
1183  do n = 1, xmap%your2my1_size(p)
1184  iarray(pos_x(p)+n) = iarray2(pos_s(p)+n)
1185  jarray(pos_x(p)+n) = jarray2(pos_s(p)+n)
1186  enddo
1187  enddo
1188  deallocate(iarray2, jarray2)
1189  else
1190  allocate(iarray(nxgrid1), jarray(nxgrid1))
1191  iarray(:) = 0
1192  jarray(:) = 0
1193  y2m1_size(:) = 0
1194  endif
1195 
1196  do l=1,nxgrid1
1197  p = y2m1_pe(l)
1198  if(p<0) cycle
1199  found = .false.
1200  if(y2m1_size(p) > 0) then
1201  pos = pos_x(p)+y2m1_size(p)
1202  if( i1_side1(l) == iarray(pos) .AND. j1_side1(l) == jarray(pos) ) then
1203  found = .true.
1204  else
1205  !---may need to replace with a fast search algorithm
1206  do n = 1, y2m1_size(p)
1207  pos = pos_x(p)+n
1208  if(i1_side1(l) == iarray(pos) .AND. j1_side1(l) == jarray(pos)) then
1209  found = .true.
1210  exit
1211  endif
1212  enddo
1213  endif
1214  endif
1215  if( (.NOT. found) .OR. monotonic_exchange ) then
1216  y2m1_size(p) = y2m1_size(p)+1
1217  pos = pos_x(p)+y2m1_size(p)
1218  iarray(pos) = i1_side1(l)
1219  jarray(pos) = j1_side1(l)
1220  endif
1221  end do
1222  xmap%your2my1_size(:) = y2m1_size(:)
1223  deallocate(y2m1_pe)
1224  if(last_grid) then
1225  deallocate(iarray, jarray)
1226  if(allocated(pos_s)) deallocate(pos_s)
1227  end if
1228  end if
1229 
1230  if (grid1%tile_me == tile1 .and. size_repro > 0) then
1231  ll_repro = grid%size_repro
1232  grid%size_repro = ll_repro + size_repro
1233  if(ll_repro > 0) then ! extend data
1234  allocate(x_local(ll_repro))
1235  x_local = grid%x_repro
1236  if(ASSOCIATED(grid%x_repro)) deallocate(grid%x_repro)
1237  allocate( grid%x_repro(grid%size_repro ) )
1238  grid%x_repro(1:ll_repro) = x_local
1239  deallocate(x_local)
1240  else
1241  if(ASSOCIATED(grid%x_repro)) deallocate(grid%x_repro) !< Check if allocated
1242  allocate( grid%x_repro( grid%size_repro ) )
1243  grid%x_repro%di = 0.0_r8_kind; grid%x_repro%dj = 0.0_r8_kind
1244  end if
1245  do l=1,nxgrid1
1246  if (in_box_me(i1_side1(l),j1_side1(l), grid1) ) then
1247  ll_repro = ll_repro + 1
1248  grid%x_repro(ll_repro)%i1 = i1_side1(l); grid%x_repro(ll_repro)%i2 = i2_side1(l)
1249  grid%x_repro(ll_repro)%j1 = j1_side1(l); grid%x_repro(ll_repro)%j2 = j2_side1(l)
1250  if(grid1%is_ug) then
1251  grid%x_repro(ll_repro)%l1 = grid1%l_index((j1_side1(l)-1)*grid1%im+i1_side1(l))
1252  endif
1253  if(grid%is_ug) then
1254 ! grid%x_repro(ll_repro)%l2 = grid%l_index((j2_side1(l)-1)*grid%im+i2_side1(l))
1255  endif
1256  grid%x_repro(ll_repro)%tile = tile1
1257  grid%x_repro(ll_repro)%area = area_side1(l)
1258  if(use_higher_order) then
1259  grid%x_repro(ll_repro)%di = di_side1(l)
1260  grid%x_repro(ll_repro)%dj = dj_side1(l)
1261  end if
1262 
1263  do p=0,xmap%npes-1
1264  if(grid%tile(p) == tile2) then
1265  if (in_box_nbr(i2_side1(l), j2_side1(l), grid, p)) then
1266  grid%x_repro(ll_repro)%pe = p + xmap%root_pe
1267  end if
1268  end if
1269  end do
1270  end if ! make_exchange_reproduce
1271  end do
1272  end if
1273 
1274  deallocate(i1, j1, i2, j2, area)
1275  if(use_higher_order) deallocate(di, dj)
1276  if(scale_exist) deallocate(scale)
1277  if(is_distribute) then
1278  deallocate(i1_side1, j1_side1, i2_side1, j2_side1, area_side1)
1279  if(use_higher_order) deallocate(di_side1, dj_side1)
1280  endif
1281 
1282  i1=>null(); j1=>null(); i2=>null(); j2=>null()
1283  call mpp_clock_end(id_load_xgrid5)
1284 
1285 
1286 
1287 end subroutine load_xgrid
1288 
1289 !#######################################################################
1290 
1291 !> @brief read the center point of the grid from version 1 grid file.
1292 !! only the grid at the side 1 is needed, so we only read
1293 !! atm and land grid.
1294 subroutine get_grid_version1(grid, grid_id, grid_file)
1295  type(grid_type), intent(inout) :: grid
1296  character(len=3), intent(in) :: grid_id
1297  character(len=*), intent(in) :: grid_file
1298 
1299  real(r8_kind), dimension(grid%im) :: lonb
1300  real(r8_kind), dimension(grid%jm) :: latb
1301  real(r8_kind) :: d2r
1302  integer :: is, ie, js, je
1303  type(fmsnetcdfdomainfile_t) :: fileobj
1304 
1305  d2r = pi / 180.0_r8_kind
1306 
1307  if(.not. open_file(fileobj, grid_file, 'read', grid%domain) ) then
1308  call error_mesg('xgrid_mod(get_grid_version1)', 'Error in opening file '//trim(grid_file), fatal)
1309  endif
1310 
1311  call mpp_get_compute_domain(grid%domain, is, ie, js, je)
1312  if (associated(grid%lon)) deallocate(grid%lon) !< Check if allocated
1313  if (associated(grid%lat)) deallocate(grid%lat) !< Check if allocated
1314  allocate(grid%lon(grid%im), grid%lat(grid%jm))
1315  if(grid_id == 'ATM') then
1316  call read_data(fileobj, 'xta', lonb)
1317  call read_data(fileobj, 'yta', latb)
1318 
1319  if(.not. allocated(area_atm_model)) then
1320  allocate(area_atm_model(is:ie, js:je))
1321  call get_area_elements(fileobj, 'AREA_ATM_MODEL', area_atm_model)
1322  endif
1323  if(.not. allocated(area_atm_sphere)) then
1324  allocate(area_atm_sphere(is:ie, js:je))
1325  call get_area_elements(fileobj, 'AREA_ATM', area_atm_sphere)
1326  endif
1327  else if(grid_id == 'LND') then
1328  call read_data(fileobj, 'xtl', lonb)
1329  call read_data(fileobj, 'ytl', latb)
1330  if(.not. allocated(area_lnd_model)) then
1331  allocate(area_lnd_model(is:ie, js:je))
1332  call get_area_elements(fileobj, 'AREA_LND_MODEL', area_lnd_model)
1333  endif
1334  if(.not. allocated(area_lnd_sphere)) then
1335  allocate(area_lnd_sphere(is:ie, js:je))
1336  call get_area_elements(fileobj, 'AREA_LND', area_lnd_sphere)
1337  endif
1338  else if(grid_id == 'OCN' ) then
1339  if(.not. allocated(area_ocn_sphere)) then
1340  allocate(area_ocn_sphere(is:ie, js:je))
1341  call get_area_elements(fileobj, 'AREA_OCN', area_ocn_sphere)
1342  endif
1343  endif
1344  !--- second order remapping suppose second order
1345  if(grid_id == 'LND' .or. grid_id == 'ATM') then
1346  grid%lon = lonb * d2r
1347  grid%lat = latb * d2r
1348  endif
1349  grid%is_latlon = .true.
1350 
1351  call close_file(fileobj)
1352 
1353  return
1354 
1355 end subroutine get_grid_version1
1356 
1357 !#######################################################################
1358 
1359 !> @brief read the center point of the grid from version 1 grid file.
1360 !! only the grid at the side 1 is needed, so we only read
1361 !! atm and land grid
1362 subroutine get_grid_version2(grid, grid_id, grid_file)
1363  type(grid_type), intent(inout) :: grid
1364  character(len=3), intent(in) :: grid_id
1365  character(len=*), intent(in) :: grid_file
1366 
1367  real(r8_kind), allocatable :: tmpx(:,:), tmpy(:,:)
1368  real(r8_kind) :: d2r
1369  integer :: is, ie, js, je, nlon, nlat, i, j
1370  integer :: start(4), nread(4), isc2, iec2, jsc2, jec2
1371  type(fmsnetcdffile_t) :: fileobj
1372 
1373  if(.not. open_file(fileobj, grid_file, 'read') ) then
1374  call error_mesg('xgrid_mod(get_grid_version2)', 'Error in opening file '//trim(grid_file), fatal)
1375  endif
1376 
1377  d2r = pi / 180.0_r8_kind
1378 
1379  call mpp_get_compute_domain(grid%domain, is, ie, js, je)
1380 
1381  call get_dimension_size(fileobj, "nx", nlon)
1382  call get_dimension_size(fileobj, "ny", nlat)
1383  if( mod(nlon,2) .NE. 0) call error_mesg('xgrid_mod', &
1384  'flux_exchange_mod: atmos supergrid longitude size can not be divided by 2', fatal)
1385  if( mod(nlat,2) .NE. 0) call error_mesg('xgrid_mod', &
1386  'flux_exchange_mod: atmos supergrid latitude size can not be divided by 2', fatal)
1387  nlon = nlon/2
1388  nlat = nlat/2
1389  if(nlon .NE. grid%im .OR. nlat .NE. grid%jm) call error_mesg('xgrid_mod', &
1390  'grid size in tile_file does not match the global grid size', fatal)
1391 
1392  if( grid_id == 'LND' .or. grid_id == 'ATM' .or. grid_id == 'WAV' ) then
1393  isc2 = 2*grid%is_me-1; iec2 = 2*grid%ie_me+1
1394  jsc2 = 2*grid%js_me-1; jec2 = 2*grid%je_me+1
1395  allocate(tmpx(isc2:iec2, jsc2:jec2) )
1396  allocate(tmpy(isc2:iec2, jsc2:jec2) )
1397  start = 1; nread = 1
1398  start(1) = isc2; nread(1) = iec2 - isc2 + 1
1399  start(2) = jsc2; nread(2) = jec2 - jsc2 + 1
1400  call read_data(fileobj, 'x', tmpx, corner=start, edge_lengths=nread)
1401  call read_data(fileobj, 'y', tmpy, corner=start, edge_lengths=nread)
1402  if(is_lat_lon(tmpx, tmpy) ) then
1403  deallocate(tmpx, tmpy)
1404  start = 1; nread = 1
1405  start(2) = 2; nread(1) = nlon*2+1
1406  allocate(tmpx(nlon*2+1, 1), tmpy(1, nlat*2+1))
1407  call read_data(fileobj, "x", tmpx, corner=start, edge_lengths=nread)
1408  if (associated(grid%lon)) deallocate(grid%lon) !< Check if allocated
1409  if (associated(grid%lat)) deallocate(grid%lat) !< Check if allocated
1410  allocate(grid%lon(grid%im), grid%lat(grid%jm))
1411  do i = 1, grid%im
1412  grid%lon(i) = tmpx(2*i,1) * d2r
1413  end do
1414  start = 1; nread = 1
1415  start(1) = 2; nread(2) = nlat*2+1
1416  call read_data(fileobj, "y", tmpy, corner=start, edge_lengths=nread)
1417  do j = 1, grid%jm
1418  grid%lat(j) = tmpy(1, 2*j) * d2r
1419  end do
1420  grid%is_latlon = .true.
1421  else
1422  if (associated(grid%geolon)) deallocate(grid%geolon) !< Check if allocated
1423  if (associated(grid%geolat)) deallocate(grid%geolat) !< Check if allocated
1424  allocate(grid%geolon(grid%isd_me:grid%ied_me, grid%jsd_me:grid%jed_me))
1425  allocate(grid%geolat(grid%isd_me:grid%ied_me, grid%jsd_me:grid%jed_me))
1426  grid%geolon = 1.0e10_r8_kind
1427  grid%geolat = 1.0e10_r8_kind
1428  !--- area_ocn_sphere, area_lnd_sphere, area_atm_sphere is not been defined.
1429  do j = grid%js_me,grid%je_me
1430  do i = grid%is_me,grid%ie_me
1431  grid%geolon(i, j) = tmpx(i*2,j*2)*d2r
1432  grid%geolat(i, j) = tmpy(i*2,j*2)*d2r
1433  end do
1434  end do
1435  call mpp_update_domains(grid%geolon, grid%domain)
1436  call mpp_update_domains(grid%geolat, grid%domain)
1437  grid%is_latlon = .false.
1438  end if
1439  deallocate(tmpx, tmpy)
1440  end if
1441 
1442  call close_file(fileobj)
1443 
1444 return
1445 
1446 end subroutine get_grid_version2
1447 
1448 !#######################################################################
1449 !> @brief Read the area elements from NetCDF file
1450 subroutine get_area_elements_fms2_io(fileobj, name, get_area_data)
1451  type(fmsnetcdfdomainfile_t), intent(in) :: fileobj
1452  character(len=*), intent(in) :: name
1453  real(r8_kind), intent(out) :: get_area_data(:,:)
1454 
1455  if(variable_exists(fileobj, name)) then
1456  call read_data(fileobj, name, get_area_data)
1457  else
1458  call error_mesg('xgrid_mod', 'no field named '//trim(name)//' in grid file '//trim(fileobj%path)// &
1459  ' Will set data to negative values...', note)
1460  ! area elements no present in grid_spec file, set to negative values....
1461  get_area_data = -1.0_r8_kind
1462  endif
1463 
1464 end subroutine get_area_elements_fms2_io
1465 
1466 !#######################################################################
1467 
1468 !> @brief Read Ocean area element data from netCDF file.
1469 !! @details If available in the NetCDF file, this routine will read the
1470 !! AREA_OCN_MODEL field and load the data into global AREA_OCN_MODEL.
1471 !! If not available, then the array AREA_OCN_MODEL will be left
1472 !! unallocated. Must be called by all PEs.
1473 subroutine get_ocean_model_area_elements(domain, grid_file)
1474 
1475  type(domain2d), intent(in) :: domain
1476  character(len=*), intent(in) :: grid_file
1477  integer :: is, ie, js, je
1478  type(fmsnetcdffile_t) :: fileobj
1479 
1480  if(allocated(area_ocn_model)) return
1481 
1482  call mpp_get_compute_domain(domain, is, ie, js, je)
1483  ! allocate even if ie<is, ... in which case the array will have zero size
1484  ! but will still return .T. for allocated(...)
1485  allocate(area_ocn_model(is:ie, js:je))
1486  if(ie < is .or. je < js ) return
1487 
1488  if(.not. open_file(fileobj, grid_file, 'read') ) then
1489  call error_mesg('xgrid_mod(get_ocean_model_area_elements)', 'Error in opening file '//trim(grid_file), fatal)
1490  endif
1491 
1492  if(variable_exists(fileobj, 'AREA_OCN_MODEL') )then
1493  call read_data(fileobj, 'AREA_OCN_MODEL', area_ocn_model)
1494  else
1495  deallocate(area_ocn_model)
1496  endif
1497  call close_file(fileobj)
1498 
1499 
1500 end subroutine get_ocean_model_area_elements
1501 
1502 !#######################################################################
1503 
1504 !> @brief Sets up exchange grid connectivity using grid specification file and
1505 !! processor domain decomposition.
1506 subroutine setup_xmap(xmap, grid_ids, grid_domains, grid_file, atm_grid, lnd_ug_domain)
1507  type(xmap_type), intent(inout) :: xmap
1508  character(len=3), dimension(:), intent(in ) :: grid_ids
1509  type(domain2d), dimension(:), intent(in ) :: grid_domains
1510  character(len=*), intent(in ) :: grid_file
1511  type(grid_box_type), optional, intent(in ) :: atm_grid
1512  type(domainug), optional, intent(in ) :: lnd_ug_domain
1513 
1514  integer :: g, p, i
1515  integer :: nxgrid_file, i1, i2, i3, tile1, tile2, j
1516  integer :: nxc, nyc, out_unit
1517  type(grid_type), pointer :: grid => null()!< pointer to loop through grid_type's in list
1518  type(grid_type), pointer, save :: grid1 => null() !< saved pointer to the first grid in the list
1519  real(r8_kind), dimension(3) :: xxx
1520  real(r8_kind), dimension(:,:), allocatable :: check_data
1521  real(r8_kind), dimension(:,:,:), allocatable :: check_data_3d
1522  real(r8_kind), allocatable :: tmp_2d(:,:), tmp_3d(:,:,:)
1523  character(len=FMS_FILE_LEN) :: xgrid_file, xgrid_name
1524  character(len=FMS_FILE_LEN) :: tile_file, mosaic_file
1525  character(len=256) :: mosaic1, mosaic2, contact, xgrid_dimname
1526  character(len=256) :: tile1_name, tile2_name
1527  character(len=256), allocatable :: tile1_list(:), tile2_list(:)
1528  character(len=FMS_FILE_LEN), allocatable :: xgrid_filelist(:)
1529  integer :: npes, npes2
1530  integer, allocatable :: pelist(:)
1531  type(domain2d), save :: domain2
1532  logical :: use_higher_order = .false.
1533  integer :: lnd_ug_id, l
1534  integer, allocatable :: grid_index(:)
1535  type(fmsnetcdffile_t) :: gridfileobj, mosaicfileobj, fileobj
1536  type(grid_type), allocatable, target :: grids_tmp(:) !< added for nvhpc workaround, stores xmap's
1537  !! grid_type array so we can safely point to it
1538 
1539  call mpp_clock_begin(id_setup_xmap)
1540 
1541  if(interp_method .ne. 'first_order') use_higher_order = .true.
1542 
1543  out_unit = stdout()
1544  xmap%me = mpp_pe()
1545  xmap%npes = mpp_npes()
1546  xmap%root_pe = mpp_root_pe()
1547 
1548  if (associated(xmap%grids)) deallocate(xmap%grids) !< Check if allocated
1549  allocate( xmap%grids(1:size(grid_ids(:))) )
1550 
1551  if (associated(xmap%your1my2)) deallocate(xmap%your1my2) !< Check if allocated
1552  if (associated(xmap%your2my1)) deallocate(xmap%your2my1) !< Check if allocated
1553  if (associated(xmap%your2my1_size)) deallocate(xmap%your2my1_size) !< Check if allocated
1554  allocate ( xmap%your1my2(0:xmap%npes-1), xmap%your2my1(0:xmap%npes-1) )
1555  allocate ( xmap%your2my1_size(0:xmap%npes-1) )
1556 
1557  xmap%your1my2 = .false.; xmap%your2my1 = .false.;
1558  xmap%your2my1_size = 0
1559 
1560  if(.not. open_file(gridfileobj,trim(grid_file), "read")) then
1561  call error_mesg('xgrid_mod', 'Error when opening file'//trim(grid_file), fatal)
1562  endif
1563 
1564 ! check the exchange grid file version to be used by checking the field in the file
1565  if(variable_exists(gridfileobj, "AREA_ATMxOCN" ) ) then
1566  call close_file(gridfileobj)
1567  xmap%version = version1
1568  else if(variable_exists(gridfileobj, "ocn_mosaic_file" ) ) then
1569  xmap%version = version2
1570  else
1571  call error_mesg('xgrid_mod', 'both AREA_ATMxOCN and ocn_mosaic_file does not exist in '//trim(grid_file), fatal)
1572  end if
1573 
1574 
1575  if(xmap%version==version1) then
1576  call error_mesg('xgrid_mod', 'reading exchange grid information from grid spec file', note)
1577  else
1578  call error_mesg('xgrid_mod', 'reading exchange grid information from mosaic grid file', note)
1579  end if
1580 
1581  ! check to see the id of lnd.
1582  lnd_ug_id = 0
1583  if(present(lnd_ug_domain)) then
1584  do g=1,size(grid_ids(:))
1585  if(grid_ids(g) == 'LND') lnd_ug_id = g
1586  enddo
1587  endif
1588 
1589  call mpp_clock_begin(id_load_xgrid)
1590 
1591  ! nvhpc compiler workaround
1592  ! saves grid array as an allocatable and points to that to avoid error from pointing to xmap%grids in loop
1593  grids_tmp = xmap%grids
1594 
1595  grid1 => xmap%grids(1)
1596 
1597  do g=1, size(grid_ids(:))
1598 
1599  grid => grids_tmp(g)
1600 
1601  grid%id = grid_ids(g)
1602  grid%domain = grid_domains(g)
1603  grid%on_this_pe = mpp_domain_is_initialized(grid_domains(g))
1604  if (associated(grid%is)) deallocate(grid%is) !< Check if allocated
1605  if (associated(grid%ie)) deallocate(grid%ie) !< Check if allocated
1606  if (associated(grid%js)) deallocate(grid%js) !< Check if allocated
1607  if (associated(grid%je)) deallocate(grid%je) !< Check if allocated
1608  if (associated(grid%tile)) deallocate(grid%tile) !< Check if allocated
1609  allocate ( grid%is(0:xmap%npes-1), grid%ie(0:xmap%npes-1) )
1610  allocate ( grid%js(0:xmap%npes-1), grid%je(0:xmap%npes-1) )
1611  allocate ( grid%tile(0:xmap%npes-1) )
1612  grid%npes = 0
1613  grid%ni = 0
1614  grid%nj = 0
1615  grid%is = 0
1616  grid%ie = -1
1617  grid%js = 0
1618  grid%je = -1
1619  grid%tile = -1
1620 
1621  select case(xmap%version)
1622  case(version1)
1623  grid%ntile = 1
1624  case(version2)
1625  call read_data(gridfileobj, lowercase(grid_ids(g))//'_mosaic_file', mosaic_file)
1626  if(.not. open_file(mosaicfileobj,'INPUT/'//trim(mosaic_file), "read")) then
1627  call error_mesg('xgrid_mod', 'Error when opening solo mosaic file INPUT/'//trim(mosaic_file), fatal)
1628  endif
1629  call get_dimension_size(mosaicfileobj, 'ntiles', grid%ntile)
1630  end select
1631 
1632  if( g == 1 .AND. grid_ids(1) == 'ATM' ) then
1633  if( .NOT. grid%on_this_pe ) call error_mesg('xgrid_mod', 'ATM domain is not defined on some processor' ,fatal)
1634  endif
1635  grid%npes = mpp_get_domain_npes(grid%domain)
1636  if( xmap%npes > grid%npes .AND. g == 1 .AND. grid_ids(1) == 'ATM' ) then
1637  call mpp_broadcast_domain(grid%domain, domain2)
1638  else if(xmap%npes > grid%npes) then
1639  call mpp_broadcast_domain(grid%domain)
1640  grid%npes = mpp_get_domain_npes(grid%domain)
1641  endif
1642 
1643  npes = grid%npes
1644  allocate(grid%pelist(0:npes-1))
1645  call mpp_get_domain_pelist(grid%domain, grid%pelist)
1646  grid%root_pe = mpp_get_domain_root_pe(grid%domain)
1647 
1648  call mpp_get_data_domain(grid%domain, grid%isd_me, grid%ied_me, grid%jsd_me, grid%jed_me, &
1649  xsize=grid%nxd_me, ysize=grid%nyd_me)
1650  call mpp_get_global_domain(grid%domain, xsize=grid%ni, ysize=grid%nj)
1651 
1652  if( grid%root_pe == xmap%root_pe ) then
1653  call mpp_get_compute_domains(grid%domain, xbegin=grid%is(0:npes-1), xend=grid%ie(0:npes-1), &
1654  ybegin=grid%js(0:npes-1), yend=grid%je(0:npes-1) )
1655  call mpp_get_tile_list(grid%domain, grid%tile(0:npes-1))
1656  if( xmap%npes > npes .AND. g == 1 .AND. grid_ids(1) == 'ATM' ) then
1657  call mpp_get_compute_domains(domain2, xbegin=grid%is(npes:xmap%npes-1), xend=grid%ie(npes:xmap%npes-1), &
1658  ybegin=grid%js(npes:xmap%npes-1), yend=grid%je(npes:xmap%npes-1) )
1659  call mpp_get_tile_list(domain2, grid%tile(npes:xmap%npes-1))
1660  endif
1661  else
1662  npes2 = xmap%npes-npes
1663  call mpp_get_compute_domains(domain2, xbegin=grid%is(0:npes2-1), xend=grid%ie(0:npes2-1), &
1664  ybegin=grid%js(0:npes2-1), yend=grid%je(0:npes2-1) )
1665  call mpp_get_compute_domains(grid%domain, xbegin=grid%is(npes2:xmap%npes-1), xend=grid%ie(npes2:xmap%npes-1), &
1666  ybegin=grid%js(npes2:xmap%npes-1), yend=grid%je(npes2:xmap%npes-1) )
1667  call mpp_get_tile_list(domain2, grid%tile(0:npes2-1))
1668  call mpp_get_tile_list(grid%domain, grid%tile(npes2:xmap%npes-1))
1669  endif
1670  if( xmap%npes > grid%npes .AND. g == 1 .AND. grid_ids(1) == 'ATM' ) then
1671  call mpp_deallocate_domain(domain2)
1672  endif
1673  npes = grid%npes
1674  if( g == 1 .AND. grid_ids(1) == 'ATM' ) npes = xmap%npes
1675  do p = 0, npes-1
1676  if(grid%tile(p) > grid%ntile .or. grid%tile(p) < 1) call error_mesg('xgrid_mod', &
1677  'tile id should between 1 and ntile', fatal)
1678  end do
1679 
1680  grid%im = grid%ni
1681  grid%jm = grid%nj
1682  call mpp_max(grid%ni)
1683  call mpp_max(grid%nj)
1684 
1685  grid%is_me => grid%is(xmap%me-xmap%root_pe); grid%ie_me => grid%ie(xmap%me-xmap%root_pe)
1686  grid%js_me => grid%js(xmap%me-xmap%root_pe); grid%je_me => grid%je(xmap%me-xmap%root_pe)
1687  grid%nxc_me = grid%ie_me - grid%is_me + 1
1688  grid%nyc_me = grid%je_me - grid%js_me + 1
1689  grid%tile_me => grid%tile(xmap%me-xmap%root_pe)
1690 
1691  grid%km = 1
1692  grid%is_ug = .false.
1693  !--- setup for land unstructure grid
1694  if( g == lnd_ug_id ) then
1695  if(xmap%version == version1) call error_mesg('xgrid_mod', &
1696  'does not support unstructured grid for VERSION1 grid' ,fatal)
1697  grid%is_ug = .true.
1698  grid%ug_domain = lnd_ug_domain
1699  if (associated(grid%ls)) deallocate(grid%ls) !< Check if allocated
1700  if (associated(grid%le)) deallocate(grid%le) !< Check if allocated
1701  if (associated(grid%gs)) deallocate(grid%gs) !< Check if allocated
1702  if (associated(grid%ge)) deallocate(grid%ge) !< Check if allocated
1703  allocate ( grid%ls(0:xmap%npes-1), grid%le(0:xmap%npes-1) )
1704  allocate ( grid%gs(0:xmap%npes-1), grid%ge(0:xmap%npes-1) )
1705  grid%ls = 0
1706  grid%le = -1
1707  grid%gs = 0
1708  grid%ge = -1
1709  if(xmap%npes > grid%npes) then
1710  call mpp_broadcast_domain(grid%ug_domain)
1711  endif
1712  call mpp_get_ug_compute_domains(grid%ug_domain, begin=grid%ls(0:npes-1), end=grid%le(0:npes-1) )
1713  call mpp_get_ug_domains_index(grid%ug_domain, grid%gs(0:npes-1), grid%ge(0:npes-1) )
1714  call mpp_get_ug_domain_tile_list(grid%ug_domain, grid%tile(0:npes-1))
1715  grid%ls_me => grid%ls(xmap%me-xmap%root_pe); grid%le_me => grid%le(xmap%me-xmap%root_pe)
1716  grid%gs_me => grid%gs(xmap%me-xmap%root_pe); grid%ge_me => grid%ge(xmap%me-xmap%root_pe)
1717  grid%tile_me => grid%tile(xmap%me-xmap%root_pe)
1718  grid%nxl_me = grid%le_me - grid%ls_me + 1
1719  if (associated(grid%l_index)) deallocate(grid%l_index) !< Check if allocated
1720  allocate(grid%l_index(grid%gs_me:grid%ge_me))
1721  allocate(grid_index(grid%ls_me:grid%le_me))
1722  call mpp_get_ug_domain_grid_index(grid%ug_domain, grid_index)
1723 
1724  grid%l_index = 0
1725  do l = grid%ls_me,grid%le_me
1726  grid%l_index(grid_index(l)) = l
1727  enddo
1728 
1729  if( grid%on_this_pe ) then
1730  if (associated(grid%area)) deallocate(grid%area) !< Check if allocated
1731  if (associated(grid%area_inv)) deallocate(grid%area_inv) !< Check if allocated
1732  allocate( grid%area (grid%ls_me:grid%le_me,1) )
1733  allocate( grid%area_inv(grid%ls_me:grid%le_me,1) )
1734  grid%area = 0.0_r8_kind
1735  grid%size = 0
1736  grid%size_repro = 0
1737  endif
1738  else if( grid%on_this_pe ) then
1739  if (associated(grid%area)) deallocate(grid%area) !< Check if allocated
1740  if (associated(grid%area_inv)) deallocate(grid%area_inv) !< Check if allocated
1741  allocate( grid%area (grid%is_me:grid%ie_me, grid%js_me:grid%je_me) )
1742  allocate( grid%area_inv(grid%is_me:grid%ie_me, grid%js_me:grid%je_me) )
1743  grid%area = 0.0_r8_kind
1744  grid%size = 0
1745  grid%size_repro = 0
1746  endif
1747 
1748  ! get the center point of the grid box
1749  if(.not. grid%is_ug) then
1750  select case(xmap%version)
1751  case(version1)
1752  if( grid%npes .NE. xmap%npes ) then
1753  call error_mesg('xgrid_mod', .NE.' grid%npes xmap%npes ', fatal)
1754  endif
1755  call get_grid_version1(grid, grid_ids(g), grid_file)
1756  case(version2)
1757  allocate(pelist(0:xmap%npes-1))
1758  call mpp_get_current_pelist(pelist)
1759  if( grid%on_this_pe ) then
1760  call mpp_set_current_pelist(grid%pelist)
1761  call get_mosaic_tile_grid(tile_file, mosaicfileobj, grid%domain)
1762  call get_grid_version2(grid, grid_ids(g), tile_file)
1763  endif
1764  call mpp_set_current_pelist(pelist)
1765  deallocate(pelist)
1766  ! read the contact information from mosaic_file to check if atmosphere is nested model
1767  if( g == 1 .AND. grid_ids(1) == 'ATM' ) then
1768  nnest = get_nest_contact(mosaicfileobj, tile_nest, tile_parent, is_nest, &
1769  ie_nest, js_nest, je_nest, is_parent, ie_parent, js_parent, je_parent)
1770 
1771  endif
1772  end select
1773 
1774  if( use_higher_order .AND. grid%id == 'ATM') then
1775  if( nnest > 0 ) call error_mesg('xgrid_mod', 'second_order is not supported for nested coupler', fatal)
1776  if( grid%is_latlon ) then
1777  call mpp_modify_domain(grid%domain, grid%domain_with_halo, whalo=1, ehalo=1, shalo=1, nhalo=1)
1778  call mpp_get_data_domain(grid%domain_with_halo, grid%isd_me, grid%ied_me, grid%jsd_me, grid%jed_me, &
1779  xsize=grid%nxd_me, ysize=grid%nyd_me)
1780  else
1781  if(.NOT. present(atm_grid)) call error_mesg('xgrid_mod', &
1782  'when first grid is "ATM", atm_grid should be present', fatal)
1783  if(grid%is_me-grid%isd_me .NE. 1 .or. grid%ied_me-grid%ie_me .NE. 1 .or. &
1784  grid%js_me-grid%jsd_me .NE. 1 .or. grid%jed_me-grid%je_me .NE. 1 ) &
1785  & call error_mesg('xgrid_mod', 'for non-latlon grid (cubic grid), '//&
1786  & 'the halo size should be 1 in all four direction', fatal)
1787  if(.NOT.( ASSOCIATED(atm_grid%dx) .AND. ASSOCIATED(atm_grid%dy) .AND. ASSOCIATED(atm_grid%edge_w) .AND. &
1788  ASSOCIATED(atm_grid%edge_e) .AND. ASSOCIATED(atm_grid%edge_s) .AND.ASSOCIATED(atm_grid%edge_n).AND.&
1789  ASSOCIATED(atm_grid%en1) .AND. ASSOCIATED(atm_grid%en2) .AND. ASSOCIATED(atm_grid%vlon) .AND. &
1790  ASSOCIATED(atm_grid%vlat) ) ) call error_mesg( 'xgrid_mod', &
1791  'for non-latlon grid (cubic grid), all the fields in atm_grid data type should be allocated', fatal)
1792  nxc = grid%ie_me - grid%is_me + 1
1793  nyc = grid%je_me - grid%js_me + 1
1794  if(size(atm_grid%dx,1) .NE. nxc .OR. size(atm_grid%dx,2) .NE. nyc+1) &
1795  call error_mesg('xgrid_mod', 'incorrect dimension size of atm_grid%dx', fatal)
1796  if(size(atm_grid%dy,1) .NE. nxc+1 .OR. size(atm_grid%dy,2) .NE. nyc) &
1797  call error_mesg('xgrid_mod', 'incorrect dimension sizeof atm_grid%dy', fatal)
1798  if(size(atm_grid%area,1) .NE. nxc .OR. size(atm_grid%area,2) .NE. nyc) &
1799  call error_mesg('xgrid_mod', 'incorrect dimension size of atm_grid%area', fatal)
1800  if(size(atm_grid%edge_w(:)) .NE. nyc+1 .OR. size(atm_grid%edge_e(:)) .NE. nyc+1) &
1801  call error_mesg('xgrid_mod', 'incorrect dimension size of atm_grid%edge_w/edge_e', fatal)
1802  if(size(atm_grid%edge_s(:)) .NE. nxc+1 .OR. size(atm_grid%edge_n(:)) .NE. nxc+1) &
1803  call error_mesg('xgrid_mod', 'incorrect dimension size of atm_grid%edge_s/edge_n', fatal)
1804  if(size(atm_grid%en1,1) .NE. 3 .OR. size(atm_grid%en1,2) .NE. nxc .OR. size(atm_grid%en1,3) .NE. nyc+1) &
1805  call error_mesg( 'xgrid_mod', 'incorrect dimension size of atm_grid%en1', fatal)
1806  if(size(atm_grid%en2,1) .NE. 3 .OR. size(atm_grid%en2,2) .NE. nxc+1 .OR. size(atm_grid%en2,3) .NE. nyc) &
1807  call error_mesg( 'xgrid_mod', 'incorrect dimension size of atm_grid%en2', fatal)
1808  if(size(atm_grid%vlon,1) .NE. 3 .OR. size(atm_grid%vlon,2) .NE. nxc .OR. size(atm_grid%vlon,3) .NE. nyc)&
1809  call error_mesg('xgrid_mod', 'incorrect dimension size of atm_grid%vlon', fatal)
1810  if(size(atm_grid%vlat,1) .NE. 3 .OR. size(atm_grid%vlat,2) .NE. nxc .OR. size(atm_grid%vlat,3) .NE. nyc)&
1811  call error_mesg('xgrid_mod', 'incorrect dimension size of atm_grid%vlat', fatal)
1812  if (associated(grid%box%dx)) deallocate(grid%box%dx) !< Check if allocated
1813  if (associated(grid%box%dy)) deallocate(grid%box%dy) !< Check if allocated
1814  if (associated(grid%box%area)) deallocate(grid%box%area) !< Check if allocated
1815  if (associated(grid%box%edge_w)) deallocate(grid%box%edge_w) !< Check if allocated
1816  if (associated(grid%box%edge_e)) deallocate(grid%box%edge_e) !< Check if allocated
1817  if (associated(grid%box%edge_s)) deallocate(grid%box%edge_s) !< Check if allocated
1818  if (associated(grid%box%edge_n)) deallocate(grid%box%edge_n) !< Check if allocated
1819  if (associated(grid%box%en1)) deallocate(grid%box%en1) !< Check if allocated
1820  if (associated(grid%box%en2)) deallocate(grid%box%en2) !< Check if allocated
1821  if (associated(grid%box%vlon)) deallocate(grid%box%vlon) !< Check if allocated
1822  if (associated(grid%box%vlat)) deallocate(grid%box%vlat) !< Check if allocated
1823  allocate(grid%box%dx (grid%is_me:grid%ie_me, grid%js_me:grid%je_me+1 ))
1824  allocate(grid%box%dy (grid%is_me:grid%ie_me+1, grid%js_me:grid%je_me ))
1825  allocate(grid%box%area (grid%is_me:grid%ie_me, grid%js_me:grid%je_me ))
1826  allocate(grid%box%edge_w(grid%js_me:grid%je_me+1))
1827  allocate(grid%box%edge_e(grid%js_me:grid%je_me+1))
1828  allocate(grid%box%edge_s(grid%is_me:grid%ie_me+1))
1829  allocate(grid%box%edge_n(grid%is_me:grid%ie_me+1))
1830  allocate(grid%box%en1 (3, grid%is_me:grid%ie_me, grid%js_me:grid%je_me+1 ))
1831  allocate(grid%box%en2 (3, grid%is_me:grid%ie_me+1, grid%js_me:grid%je_me ))
1832  allocate(grid%box%vlon (3, grid%is_me:grid%ie_me, grid%js_me:grid%je_me ))
1833  allocate(grid%box%vlat (3, grid%is_me:grid%ie_me, grid%js_me:grid%je_me ))
1834  grid%box%dx = atm_grid%dx
1835  grid%box%dy = atm_grid%dy
1836  grid%box%area = atm_grid%area
1837  grid%box%edge_w = atm_grid%edge_w
1838  grid%box%edge_e = atm_grid%edge_e
1839  grid%box%edge_s = atm_grid%edge_s
1840  grid%box%edge_n = atm_grid%edge_n
1841  grid%box%en1 = atm_grid%en1
1842  grid%box%en2 = atm_grid%en2
1843  grid%box%vlon = atm_grid%vlon
1844  grid%box%vlat = atm_grid%vlat
1845  end if
1846  end if
1847  end if
1848  if(xmap%version==version2) call close_file(mosaicfileobj)
1849  if (g>1) then
1850  if(grid%on_this_pe) then
1851  if (associated(grid%frac_area)) deallocate(grid%frac_area) !< Check if allocated
1852  if(grid%is_ug) then
1853  allocate( grid%frac_area(grid%ls_me:grid%le_me, 1, grid%km) )
1854  else
1855  allocate( grid%frac_area(grid%is_me:grid%ie_me, grid%js_me:grid%je_me, grid%km) )
1856  endif
1857  grid%frac_area = 1.0_r8_kind
1858  endif
1859 
1860  ! nvhpc workaround, needs to save the grid pointer since its allocatable
1861  xmap%grids(g) = grid
1862 
1863  ! load exchange cells, sum grid cell areas, set your1my2/your2my1
1864  select case(xmap%version)
1865  case(version1)
1866  call load_xgrid (xmap, grid, grid_file, grid_ids(1), grid_ids(g), 1, 1, use_higher_order)
1867  case(version2)
1868  select case(grid_ids(1))
1869  case( 'ATM' )
1870  xgrid_name = 'a'
1871  case( 'LND' )
1872  xgrid_name = 'l'
1873  case( 'WAV' )
1874  xgrid_name = 'w'
1875  case default
1876  call error_mesg('xgrid_mod', 'grid_ids(1) should be ATM, LND or WAV', fatal)
1877  end select
1878  select case(grid_ids(g))
1879  case( 'LND' )
1880  xgrid_dimname = 'nfile_'//trim(xgrid_name)//'Xl'
1881  xgrid_name = trim(xgrid_name)//'Xl_file'
1882  case( 'OCN' )
1883  xgrid_dimname = 'nfile_'//trim(xgrid_name)//'Xo'
1884  xgrid_name = trim(xgrid_name)//'Xo_file'
1885  case( 'WAV' )
1886  xgrid_dimname = 'nfile_'//trim(xgrid_name)//'Xw'
1887  xgrid_name = trim(xgrid_name)//'Xw_file'
1888  case default
1889  call error_mesg('xgrid_mod', 'grid_ids(g) should be LND, OCN or WAV', fatal)
1890  end select
1891  ! get the tile list for each mosaic
1892 
1893  call read_data(gridfileobj, lowercase(grid_ids(1))//'_mosaic_file', mosaic1)
1894  call read_data(gridfileobj, lowercase(grid_ids(g))//'_mosaic_file', mosaic2)
1895 
1896  mosaic1 = 'INPUT/'//trim(mosaic1)
1897  mosaic2 = 'INPUT/'//trim(mosaic2)
1898 
1899  allocate(tile1_list(grid1%ntile), tile2_list(grid%ntile) )
1900  if(.not. open_file(fileobj,mosaic1, "read")) then
1901  call error_mesg('xgrid_mod(setup_xmap)', 'Error when opening mosaic1 file '//trim(mosaic1), fatal)
1902  endif
1903  call read_data(fileobj, 'gridtiles', tile1_list)
1904  call close_file(fileobj)
1905 
1906  if(.not. open_file(fileobj,mosaic2, "read")) then
1907  call error_mesg('xgrid_mod(setup_xmap)', 'Error when opening mosaic2 file '//trim(mosaic2), fatal)
1908  endif
1909  call read_data(fileobj, 'gridtiles', tile2_list)
1910  call close_file(fileobj)
1911 
1912  if(variable_exists(gridfileobj, xgrid_name)) then
1913  call get_dimension_size(gridfileobj, xgrid_dimname, nxgrid_file)
1914  if(nxgrid_file>0) then
1915  allocate(xgrid_filelist(nxgrid_file))
1916  call read_data(gridfileobj, xgrid_name, xgrid_filelist)
1917  endif
1918  ! loop through all the exchange grid file
1919  do i = 1, nxgrid_file
1920  xgrid_file = 'INPUT/'//trim(xgrid_filelist(i))
1921  if(.not. open_file(fileobj,xgrid_file, "read")) then
1922  call error_mesg('xgrid_mod(setup_xmap)', 'Error when opening xgrid file '// &
1923  & trim(xgrid_file), fatal)
1924  endif
1925 
1926  ! find the tile number of side 1 and side 2 mosaic, which is contained in field contact
1927  call read_data(fileobj, "contact", contact)
1928  i1 = index(contact, ":")
1929  i2 = index(contact, "::")
1930  i3 = index(contact, ":", back=.true. )
1931  if(i1 == 0 .OR. i2 == 0) call error_mesg('xgrid_mod', &
1932  'field contact in file '//trim(xgrid_file)//' should contains ":" and "::" ', fatal)
1933  if(i1 == i3) call error_mesg('xgrid_mod', &
1934  'field contact in file '//trim(xgrid_file)//' should contains two ":"', fatal)
1935  tile1_name = contact(i1+1:i2-1)
1936  tile2_name = contact(i3+1:len_trim(contact))
1937  tile1 = 0; tile2 = 0
1938  do j = 1, grid1%ntile
1939  if( trim(tile1_name) == trim(tile1_list(j)) ) then
1940  tile1 = j
1941  exit
1942  end if
1943  end do
1944  do j = 1, grid%ntile
1945  if( tile2_name == tile2_list(j) ) then
1946  tile2 = j
1947  exit
1948  end if
1949  end do
1950 
1951  if(tile1 == 0) call error_mesg('xgrid_mod', &
1952  trim(tile1_name)//' is not a tile of mosaic '//trim(mosaic1), fatal)
1953  if(tile2 == 0) call error_mesg('xgrid_mod', &
1954  trim(tile2_name)//' is not a tile of mosaic '//trim(mosaic2), fatal)
1955  call close_file(fileobj)
1956  call load_xgrid (xmap, grid, xgrid_file, grid_ids(1), grid_ids(g), tile1, tile2, &
1957  use_higher_order)
1958  end do
1959  deallocate(xgrid_filelist)
1960  endif
1961  deallocate(tile1_list, tile2_list)
1962  end select
1963  if(grid%on_this_pe) then
1964  grid%area_inv = 0.0_r8_kind;
1965  where (grid%area>0.0_r8_kind) grid%area_inv = 1.0_r8_kind/grid%area
1966  endif
1967  end if
1968 
1969  ! nvhpc workaround, needs to save the grid pointer since its allocatable
1970  xmap%grids(g) = grid
1971  end do
1972 
1973  if(xmap%version == version2) call close_file(gridfileobj)
1974 
1975  call mpp_clock_end(id_load_xgrid)
1976 
1977  grid1%area_inv = 0.0_r8_kind;
1978  where (grid1%area>0.0_r8_kind)
1979  grid1%area_inv = 1.0_r8_kind/grid1%area
1980  end where
1981 
1982  xmap%your1my2(xmap%me-xmap%root_pe) = .false. ! this is not necessarily true but keeps
1983  xmap%your2my1(xmap%me-xmap%root_pe) = .false. ! a PE from communicating with itself
1984 
1985  if (make_exchange_reproduce) then
1986  if (associated(xmap%send_count_repro)) deallocate(xmap%send_count_repro) !< Check if allocated
1987  if (associated(xmap%recv_count_repro)) deallocate(xmap%recv_count_repro) !< Check if allocated
1988  allocate( xmap%send_count_repro(0:xmap%npes-1) )
1989  allocate( xmap%recv_count_repro(0:xmap%npes-1) )
1990  xmap%send_count_repro = 0
1991  xmap%recv_count_repro = 0
1992  do g=2,size(xmap%grids(:))
1993  do p=0,xmap%npes-1
1994  if(xmap%grids(g)%size >0) &
1995  xmap%send_count_repro(p) = xmap%send_count_repro(p) &
1996  +count(xmap%grids(g)%x (:)%pe==p+xmap%root_pe)
1997  if(xmap%grids(g)%size_repro >0) &
1998  xmap%recv_count_repro(p) = xmap%recv_count_repro(p) &
1999  +count(xmap%grids(g)%x_repro(:)%pe==p+xmap%root_pe)
2000  end do
2001  end do
2002  xmap%send_count_repro_tot = sum(xmap%send_count_repro)
2003  xmap%recv_count_repro_tot = sum(xmap%recv_count_repro)
2004  else
2005  xmap%send_count_repro_tot = 0
2006  xmap%recv_count_repro_tot = 0
2007  end if
2008 
2009  if (associated(xmap%x1)) deallocate(xmap%x1) !< Check if allocated
2010  if (associated(xmap%x2)) deallocate(xmap%x2) !< Check if allocated
2011  if (associated(xmap%x1_put)) deallocate(xmap%x1_put) !< Check if allocated
2012  if (associated(xmap%x2_get)) deallocate(xmap%x2_get) !< Check if allocated
2013  allocate( xmap%x1(1:sum(xmap%grids(2:size(xmap%grids(:)))%size)) )
2014  allocate( xmap%x2(1:sum(xmap%grids(2:size(xmap%grids(:)))%size)) )
2015  allocate( xmap%x1_put(1:sum(xmap%grids(2:size(xmap%grids(:)))%size)) )
2016  allocate( xmap%x2_get(1:sum(xmap%grids(2:size(xmap%grids(:)))%size)) )
2017 
2018  !--- The following will setup indx to be used in regen
2019  if (associated(xmap%get1)) deallocate(xmap%get1) !< Check if allocated
2020  if (associated(xmap%put1)) deallocate(xmap%put1) !< Check if allocated
2021  allocate(xmap%get1, xmap%put1)
2022  call mpp_clock_begin(id_set_comm)
2023 
2024  call set_comm_get1(xmap)
2025 
2026  call set_comm_put1(xmap)
2027 
2028  if(make_exchange_reproduce) then
2029  if (associated(xmap%get1_repro)) deallocate(xmap%get1_repro) !< Check if allocated
2030  allocate(xmap%get1_repro)
2031  call set_comm_get1_repro(xmap)
2032  endif
2033 
2034  call mpp_clock_end(id_set_comm)
2035 
2036  call mpp_clock_begin(id_regen)
2037  call regen(xmap)
2038  call mpp_clock_end(id_regen)
2039 
2040  call mpp_clock_begin(id_conservation_check)
2041 
2042  if(lnd_ug_id ==0) then
2043  xxx = conservation_check(grid1%area*0.0_r8_kind+1.0_r8_kind, grid1%id, xmap)
2044  else
2045  allocate(tmp_2d(grid1%is_me:grid1%ie_me, grid1%js_me:grid1%je_me))
2046  tmp_2d = 1.0_r8_kind
2047  xxx = conservation_check_ug(tmp_2d, grid1%id, xmap)
2048  deallocate(tmp_2d)
2049  endif
2050  write(out_unit,* )"Checked data is array of constant 1"
2051  write(out_unit,* )grid1%id,'(',xmap%grids(:)%id,')=', xxx
2052 
2053  if(lnd_ug_id == 0) then
2054  do g=2,size(xmap%grids(:))
2055  xxx = conservation_check(xmap%grids(g)%frac_area*0.0_r8_kind+1.0_r8_kind, xmap%grids(g)%id, xmap )
2056  write( out_unit,* )xmap%grids(g)%id,'(',xmap%grids(:)%id,')=', xxx
2057  enddo
2058  else
2059  do g=2,size(xmap%grids(:))
2060  grid => xmap%grids(g)
2061  allocate(tmp_3d(grid%is_me:grid%ie_me, grid%js_me:grid%je_me,grid%km))
2062  tmp_3d = 1.0_r8_kind
2063  xxx = conservation_check_ug(tmp_3d, xmap%grids(g)%id, xmap )
2064  write( out_unit,* )xmap%grids(g)%id,'(',xmap%grids(:)%id,')=', xxx
2065  deallocate(tmp_3d)
2066  enddo
2067  endif
2068  ! create an random number 2d array
2069  if(grid1%id == "ATM") then
2070  allocate(check_data(size(grid1%area,1), size(grid1%area,2)))
2071  call random_number(check_data)
2072 
2073  !--- second order along both zonal and meridinal direction
2074  if(lnd_ug_id ==0) then
2075  xxx = conservation_check(check_data, grid1%id, xmap, remap_method = remapping_method )
2076  else
2077  xxx = conservation_check_ug(check_data, grid1%id, xmap, remap_method = remapping_method )
2078  endif
2079  write( out_unit,* ) &
2080  "Checked data is array of random number between 0 and 1 using "//trim(interp_method)
2081  write( out_unit,* )grid1%id,'(',xmap%grids(:)%id,')=', xxx
2082 
2083  deallocate(check_data)
2084  do g=2,size(xmap%grids(:))
2085  allocate(check_data_3d(xmap%grids(g)%is_me:xmap%grids(g)%ie_me, &
2086  xmap%grids(g)%js_me:xmap%grids(g)%je_me, grid1%km))
2087  call random_number(check_data_3d)
2088  if(lnd_ug_id ==0) then
2089  xxx = conservation_check(check_data_3d, xmap%grids(g)%id, xmap, remap_method = remapping_method )
2090  else
2091  xxx = conservation_check_ug(check_data_3d, xmap%grids(g)%id, xmap, remap_method = remapping_method )
2092  endif
2093  write( out_unit,* )xmap%grids(g)%id,'(',xmap%grids(:)%id,')=', xxx
2094  deallocate( check_data_3d)
2095  end do
2096  endif
2097  call mpp_clock_end(id_conservation_check)
2098 
2099  call mpp_clock_end(id_setup_xmap)
2100 
2101 end subroutine setup_xmap
2102 
2103 !----------------------------------------------------------------------------
2104 
2105 !> @brief currently we are assuming there is only one nest region
2106 !! @return integer get_nest_contact
2107 function get_nest_contact_fms2_io(fileobj, tile_nest_out, tile_parent_out, is_nest_out, &
2108  ie_nest_out, js_nest_out, je_nest_out, is_parent_out, &
2109  ie_parent_out, js_parent_out, je_parent_out) &
2110  result(get_nest_contact)
2111 type(fmsnetcdffile_t), intent(in) :: fileobj
2112 integer, intent(out) :: tile_nest_out, tile_parent_out
2113 integer, intent(out) :: is_nest_out, ie_nest_out
2114 integer, intent(out) :: js_nest_out, je_nest_out
2115 integer, intent(out) :: is_parent_out, ie_parent_out
2116 integer, intent(out) :: js_parent_out, je_parent_out
2117 integer :: get_nest_contact
2118 !--- local variables
2119 integer :: ntiles, ncontacts, n, t1, t2
2120 integer :: nx1_contact, ny1_contact
2121 integer :: nx2_contact, ny2_contact
2122 integer, allocatable, dimension(:) :: nx, ny
2123 integer, allocatable, dimension(:) :: tile1, tile2
2124 integer, allocatable, dimension(:) :: istart1, iend1, jstart1, jend1
2125 integer, allocatable, dimension(:) :: istart2, iend2, jstart2, jend2
2126 
2127  tile_nest_out = 0; tile_parent_out = 0
2128  is_nest_out = 0; ie_nest_out = 0
2129  js_nest_out = 0; je_nest_out = 0
2130  is_parent_out = 0; ie_parent_out = 0
2131  js_parent_out = 0; je_parent_out = 0
2132  get_nest_contact = 0
2133 
2134  ! first read the contact information
2135  ntiles = get_mosaic_ntiles(fileobj)
2136  if( ntiles == 1 ) return
2137 
2138  allocate(nx(ntiles), ny(ntiles))
2139  call get_mosaic_grid_sizes(fileobj, nx, ny)
2140 
2141  ncontacts = get_mosaic_ncontacts(fileobj)
2142  if(ncontacts == 0) return
2143  allocate(tile1(ncontacts), tile2(ncontacts))
2144  allocate(istart1(ncontacts), iend1(ncontacts))
2145  allocate(jstart1(ncontacts), jend1(ncontacts))
2146  allocate(istart2(ncontacts), iend2(ncontacts))
2147  allocate(jstart2(ncontacts), jend2(ncontacts))
2148 
2149  call get_mosaic_contact( fileobj, tile1, tile2, istart1, iend1, jstart1, jend1, &
2150  istart2, iend2, jstart2, jend2)
2151 
2152  do n = 1, ncontacts
2153  if( tile1(n) == tile2(n) ) cycle ! same tile could not be nested
2154 
2155  nx1_contact = iend1(n)-istart1(n)+1
2156  ny1_contact = jend1(n)-jstart1(n)+1
2157  nx2_contact = iend2(n)-istart2(n)+1
2158  ny2_contact = jend2(n)-jstart2(n)+1
2159  t1 = tile1(n);
2160  t2 = tile2(n);
2161  ! For nesting, the contact index of one tile must match its global domain
2162  if( (nx(t1) .NE. nx1_contact .OR. ny(t1) .NE. ny1_contact ) .AND. &
2163  (nx(t2) .NE. nx2_contact .OR. ny(t2) .NE. ny2_contact ) ) cycle
2164  if(nx1_contact == nx2_contact .AND. ny1_contact == ny2_contact) then
2165  call error_mesg('xgrid_mod', 'There is no refinement for the overlapping region', fatal)
2166  endif
2167 
2169  if(get_nest_contact>1) then
2170  call error_mesg('xgrid_mod', 'only support one nest region, contact developer' ,fatal)
2171  endif
2172  if(nx2_contact*ny2_contact > nx1_contact*ny1_contact) then
2173  is_nest_out = istart2(n);
2174  ie_nest_out = iend2(n);
2175  js_nest_out = jstart2(n);
2176  je_nest_out = jend2(n);
2177  tile_nest_out = tile2(n);
2178  is_parent_out = istart1(n);
2179  ie_parent_out = iend1(n);
2180  js_parent_out = jstart1(n);
2181  je_parent_out = jend1(n);
2182  tile_parent_out = tile1(n);
2183  else
2184  is_nest_out = istart1(n);
2185  ie_nest_out = iend1(n);
2186  js_nest_out = jstart1(n);
2187  je_nest_out = jend1(n);
2188  tile_nest_out = tile1(n);
2189  is_parent_out = istart2(n);
2190  ie_parent_out = iend2(n);
2191  js_parent_out = jstart2(n);
2192  je_parent_out = jend2(n);
2193  tile_parent_out = tile2(n);
2194  endif
2195  enddo
2196 
2197  deallocate(nx, ny, tile1, tile2)
2198  deallocate(istart1, iend1, jstart1, jend1)
2199  deallocate(istart2, iend2, jstart2, jend2)
2200 
2201 
2202  return
2203 
2204 end function get_nest_contact_fms2_io
2205 
2206 !#######################################################################
2207 subroutine set_comm_get1_repro(xmap)
2208  type (xmap_type), intent(inout) :: xmap
2209  integer, dimension(xmap%npes) :: pe_ind, cnt
2210  integer, dimension(0:xmap%npes-1) :: send_ind, pl
2211  integer :: npes, nsend, nrecv, mypos
2212  integer :: m, p, pos, n, g, l, im, i, j
2213  type(comm_type), pointer, save :: comm => null()
2214 
2215  comm => xmap%get1_repro
2216  npes = xmap%npes
2217 
2218  nrecv = 0
2219  mypos = mpp_pe() - mpp_root_pe()
2220  do m=0,npes-1
2221  p = mod(mypos+npes-m, npes)
2222  if( xmap%recv_count_repro(p) > 0 ) then
2223  nrecv = nrecv + 1
2224  pe_ind(nrecv) = p
2225  endif
2226  enddo
2227 
2228  comm%nrecv = nrecv
2229  if( nrecv > 0 ) then
2230  if (associated(comm%recv)) deallocate(comm%recv) !< Check if allocated
2231  allocate(comm%recv(nrecv))
2232  pos = 0
2233  do n = 1, nrecv
2234  p = pe_ind(n)
2235  comm%recv(n)%count = xmap%recv_count_repro(p)
2236  comm%recv(n)%pe = p + xmap%root_pe
2237  comm%recv(n)%buffer_pos = pos
2238  pos = pos + comm%recv(n)%count
2239  enddo
2240  endif
2241 
2242 
2243  ! send information
2244  nsend = 0
2245  mypos = mpp_pe() - mpp_root_pe()
2246  do m=0,xmap%npes-1
2247  p = mod(mypos+m, npes)
2248  if( xmap%send_count_repro(p) > 0 ) then
2249  nsend = nsend + 1
2250  pe_ind(nsend) = p
2251  send_ind(p) = nsend
2252  endif
2253  enddo
2254 
2255  comm%nsend = nsend
2256  if( nsend > 0 ) then
2257  if (associated(comm%send)) deallocate(comm%send) !< Check if allocated
2258  allocate(comm%send(nsend))
2259  pos = 0
2260  cnt(:) = 0
2261  do n = 1, nsend
2262  p = pe_ind(n)
2263  comm%send(n)%count = xmap%send_count_repro(p)
2264  comm%send(n)%pe = p + xmap%root_pe
2265  comm%send(n)%buffer_pos = pos
2266  pos = pos + comm%send(n)%count
2267  allocate(comm%send(n)%i(comm%send(n)%count))
2268  allocate(comm%send(n)%j(comm%send(n)%count))
2269  allocate(comm%send(n)%g(comm%send(n)%count))
2270  allocate(comm%send(n)%xLoc(comm%send(n)%count))
2271  enddo
2272 
2273  do g=2,size(xmap%grids(:))
2274  im = xmap%grids(g)%im
2275  do l=1,xmap%grids(g)%size ! index into this side 2 grid's patterns
2276  p = xmap%grids(g)%x(l)%pe-xmap%root_pe
2277  n = send_ind(p)
2278  cnt(n) = cnt(n) + 1
2279  pos = cnt(n)
2280  i = xmap%grids(g)%x(l)%i2
2281  j = xmap%grids(g)%x(l)%j2
2282  if(xmap%grids(g)%is_ug) then
2283  comm%send(n)%i(pos) = xmap%grids(g)%l_index((j-1)*im+i)
2284  comm%send(n)%j(pos) = 1
2285  else
2286  comm%send(n)%i(pos) = xmap%grids(g)%x(l)%i2
2287  comm%send(n)%j(pos) = xmap%grids(g)%x(l)%j2
2288  endif
2289  comm%send(n)%g(pos) = g
2290  enddo
2291  enddo
2292  !--- make sure the count is correct
2293  do n = 1, nsend
2294  if( comm%send(n)%count .NE. cnt(n) ) call error_mesg('xgrid_mod', &
2295  .NE.'comm%send(n)%count cnt(n)', fatal)
2296  enddo
2297  endif
2298 
2299  !--- set up the recv_pos for unpack the data.
2300  pl(:) = 1
2301  do g=2,size(xmap%grids(:))
2302  do l=1,xmap%grids(g)%size_repro ! index into side1 grid's patterns
2303  p = xmap%grids(g)%x_repro(l)%pe-xmap%root_pe
2304  xmap%grids(g)%x_repro(l)%recv_pos = pl(p)
2305  pl(p) = pl(p) + 1
2306  end do
2307  end do
2308 
2309 
2310 
2311 end subroutine set_comm_get1_repro
2312 
2313 !#######################################################################
2314 subroutine set_comm_get1(xmap)
2315  type (xmap_type), intent(inout) :: xmap
2316  type (grid_type), pointer, save :: grid1 =>null()
2317  integer, allocatable :: send_size(:)
2318  integer, allocatable :: recv_size(:)
2319  integer :: max_size, g, npes, l, ll, nset, m
2320  integer :: i1, j1, tile1, p, n, pos, buffer_pos, mypos
2321  integer :: nsend, nrecv, rbuf_size, sbuf_size, msgsize
2322  logical :: found
2323  real(r8_kind), allocatable :: recv_buf(:), send_buf(:)
2324  real(r8_kind), allocatable :: diarray(:), djarray(:)
2325  integer, allocatable :: iarray(:), jarray(:), tarray(:)
2326  integer, allocatable :: pos_x(:), pelist(:), size_pe(:), pe_side1(:)
2327  integer :: recv_buffer_pos(0:xmap%npes)
2328  integer :: send_buffer_pos(0:xmap%npes)
2329  type(comm_type), pointer, save :: comm => null()
2330  integer :: i, j
2331 
2332  max_size = 0
2333  do g=2,size(xmap%grids(:))
2334  max_size = max_size + xmap%grids(g)%size
2335  enddo
2336  comm => xmap%get1
2337  grid1 => xmap%grids(1)
2338  comm%nsend = 0
2339  comm%nrecv = 0
2340  npes = xmap%npes
2341 
2342  allocate(pelist(0:npes-1))
2343  call mpp_get_current_pelist(pelist)
2344  allocate(send_size(0:npes-1))
2345  allocate(recv_size(0:npes-1))
2346  allocate(size_pe(0:npes-1))
2347  allocate(pos_x(0:npes-1))
2348  size_pe = 0
2349  send_size = 0
2350  recv_size = 0
2351 
2352  if(max_size > 0) then
2353  allocate(pe_side1(max_size))
2354  if (associated(xmap%ind_get1)) deallocate(xmap%ind_get1) !< Check if allocated
2355  allocate(xmap%ind_get1(max_size))
2356 
2357  !--- find the recv_indx
2358  ll = 0
2359  do g=2,size(xmap%grids(:))
2360  do l=1,xmap%grids(g)%size
2361  i1 = xmap%grids(g)%x(l)%i1
2362  j1 = xmap%grids(g)%x(l)%j1
2363  tile1 = xmap%grids(g)%x(l)%tile
2364  do p=0,npes-1
2365  if(grid1%tile(p) == tile1) then
2366  if(in_box_nbr(i1, j1, grid1, p)) then
2367  size_pe(p) = size_pe(p) + 1
2368  exit
2369  endif
2370  endif
2371  enddo
2372  if( p == npes ) then
2373  call error_mesg('xgrid_mod', 'tile is not in grid1%tile(:)', fatal)
2374  endif
2375  ll = ll + 1
2376  pe_side1(ll) = p
2377  enddo
2378  enddo
2379 
2380  pos_x = 0
2381  do p = 1, npes-1
2382  pos_x(p) = pos_x(p-1) + size_pe(p-1)
2383  enddo
2384 
2385  !---find the send size for get_1_from_xgrid
2386  allocate(iarray(max_size))
2387  allocate(jarray(max_size))
2388  allocate(tarray(max_size))
2389  if(monotonic_exchange) then
2390  allocate(diarray(max_size))
2391  allocate(djarray(max_size))
2392  endif
2393 
2394  ll = 0
2395 
2396  do g=2,size(xmap%grids(:))
2397  do l=1,xmap%grids(g)%size
2398  i1 = xmap%grids(g)%x(l)%i1
2399  j1 = xmap%grids(g)%x(l)%j1
2400  tile1 = xmap%grids(g)%x(l)%tile
2401  ll = ll + 1
2402  p = pe_side1(ll)
2403 
2404  found = .false.
2405  if(send_size(p) > 0) then
2406  if( i1 == iarray(pos_x(p)+send_size(p)) .AND. j1 == jarray(pos_x(p)+send_size(p)) &
2407  .AND. tile1 == tarray(pos_x(p)+send_size(p))) then
2408  found = .true.
2409  n = send_size(p)
2410  else
2411  !---may need to replace with a fast search algorithm
2412  do n = 1, send_size(p)
2413  if(i1 == iarray(pos_x(p)+n) .AND. j1 == jarray(pos_x(p)+n) .AND. tile1 == tarray(pos_x(p)+n)) then
2414  found = .true.
2415  exit
2416  endif
2417  enddo
2418  endif
2419  endif
2420  if( (.NOT. found) .OR. monotonic_exchange ) then
2421  send_size(p) = send_size(p)+1
2422  pos = pos_x(p)+send_size(p)
2423  iarray(pos) = i1
2424  jarray(pos) = j1
2425  tarray(pos) = tile1
2426  if(monotonic_exchange) then
2427  diarray(pos) = xmap%grids(g)%x(l)%di
2428  djarray(pos) = xmap%grids(g)%x(l)%dj
2429  endif
2430  n = send_size(p)
2431  endif
2432  xmap%ind_get1(ll) = n
2433  enddo
2434  enddo
2435 
2436  pos_x = 0
2437  do p = 1, npes-1
2438  pos_x(p) = pos_x(p-1) + send_size(p-1)
2439  enddo
2440 
2441  ll = 0
2442  do g=2,size(xmap%grids(:))
2443  do l=1,xmap%grids(g)%size
2444  ll = ll + 1
2445  p = pe_side1(ll)
2446  xmap%ind_get1(ll) = pos_x(p) + xmap%ind_get1(ll)
2447  enddo
2448  enddo
2449  endif
2450 
2451  mypos = mpp_pe()-mpp_root_pe()
2452 
2453  ! send/recv for get_1_from_xgrid_recv
2454  recv_size(:) = xmap%your2my1_size(:)
2455  nsend = count( send_size> 0)
2456  comm%nsend = nsend
2457  if(nsend>0) then
2458  if (associated(comm%send)) deallocate(comm%send) !< Check if allocated
2459  allocate(comm%send(nsend))
2460  comm%send(:)%count = 0
2461  endif
2462 
2463  pos = 0
2464  do p = 0, npes-1
2465  send_buffer_pos(p) = pos
2466  pos = pos + send_size(p)
2467  enddo
2468 
2469  pos = 0
2470  comm%sendsize = 0
2471  do n = 0, npes-1
2472  p = mod(mypos+n, npes)
2473  if(send_size(p)>0) then
2474  pos = pos + 1
2475  allocate(comm%send(pos)%i(send_size(p)))
2476  comm%send(pos)%buffer_pos = send_buffer_pos(p)
2477  comm%send(pos)%count = send_size(p)
2478  comm%send(pos)%pe = pelist(p)
2479  comm%sendsize = comm%sendsize + send_size(p)
2480  endif
2481  enddo
2482 
2483  nset = 3
2484  if(monotonic_exchange) nset = 5
2485  rbuf_size = sum(recv_size)*nset
2486  sbuf_size = sum(send_size)*nset
2487  if(rbuf_size>0) allocate(recv_buf(rbuf_size))
2488  if(sbuf_size>0) allocate(send_buf(sbuf_size))
2489 
2490  pos = 0
2491  do n = 0, npes-1
2492  p = mod(mypos+npes-n, npes)
2493  if(recv_size(p) ==0) cycle
2494  msgsize = recv_size(p)*nset
2495  call mpp_recv(recv_buf(pos+1), glen=msgsize, from_pe=pelist(p), block=.false., tag=comm_tag_4)
2496  pos = pos + msgsize
2497  enddo
2498 
2499  pos_x = 0
2500  do p = 1, npes-1
2501  pos_x(p) = pos_x(p-1) + size_pe(p-1)
2502  enddo
2503  ll = 0
2504  pos = 0
2505  do n = 0, npes-1
2506  p = mod(mypos+n, npes)
2507  do l = 1, send_size(p)
2508  send_buf(pos+1) = real(iarray(pos_x(p)+l), r8_kind)
2509  send_buf(pos+2) = real(jarray(pos_x(p)+l), r8_kind)
2510  send_buf(pos+3) = real(tarray(pos_x(p)+l), r8_kind)
2511  if(monotonic_exchange) then
2512  send_buf(pos+4) = diarray(pos_x(p)+l)
2513  send_buf(pos+5) = djarray(pos_x(p)+l)
2514  endif
2515  pos = pos + nset
2516  enddo
2517  enddo
2518 
2519  pos = 0
2520  do n = 0, npes-1
2521  p = mod(mypos+n, npes)
2522  if(send_size(p) ==0) cycle
2523  msgsize = send_size(p)*nset
2524  call mpp_send(send_buf(pos+1), plen=msgsize, to_pe=pelist(p), tag=comm_tag_4 )
2525  pos = pos + msgsize
2526  enddo
2527 
2528  call mpp_sync_self(check=event_recv)
2529  nrecv = count(recv_size>0)
2530  comm%nrecv = nrecv
2531  comm%recvsize = 0
2532 
2533  if(nrecv >0) then
2534  if (associated(comm%recv)) deallocate(comm%recv) !< Check if allocated
2535  allocate(comm%recv(nrecv))
2536  comm%recv(:)%count = 0
2537  !--- set up the buffer pos for each receiving
2538  buffer_pos = 0
2539  do p = 0, npes-1
2540  recv_buffer_pos(p) = buffer_pos
2541  buffer_pos = buffer_pos + recv_size(p)
2542  enddo
2543  pos = 0
2544  buffer_pos = 0
2545  do m=0,npes-1
2546  p = mod(mypos+npes-m, npes)
2547  if(recv_size(p)>0) then
2548  pos = pos + 1
2549  allocate(comm%recv(pos)%i(recv_size(p)))
2550  allocate(comm%recv(pos)%j(recv_size(p)))
2551  allocate(comm%recv(pos)%tile(recv_size(p)))
2552  comm%recv(pos)%buffer_pos = recv_buffer_pos(p)
2553  comm%recv(pos)%pe = pelist(p)
2554  comm%recv(pos)%count = recv_size(p)
2555  comm%recvsize = comm%recvsize + recv_size(p)
2556  if(monotonic_exchange) then
2557  allocate(comm%recv(pos)%di(recv_size(p)))
2558  allocate(comm%recv(pos)%dj(recv_size(p)))
2559  endif
2560  if(grid1%is_ug) then
2561  do n = 1, recv_size(p)
2562  i = int(recv_buf(buffer_pos+1))
2563  j = int(recv_buf(buffer_pos+2))
2564  comm%recv(pos)%i(n) = grid1%l_index((j-1)*grid1%im+i)
2565  comm%recv(pos)%j(n) = 1
2566  comm%recv(pos)%tile(n) = int(recv_buf(buffer_pos+3))
2567  if(monotonic_exchange) then
2568  comm%recv(pos)%di(n) = recv_buf(buffer_pos+4)
2569  comm%recv(pos)%dj(n) = recv_buf(buffer_pos+5)
2570  endif
2571  buffer_pos = buffer_pos + nset
2572  enddo
2573  else
2574  do n = 1, recv_size(p)
2575  comm%recv(pos)%i(n) = int(recv_buf(buffer_pos+1) )- grid1%is_me + 1
2576  comm%recv(pos)%j(n) = int(recv_buf(buffer_pos+2) )- grid1%js_me + 1
2577  comm%recv(pos)%tile(n) = int(recv_buf(buffer_pos+3))
2578  if(monotonic_exchange) then
2579  comm%recv(pos)%di(n) = recv_buf(buffer_pos+4)
2580  comm%recv(pos)%dj(n) = recv_buf(buffer_pos+5)
2581  endif
2582  buffer_pos = buffer_pos + nset
2583  enddo
2584  endif
2585  endif
2586  enddo
2587  if (associated(comm%unpack_ind)) deallocate(comm%unpack_ind) !< Check if allocated
2588  allocate(comm%unpack_ind(nrecv))
2589  pos = 0
2590  do p = 0, npes-1
2591  if(recv_size(p)>0) then
2592  pos = pos + 1
2593  do m = 1, nrecv
2594  if(comm%recv(m)%pe == pelist(p)) then
2595  comm%unpack_ind(pos) = m
2596  exit
2597  endif
2598  enddo
2599  endif
2600  enddo
2601  endif
2602  call mpp_sync_self()
2603 
2604  if(allocated(send_buf) ) deallocate(send_buf)
2605  if(allocated(recv_buf) ) deallocate(recv_buf)
2606  if(allocated(pelist) ) deallocate(pelist)
2607  if(allocated(pos_x) ) deallocate(pos_x)
2608  if(allocated(pelist) ) deallocate(pelist)
2609  if(allocated(iarray) ) deallocate(iarray)
2610  if(allocated(jarray) ) deallocate(jarray)
2611  if(allocated(tarray) ) deallocate(tarray)
2612  if(allocated(size_pe) ) deallocate(size_pe)
2613 
2614 end subroutine set_comm_get1
2615 
2616 !###############################################################################
2617 subroutine set_comm_put1(xmap)
2618  type (xmap_type), intent(inout) :: xmap
2619  type (grid_type), pointer, save :: grid1 =>null()
2620  integer, allocatable :: send_size(:)
2621  integer, allocatable :: recv_size(:)
2622  integer :: max_size, g, npes, l, ll, m, mypos
2623  integer :: i1, j1, tile1, p, n, pos, buffer_pos
2624  integer :: nsend, nrecv, msgsize, nset, rbuf_size, sbuf_size
2625  logical :: found
2626  real(r8_kind), allocatable :: recv_buf(:), send_buf(:)
2627  real(r8_kind), allocatable :: diarray(:), djarray(:)
2628  integer, allocatable :: iarray(:), jarray(:), tarray(:)
2629  integer, allocatable :: pos_x(:), pelist(:), size_pe(:), pe_put1(:)
2630  integer :: recv_buffer_pos(0:xmap%npes)
2631  type(comm_type), pointer, save :: comm => null()
2632 
2633 
2634  comm => xmap%put1
2635  if(nnest == 0 .OR. xmap%grids(1)%id .NE. 'ATM' ) then
2636  comm%nsend = xmap%get1%nrecv
2637  comm%nrecv = xmap%get1%nsend
2638  comm%sendsize = xmap%get1%recvsize
2639  comm%recvsize = xmap%get1%sendsize
2640  comm%send => xmap%get1%recv
2641  comm%recv => xmap%get1%send
2642  xmap%ind_put1 => xmap%ind_get1
2643  return
2644  endif
2645 
2646  max_size = 0
2647  do g=2,size(xmap%grids(:))
2648  max_size = max_size + xmap%grids(g)%size
2649  enddo
2650  grid1 => xmap%grids(1)
2651  comm%nsend = 0
2652  comm%nrecv = 0
2653  npes = xmap%npes
2654  allocate(pelist(0:npes-1))
2655  call mpp_get_current_pelist(pelist)
2656  allocate(send_size(0:npes-1))
2657  allocate(recv_size(0:npes-1))
2658  allocate(size_pe(0:npes-1))
2659  allocate(pos_x(0:npes-1))
2660  size_pe = 0
2661  send_size = 0
2662  recv_size = 0
2663 
2664  if(max_size > 0) then
2665  allocate(pe_put1(max_size))
2666  if (associated(xmap%ind_put1)) deallocate(xmap%ind_put1) !< Check if allocated
2667  allocate(xmap%ind_put1(max_size))
2668 
2669  !--- find the recv_indx
2670  ll = 0
2671  do g=2,size(xmap%grids(:))
2672  do l=1,xmap%grids(g)%size
2673  i1 = xmap%grids(g)%x(l)%i1
2674  j1 = xmap%grids(g)%x(l)%j1
2675  tile1 = xmap%grids(g)%x(l)%tile
2676  do p=0,npes-1
2677  if(grid1%tile(p) == tile1) then
2678  if(in_box(i1, j1, grid1%is(p), grid1%ie(p), grid1%js(p), grid1%je(p))) then
2679  size_pe(p) = size_pe(p) + 1
2680  exit
2681  endif
2682  endif
2683  enddo
2684  ll = ll + 1
2685  pe_put1(ll) = p
2686  enddo
2687  enddo
2688 
2689  pos_x = 0
2690  do p = 1, npes-1
2691  pos_x(p) = pos_x(p-1) + size_pe(p-1)
2692  enddo
2693 
2694  !---find the send size for get_1_from_xgrid
2695  allocate(iarray(max_size))
2696  allocate(jarray(max_size))
2697  allocate(tarray(max_size))
2698  if(monotonic_exchange) then
2699  allocate(diarray(max_size))
2700  allocate(djarray(max_size))
2701  endif
2702 
2703  ll = 0
2704 
2705  do g=2,size(xmap%grids(:))
2706  do l=1,xmap%grids(g)%size
2707  i1 = xmap%grids(g)%x(l)%i1
2708  j1 = xmap%grids(g)%x(l)%j1
2709  tile1 = xmap%grids(g)%x(l)%tile
2710  ll = ll + 1
2711  p = pe_put1(ll)
2712 
2713  found = .false.
2714  if(send_size(p) > 0) then
2715  if( i1 == iarray(pos_x(p)+send_size(p)) .AND. j1 == jarray(pos_x(p)+send_size(p)) &
2716  .AND. tile1 == tarray(pos_x(p)+send_size(p))) then
2717  found = .true.
2718  n = send_size(p)
2719  else
2720  !---may need to replace with a fast search algorithm
2721  do n = 1, send_size(p)
2722  if(i1 == iarray(pos_x(p)+n) .AND. j1 == jarray(pos_x(p)+n) .AND. tile1 == tarray(pos_x(p)+n)) then
2723  found = .true.
2724  exit
2725  endif
2726  enddo
2727  endif
2728  endif
2729  if( (.NOT. found) .OR. monotonic_exchange ) then
2730  send_size(p) = send_size(p)+1
2731  pos = pos_x(p)+send_size(p)
2732  iarray(pos) = i1
2733  jarray(pos) = j1
2734  tarray(pos) = tile1
2735  if(monotonic_exchange) then
2736  diarray(pos) = xmap%grids(g)%x(l)%di
2737  djarray(pos) = xmap%grids(g)%x(l)%dj
2738  endif
2739  n = send_size(p)
2740  endif
2741  xmap%ind_put1(ll) = n
2742  enddo
2743  enddo
2744 
2745  pos_x = 0
2746  do p = 1, npes-1
2747  pos_x(p) = pos_x(p-1) + send_size(p-1)
2748  enddo
2749 
2750  ll = 0
2751  do g=2,size(xmap%grids(:))
2752  do l=1,xmap%grids(g)%size
2753  i1 = xmap%grids(g)%x(l)%i1
2754  j1 = xmap%grids(g)%x(l)%j1
2755  tile1 = xmap%grids(g)%x(l)%tile
2756  ll = ll + 1
2757  p = pe_put1(ll)
2758  xmap%ind_put1(ll) = pos_x(p) + xmap%ind_put1(ll)
2759  enddo
2760  enddo
2761  endif
2762 
2763 
2764  mypos = mpp_pe()-mpp_root_pe()
2765 
2766  if (do_alltoall) then
2767  call mpp_alltoall(send_size, 1, recv_size, 1)
2768  else
2769  do n = 0, npes-1
2770  p = mod(mypos+npes-n, npes)
2771  call mpp_recv(recv_size(p), glen=1, from_pe=pelist(p), block=.false., tag=comm_tag_5)
2772  enddo
2773 
2774  !--- send data
2775  do n = 0, npes-1
2776  p = mod(mypos+n, npes)
2777  call mpp_send(send_size(p), plen=1, to_pe=pelist(p), tag=comm_tag_5)
2778  enddo
2779 
2780  call mpp_sync_self(check=event_recv)
2781  call mpp_sync_self()
2782  endif
2783  !--- recv for put_1_to_xgrid
2784  nrecv = count( send_size> 0)
2785  comm%nrecv = nrecv
2786  if(nrecv>0) then
2787  if (associated(comm%recv)) deallocate(comm%recv) !< Check if allocated
2788  allocate(comm%recv(nrecv))
2789  comm%recv(:)%count = 0
2790  endif
2791  pos = 0
2792  comm%recvsize = 0
2793  do p = 0, npes-1
2794  recv_buffer_pos(p) = pos
2795  pos = pos + send_size(p)
2796  enddo
2797 
2798  pos = 0
2799  do n = 0, npes-1
2800  p = mod(mypos+npes-n, npes)
2801  if(send_size(p)>0) then
2802  pos = pos + 1
2803  allocate(comm%recv(pos)%i(send_size(p)))
2804  comm%recv(pos)%buffer_pos = recv_buffer_pos(p)
2805  comm%recv(pos)%count = send_size(p)
2806  comm%recv(pos)%pe = pelist(p)
2807  comm%recvsize = comm%recvsize + send_size(p)
2808  endif
2809  enddo
2810 
2811  nset = 3
2812  if(monotonic_exchange) nset = 5
2813  rbuf_size = sum(recv_size)*nset
2814  sbuf_size = sum(send_size)*nset
2815  if(rbuf_size>0) allocate(recv_buf(rbuf_size))
2816  if(sbuf_size>0) allocate(send_buf(sbuf_size))
2817 
2818  pos = 0
2819  do n = 0, npes-1
2820  p = mod(mypos+npes-n, npes)
2821  if(recv_size(p) ==0) cycle
2822  msgsize = recv_size(p)*nset
2823  call mpp_recv(recv_buf(pos+1), glen=msgsize, from_pe=pelist(p), block=.false., tag=comm_tag_6)
2824  pos = pos + msgsize
2825  enddo
2826 
2827  pos_x = 0
2828  do p = 1, npes-1
2829  pos_x(p) = pos_x(p-1) + size_pe(p-1)
2830  enddo
2831  ll = 0
2832  pos = 0
2833  do n = 0, npes-1
2834  p = mod(mypos+n, npes)
2835  do l = 1, send_size(p)
2836  send_buf(pos+1) = real(iarray(pos_x(p)+l), r8_kind)
2837  send_buf(pos+2) = real(jarray(pos_x(p)+l), r8_kind)
2838  send_buf(pos+3) = real(tarray(pos_x(p)+l), r8_kind)
2839  if(monotonic_exchange) then
2840  send_buf(pos+4) = diarray(pos_x(p)+l)
2841  send_buf(pos+5) = djarray(pos_x(p)+l)
2842  endif
2843  pos = pos + nset
2844  enddo
2845  enddo
2846 
2847  pos = 0
2848  do n = 0, npes-1
2849  p = mod(mypos+n, npes)
2850  if(send_size(p) ==0) cycle
2851  msgsize = send_size(p)*nset
2852  call mpp_send(send_buf(pos+1), plen=msgsize, to_pe=pelist(p), tag=comm_tag_6 )
2853  pos = pos + msgsize
2854  enddo
2855 
2856  call mpp_sync_self(check=event_recv)
2857  nsend = count(recv_size>0)
2858  comm%nsend = nsend
2859  comm%sendsize = 0
2860 
2861  if(nsend >0) then
2862  if (associated(comm%send)) deallocate(comm%send) !< Check if allocated
2863  allocate(comm%send(nsend))
2864  comm%send(:)%count = 0
2865  pos = 0
2866  buffer_pos = 0
2867  do m=0,npes-1
2868  p = mod(mypos+npes-m, npes)
2869  if(recv_size(p)>0) then
2870  pos = pos + 1
2871  allocate(comm%send(pos)%i(recv_size(p)))
2872  allocate(comm%send(pos)%j(recv_size(p)))
2873  allocate(comm%send(pos)%tile(recv_size(p)))
2874  comm%send(pos)%pe = pelist(p)
2875  comm%send(pos)%count = recv_size(p)
2876  comm%sendsize = comm%sendsize + recv_size(p)
2877  if(monotonic_exchange) then
2878  allocate(comm%send(pos)%di(recv_size(p)))
2879  allocate(comm%send(pos)%dj(recv_size(p)))
2880  endif
2881  do n = 1, recv_size(p)
2882  comm%send(pos)%i(n) = int(recv_buf(buffer_pos+1) )- grid1%is_me + 1
2883  comm%send(pos)%j(n) = int(recv_buf(buffer_pos+2) )- grid1%js_me + 1
2884  comm%send(pos)%tile(n) = int(recv_buf(buffer_pos+3))
2885  if(monotonic_exchange) then
2886  comm%send(pos)%di(n) = recv_buf(buffer_pos+4)
2887  comm%send(pos)%dj(n) = recv_buf(buffer_pos+5)
2888  endif
2889  buffer_pos = buffer_pos + nset
2890  enddo
2891  endif
2892  enddo
2893  endif
2894 
2895  call mpp_sync_self()
2896  if(allocated(send_buf) ) deallocate(send_buf)
2897  if(allocated(recv_buf) ) deallocate(recv_buf)
2898  if(allocated(pelist) ) deallocate(pelist)
2899  if(allocated(pos_x) ) deallocate(pos_x)
2900  if(allocated(pelist) ) deallocate(pelist)
2901  if(allocated(iarray) ) deallocate(iarray)
2902  if(allocated(jarray) ) deallocate(jarray)
2903  if(allocated(tarray) ) deallocate(tarray)
2904  if(allocated(size_pe) ) deallocate(size_pe)
2905 
2906 end subroutine set_comm_put1
2907 
2908 
2909 !###############################################################################
2910 !> @brief Regenerate/Update the xmap
2911 !! @details This subroutine basically regenerates the exchange grid via updating the xmap.
2912 !! Practically xmap is the object specifying the exchange grid and has all the relevant information of Xgrid.
2913 !! Particularly note that regenerating the xmap/Xgrid accounts for dynamical changes of the subgrid parametrization
2914 !! of the side 2 components (land and ice-ocean).
2915 !! E.g., for when side 2 is the ice , the xgrid is regenrated so that
2916 !! OCN grid cells that are partially or totally open water contribute to (are side2 parent of) the Xgrid
2917 !! and conversely
2918 !! OCN grid cells that are totally ice covered do not contribute to (are kicked out of) the Xgrid.
2919 !! This makes xmap a dynamical object and a powerful tool for flux exchange calculations.
2920 !!
2921 !! Things to keep in mind about xmap/xgrid:
2922 !! xgrid contains two sides:
2923 !! side1: This is the side where 2d arrays are put to and get from the Xgrid
2924 !! side2: This is the side where 3d arrays are put to and get from the Xgrid.
2925 !! This was designed to enable exchange along sub-grid-scale (3rd dimension) for component models that have
2926 !! subgrid scale parametrization (e.g., seaice categories and land tiles).
2927 !! @param[inout] xmap exchange grid
2928 !!
2929 subroutine regen(xmap)
2930 type (xmap_type), intent(inout) :: xmap
2931 
2932  integer :: g, l, k, max_size
2933  integer :: i1, j1, i2, j2, p
2934  integer :: tile1
2935  integer :: ll, lll
2936  logical :: overlap_with_nest
2937  integer :: cnt(xmap%get1%nsend)
2938  integer :: i,j,n,xloc,pos,nsend,m,npes, mypos
2939  integer :: send_ind(0:xmap%npes-1)
2940 
2941  max_size = 0
2942 
2943  do g=2,size(xmap%grids(:))
2944  max_size = max_size + xmap%grids(g)%size * xmap%grids(g)%km
2945  end do
2946 
2947  if (max_size>size(xmap%x1(:))) then
2948  if (associated(xmap%x1)) deallocate(xmap%x1) !< Check x1 if allocated
2949  if (associated(xmap%x2)) deallocate(xmap%x2) !< Check x2 if allocated
2950  allocate( xmap%x1(1:max_size) )
2951  allocate( xmap%x2(1:max_size) )
2952  endif
2953 
2954 
2955  do g=2,size(xmap%grids(:))
2956  xmap%grids(g)%first = 1
2957  xmap%grids(g)%last = 0
2958  end do
2959 
2960  xmap%size = 0
2961  ll = 0
2962  do g=2,size(xmap%grids(:))
2963  xmap%grids(g)%first = xmap%size + 1;
2964 
2965  do l=1,xmap%grids(g)%size
2966  i1 = xmap%grids(g)%x(l)%i1
2967  j1 = xmap%grids(g)%x(l)%j1
2968  i2 = xmap%grids(g)%x(l)%i2
2969  j2 = xmap%grids(g)%x(l)%j2
2970  tile1 = xmap%grids(g)%x(l)%tile
2971  ll = ll + 1
2972  if(xmap%grids(g)%is_ug) then
2973  do k=1,xmap%grids(g)%km
2974  lll = xmap%grids(g)%l_index((j2-1)*xmap%grids(g)%im+i2)
2975  if (xmap%grids(g)%frac_area(lll,1,k)/=0.0_r8_kind) then
2976  xmap%size = xmap%size+1
2977  xmap%x1(xmap%size)%pos = xmap%ind_get1(ll)
2978  xmap%x1(xmap%size)%i = xmap%grids(g)%x(l)%i1
2979  xmap%x1(xmap%size)%j = xmap%grids(g)%x(l)%j1
2980  xmap%x1(xmap%size)%tile = xmap%grids(g)%x(l)%tile
2981  xmap%x1(xmap%size)%area = xmap%grids(g)%x(l)%area &
2982  *xmap%grids(g)%frac_area(lll,1,k)
2983  xmap%x1(xmap%size)%di = xmap%grids(g)%x(l)%di
2984  xmap%x1(xmap%size)%dj = xmap%grids(g)%x(l)%dj
2985  xmap%x2(xmap%size)%i = xmap%grids(g)%x(l)%i2
2986  xmap%x2(xmap%size)%j = xmap%grids(g)%x(l)%j2
2987  xmap%x2(xmap%size)%l = lll
2988  xmap%x2(xmap%size)%k = k
2989  xmap%x2(xmap%size)%area = xmap%grids(g)%x(l)%area * xmap%grids(g)%x(l)%scale
2990  endif
2991  enddo
2992  else
2993  do k=1,xmap%grids(g)%km
2994  if (xmap%grids(g)%frac_area(i2,j2,k)/=0.0_r8_kind) then
2995  xmap%size = xmap%size+1
2996  xmap%x1(xmap%size)%pos = xmap%ind_get1(ll)
2997  xmap%x1(xmap%size)%i = xmap%grids(g)%x(l)%i1
2998  xmap%x1(xmap%size)%j = xmap%grids(g)%x(l)%j1
2999  xmap%x1(xmap%size)%tile = xmap%grids(g)%x(l)%tile
3000  xmap%x1(xmap%size)%area = xmap%grids(g)%x(l)%area &
3001  *xmap%grids(g)%frac_area(i2,j2,k)
3002  xmap%x1(xmap%size)%di = xmap%grids(g)%x(l)%di
3003  xmap%x1(xmap%size)%dj = xmap%grids(g)%x(l)%dj
3004  xmap%x2(xmap%size)%i = xmap%grids(g)%x(l)%i2
3005  xmap%x2(xmap%size)%j = xmap%grids(g)%x(l)%j2
3006  xmap%x2(xmap%size)%k = k
3007  xmap%x2(xmap%size)%area = xmap%grids(g)%x(l)%area * xmap%grids(g)%x(l)%scale
3008  end if
3009  enddo
3010  end if
3011  end do
3012  xmap%grids(g)%last = xmap%size
3013  end do
3014 
3015 
3016  if (max_size>size(xmap%x1_put(:))) then
3017  if (associated(xmap%x1_put)) deallocate(xmap%x1_put) !< Check if allocated
3018  allocate( xmap%x1_put(1:max_size) )
3019  endif
3020  if (max_size>size(xmap%x2_get(:))) then
3021  if (associated(xmap%x2_get)) deallocate(xmap%x2_get) !< Check if allocated
3022  allocate( xmap%x2_get(1:max_size) )
3023  endif
3024 
3025  do g=2,size(xmap%grids(:))
3026  xmap%grids(g)%first_get = 1
3027  xmap%grids(g)%last_get = 0
3028  end do
3029 
3030  xmap%size_put1 = 0
3031  xmap%size_get2 = 0
3032  ll = 0
3033  do g=2,size(xmap%grids(:))
3034  xmap%grids(g)%first_get = xmap%size_get2 + 1;
3035 
3036  do l=1,xmap%grids(g)%size
3037  i1 = xmap%grids(g)%x(l)%i1
3038  j1 = xmap%grids(g)%x(l)%j1
3039  i2 = xmap%grids(g)%x(l)%i2
3040  j2 = xmap%grids(g)%x(l)%j2
3041  tile1 = xmap%grids(g)%x(l)%tile
3042  ll = ll + 1
3043  overlap_with_nest = .false.
3044  if( xmap%grids(1)%id == "ATM" .AND. tile1 == tile_parent .AND. &
3045  in_box(i1, j1, is_parent, ie_parent, js_parent, je_parent) ) overlap_with_nest = .true.
3046  if(xmap%grids(g)%is_ug) then
3047  do k=1,xmap%grids(g)%km
3048  lll = xmap%grids(g)%l_index((j2-1)*xmap%grids(g)%im+i2)
3049  if (xmap%grids(g)%frac_area(lll,1,k)/=0.0_r8_kind) then
3050  xmap%size_put1 = xmap%size_put1+1
3051  xmap%x1_put(xmap%size_put1)%pos = xmap%ind_put1(ll)
3052  xmap%x1_put(xmap%size_put1)%i = xmap%grids(g)%x(l)%i1
3053  xmap%x1_put(xmap%size_put1)%j = xmap%grids(g)%x(l)%j1
3054  xmap%x1_put(xmap%size_put1)%tile = xmap%grids(g)%x(l)%tile
3055  xmap%x1_put(xmap%size_put1)%area = xmap%grids(g)%x(l)%area &
3056  *xmap%grids(g)%frac_area(lll,1,k)
3057  xmap%x1_put(xmap%size_put1)%di = xmap%grids(g)%x(l)%di
3058  xmap%x1_put(xmap%size_put1)%dj = xmap%grids(g)%x(l)%dj
3059  if( .not. overlap_with_nest) then
3060  xmap%size_get2 = xmap%size_get2+1
3061  xmap%x2_get(xmap%size_get2)%i = xmap%grids(g)%x(l)%i2
3062  xmap%x2_get(xmap%size_get2)%j = xmap%grids(g)%x(l)%j2
3063  xmap%x2_get(xmap%size_get2)%l = lll
3064  xmap%x2_get(xmap%size_get2)%k = k
3065  xmap%x2_get(xmap%size_get2)%area = xmap%grids(g)%x(l)%area * xmap%grids(g)%x(l)%scale
3066  xmap%x2_get(xmap%size_get2)%pos = xmap%size_put1
3067  endif
3068  end if
3069  end do
3070  else
3071  do k=1,xmap%grids(g)%km
3072  if (xmap%grids(g)%frac_area(i2,j2,k)/=0.0_r8_kind) then
3073  xmap%size_put1 = xmap%size_put1+1
3074  xmap%x1_put(xmap%size_put1)%pos = xmap%ind_put1(ll)
3075  xmap%x1_put(xmap%size_put1)%i = xmap%grids(g)%x(l)%i1
3076  xmap%x1_put(xmap%size_put1)%j = xmap%grids(g)%x(l)%j1
3077  xmap%x1_put(xmap%size_put1)%tile = xmap%grids(g)%x(l)%tile
3078  xmap%x1_put(xmap%size_put1)%area = xmap%grids(g)%x(l)%area &
3079  *xmap%grids(g)%frac_area(i2,j2,k)
3080  xmap%x1_put(xmap%size_put1)%di = xmap%grids(g)%x(l)%di
3081  xmap%x1_put(xmap%size_put1)%dj = xmap%grids(g)%x(l)%dj
3082  if( .not. overlap_with_nest) then
3083  xmap%size_get2 = xmap%size_get2+1
3084  xmap%x2_get(xmap%size_get2)%i = xmap%grids(g)%x(l)%i2
3085  xmap%x2_get(xmap%size_get2)%j = xmap%grids(g)%x(l)%j2
3086  xmap%x2_get(xmap%size_get2)%k = k
3087  xmap%x2_get(xmap%size_get2)%area = xmap%grids(g)%x(l)%area * xmap%grids(g)%x(l)%scale
3088  xmap%x2_get(xmap%size_get2)%pos = xmap%size_put1
3089  endif
3090  end if
3091  end do
3092  endif
3093  end do
3094  xmap%grids(g)%last_get = xmap%size_get2
3095  end do
3096 
3097  !---set up information for get_1_from_xgrid_repro
3098  if (make_exchange_reproduce) then
3099  if (xmap%get1_repro%nsend > 0) then
3100  xloc = 0
3101  nsend = 0
3102  npes = xmap%npes
3103  mypos = mpp_pe() - mpp_root_pe()
3104  cnt(:) = 0
3105  do m=0,npes-1
3106  p = mod(mypos+m, npes)
3107  if( xmap%send_count_repro(p) > 0 ) then
3108  nsend = nsend + 1
3109  send_ind(p) = nsend
3110  endif
3111  enddo
3112  do g=2,size(xmap%grids(:))
3113  do l=1,xmap%grids(g)%size ! index into this side 2 grid's patterns
3114  p = xmap%grids(g)%x(l)%pe-xmap%root_pe
3115  n = send_ind(p)
3116  cnt(n) = cnt(n) + 1
3117  pos = cnt(n)
3118  xmap%get1_repro%send(n)%xLoc(pos) = xloc
3119  if( xmap%grids(g)%is_ug ) then
3120  i = xmap%grids(g)%x(l)%l2
3121  xloc = xloc + count(xmap%grids(g)%frac_area(i,1,:)/=0.0_r8_kind)
3122  else
3123  i = xmap%grids(g)%x(l)%i2
3124  j = xmap%grids(g)%x(l)%j2
3125  xloc = xloc + count(xmap%grids(g)%frac_area(i,j,:)/=0.0_r8_kind)
3126  endif
3127  enddo
3128  enddo
3129  endif
3130  endif
3131 
3132 end subroutine regen
3133 
3134 !#######################################################################
3135 !> @brief Changes sub-grid portion areas and/or number.
3136 !! @details (re)sets the "fraction area" of the side 2 component grid cell.
3137 !! "fraction area" is a dynamic property of the component model (seaice or land)
3138 !! that needs to be updated after each timestep of that component in order for the exhange mechanism to work properly.
3139 !! The input is a 3d array of numbers between 0 and 1. It signifies the
3140 !! fraction of the component grid cell area which has a model-specific property.
3141 !! This property is used for some sub-grid scale parametrization in the component model.
3142 !! E.g., for the seaice component model, the quantity of seaice in each grid cell (i,j)
3143 !! is distibuted into N=grid%km partitions (ice categories) each parametrized with a weight (part_size) that add to 1.
3144 !! E.g., for 6+2 thickness (h) categories used in GFDL seaice models we have
3145 !! given hlim(1, ..., 8) = [1.0e-10, 0.1, 0.3, 0.7, 1.1, 1.5, 2.0, 2.5] (meters)
3146 !! Caterory n=1 : h <= hlim(1), essentially no ice
3147 !! Caterory n=2...7 : hlim(n-1) < h <= hlim(n)
3148 !! Caterory n=8 : hlim(n-1) < h , unlimimitted ice thickness
3149 !! E.g., if seaice in grid cell (i,j) is parameterized as
3150 !! 10 % open water, 0% category 1, 40% category 2 , 50% category 3 then we have
3151 !! f(i,j,1:km) = part_size(i,j,1:8) = [0.1, 0.0, 0.4, 0.5, 0.0, 0.0, 0.0, 0.0]
3152 !!
3153 !! @param[in] f real(r8_kind) 3D array
3154 !! @param[in] grid_id 3 character grid ID
3155 !! @param[inout] xmap exchange grid
3156 !!
3157 !! <br>Example usage:
3158 !! @code{.F90}
3159 !! call fms_xgrid_set_frac_area (Ice%part_size(isc:iec,jsc:jec,:) , 'OCN', xmap_sfc)
3160 !! @endcode
3161 !!
3162 subroutine set_frac_area_sg(f, grid_id, xmap)
3163 real(r8_kind), dimension(:,:,:), intent(in) :: f !< fraction area to be set
3164 character(len=3), intent(in) :: grid_id !< 3 character grid ID
3165 type (xmap_type), intent(inout) :: xmap !< exchange grid with given grid ID
3166 
3167  integer :: g
3168  type(grid_type), pointer, save :: grid =>null()
3169 
3170  if (grid_id==xmap%grids(1)%id) call error_mesg ('xgrid_mod', &
3171  'set_frac_area called on side 1 grid', fatal)
3172  do g=2,size(xmap%grids(:))
3173  grid => xmap%grids(g)
3174  if (grid_id==grid%id) then
3175  if (size(f,3)/=size(grid%frac_area,3)) then
3176  if (associated(grid%frac_area)) deallocate (grid%frac_area) !< Check if allocated
3177  grid%km = size(f,3);
3178  allocate( grid%frac_area(grid%is_me:grid%ie_me, grid%js_me:grid%je_me, &
3179  grid%km) )
3180  end if
3181  grid%frac_area = f;
3182  call regen(xmap)
3183  return;
3184  end if
3185  end do
3186 
3187  call error_mesg ('xgrid_mod', 'set_frac_area: could not find grid id', fatal)
3188 
3189 end subroutine set_frac_area_sg
3190 
3191 !#######################################################################
3192 
3193 !> @brief Changes sub-grid portion areas and/or number.
3194 subroutine set_frac_area_ug(f, grid_id, xmap)
3195 real(r8_kind), dimension(:,:), intent(in) :: f !< fractional area to set
3196 character(len=3), intent(in) :: grid_id !< 3 character grid ID
3197 type (xmap_type), intent(inout) :: xmap !< exchange grid with given grid ID
3198 
3199  integer :: g
3200  type(grid_type), pointer, save :: grid =>null()
3201 
3202  if (grid_id==xmap%grids(1)%id) call error_mesg ('xgrid_mod', &
3203  'set_frac_area_ug called on side 1 grid', fatal)
3204  if (grid_id .NE. 'LND' ) call error_mesg ('xgrid_mod', &
3205  .NE.'set_frac_area_ug called for grid_id LND', fatal)
3206  do g=2,size(xmap%grids(:))
3207  grid => xmap%grids(g)
3208  if (grid_id==grid%id) then
3209  if (size(f,2)/=size(grid%frac_area,3)) then
3210  if (associated(grid%frac_area)) deallocate (grid%frac_area) !< Check if allocated
3211  grid%km = size(f,2);
3212  allocate( grid%frac_area(grid%ls_me:grid%le_me, 1, grid%km) )
3213  end if
3214  grid%frac_area(:,1,:) = f(:,:);
3215  call regen(xmap)
3216  return;
3217  end if
3218  end do
3219 
3220  call error_mesg ('xgrid_mod', 'set_frac_area_ug: could not find grid id', fatal)
3221 
3222 end subroutine set_frac_area_ug
3223 
3224 !#######################################################################
3225 
3226 !> @brief Returns current size of exchange grid variables.
3227 !! @return size of given exchange grid's variable
3228 integer function xgrid_count(xmap)
3229 type (xmap_type), intent(inout) :: xmap
3230 
3231  xgrid_count = xmap%size
3232 end function xgrid_count
3233 
3234 !#######################################################################
3235 
3236 !> Scatters data to exchange grid
3237 subroutine put_side1_to_xgrid(d, grid_id, x, xmap, remap_method, complete)
3238  use, intrinsic :: iso_c_binding, only: c_ptr, c_null_ptr, c_loc
3239  real(r8_kind), target, contiguous, intent(in) :: d(:,:) !< data to send
3240  character(len=3), intent(in) :: grid_id !< 3 character grid ID
3241  real(r8_kind), target, contiguous, intent(inout) :: x(:) !< xgrid data
3242  type (xmap_type), intent(inout) :: xmap !< exchange grid
3243  integer, intent(in), optional :: remap_method !< exchange grid interpolation method can
3244  !! be FIRST_ORDER(=1) or SECOND_ORDER(=2)
3245  logical, intent(in), optional :: complete
3246 
3247  logical :: is_complete, set_mismatch
3248  integer :: g, method
3249  character(len=2) :: text
3250  integer, save :: isize=0
3251  integer, save :: jsize=0
3252  integer, save :: lsize=0
3253  integer, save :: xsize=0
3254  integer, save :: method_saved=0
3255  character(len=3), save :: grid_id_saved=""
3256  type(c_ptr), dimension(MAX_FIELDS), save :: d_addrs = c_null_ptr
3257  type(c_ptr), dimension(MAX_FIELDS), save :: x_addrs = c_null_ptr
3258 
3259  if (grid_id==xmap%grids(1)%id) then
3260  method = first_order ! default
3261  if(present(remap_method)) method = remap_method
3262  is_complete = .true.
3263  if(present(complete)) is_complete=complete
3264  lsize = lsize + 1
3265  if( lsize > max_fields ) then
3266  write( text,'(i2)' ) max_fields
3267  call error_mesg ('xgrid_mod', 'MAX_FIELDS='//trim(text)//' exceeded for group put_side1_to_xgrid', fatal)
3268  endif
3269  d_addrs(lsize) = c_loc(d)
3270  x_addrs(lsize) = c_loc(x)
3271 
3272  if(lsize == 1) then
3273  isize = size(d,1)
3274  jsize = size(d,2)
3275  xsize = size(x(:))
3276  method_saved = method
3277  grid_id_saved = grid_id
3278  else
3279  set_mismatch = .false.
3280  set_mismatch = set_mismatch .OR. (isize /= size(d,1))
3281  set_mismatch = set_mismatch .OR. (jsize /= size(d,2))
3282  set_mismatch = set_mismatch .OR. (xsize /= size(x(:)))
3283  set_mismatch = set_mismatch .OR. (method_saved /= method)
3284  set_mismatch = set_mismatch .OR. (grid_id_saved /= grid_id)
3285  if(set_mismatch)then
3286  write( text,'(i2)' ) lsize
3287  call error_mesg ('xgrid_mod', 'Incompatible field at count '//text//' for group put_side1_to_xgrid', fatal )
3288  endif
3289  endif
3290 
3291  if(is_complete) then
3292  !--- when exchange_monotonic is true and the side 1 ia atm, will always use monotonic
3293  !second order conservative.
3294  if(monotonic_exchange .AND. grid_id == 'ATM') then
3295  call put_1_to_xgrid_order_2(d_addrs, x_addrs, xmap, isize, jsize, xsize, lsize)
3296  else if(method == first_order) then
3297  call put_1_to_xgrid_order_1(d_addrs, x_addrs, xmap, isize, jsize, xsize, lsize)
3298  else
3299  if(grid_id .NE. 'ATM') call error_mesg ('xgrid_mod', &
3300  "second order put_to_xgrid should only be applied to 'ATM' model, "//&
3301  "contact developer", fatal)
3302  call put_1_to_xgrid_order_2(d_addrs, x_addrs, xmap, isize, jsize, xsize, lsize)
3303  endif
3304 
3305  d_addrs = c_null_ptr
3306  x_addrs = c_null_ptr
3307  isize = 0
3308  jsize = 0
3309  xsize = 0
3310  lsize = 0
3311  method_saved = 0
3312  grid_id_saved = ""
3313  endif
3314  return
3315  end if
3316 
3317  do g=2,size(xmap%grids(:))
3318  if (grid_id==xmap%grids(g)%id) &
3319  call error_mesg ('xgrid_mod', &
3320  'put_to_xgrid expects a 3D side 2 grid', fatal)
3321  end do
3322 
3323  call error_mesg ('xgrid_mod', 'put_to_xgrid: could not find grid id', fatal)
3324 
3325 end subroutine put_side1_to_xgrid
3326 
3327 !#######################################################################
3328 
3329 !> Scatters data to exchange grid
3330 subroutine put_side2_to_xgrid(d, grid_id, x, xmap)
3331 real(r8_kind), dimension(:,:,:), intent(in) :: d !< data to send
3332 character(len=3), intent(in) :: grid_id !< 3 character grid ID
3333 real(r8_kind), dimension(:), intent(inout) :: x !< xgrid data
3334 type (xmap_type), intent(inout) :: xmap !< exchange grid
3335 
3336  integer :: g
3337 
3338  if (grid_id==xmap%grids(1)%id) &
3339  call error_mesg ('xgrid_mod', &
3340  'put_side2_to_xgrid expects a 3D side 2 grid', fatal)
3341 
3342  do g=2,size(xmap%grids(:))
3343  if (grid_id==xmap%grids(g)%id) then
3344  call put_2_to_xgrid(d, xmap%grids(g), x, xmap)
3345  return;
3346  end if
3347  end do
3348 
3349  call error_mesg ('xgrid_mod', 'put_to_xgrid: could not find grid id', fatal)
3350 
3351 end subroutine put_side2_to_xgrid
3352 
3353 !#######################################################################
3354 
3355 subroutine get_side1_from_xgrid(d, grid_id, x, xmap, complete)
3356  use, intrinsic :: iso_c_binding, only: c_ptr, c_null_ptr, c_loc
3357  real(r8_kind), target, contiguous, intent(out) :: d(:,:) !< received xgrid data
3358  character(len=3), intent(in) :: grid_id !< 3 character grid ID
3359  real(r8_kind), target, contiguous, intent(in) :: x(:) !< xgrid data
3360  type (xmap_type), intent(inout) :: xmap !< exchange grid
3361  logical, intent(in), optional :: complete
3362 
3363  logical :: is_complete, set_mismatch
3364  integer :: g
3365  character(len=2) :: text
3366  integer, save :: isize=0
3367  integer, save :: jsize=0
3368  integer, save :: lsize=0
3369  integer, save :: xsize=0
3370  character(len=3), save :: grid_id_saved=""
3371  type(c_ptr), dimension(MAX_FIELDS), save :: d_addrs = c_null_ptr
3372  type(c_ptr), dimension(MAX_FIELDS), save :: x_addrs = c_null_ptr
3373 
3374  d = 0.0_r8_kind
3375  if (grid_id==xmap%grids(1)%id) then
3376  is_complete = .true.
3377  if(present(complete)) is_complete=complete
3378  lsize = lsize + 1
3379  if( lsize > max_fields ) then
3380  write( text,'(i2)' ) max_fields
3381  call error_mesg ('xgrid_mod', 'MAX_FIELDS='//trim(text)//' exceeded for group get_side1_from_xgrid', fatal)
3382  endif
3383  d_addrs(lsize) = c_loc(d)
3384  x_addrs(lsize) = c_loc(x)
3385 
3386  if(lsize == 1) then
3387  isize = size(d,1)
3388  jsize = size(d,2)
3389  xsize = size(x(:))
3390  grid_id_saved = grid_id
3391  else
3392  set_mismatch = .false.
3393  set_mismatch = set_mismatch .OR. (isize /= size(d,1))
3394  set_mismatch = set_mismatch .OR. (jsize /= size(d,2))
3395  set_mismatch = set_mismatch .OR. (xsize /= size(x(:)))
3396  set_mismatch = set_mismatch .OR. (grid_id_saved /= grid_id)
3397  if(set_mismatch)then
3398  write( text,'(i2)' ) lsize
3399  call error_mesg ('xgrid_mod', 'Incompatible field at count '//text// &
3400  & ' for group get_side1_from_xgrid', fatal )
3401  endif
3402  endif
3403 
3404  if(is_complete) then
3405  if (make_exchange_reproduce) then
3406  call get_1_from_xgrid_repro(d_addrs, x_addrs, xmap, xsize, lsize)
3407  else
3408  call get_1_from_xgrid(d_addrs, x_addrs, xmap, isize, jsize, xsize, lsize)
3409  end if
3410  d_addrs(1:lsize) = c_null_ptr
3411  x_addrs(1:lsize) = c_null_ptr
3412  isize = 0
3413  jsize = 0
3414  xsize = 0
3415  lsize = 0
3416  grid_id_saved = ""
3417  endif
3418  return;
3419  end if
3420 
3421  do g=2,size(xmap%grids(:))
3422  if (grid_id==xmap%grids(g)%id) &
3423  call error_mesg ('xgrid_mod', &
3424  'get_from_xgrid expects a 3D side 2 grid', fatal)
3425  end do
3426 
3427  call error_mesg ('xgrid_mod', 'get_from_xgrid: could not find grid id', fatal)
3428 
3429 end subroutine get_side1_from_xgrid
3430 
3431 !#######################################################################
3432 
3433 subroutine get_side2_from_xgrid(d, grid_id, x, xmap)
3434 real(r8_kind), dimension(:,:,:), intent(out) :: d !< received xgrid data
3435 character(len=3), intent(in) :: grid_id !< 3 character grid ID
3436 real(r8_kind), dimension(:), intent(in) :: x !< xgrid data
3437 type (xmap_type), intent(in) :: xmap !< exchange grid
3438 
3439  integer :: g
3440 
3441  if (grid_id==xmap%grids(1)%id) &
3442  call error_mesg ('xgrid_mod', &
3443  'get_from_xgrid expects a 2D side 1 grid', fatal)
3444 
3445  do g=2,size(xmap%grids(:))
3446  if (grid_id==xmap%grids(g)%id) then
3447  call get_2_from_xgrid(d, xmap%grids(g), x, xmap)
3448  return;
3449  end if
3450  end do
3451 
3452  call error_mesg ('xgrid_mod', 'get_from_xgrid: could not find grid id', fatal)
3453 
3454 end subroutine get_side2_from_xgrid
3455 
3456 !#######################################################################
3457 
3458 !> @brief Returns logical associating exchange grid cells with given side two grid.
3459 subroutine some(xmap, some_arr, grid_id)
3460 type (xmap_type), intent(in) :: xmap
3461 character(len=3), optional, intent(in) :: grid_id
3462 logical, dimension(:), intent(out) :: some_arr !< logical associating exchange grid cells with given side 2 grid.
3463 
3464  integer :: g
3465 
3466  if (.not.present(grid_id)) then
3467 
3468  if(xmap%size > 0) then
3469  some_arr = .true.
3470  else
3471  some_arr = .false.
3472  end if
3473  return;
3474  end if
3475 
3476  if (grid_id==xmap%grids(1)%id) &
3477  call error_mesg ('xgrid_mod', 'some expects a side 2 grid id', fatal)
3478 
3479  do g=2,size(xmap%grids(:))
3480  if (grid_id==xmap%grids(g)%id) then
3481  some_arr = .false.
3482  some_arr(xmap%grids(g)%first:xmap%grids(g)%last) = .true.;
3483  return;
3484  end if
3485  end do
3486 
3487  call error_mesg ('xgrid_mod', 'some could not find grid id', fatal)
3488 
3489 end subroutine some
3490 
3491 !#######################################################################
3492 
3493 subroutine put_2_to_xgrid(d, grid, x, xmap)
3494 type (grid_type), intent(in) :: grid
3495 real(r8_kind), dimension(grid%is_me:grid%ie_me, & grid%js_me:grid%je_me, grid%km), intent(in) :: d
3496 real(r8_kind), dimension(:), intent(inout) :: x
3497 type (xmap_type), intent(in) :: xmap
3498 
3499  integer :: l
3500  call mpp_clock_begin(id_put_2_to_xgrid)
3501 
3502  do l=grid%first,grid%last
3503  x(l) = d(xmap%x2(l)%i,xmap%x2(l)%j,xmap%x2(l)%k)
3504  end do
3505 
3506  call mpp_clock_end(id_put_2_to_xgrid)
3507 end subroutine put_2_to_xgrid
3508 
3509 !#######################################################################
3510 
3511 subroutine get_2_from_xgrid(d, grid, x, xmap)
3512 type (grid_type), intent(in) :: grid
3513 real(r8_kind), dimension(grid%is_me:grid%ie_me, & grid%js_me:grid%je_me, grid%km), intent(out) :: d
3514 real(r8_kind), dimension(:), intent(in) :: x
3515 type (xmap_type), intent(in) :: xmap
3516 
3517  integer :: l, k
3518 
3519  call mpp_clock_begin(id_get_2_from_xgrid)
3520 
3521  d = 0.0_r8_kind
3522  do l=grid%first_get,grid%last_get
3523  d(xmap%x2_get(l)%i,xmap%x2_get(l)%j,xmap%x2_get(l)%k) = &
3524  d(xmap%x2_get(l)%i,xmap%x2_get(l)%j,xmap%x2_get(l)%k) + xmap%x2_get(l)%area*x(xmap%x2_get(l)%pos)
3525  end do
3526  !
3527  ! normalize with side 2 grid cell areas
3528  !
3529  do k=1,size(d,3)
3530  d(:,:,k) = d(:,:,k) * grid%area_inv
3531  end do
3532 
3533  call mpp_clock_end(id_get_2_from_xgrid)
3534 
3535 end subroutine get_2_from_xgrid
3536 
3537 !#######################################################################
3538 
3539 subroutine put_1_to_xgrid_order_1(d_addrs, x_addrs, xmap, isize, jsize, xsize, lsize)
3540  use, intrinsic :: iso_c_binding, only: c_ptr, c_f_pointer
3541  type(c_ptr), dimension(:), intent(in) :: d_addrs
3542  type(c_ptr), dimension(:), intent(in) :: x_addrs
3543  type (xmap_type), intent(inout) :: xmap
3544  integer, intent(in) :: isize, jsize, xsize, lsize
3545 
3546  integer :: i, j, p, buffer_pos, msgsize
3547  integer :: from_pe, to_pe, pos, n, l, count
3548  integer :: ibegin, istart, iend, start_pos
3549  type (comm_type), pointer, save :: comm =>null()
3550  real(r8_kind) :: recv_buffer(xmap%put1%recvsize*lsize)
3551  real(r8_kind) :: send_buffer(xmap%put1%sendsize*lsize)
3552  real(r8_kind) :: unpack_buffer(xmap%put1%recvsize)
3553 
3554  real(r8_kind), pointer :: d(:,:) ! isize, jsize
3555  real(r8_kind), pointer :: x(:) ! xsize
3556 
3557  call mpp_clock_begin(id_put_1_to_xgrid_order_1)
3558 
3559  !--- pre-post receiving
3560  comm => xmap%put1
3561  do p = 1, comm%nrecv
3562  msgsize = comm%recv(p)%count*lsize
3563  from_pe = comm%recv(p)%pe
3564  buffer_pos = comm%recv(p)%buffer_pos*lsize
3565  call mpp_recv(recv_buffer(buffer_pos+1), glen=msgsize, from_pe = from_pe, block=.false., tag=comm_tag_7)
3566  enddo
3567 
3568  !--- send the data
3569  buffer_pos = 0
3570  do p = 1, comm%nsend
3571  msgsize = comm%send(p)%count*lsize
3572  to_pe = comm%send(p)%pe
3573  pos = buffer_pos
3574  do l = 1, lsize
3575  call c_f_pointer(d_addrs(l), d, shape=[isize, jsize])
3576  do n = 1, comm%send(p)%count
3577  pos = pos + 1
3578  i = comm%send(p)%i(n)
3579  j = comm%send(p)%j(n)
3580  send_buffer(pos) = d(i,j)
3581  enddo
3582  enddo
3583  call mpp_send(send_buffer(buffer_pos+1), plen=msgsize, to_pe = to_pe, tag=comm_tag_7 )
3584  buffer_pos = buffer_pos + msgsize
3585  enddo
3586 
3587  call mpp_sync_self(check=event_recv)
3588 
3589  !--- unpack the buffer
3590  if( lsize == 1) then
3591  call c_f_pointer(x_addrs(1), x, shape=[xsize])
3592  do l=1,xmap%size_put1
3593  x(l) = recv_buffer(xmap%x1_put(l)%pos)
3594  end do
3595  else
3596  start_pos = 0
3597 !$OMP parallel do default(none) shared(lsize,xsize,x_addrs,comm,recv_buffer,xmap) &
3598 !$OMP private(x,count,ibegin,istart,iend,pos,unpack_buffer)
3599  do l = 1, lsize
3600  call c_f_pointer(x_addrs(l), x, shape=[xsize])
3601  do p = 1, comm%nrecv
3602  count = comm%recv(p)%count
3603  ibegin = comm%recv(p)%buffer_pos*lsize + 1
3604  istart = ibegin + (l-1)*count
3605  iend = istart + count - 1
3606  pos = comm%recv(p)%buffer_pos
3607  do n = istart, iend
3608  pos = pos + 1
3609  unpack_buffer(pos) = recv_buffer(n)
3610  enddo
3611  enddo
3612  do i=1,xmap%size_put1
3613  x(i) = unpack_buffer(xmap%x1_put(i)%pos)
3614  end do
3615  enddo
3616  endif
3617 
3618  call mpp_sync_self()
3619 
3620  call mpp_clock_end(id_put_1_to_xgrid_order_1)
3621 
3622 end subroutine put_1_to_xgrid_order_1
3623 
3624 !#######################################################################
3625 
3626 
3627 subroutine put_1_to_xgrid_order_2(d_addrs, x_addrs, xmap, isize, jsize, xsize, lsize)
3628  use, intrinsic :: iso_c_binding, only: c_ptr, c_f_pointer
3629  type(c_ptr), intent(in) :: d_addrs(:)
3630  type(c_ptr), intent(in) :: x_addrs(:)
3631  type (xmap_type), intent(inout) :: xmap
3632  integer, intent(in) :: isize, jsize, xsize, lsize
3633 
3634  !: NOTE: halo size is assumed to be 1 in setup_xmap
3635  real(r8_kind), dimension(0:isize+1, 0:jsize+1, lsize) :: tmp
3636  real(r8_kind), dimension(isize, jsize, lsize) :: tmpx, tmpy
3637  real(r8_kind), dimension(isize, jsize, lsize) :: d_bar_max, d_bar_min
3638  real(r8_kind), dimension(isize, jsize, lsize) :: d_max, d_min
3639  real(r8_kind) :: d_bar
3640  integer :: i, is, ie, j, js, je, ii, jj
3641  integer :: p, l, isd, jsd
3642  type (grid_type), pointer, save :: grid1 =>null()
3643  type (comm_type), pointer, save :: comm =>null()
3644  integer :: buffer_pos, msgsize, from_pe, to_pe, pos, n
3645  integer :: ibegin, count, istart, iend
3646  real(r8_kind) :: recv_buffer(xmap%put1%recvsize*lsize*3)
3647  real(r8_kind) :: send_buffer(xmap%put1%sendsize*lsize*3)
3648  real(r8_kind) :: unpack_buffer(xmap%put1%recvsize*3)
3649  logical :: on_west_edge, on_east_edge, on_south_edge, on_north_edge
3650  real(r8_kind), pointer :: d(:,:)
3651  real(r8_kind), pointer :: x(:)
3652 
3653  call mpp_clock_begin(id_put_1_to_xgrid_order_2)
3654  grid1 => xmap%grids(1)
3655 
3656  is = grid1%is_me; ie = grid1%ie_me
3657  js = grid1%js_me; je = grid1%je_me
3658  isd = grid1%isd_me
3659  jsd = grid1%jsd_me
3660 
3661 !$OMP parallel do default(none) shared(lsize,isize,jsize,tmp,d_addrs) private(d)
3662  do l = 1, lsize
3663  tmp(:,:,l) = large_number
3664  call c_f_pointer(d_addrs(l), d, shape=[isize, jsize])
3665  tmp(1:isize,1:jsize,l) = d(:,:)
3666  enddo
3667 
3668  if(grid1%is_latlon) then
3669  call mpp_update_domains(tmp,grid1%domain_with_halo)
3670 !$OMP parallel do default(none) shared(lsize,tmp,grid1,is,ie,js,je,isd,jsd,tmpx,tmpy)
3671  do l = 1, lsize
3672  tmpy(:,:,l) = grad_merid_latlon(tmp(:,:,l), grid1%lat, is, ie, js, je, isd, jsd)
3673  tmpx(:,:,l) = grad_zonal_latlon(tmp(:,:,l), grid1%lon, grid1%lat, is, ie, js, je, isd, jsd)
3674  enddo
3675  else
3676  call mpp_update_domains(tmp,grid1%domain)
3677  on_west_edge = (is==1)
3678  on_east_edge = (ie==grid1%im)
3679  on_south_edge = (js==1)
3680  on_north_edge = (je==grid1%jm)
3681 !$OMP parallel do default(none) shared(lsize,tmp,grid1,tmpx,tmpy, &
3682 !$OMP on_west_edge,on_east_edge,on_south_edge,on_north_edge)
3683  do l = 1, lsize
3684  call gradient_cubic(tmp(:,:,l), grid1%box%dx, grid1%box%dy, grid1%box%area, &
3685  grid1%box%edge_w, grid1%box%edge_e, grid1%box%edge_s, &
3686  grid1%box%edge_n, grid1%box%en1, grid1%box%en2, &
3687  grid1%box%vlon, grid1%box%vlat, tmpx(:,:,l), tmpy(:,:,l), &
3688  on_west_edge, on_east_edge, on_south_edge, on_north_edge)
3689  enddo
3690  end if
3691 
3692  !--- pre-post receiving
3693  buffer_pos = 0
3694  comm => xmap%put1
3695  do p = 1, comm%nrecv
3696  msgsize = comm%recv(p)%count*lsize
3697  buffer_pos = comm%recv(p)%buffer_pos*lsize
3698  if(.NOT. monotonic_exchange) then
3699  msgsize = msgsize*3
3700  buffer_pos = buffer_pos*3
3701  endif
3702  from_pe = comm%recv(p)%pe
3703  call mpp_recv(recv_buffer(buffer_pos+1), glen=msgsize, from_pe = from_pe, block=.false., tag=comm_tag_8)
3704  enddo
3705 
3706  !--- compute d_bar_max and d_bar_min.
3707  if(monotonic_exchange) then
3708 !$OMP parallel do default(none) shared(lsize,isize,jsize,d_bar_max,d_bar_min,d_max,d_min,tmp)
3709  do l = 1, lsize
3710  do j = 1, jsize
3711  do i = 1, isize
3712  d_bar_max(i,j,l) = -large_number
3713  d_bar_min(i,j,l) = large_number
3714  d_max(i,j,l) = -large_number
3715  d_min(i,j,l) = large_number
3716  do jj = j-1, j+1
3717  do ii = i-1, i+1
3718  if(tmp(i,j,l) .NE. large_number) then
3719  if(tmp(i,j,l) > d_bar_max(i,j,l)) d_bar_max(i,j,l) = tmp(i,j,l)
3720  if(tmp(i,j,l) < d_bar_min(i,j,l)) d_bar_min(i,j,l) = tmp(i,j,l)
3721  endif
3722  enddo
3723  enddo
3724  enddo
3725  enddo
3726  enddo
3727  endif
3728 
3729  !--- send the data
3730  buffer_pos = 0
3731  if(monotonic_exchange) then
3732  pos = 0
3733  do p = 1, comm%nsend
3734  msgsize = comm%send(p)%count*lsize
3735  to_pe = comm%send(p)%pe
3736  do l = 1, lsize
3737  call c_f_pointer(d_addrs(l), d, shape=[isize, jsize])
3738  do n = 1, comm%send(p)%count
3739  pos = pos + 1
3740  i = comm%send(p)%i(n)
3741  j = comm%send(p)%j(n)
3742  send_buffer(pos) = d(i,j) + tmpy(i,j,l)*comm%send(p)%dj(n) + tmpx(i,j,l)*comm%send(p)%di(n)
3743  if(send_buffer(pos) > d_max(i,j,l)) d_max(i,j,l) = send_buffer(pos)
3744  if(send_buffer(pos) < d_min(i,j,l)) d_min(i,j,l) = send_buffer(pos)
3745  enddo
3746  enddo
3747  enddo
3748 
3749  do p = 1, comm%nsend
3750  msgsize = comm%send(p)%count*lsize
3751  to_pe = comm%send(p)%pe
3752  pos = buffer_pos
3753  do l = 1, lsize
3754  call c_f_pointer(d_addrs(l), d, shape=[isize, jsize])
3755  do n = 1, comm%send(p)%count
3756  pos = pos + 1
3757  i = comm%send(p)%i(n)
3758  j = comm%send(p)%j(n)
3759  d_bar = d(i,j)
3760  if( d_max(i,j,l) > d_bar_max(i,j,l) ) then
3761  send_buffer(pos) = d_bar + ((send_buffer(pos)-d_bar)/(d_max(i,j,l)-d_bar)) * (d_bar_max(i,j,l)-d_bar)
3762  else if( d_min(i,j,l) < d_bar_min(i,j,l) ) then
3763  send_buffer(pos) = d_bar + ((send_buffer(pos)-d_bar)/(d_min(i,j,l)-d_bar)) * (d_bar_min(i,j,l)-d_bar)
3764  endif
3765  enddo
3766  enddo
3767  call mpp_send(send_buffer(buffer_pos+1), plen=msgsize, to_pe = to_pe, tag=comm_tag_8 )
3768  buffer_pos = buffer_pos + msgsize
3769  enddo
3770  else
3771  do p = 1, comm%nsend
3772  msgsize = comm%send(p)%count*lsize*3
3773  to_pe = comm%send(p)%pe
3774  pos = buffer_pos
3775  do l = 1, lsize
3776  call c_f_pointer(d_addrs(l), d, shape=[isize, jsize])
3777  do n = 1, comm%send(p)%count
3778  pos = pos + 3
3779  i = comm%send(p)%i(n)
3780  j = comm%send(p)%j(n)
3781  send_buffer(pos-2) = d(i,j)
3782  send_buffer(pos-1) = tmpy(i,j,l)
3783  send_buffer(pos ) = tmpx(i,j,l)
3784  enddo
3785  enddo
3786  call mpp_send(send_buffer(buffer_pos+1), plen=msgsize, to_pe = to_pe, tag=comm_tag_8 )
3787  buffer_pos = buffer_pos + msgsize
3788  enddo
3789  endif
3790 
3791  call mpp_sync_self(check=event_recv)
3792 
3793  !--- unpack the buffer
3794  if(monotonic_exchange) then
3795  if( lsize == 1) then
3796  call c_f_pointer(x_addrs(1), x, shape=[xsize])
3797  do l=1,xmap%size_put1
3798  pos = xmap%x1_put(l)%pos
3799  x(l) = recv_buffer(pos)
3800  end do
3801  else
3802  do l = 1, lsize
3803  call c_f_pointer(x_addrs(l), x, shape=[xsize])
3804  pos = 0
3805  do p = 1, comm%nsend
3806  count = comm%send(p)%count
3807  ibegin = comm%recv(p)%buffer_pos*lsize + 1
3808  istart = ibegin + (l-1)*count
3809  iend = istart + count - 1
3810  pos = comm%recv(p)%buffer_pos
3811  do n = istart, iend
3812  pos = pos + 1
3813  unpack_buffer(pos) = recv_buffer(n)
3814  enddo
3815  enddo
3816  do i=1,xmap%size_put1
3817  pos = xmap%x1_put(i)%pos
3818  x(i) = unpack_buffer(pos)
3819  end do
3820  enddo
3821  endif
3822  else
3823  if( lsize == 1) then
3824  call c_f_pointer(x_addrs(1), x, shape=[xsize])
3825 !$OMP parallel do default(none) shared(xmap,recv_buffer,x) private(pos)
3826  do l=1,xmap%size_put1
3827  pos = xmap%x1_put(l)%pos
3828  x(l) = recv_buffer(3*pos-2) + recv_buffer(3*pos-1)*xmap%x1_put(l)%dj + recv_buffer(3*pos)*xmap%x1_put(l)%di
3829  end do
3830  else
3831 !$OMP parallel do default(none) shared(lsize,xsize,comm,xmap,recv_buffer,x_addrs) &
3832 !$OMP private(x,pos,ibegin,istart,iend,count,unpack_buffer)
3833  do l = 1, lsize
3834  call c_f_pointer(x_addrs(l), x, shape=[xsize])
3835  pos = 0
3836  ibegin = 1
3837  do p = 1, comm%nrecv
3838  count = comm%recv(p)%count*3
3839  ibegin = comm%recv(p)%buffer_pos*lsize*3 + 1
3840  istart = ibegin + (l-1)*count
3841  iend = istart + count - 1
3842  pos = comm%recv(p)%buffer_pos*3
3843  do n = istart, iend
3844  pos = pos + 1
3845  unpack_buffer(pos) = recv_buffer(n)
3846  enddo
3847  enddo
3848  do i=1,xmap%size_put1
3849  pos = xmap%x1_put(i)%pos
3850  x(i) = unpack_buffer(3*pos-2) + unpack_buffer(3*pos-1)*xmap%x1_put(i)%dj + unpack_buffer(3*pos) &
3851  & * xmap%x1_put(i)%di
3852  end do
3853  enddo
3854  endif
3855  endif
3856 
3857  call mpp_sync_self()
3858  call mpp_clock_end(id_put_1_to_xgrid_order_2)
3859 
3860 end subroutine put_1_to_xgrid_order_2
3861 
3862 !#######################################################################
3863 
3864 subroutine get_1_from_xgrid(d_addrs, x_addrs, xmap, isize, jsize, xsize, lsize)
3865  use, intrinsic :: iso_c_binding, only: c_ptr, c_f_pointer
3866  type(c_ptr), intent(in) :: d_addrs(:)
3867  type(c_ptr), intent(in) :: x_addrs(:)
3868  type (xmap_type), intent(inout) :: xmap
3869  integer, intent(in) :: isize, jsize, xsize, lsize
3870 
3871  real(r8_kind), dimension(xmap%size), target :: dg(xmap%size, lsize)
3872  integer :: i, j, l, p, n, m
3873  integer :: msgsize, buffer_pos, pos
3874  integer :: istart, iend, count
3875  real(r8_kind) , pointer, save :: dgp =>null()
3876  type(grid_type) , pointer, save :: grid1 =>null()
3877  type(comm_type) , pointer, save :: comm =>null()
3878  type(overlap_type), pointer, save :: send => null()
3879  type(overlap_type), pointer, save :: recv => null()
3880  real(r8_kind) :: recv_buffer(xmap%get1%recvsize*lsize*3)
3881  real(r8_kind) :: send_buffer(xmap%get1%sendsize*lsize*3)
3882  real(r8_kind), pointer :: d(:,:)
3883  real(r8_kind), pointer :: x(:)
3884 
3885  call mpp_clock_begin(id_get_1_from_xgrid)
3886 
3887  comm => xmap%get1
3888  grid1 => xmap%grids(1)
3889 
3890  do p = 1, comm%nrecv
3891  recv => comm%recv(p)
3892  msgsize = recv%count*lsize
3893  buffer_pos = recv%buffer_pos*lsize
3894  call mpp_recv(recv_buffer(buffer_pos+1), glen=msgsize, from_pe = recv%pe, block=.false., tag=comm_tag_9)
3895  enddo
3896 
3897  dg = 0.0_r8_kind;
3898 !$OMP parallel do default(none) shared(lsize,xsize,xmap,dg,x_addrs) private(dgp,x)
3899  do l = 1, lsize
3900  call c_f_pointer(x_addrs(l), x, shape=[xsize])
3901  do i=1,xmap%size
3902  dgp => dg(xmap%x1(i)%pos,l)
3903  dgp = dgp + xmap%x1(i)%area*x(i)
3904  enddo
3905  enddo
3906 
3907 
3908  !--- send the data
3909  buffer_pos = 0
3910  istart = 1
3911  do p = 1, comm%nsend
3912  send => comm%send(p)
3913  msgsize = send%count*lsize
3914  pos = buffer_pos
3915  istart = send%buffer_pos+1
3916  iend = istart + send%count - 1
3917  do l = 1, lsize
3918  do n = istart, iend
3919  pos = pos + 1
3920  send_buffer(pos) = dg(n,l)
3921  enddo
3922  enddo
3923  call mpp_send(send_buffer(buffer_pos+1), plen=msgsize, to_pe = send%pe, tag=comm_tag_9 )
3924  buffer_pos = buffer_pos + msgsize
3925  istart = iend + 1
3926  enddo
3927 
3928  call mpp_sync_self(check=event_recv)
3929 
3930  !--- unpack the buffer
3931  do l = 1, lsize
3932  call c_f_pointer(d_addrs(l), d, shape=[isize, jsize])
3933  d = 0.0_r8_kind
3934  enddo
3935  !--- To bitwise reproduce old results, first copy the data onto its own pe.
3936 
3937  do p = 1, comm%nrecv
3938  recv => comm%recv(p)
3939  count = recv%count
3940  buffer_pos = recv%buffer_pos*lsize
3941  if( recv%pe == xmap%me ) then
3942 !$OMP parallel do default(none) shared(lsize,isize,jsize,recv,recv_buffer,buffer_pos,d_addrs,count) &
3943 !$OMP private(d,i,j,pos)
3944  do l = 1, lsize
3945  pos = buffer_pos + (l-1)*count
3946  call c_f_pointer(d_addrs(l), d, shape=[isize, jsize])
3947  do n = 1,count
3948  i = recv%i(n)
3949  j = recv%j(n)
3950  pos = pos + 1
3951  d(i,j) = recv_buffer(pos)
3952  enddo
3953  enddo
3954  exit
3955  endif
3956  enddo
3957 
3958  pos = 0
3959  do m = 1, comm%nrecv
3960  p = comm%unpack_ind(m)
3961  recv => comm%recv(p)
3962  if( recv%pe == xmap%me ) then
3963  cycle
3964  endif
3965  buffer_pos = recv%buffer_pos*lsize
3966 !$OMP parallel do default(none) shared(lsize,isize,jsize,recv,recv_buffer,buffer_pos,d_addrs) &
3967 !$OMP private(d,i,j,pos)
3968  do l = 1, lsize
3969  pos = buffer_pos + (l-1)*recv%count
3970  call c_f_pointer(d_addrs(l), d, shape=[isize, jsize])
3971  do n = 1, recv%count
3972  i = recv%i(n)
3973  j = recv%j(n)
3974  pos = pos + 1
3975  d(i,j) = d(i,j) + recv_buffer(pos)
3976  enddo
3977  enddo
3978  enddo
3979 
3980  !
3981  ! normalize with side 1 grid cell areas
3982  !
3983 !$OMP parallel do default(none) shared(lsize,isize,jsize,d_addrs,grid1) private(d)
3984  do l = 1, lsize
3985  call c_f_pointer(d_addrs(l), d, shape=[isize, jsize])
3986  d = d * grid1%area_inv
3987  enddo
3988  call mpp_sync_self()
3989  call mpp_clock_end(id_get_1_from_xgrid)
3990 
3991 end subroutine get_1_from_xgrid
3992 
3993 !#######################################################################
3994 
3995 subroutine get_1_from_xgrid_repro(d_addrs, x_addrs, xmap, xsize, lsize)
3996  use, intrinsic :: iso_c_binding, only: c_ptr, c_f_pointer
3997  type(c_ptr), intent(in) :: d_addrs(:)
3998  type(c_ptr), intent(in) :: x_addrs(:)
3999  type (xmap_type), intent(inout) :: xmap
4000  integer, intent(in) :: xsize, lsize
4001 
4002  integer :: g, i, j, k, p, l, n, l2, l3
4003  integer :: msgsize, buffer_pos, pos
4004  type (grid_type), pointer, save :: grid =>null()
4005  type(comm_type), pointer, save :: comm => null()
4006  type(overlap_type), pointer, save :: send => null()
4007  type(overlap_type), pointer, save :: recv => null()
4008  integer, dimension(0:xmap%npes-1) :: pl, ml
4009  real(r8_kind) :: recv_buffer(xmap%recv_count_repro_tot*lsize)
4010  real(r8_kind) :: send_buffer(xmap%send_count_repro_tot*lsize)
4011  real(r8_kind), pointer :: d(:,:)
4012  real(r8_kind), pointer :: x(:)
4013  real(r8_kind), pointer, contiguous :: tmpptr(:,:)
4014  integer :: shape_d(2)
4015  integer :: i_off, j_off
4016 
4017  call mpp_clock_begin(id_get_1_from_xgrid_repro)
4018  shape_d = [xmap%grids(1)%ie_me-xmap%grids(1)%is_me+1, xmap%grids(1)%je_me-xmap%grids(1)%js_me+1]
4019  i_off = xmap%grids(1)%is_me - 1
4020  j_off = xmap%grids(1)%js_me - 1
4021  comm => xmap%get1_repro
4022  !--- pre-post receiving
4023  do p = 1, comm%nrecv
4024  recv => comm%recv(p)
4025  msgsize = recv%count*lsize
4026  buffer_pos = recv%buffer_pos*lsize
4027  call mpp_recv(recv_buffer(buffer_pos+1), glen=msgsize, from_pe = recv%pe, block=.false., tag=comm_tag_10)
4028  n = recv%pe -xmap%root_pe
4029  pl(n) = buffer_pos
4030  ml(n) = recv%count
4031  enddo
4032 
4033  !pack the data
4034  send_buffer(:) = 0.0_r8_kind
4035 !$OMP parallel do default(none) shared(lsize,xsize,x_addrs,comm,xmap,send_buffer) &
4036 !$OMP private(x,i,j,g,l2,pos,send)
4037  do p = 1, comm%nsend
4038  pos = comm%send(p)%buffer_pos*lsize
4039  send => comm%send(p)
4040  do l = 1,lsize
4041  call c_f_pointer(x_addrs(l), x, shape=[xsize])
4042  do n = 1, send%count
4043  i = send%i(n)
4044  j = send%j(n)
4045  g = send%g(n)
4046  l2 = send%xloc(n)
4047  pos = pos + 1
4048  do k =1, xmap%grids(g)%km
4049  if(xmap%grids(g)%frac_area(i,j,k)/=0.0_r8_kind) then
4050  l2 = l2+1
4051  send_buffer(pos) = send_buffer(pos) + xmap%x1(l2)%area *x(l2)
4052  endif
4053  enddo
4054  enddo
4055  enddo
4056  enddo
4057 
4058  do p =1, comm%nsend
4059  buffer_pos = comm%send(p)%buffer_pos*lsize
4060  msgsize = comm%send(p)%count*lsize
4061  call mpp_send(send_buffer(buffer_pos+1), plen=msgsize, to_pe=comm%send(p)%pe, tag=comm_tag_10)
4062  enddo
4063 
4064  do l = 1, lsize
4065  call c_f_pointer(d_addrs(l), tmpptr, shape=shape_d)
4066  d => tmpptr
4067  d = 0
4068  enddo
4069 
4070  call mpp_sync_self(check=event_recv)
4071 
4072 !$OMP parallel do default(none) shared(lsize,shape_d,d_addrs,xmap,recv_buffer,pl,ml,i_off,j_off) &
4073 !$OMP private(d,tmpptr,grid,i,j,p,pos)
4074  do l = 1, lsize
4075  call c_f_pointer(d_addrs(l), tmpptr, shape=shape_d)
4076  d => tmpptr
4077  do g=2,size(xmap%grids(:))
4078  grid => xmap%grids(g)
4079  do l3=1,grid%size_repro ! index into side1 grid's patterns
4080  i = grid%x_repro(l3)%i1
4081  j = grid%x_repro(l3)%j1
4082  p = grid%x_repro(l3)%pe-xmap%root_pe
4083  pos = pl(p) + (l-1)*ml(p) + grid%x_repro(l3)%recv_pos
4084  d(i - i_off, j - j_off) = d(i - i_off, j - j_off) + recv_buffer(pos)
4085  end do
4086  end do
4087  ! normalize with side 1 grid cell areas
4088  d = d * xmap%grids(1)%area_inv
4089  enddo
4090 
4091  call mpp_sync_self()
4092 
4093  call mpp_clock_end(id_get_1_from_xgrid_repro)
4094 
4095 end subroutine get_1_from_xgrid_repro
4096 
4097 !#######################################################################
4098 
4099 !> @brief conservation_check - returns three numbers which are the global sum of a
4100 !! variable (1) on its home model grid, (2) after interpolation to the other
4101 !! side grid(s), and (3) after re_interpolation back onto its home side grid(s).
4102 !! @return real(r8_kind) conservation_check_side1
4103 function conservation_check_side1(d, grid_id, xmap,remap_method) ! this one for 1->2->1
4104 real(r8_kind), dimension(:,:), intent(in) :: d !< model data to check
4105 character(len=3), intent(in) :: grid_id !< 3 character grid id
4106 type (xmap_type), intent(inout) :: xmap !< exchange grid
4107 real(r8_kind), dimension(3) :: conservation_check_side1
4108 integer, intent(in), optional :: remap_method
4109 
4110 
4111  real(r8_kind), dimension(xmap%size) :: x_over, x_back
4112  real(r8_kind), dimension(size(d,1),size(d,2)) :: d1
4113  real(r8_kind), dimension(:,:,:), allocatable :: d2
4114  integer :: g
4115  type (grid_type), pointer, save :: grid1 =>null(), grid2 =>null()
4116 
4117  grid1 => xmap%grids(1)
4118  conservation_check_side1 = 0.0_r8_kind
4119  if(grid1%tile_me .NE. tile_nest) conservation_check_side1(1) = sum(grid1%area*d)
4120 ! if(grid1%tile_me .NE. tile_parent .OR. grid1%id .NE. "ATM") &
4121 ! conservation_check_side1(1) = sum(grid1%area*d)
4122 
4123  call put_to_xgrid (d, grid1%id, x_over, xmap, remap_method) ! put from side 1
4124  do g=2,size(xmap%grids(:))
4125  grid2 => xmap%grids(g)
4126  if(grid2%on_this_pe) then
4127  allocate (d2(grid2%is_me:grid2%ie_me, grid2%js_me:grid2%je_me, grid2%km) )
4128  endif
4129  call get_from_xgrid (d2, grid2%id, x_over, xmap) ! get onto side 2's
4130  if(grid2%on_this_pe) then
4131  conservation_check_side1(2) = conservation_check_side1(2) + sum( grid2%area * sum(grid2%frac_area*d2,dim=3) )
4132  endif
4133  call put_to_xgrid (d2, grid2%id, x_back, xmap) ! put from side 2's
4134  if(allocated(d2))deallocate (d2)
4135  end do
4136  call get_from_xgrid(d1, grid1%id, x_back, xmap) ! get onto side 1
4137  if(grid1%tile_me .NE. tile_nest) conservation_check_side1(3) = sum(grid1%area*d1)
4138 ! if(grid1%tile_me .NE. tile_parent .OR. grid1%id .NE. "ATM") &
4139 ! conservation_check_side1(3) = sum(grid1%area*d1)
4140  call mpp_sum(conservation_check_side1,3)
4141 
4142 end function conservation_check_side1
4143 
4144 !#######################################################################
4145 
4146 !> @brief conservation_check - returns three numbers which are the global sum of a
4147 !! variable (1) on its home model grid, (2) after interpolation to the other
4148 !! side grid(s), and (3) after re_interpolation back onto its home side grid(s).
4149 !! @return real(r8_kind) conservation_check_side2
4150 function conservation_check_side2(d, grid_id, xmap,remap_method) ! this one for 2->1->2
4151 real(r8_kind), dimension(:,:,:), intent(in) :: d !< model data to check
4152 character(len=3), intent(in) :: grid_id !< 3 character grid ID
4153 type (xmap_type), intent(inout) :: xmap !< exchange grid
4154 real(r8_kind), dimension(3) :: conservation_check_side2
4155 integer, intent(in), optional :: remap_method
4156 
4157 
4158  real(r8_kind), dimension(xmap%size) :: x_over, x_back
4159  real(r8_kind), dimension(:,: ), allocatable :: d1
4160  real(r8_kind), dimension(:,:,:), allocatable :: d2
4161  integer :: g
4162  type (grid_type), pointer, save :: grid1 =>null(), grid2 =>null()
4163 
4164  grid1 => xmap%grids(1)
4165  conservation_check_side2 = 0.0_r8_kind
4166  do g = 2,size(xmap%grids(:))
4167  grid2 => xmap%grids(g)
4168  if (grid_id==grid2%id) then
4169  if(grid2%on_this_pe) then
4170  conservation_check_side2(1) = sum( grid2%area * sum(grid2%frac_area*d,dim=3) )
4171  endif
4172  call put_to_xgrid(d, grid_id, x_over, xmap) ! put from this side 2
4173  else
4174  call put_to_xgrid(0.0_r8_kind * grid2%frac_area, grid2%id, x_over, xmap) ! zero rest
4175  end if
4176  end do
4177 
4178  allocate ( d1(size(grid1%area,1),size(grid1%area,2)) )
4179  call get_from_xgrid(d1, grid1%id, x_over, xmap) ! get onto side 1
4180  if(grid1%tile_me .NE. tile_nest)conservation_check_side2(2) = sum(grid1%area*d1)
4181  call put_to_xgrid(d1, grid1%id, x_back, xmap,remap_method) ! put from side 1
4182  deallocate ( d1 )
4183 
4184  conservation_check_side2(3) = 0.0_r8_kind;
4185  do g = 2,size(xmap%grids(:))
4186  grid2 => xmap%grids(g)
4187  if(grid2%on_this_pe) then
4188  allocate ( d2( size(grid2%frac_area, 1), size(grid2%frac_area, 2), &
4189  size(grid2%frac_area, 3) ) )
4190  endif
4191  call get_from_xgrid(d2, grid2%id, x_back, xmap) ! get onto side 2's
4192  conservation_check_side2(3) = conservation_check_side2(3) + sum( grid2%area * sum(grid2%frac_area*d2,dim=3) )
4193  if(allocated(d2) )deallocate ( d2 )
4194  end do
4195  call mpp_sum(conservation_check_side2, 3)
4196 
4197 end function conservation_check_side2
4198 ! </FUNCTION>
4199 
4200 !#######################################################################
4201 
4202 !> @brief conservation_check_ug - returns three numbers which are the global sum of a
4203 !! variable (1) on its home model grid, (2) after interpolation to the other
4204 !! side grid(s), and (3) after re_interpolation back onto its home side grid(s).
4205 !! @return real(r8_kind) conservation_check_ug_side1
4206 function conservation_check_ug_side1(d, grid_id, xmap,remap_method) ! this one for 1->2->1
4207 real(r8_kind), dimension(:,:), intent(in) :: d !< model data to check
4208 character(len=3), intent(in) :: grid_id !< 3 character grid ID
4209 type (xmap_type), intent(inout) :: xmap !< exchange grid
4210 real(r8_kind), dimension(3) :: conservation_check_ug_side1
4211 integer, intent(in), optional :: remap_method
4212 
4213  real(r8_kind), dimension(xmap%size) :: x_over, x_back
4214  real(r8_kind), dimension(size(d,1),size(d,2)) :: d1
4215  real(r8_kind), dimension(:,:,:), allocatable :: d2
4216  real(r8_kind), dimension(: ), allocatable :: d_ug
4217  real(r8_kind), dimension(:,:), allocatable :: d2_ug
4218  integer :: g
4219  type (grid_type), pointer, save :: grid1 =>null(), grid2 =>null()
4220 
4221  grid1 => xmap%grids(1)
4222  conservation_check_ug_side1 = 0.0_r8_kind
4223 
4224 
4225  if(grid1%is_ug) then
4226  allocate(d_ug(grid1%ls_me:grid1%le_me))
4227  call mpp_pass_sg_to_ug(grid1%ug_domain, d, d_ug)
4228  if(grid1%tile_me .NE. tile_nest) conservation_check_ug_side1(1) = sum(grid1%area(:,1)*d_ug)
4229  call put_to_xgrid_ug (d_ug, grid1%id, x_over, xmap) ! put from side 1
4230  else
4231  if(grid1%tile_me .NE. tile_nest) conservation_check_ug_side1(1) = sum(grid1%area*d)
4232  call put_to_xgrid (d, grid1%id, x_over, xmap, remap_method) ! put from side 1
4233  endif
4234  do g=2,size(xmap%grids(:))
4235  grid2 => xmap%grids(g)
4236  if(grid2%is_ug) then
4237  if(grid2%on_this_pe) then
4238  allocate (d2_ug(grid2%ls_me:grid2%le_me, grid2%km) )
4239  d2_ug = 0
4240  endif
4241  call get_from_xgrid_ug (d2_ug, grid2%id, x_over, xmap) ! get onto side 2's
4242  if(grid2%on_this_pe) then
4244  sum( grid2%area(:,1) * sum(grid2%frac_area(:,1,:)*d2_ug,dim=2) )
4245  endif
4246  call put_to_xgrid_ug (d2_ug, grid2%id, x_back, xmap) ! put from side 2's
4247  if(allocated(d2_ug))deallocate (d2_ug)
4248  else
4249  if(grid2%on_this_pe) then
4250  allocate (d2(grid2%is_me:grid2%ie_me, grid2%js_me:grid2%je_me, grid2%km) )
4251  endif
4252  call get_from_xgrid (d2, grid2%id, x_over, xmap) ! get onto side 2's
4253  if(grid2%on_this_pe) then
4255  & + sum( grid2%area * sum(grid2%frac_area*d2,dim=3) )
4256  endif
4257  call put_to_xgrid (d2, grid2%id, x_back, xmap) ! put from side 2's
4258  if(allocated(d2))deallocate (d2)
4259  endif
4260  end do
4261  if(grid1%is_ug) then
4262 ! call get_from_xgrid_ug(d_ug, grid1%id, x_back, xmap) ! get onto side 1
4263  if(grid1%tile_me .NE. tile_nest) conservation_check_ug_side1(3) = sum(grid1%area(:,1)*d_ug)
4264  else
4265  call get_from_xgrid(d1, grid1%id, x_back, xmap) ! get onto side 1
4266  if(grid1%tile_me .NE. tile_nest) conservation_check_ug_side1(3) = sum(grid1%area*d1)
4267  endif
4268  if(allocated(d_ug)) deallocate(d_ug)
4269  call mpp_sum(conservation_check_ug_side1,3)
4270 
4271 end function conservation_check_ug_side1
4272 
4273 !#######################################################################
4274 
4275 !> @brief conservation_check_ug - returns three numbers which are the global sum of a
4276 !! variable (1) on its home model grid, (2) after interpolation to the other
4277 !! side grid(s), and (3) after re_interpolation back onto its home side grid(s).
4278 !! @return real(r8_kind) conservation_check_ug_side2
4279 function conservation_check_ug_side2(d, grid_id, xmap,remap_method) ! this one for 2->1->2
4280 real(r8_kind), dimension(:,:,:), intent(in) :: d !< model data to check
4281 character(len=3), intent(in) :: grid_id !< 3 character grid ID
4282 type (xmap_type), intent(inout) :: xmap !< exchange grid
4283 real(r8_kind), dimension(3) :: conservation_check_ug_side2
4284 integer, intent(in), optional :: remap_method
4285 
4286 
4287  real(r8_kind), dimension(xmap%size) :: x_over, x_back
4288  real(r8_kind), dimension(:,: ), allocatable :: d1, d_ug
4289  real(r8_kind), dimension(:,:,:), allocatable :: d2
4290  integer :: g
4291  type (grid_type), pointer, save :: grid1 =>null(), grid2 =>null()
4292 
4293  grid1 => xmap%grids(1)
4294  conservation_check_ug_side2 = 0.0_r8_kind
4295  do g = 2,size(xmap%grids(:))
4296  grid2 => xmap%grids(g)
4297  if (grid_id==grid2%id) then
4298  if(grid2%on_this_pe) then
4299  if(grid2%is_ug) then
4300  allocate(d_ug(grid2%ls_me:grid2%le_me,grid2%km))
4301  call mpp_pass_sg_to_ug(grid2%ug_domain, d, d_ug)
4302  conservation_check_ug_side2(1) = sum( grid2%area(:,1) * sum(grid2%frac_area(:,1,:)*d_ug,dim=2) )
4303  else
4304  conservation_check_ug_side2(1) = sum( grid2%area(:,:) * sum(grid2%frac_area(:,:,:)*d,dim=3) )
4305  endif
4306  endif
4307  if(grid2%is_ug) then
4308  call put_to_xgrid_ug(d_ug, grid_id, x_over, xmap) ! put from this side 2
4309  else
4310  call put_to_xgrid(d, grid_id, x_over, xmap) ! put from this side 2
4311  endif
4312  if(allocated(d_ug)) deallocate(d_ug)
4313  else
4314  if(grid2%is_ug) then
4315  call put_to_xgrid_ug(0.0_r8_kind * grid2%frac_area(:,1,:), grid2%id, x_over, xmap) ! zero rest
4316  else
4317  call put_to_xgrid(0.0_r8_kind * grid2%frac_area, grid2%id, x_over, xmap) ! zero rest
4318  endif
4319  end if
4320  end do
4321 
4322  allocate ( d1(size(grid1%area,1),size(grid1%area,2)) )
4323  if(grid1%is_ug) then
4324  call get_from_xgrid_ug(d1(:,1), grid1%id, x_over, xmap) ! get onto side 1
4325  else
4326  call get_from_xgrid(d1, grid1%id, x_over, xmap) ! get onto side 1
4327  endif
4328  if(grid1%tile_me .NE. tile_nest)conservation_check_ug_side2(2) = sum(grid1%area*d1)
4329  if(grid1%is_ug) then
4330  call put_to_xgrid_ug(d1(:,1), grid1%id, x_back, xmap) ! put from side 1
4331  else
4332  call put_to_xgrid(d1, grid1%id, x_back, xmap,remap_method) ! put from side 1
4333  endif
4334  deallocate ( d1 )
4335 
4336  conservation_check_ug_side2(3) = 0.0_r8_kind;
4337  do g = 2,size(xmap%grids(:))
4338  grid2 => xmap%grids(g)
4339  if(grid2%on_this_pe) then
4340  allocate ( d2( size(grid2%frac_area, 1), size(grid2%frac_area, 2), &
4341  size(grid2%frac_area, 3) ) )
4342  endif
4343  if(grid2%is_ug) then
4344  call get_from_xgrid_ug(d2(:,1,:), grid2%id, x_back, xmap) ! get onto side 2's
4345  else
4346  call get_from_xgrid(d2, grid2%id, x_back, xmap) ! get onto side 2's
4347  endif
4348  conservation_check_ug_side2(3) = conservation_check_ug_side2(3) + sum( grid2%area * sum(grid2%frac_area*d2,dim=3) )
4349  if(allocated(d2) )deallocate ( d2 )
4350  end do
4351  call mpp_sum(conservation_check_ug_side2, 3)
4352 
4353 end function conservation_check_ug_side2
4354 ! </FUNCTION>
4355 
4356 
4357 !******************************************************************************
4358 !> @brief This routine is used to get the grid area of component model with id.
4359 subroutine get_xmap_grid_area(id, xmap, area)
4360  character(len=3), intent(in) :: id
4361  type (xmap_type), intent(inout) :: xmap
4362  real(r8_kind), dimension(:,:), intent(out) :: area
4363  integer :: g
4364  logical :: found
4365 
4366  found = .false.
4367  do g = 1, size(xmap%grids(:))
4368  if (id==xmap%grids(g)%id ) then
4369  if(size(area,1) .NE. size(xmap%grids(g)%area,1) .OR. size(area,2) .NE. size(xmap%grids(g)%area,2) ) &
4370  call error_mesg("xgrid_mod", "size mismatch between area and xmap%grids(g)%area", fatal)
4371  area = xmap%grids(g)%area
4372  found = .true.
4373  exit
4374  end if
4375  end do
4376 
4377  if(.not. found) call error_mesg("xgrid_mod", id//" is not found in xmap%grids id", fatal)
4378 
4379 end subroutine get_xmap_grid_area
4380 
4381 !#######################################################################
4382 
4383 !> @brief This function is used to calculate the gradient along zonal direction.
4384 !! Maybe need to setup a limit for the gradient. The grid is assumeed
4385 !! to be regular lat-lon grid
4386 !! @return real(r8_kind) grad_zonal_latlon
4387 function grad_zonal_latlon(d, lon, lat, is, ie, js, je, isd, jsd)
4388 
4389  integer, intent(in) :: isd, jsd
4390  real(r8_kind), dimension(isd:,jsd:), intent(in) :: d
4391  real(r8_kind), dimension(:), intent(in) :: lon
4392  real(r8_kind), dimension(:), intent(in) :: lat
4393  integer, intent(in) :: is, ie, js, je
4394  real(r8_kind), dimension(is:ie,js:je) :: grad_zonal_latlon
4395  real(r8_kind) :: dx, costheta
4396  integer :: i, j, ip1, im1
4397 
4398  ! calculate the gradient of the data on each grid
4399  do i = is, ie
4400  if(i == 1) then
4401  ip1 = i+1; im1 = i
4402  else if(i==size(lon(:)) ) then
4403  ip1 = i; im1 = i-1
4404  else
4405  ip1 = i+1; im1 = i-1
4406  endif
4407  dx = lon(ip1) - lon(im1)
4408  if(abs(dx).lt.eps ) call error_mesg('xgrids_mod(grad_zonal_latlon)', 'Improper grid size in lontitude', fatal)
4409  if(dx .gt. pi) dx = dx - 2.0_r8_kind* pi
4410  if(dx .lt. -pi) dx = dx + 2.0_r8_kind* pi
4411  do j = js, je
4412  costheta = cos(lat(j))
4413  if(abs(costheta) .lt. eps) call error_mesg('xgrids_mod(grad_zonal_latlon)', 'Improper latitude grid', fatal)
4414  grad_zonal_latlon(i,j) = (d(ip1,j)-d(im1,j))/(dx*costheta)
4415  enddo
4416  enddo
4417 
4418  return
4419 
4420 end function grad_zonal_latlon
4421 
4422 !#######################################################################
4423 
4424 !> @brief This function is used to calculate the gradient along meridinal direction.
4425 !! Maybe need to setup a limit for the gradient. regular lat-lon grid are assumed
4426 !! @return grad_merid_latlon
4427 function grad_merid_latlon(d, lat, is, ie, js, je, isd, jsd)
4428  integer, intent(in) :: isd, jsd
4429  real(r8_kind), dimension(isd:,jsd:), intent(in) :: d
4430  real(r8_kind), dimension(:), intent(in) :: lat
4431  integer, intent(in) :: is, ie, js, je
4432  real(r8_kind), dimension(is:ie,js:je) :: grad_merid_latlon
4433  real(r8_kind) :: dy
4434  integer :: i, j, jp1, jm1
4435 
4436  ! calculate the gradient of the data on each grid
4437  do j = js, je
4438  if(j == 1) then
4439  jp1 = j+1; jm1 = j
4440  else if(j == size(lat(:)) ) then
4441  jp1 = j; jm1 = j-1
4442  else
4443  jp1 = j+1; jm1 = j-1
4444  endif
4445  dy = lat(jp1) - lat(jm1)
4446  if(abs(dy).lt.eps) call error_mesg('xgrids_mod(grad_merid_latlon)', 'Improper grid size in latitude', fatal)
4447 
4448  do i = is, ie
4449  grad_merid_latlon(i,j) = (d(i,jp1) - d(i,jm1))/dy
4450  enddo
4451  enddo
4452 
4453  return
4454 end function grad_merid_latlon
4455 
4456 !#######################################################################
4457 subroutine get_index_range(xmap, grid_index, is, ie, js, je, km)
4458 
4459  type(xmap_type), intent(in) :: xmap
4460  integer, intent(in) :: grid_index
4461  integer, intent(out) :: is, ie, js, je, km
4462 
4463  is = xmap % grids(grid_index) % is_me
4464  ie = xmap % grids(grid_index) % ie_me
4465  js = xmap % grids(grid_index) % js_me
4466  je = xmap % grids(grid_index) % je_me
4467  km = xmap % grids(grid_index) % km
4468 
4469 end subroutine get_index_range
4470 !#######################################################################
4471 
4472 !> @brief this version takes rank 3 data, it can be used to compute the flux on anything but the
4473 !! first grid, which typically is on the atmos side.
4474 !! note that "from" and "to" are optional, the stocks will be subtracted, resp. added, only
4475 !! if these are present.
4476 subroutine stock_move_3d(from, to, grid_index, stock_data3d, xmap, &
4477  & delta_t, from_side, to_side, radius, verbose, ier)
4479  ! this version takes rank 3 data, it can be used to compute the flux on anything but the
4480  ! first grid, which typically is on the atmos side.
4481  ! note that "from" and "to" are optional, the stocks will be subtracted, resp. added, only
4482  ! if these are present.
4483 
4484  use mpp_mod, only : mpp_sum
4485  use mpp_domains_mod, only : domain2d, mpp_redistribute, mpp_get_compute_domain
4486 
4487  type(stock_type), intent(inout), optional :: from, to
4488  integer, intent(in) :: grid_index !< grid index
4489  real(r8_kind), intent(in) :: stock_data3d(:,:,:) !< data array is 3d
4490  type(xmap_type), intent(in) :: xmap
4491  real(r8_kind), intent(in) :: delta_t
4492  integer, intent(in) :: from_side !< ISTOCK_TOP, ISTOCK_BOTTOM, or ISTOCK_SIDE
4493  integer, intent(in) :: to_side !< ISTOCK_TOP, ISTOCK_BOTTOM, or ISTOCK_SIDE
4494  real(r8_kind), intent(in) :: radius !< earth radius
4495  character(len=*), intent(in), optional :: verbose
4496  integer, intent(out) :: ier
4497 
4498  real(r8_kind) :: from_dq, to_dq
4499 
4500  ier = 0
4501  if(grid_index == 1) then
4502  ! data has rank 3 so grid index must be > 1
4503  ier = 1
4504  return
4505  endif
4506 
4507  if(.not. associated(xmap%grids) ) then
4508  ier = 2
4509  return
4510  endif
4511 
4512  from_dq = delta_t * 4.0_r8_kind * pi * radius**2 * sum( sum(xmap%grids(grid_index)%area * &
4513  & sum(xmap%grids(grid_index)%frac_area * stock_data3d, dim=3), dim=1))
4514  to_dq = from_dq
4515 
4516  ! update only if argument is present.
4517  if(present(to )) to % dq( to_side) = to % dq( to_side) + to_dq
4518  if(present(from)) from % dq(from_side) = from % dq(from_side) - from_dq
4519 
4520  if(present(verbose).and.debug_stocks) then
4521  call mpp_sum(from_dq)
4522  call mpp_sum(to_dq)
4523  from_dq = from_dq/(4.0_r8_kind*pi*radius**2)
4524  to_dq = to_dq /(4.0_r8_kind*pi*radius**2)
4525  if(mpp_pe()==mpp_root_pe()) then
4526  write(stocks_file,'(a,es19.12,a,es19.12,a)') verbose, from_dq,' [*/m^2]'
4527  endif
4528  endif
4529 
4530 end subroutine stock_move_3d
4531 
4532 !...................................................................
4533 !> @brief this version takes rank 2 data, it can be used to compute the flux on the atmos side
4534 !! note that "from" and "to" are optional, the stocks will be subtracted, resp. added, only
4535 !! if these are present.
4536 subroutine stock_move_2d(from, to, grid_index, stock_data2d, xmap, &
4537  & delta_t, from_side, to_side, radius, verbose, ier)
4539  ! this version takes rank 2 data, it can be used to compute the flux on the atmos side
4540  ! note that "from" and "to" are optional, the stocks will be subtracted, resp. added, only
4541  ! if these are present.
4542 
4543  use mpp_mod, only : mpp_sum
4544  use mpp_domains_mod, only : domain2d, mpp_redistribute, mpp_get_compute_domain
4545 
4546  type(stock_type), intent(inout), optional :: from, to
4547  integer, optional, intent(in) :: grid_index
4548  real(r8_kind), intent(in) :: stock_data2d(:,:) !< data array is 2d
4549  type(xmap_type), intent(in) :: xmap
4550  real(r8_kind), intent(in) :: delta_t
4551  integer, intent(in) :: from_side !< ISTOCK_TOP, ISTOCK_BOTTOM, or ISTOCK_SIDE
4552  integer, intent(in) :: to_side !< ISTOCK_TOP, ISTOCK_BOTTOM, or ISTOCK_SIDE
4553  real(r8_kind), intent(in) :: radius !< earth radius
4554  character(len=*), intent(in) :: verbose
4555  integer, intent(out) :: ier
4556 
4557  real(r8_kind) :: to_dq, from_dq
4558 
4559  ier = 0
4560 
4561  if(.not. associated(xmap%grids) ) then
4562  ier = 3
4563  return
4564  endif
4565 
4566  if( .not. present(grid_index) .or. grid_index==1 ) then
4567 
4568  ! only makes sense if grid_index == 1
4569  from_dq = delta_t * 4.0_r8_kind*pi*radius**2 * sum(sum(xmap%grids(1)%area * stock_data2d, dim=1))
4570  to_dq = from_dq
4571 
4572  else
4573 
4574  ier = 4
4575  return
4576 
4577  endif
4578 
4579  ! update only if argument is present.
4580  if(present(to )) to % dq( to_side) = to % dq( to_side) + to_dq
4581  if(present(from)) from % dq(from_side) = from % dq(from_side) - from_dq
4582 
4583  if(debug_stocks) then
4584  call mpp_sum(from_dq)
4585  call mpp_sum(to_dq)
4586  from_dq = from_dq/(4.0_r8_kind*pi*radius**2)
4587  to_dq = to_dq /(4.0_r8_kind*pi*radius**2)
4588  if(mpp_pe()==mpp_root_pe()) then
4589  write(stocks_file,'(a,es19.12,a,es19.12,a)') verbose, from_dq,' [*/m^2]'
4590  endif
4591  endif
4592 
4593 end subroutine stock_move_2d
4594 
4595 !#######################################################################
4596 !> @brief this version takes rank 3 data, it can be used to compute the flux on anything but the
4597 !! first grid, which typically is on the atmos side.
4598 !! note that "from" and "to" are optional, the stocks will be subtracted, resp. added, only
4599 !! if these are present.
4600 subroutine stock_move_ug_3d(from, to, grid_index, stock_ug_data3d, xmap, &
4601  & delta_t, from_side, to_side, radius, verbose, ier)
4603  ! this version takes rank 3 data, it can be used to compute the flux on anything but the
4604  ! first grid, which typically is on the atmos side.
4605  ! note that "from" and "to" are optional, the stocks will be subtracted, resp. added, only
4606  ! if these are present.
4607 
4608  use mpp_mod, only : mpp_sum
4609  use mpp_domains_mod, only : domain2d, mpp_redistribute, mpp_get_compute_domain
4610 
4611  type(stock_type), intent(inout), optional :: from, to
4612  integer, intent(in) :: grid_index !< grid index
4613  real(r8_kind), intent(in) :: stock_ug_data3d(:,:) !< data array is 3d
4614  type(xmap_type), intent(in) :: xmap
4615  real(r8_kind), intent(in) :: delta_t
4616  integer, intent(in) :: from_side !< ISTOCK_TOP, ISTOCK_BOTTOM, or ISTOCK_SIDE
4617  integer, intent(in) :: to_side !< ISTOCK_TOP, ISTOCK_BOTTOM, or ISTOCK_SIDE
4618  real(r8_kind), intent(in) :: radius !< earth radius
4619  character(len=*), intent(in), optional :: verbose
4620  integer, intent(out) :: ier
4621  real(r8_kind), dimension(size(stock_ug_data3d,1),size(stock_ug_data3d,2)) :: tmp
4622 
4623  real(r8_kind) :: from_dq, to_dq
4624 
4625  ier = 0
4626  if(grid_index == 1) then
4627  ! data has rank 3 so grid index must be > 1
4628  ier = 1
4629  return
4630  endif
4631 
4632  if(.not. associated(xmap%grids) ) then
4633  ier = 2
4634  return
4635  endif
4636 
4637  tmp = xmap%grids(grid_index)%frac_area(:,1,:) * stock_ug_data3d
4638  from_dq = delta_t * 4.0_r8_kind * pi * radius**2 * sum( xmap%grids(grid_index)%area(:,1) * &
4639  & sum(tmp, dim=2))
4640  to_dq = from_dq
4641 
4642  ! update only if argument is present.
4643  if(present(to )) to % dq( to_side) = to % dq( to_side) + to_dq
4644  if(present(from)) from % dq(from_side) = from % dq(from_side) - from_dq
4645 
4646  if(present(verbose).and.debug_stocks) then
4647  call mpp_sum(from_dq)
4648  call mpp_sum(to_dq)
4649  from_dq = from_dq/(4.0_r8_kind*pi*radius**2)
4650  to_dq = to_dq /(4.0_r8_kind*pi*radius**2)
4651  if(mpp_pe()==mpp_root_pe()) then
4652  write(stocks_file,'(a,es19.12,a,es19.12,a)') verbose, from_dq,' [*/m^2]'
4653  endif
4654  endif
4655 
4656 end subroutine stock_move_ug_3d
4657 
4658 
4659 
4660 !#######################################################################
4661 !> @brief surface/time integral of a 2d array
4662 subroutine stock_integrate_2d(integrate_data2d, xmap, delta_t, radius, res, ier)
4663 
4664  ! surface/time integral of a 2d array
4665 
4666  use mpp_mod, only : mpp_sum
4667 
4668  real(r8_kind), intent(in) :: integrate_data2d(:,:) !< data array is 2d
4669  type(xmap_type), intent(in) :: xmap
4670  real(r8_kind), intent(in) :: delta_t
4671  real(r8_kind), intent(in) :: radius !< earth radius
4672  real(r8_kind), intent(out) :: res
4673  integer, intent(out) :: ier
4674 
4675  ier = 0
4676  res = 0.0_r8_kind
4677 
4678  if(.not. associated(xmap%grids) ) then
4679  ier = 6
4680  return
4681  endif
4682 
4683  res = delta_t * 4.0_r8_kind * pi * radius**2 * sum(sum(xmap%grids(1)%area * integrate_data2d, dim=1))
4684 
4685 end subroutine stock_integrate_2d
4686 !#######################################################################
4687 
4688 !#######################################################################
4689 
4690 
4691 
4692 subroutine stock_print(stck, Time, comp_name, index, ref_value, radius, pelist)
4693 
4694  use mpp_mod, only : mpp_pe, mpp_root_pe, mpp_sum
4695  use time_manager_mod, only : time_type, get_time
4696  use diag_manager_mod, only : register_diag_field,send_data
4697 
4698  type(stock_type), intent(in) :: stck
4699  type(time_type), intent(in) :: Time
4700  character(len=*) :: comp_name
4701  integer, intent(in) :: index !< to map stock element (water, heat, ..) to a name
4702  real(r8_kind), intent(in) :: ref_value !< the stock value returned by the component per PE
4703  real(r8_kind), intent(in) :: radius
4704  integer, intent(in), optional :: pelist(:)
4705 
4706  integer, parameter :: initID = -2 !< initial value for diag IDs. Must not be equal to the value
4707  !! that register_diag_field returns when it can't register the filed -- otherwise the registration
4708  !! is attempted every time this subroutine is called
4709 
4710  real(r8_kind) :: f_value, c_value, planet_area
4711  character(len=80) :: formatString
4712  integer :: iday, isec, hours
4713  integer :: diagID, compInd
4714  integer, dimension(NELEMS,4), save :: f_valueDiagID = initid
4715  integer, dimension(NELEMS,4), save :: c_valueDiagID = initid
4716  integer, dimension(NELEMS,4), save :: fmc_valueDiagID = initid
4717 
4718  real(r8_kind) :: diagField
4719  logical :: used
4720  character(len=30) :: field_name, units
4721 
4722  f_value = sum(stck % dq)
4723  c_value = ref_value - stck % q_start
4724  if(present(pelist)) then
4725  call mpp_sum(f_value, pelist=pelist)
4726  call mpp_sum(c_value, pelist=pelist)
4727  else
4728  call mpp_sum(f_value)
4729  call mpp_sum(c_value)
4730  endif
4731 
4732  if(mpp_pe() == mpp_root_pe()) then
4733  ! normalize to 1 earth m^2
4734  planet_area = 4.0_r8_kind * pi * radius**2
4735  f_value = f_value / planet_area
4736  c_value = c_value / planet_area
4737 
4738  if(comp_name == 'ATM') compind = 1
4739  if(comp_name == 'LND') compind = 2
4740  if(comp_name == 'ICE') compind = 3
4741  if(comp_name == 'OCN') compind = 4
4742 
4743 
4744  if(f_valuediagid(index,compind) == initid) then
4745  field_name = trim(comp_name) // trim(stock_names(index))
4746  field_name = trim(field_name) // 'StocksChange_Flux'
4747  units = trim(stock_units(index))
4748  f_valuediagid(index,compind) = register_diag_field('stock_print', field_name, time, &
4749  units=units)
4750  endif
4751 
4752  if(c_valuediagid(index,compind) == initid) then
4753  field_name = trim(comp_name) // trim(stock_names(index))
4754  field_name = trim(field_name) // 'StocksChange_Comp'
4755  units = trim(stock_units(index))
4756  c_valuediagid(index,compind) = register_diag_field('stock_print', field_name, time, &
4757  units=units)
4758  endif
4759 
4760  if(fmc_valuediagid(index,compind) == initid) then
4761  field_name = trim(comp_name) // trim(stock_names(index))
4762  field_name = trim(field_name) // 'StocksChange_Diff'
4763  units = trim(stock_units(index))
4764  fmc_valuediagid(index,compind) = register_diag_field('stock_print', field_name, time, &
4765  units=units)
4766  endif
4767 
4768  diagid=f_valuediagid(index,compind)
4769  diagfield = f_value
4770  if (diagid > 0) used = send_data(diagid, diagfield, time = time)
4771  diagid=c_valuediagid(index,compind)
4772  diagfield = c_value
4773  if (diagid > 0) used = send_data(diagid, diagfield, time)
4774  diagid=fmc_valuediagid(index,compind)
4775  diagfield = f_value-c_value
4776  if (diagid > 0) used = send_data(diagid, diagfield, time=time)
4777 
4778 
4779  call get_time(time, isec, iday)
4780  hours = iday*24 + isec/3600
4781  formatstring = '(a,a,a,i16,2x,es22.15,2x,es22.15,2x,es22.15)'
4782  write(stocks_file,formatstring) trim(comp_name),stock_names(index),stock_units(index) &
4783  ,hours,f_value,c_value,f_value-c_value
4784 
4785  endif
4786 
4787 
4788 end subroutine stock_print
4789 
4790 
4791 !###############################################################################
4792  !> @return logical is_lat_lon
4793  function is_lat_lon(lon, lat)
4794  real(r8_kind), dimension(:,:), intent(in) :: lon, lat
4795  logical :: is_lat_lon
4796  integer :: i, j, nlon, nlat, num
4797 
4798  is_lat_lon = .true.
4799  nlon = size(lon,1)
4800  nlat = size(lon,2)
4801  loop_lat: do j = 1, nlat
4802  do i = 2, nlon
4803  if(lat(i,j) .NE. lat(1,j)) then
4804  is_lat_lon = .false.
4805  exit loop_lat
4806  end if
4807  end do
4808  end do loop_lat
4809 
4810  if(is_lat_lon) then
4811  loop_lon: do i = 1, nlon
4812  do j = 2, nlat
4813  if(lon(i,j) .NE. lon(i,1)) then
4814  is_lat_lon = .false.
4815  exit loop_lon
4816  end if
4817  end do
4818  end do loop_lon
4819  end if
4820 
4821  num = 0
4822  if(is_lat_lon) num = 1
4823  call mpp_min(num)
4824  if(num == 1) then
4825  is_lat_lon = .true.
4826  else
4827  is_lat_lon = .false.
4828  end if
4829 
4830  return
4831  end function is_lat_lon
4832 
4833 !#######################################################################
4834 
4835 ! <SUBROUTINE NAME="get_side1_from_xgrid_ug" INTERFACE="get_from_xgrid_ug">
4836 ! <IN NAME="x" TYPE="real(r8_kind)" DIM="(:)" > </IN>
4837 ! <IN NAME="grid_id" TYPE=" character(len=3)" > </IN>
4838 ! <OUT NAME="d" TYPE="real(r8_kind)" DIM="(:)" > </OUT>
4839 ! <INOUT NAME="xmap" TYPE="xmap_type" > </INOUT>
4840 
4841 subroutine get_side1_from_xgrid_ug(d, grid_id, x, xmap, complete)
4842  use, intrinsic :: iso_c_binding, only: c_ptr, c_null_ptr, c_loc
4843  real(r8_kind), target, contiguous, intent(out) :: d(:)
4844  character(len=3), intent(in) :: grid_id
4845  real(r8_kind), target, contiguous, intent(in) :: x(:)
4846  type (xmap_type), intent(inout) :: xmap
4847  logical, intent(in), optional :: complete
4848 
4849  logical :: is_complete, set_mismatch
4850  integer :: g
4851  character(len=2) :: text
4852  integer, save :: isize=0
4853  integer, save :: lsize=0
4854  integer, save :: xsize=0
4855  character(len=3), save :: grid_id_saved=""
4856  type(c_ptr), dimension(MAX_FIELDS), save :: d_addrs = c_null_ptr
4857  type(c_ptr), dimension(MAX_FIELDS), save :: x_addrs = c_null_ptr
4858 
4859  d = 0.0_r8_kind
4860  if (grid_id==xmap%grids(1)%id) then
4861  is_complete = .true.
4862  if(present(complete)) is_complete=complete
4863  lsize = lsize + 1
4864  if( lsize > max_fields ) then
4865  write( text,'(i2)' ) max_fields
4866  call error_mesg ('xgrid_mod', 'MAX_FIELDS='//trim(text)//' exceeded for group get_side1_from_xgrid_ug', fatal)
4867  endif
4868  d_addrs(lsize) = c_loc(d)
4869  x_addrs(lsize) = c_loc(x)
4870 
4871  if(lsize == 1) then
4872  isize = size(d(:))
4873  xsize = size(x(:))
4874  grid_id_saved = grid_id
4875  else
4876  set_mismatch = .false.
4877  set_mismatch = set_mismatch .OR. (isize /= size(d(:)))
4878  set_mismatch = set_mismatch .OR. (xsize /= size(x(:)))
4879  set_mismatch = set_mismatch .OR. (grid_id_saved /= grid_id)
4880  if(set_mismatch)then
4881  write( text,'(i2)' ) lsize
4882  call error_mesg ('xgrid_mod', 'Incompatible field at count '//text// &
4883  & ' for group get_side1_from_xgrid_ug', fatal )
4884  endif
4885  endif
4886 
4887  if(is_complete) then
4888  if (make_exchange_reproduce) then
4889  call get_1_from_xgrid_ug_repro(d_addrs, x_addrs, xmap, xsize, lsize)
4890  else
4891  call get_1_from_xgrid_ug(d_addrs, x_addrs, xmap, isize, xsize, lsize)
4892  end if
4893  d_addrs(1:lsize) = c_null_ptr
4894  x_addrs(1:lsize) = c_null_ptr
4895  isize = 0
4896  xsize = 0
4897  lsize = 0
4898  grid_id_saved = ""
4899  endif
4900  return;
4901  end if
4902 
4903  do g=2,size(xmap%grids(:))
4904  if (grid_id==xmap%grids(g)%id) &
4905  call error_mesg ('xgrid_mod', &
4906  'get_from_xgrid_ug expects a 3D side 2 grid', fatal)
4907  end do
4908 
4909  call error_mesg ('xgrid_mod', 'get_from_xgrid_ug: could not find grid id', fatal)
4910 
4911 end subroutine get_side1_from_xgrid_ug
4912 ! </SUBROUTINE>
4913 
4914 !#######################################################################
4915 
4916 ! <SUBROUTINE NAME="put_side1_to_xgrid_ug" INTERFACE="put_to_xgrid_ug">
4917 ! <IN NAME="d" TYPE="real(r8_kind)" DIM="(:,:)" > </IN>
4918 ! <IN NAME="grid_id" TYPE=" character(len=3)" > </IN>
4919 ! <INOUT NAME="x" TYPE="real(r8_kind)" DIM="(:)" > </INOUT>
4920 ! <INOUT NAME="xmap" TYPE="xmap_type" > </INOUT>
4921 ! <IN NAME="remap_method" TYPE="integer,optional"></IN>
4922 
4923 !> @brief Currently only support first order.
4924 subroutine put_side1_to_xgrid_ug(d, grid_id, x, xmap, complete)
4925  use, intrinsic :: iso_c_binding, only: c_ptr, c_null_ptr, c_loc
4926  real(r8_kind), target, contiguous, intent(in) :: d(:) !<
4927  character(len=3), intent(in) :: grid_id
4928  real(r8_kind), target, contiguous, intent(inout) :: x(:)
4929  type (xmap_type), intent(inout) :: xmap
4930  logical, intent(in), optional :: complete
4931 
4932  logical :: is_complete, set_mismatch
4933  integer :: g
4934  character(len=2) :: text
4935  integer, save :: dsize=0
4936  integer, save :: lsize=0
4937  integer, save :: xsize=0
4938  character(len=3), save :: grid_id_saved=""
4939  type(c_ptr), dimension(MAX_FIELDS), save :: d_addrs = c_null_ptr
4940  type(c_ptr), dimension(MAX_FIELDS), save :: x_addrs = c_null_ptr
4941 
4942  if (grid_id==xmap%grids(1)%id) then
4943  is_complete = .true.
4944  if(present(complete)) is_complete=complete
4945  lsize = lsize + 1
4946  if( lsize > max_fields ) then
4947  write( text,'(i2)' ) max_fields
4948  call error_mesg ('xgrid_mod', 'MAX_FIELDS='//trim(text)//' exceeded for group put_side1_to_xgrid_ug', fatal)
4949  endif
4950  d_addrs(lsize) = c_loc(d)
4951  x_addrs(lsize) = c_loc(x)
4952 
4953  if(lsize == 1) then
4954  dsize = size(d(:))
4955  xsize = size(x(:))
4956  grid_id_saved = grid_id
4957  else
4958  set_mismatch = .false.
4959  set_mismatch = set_mismatch .OR. (dsize /= size(d(:)))
4960  set_mismatch = set_mismatch .OR. (xsize /= size(x(:)))
4961  set_mismatch = set_mismatch .OR. (grid_id_saved /= grid_id)
4962  if(set_mismatch)then
4963  write( text,'(i2)' ) lsize
4964  call error_mesg ('xgrid_mod', 'Incompatible field at count '//text// &
4965  & ' for group put_side1_to_xgrid_ug', fatal )
4966  endif
4967  endif
4968 
4969  if(is_complete) then
4970  call put_1_to_xgrid_ug_order_1(d_addrs, x_addrs, xmap, dsize, xsize, lsize)
4971  d_addrs(1:lsize) = c_null_ptr
4972  x_addrs(1:lsize) = c_null_ptr
4973  dsize = 0
4974  xsize = 0
4975  lsize = 0
4976  grid_id_saved = ""
4977  endif
4978  return
4979  end if
4980 
4981  do g=2,size(xmap%grids(:))
4982  if (grid_id==xmap%grids(g)%id) &
4983  call error_mesg ('xgrid_mod', &
4984  'put_to_xgrid_ug expects a 2D side 2 grid', fatal)
4985  end do
4986 
4987  call error_mesg ('xgrid_mod', 'put_to_xgrid_ug: could not find grid id', fatal)
4988 
4989 end subroutine put_side1_to_xgrid_ug
4990 ! </SUBROUTINE>
4991 
4992 !#######################################################################
4993 
4994 ! <SUBROUTINE NAME="put_side2_to_xgrid_ug" INTERFACE="put_to_xgrid_ug">
4995 ! <IN NAME="d" TYPE="real(r8_kind)" DIM="(:,:)" > </IN>
4996 ! <IN NAME="grid_id" TYPE=" character(len=3)" > </IN>
4997 ! <INOUT NAME="x" TYPE="real(r8_kind)" DIM="(:)" > </INOUT>
4998 ! <INOUT NAME="xmap" TYPE="xmap_type" > </INOUT>
4999 
5000 subroutine put_side2_to_xgrid_ug(d, grid_id, x, xmap)
5001  real(r8_kind), dimension(:,:), intent(in) :: d
5002  character(len=3), intent(in) :: grid_id
5003  real(r8_kind), dimension(:), intent(inout) :: x
5004  type (xmap_type), intent(inout) :: xmap
5005 
5006  integer :: g
5007 
5008  if (grid_id==xmap%grids(1)%id) &
5009  call error_mesg ('xgrid_mod', &
5010  'put_to_xgrid_ug expects a 2D side 1 grid', fatal)
5011 
5012  do g=2,size(xmap%grids(:))
5013  if (grid_id==xmap%grids(g)%id) then
5014  call put_2_to_xgrid_ug(d, xmap%grids(g), x, xmap)
5015  return;
5016  end if
5017  end do
5018 
5019  call error_mesg ('xgrid_mod', 'put_to_xgrid_ug: could not find grid id', fatal)
5020 
5021 end subroutine put_side2_to_xgrid_ug
5022 ! </SUBROUTINE>
5023 
5024 !#######################################################################
5025 
5026 ! <SUBROUTINE NAME="get_side2_from_xgrid_ug" INTERFACE="get_from_xgrid_ug">
5027 ! <IN NAME="x" TYPE="real(r8_kind)" DIM="(:)" > </IN>
5028 ! <IN NAME="grid_id" TYPE=" character(len=3)" > </IN>
5029 ! <OUT NAME="d" TYPE="real(r8_kind)" DIM="(:,:)" > </OUT>
5030 ! <INOUT NAME="xmap" TYPE="xmap_type" > </INOUT>
5031 
5032 subroutine get_side2_from_xgrid_ug(d, grid_id, x, xmap)
5033  real(r8_kind), dimension(:,:), intent(out) :: d
5034  character(len=3), intent(in) :: grid_id
5035  real(r8_kind), dimension(:), intent(in) :: x
5036  type (xmap_type), intent(in) :: xmap
5037 
5038  integer :: g
5039 
5040  if (grid_id==xmap%grids(1)%id) &
5041  call error_mesg ('xgrid_mod', &
5042  'get_from_xgrid_ug expects a 2D side 1 grid', fatal)
5043 
5044  do g=2,size(xmap%grids(:))
5045  if (grid_id==xmap%grids(g)%id) then
5046  call get_2_from_xgrid_ug(d, xmap%grids(g), x, xmap)
5047  return;
5048  end if
5049  end do
5050 
5051  call error_mesg ('xgrid_mod', 'get_from_xgrid_ug: could not find grid id', fatal)
5052 
5053 end subroutine get_side2_from_xgrid_ug
5054 ! </SUBROUTINE>
5055 
5056 
5057 !#######################################################################
5058 
5059 subroutine put_1_to_xgrid_ug_order_1(d_addrs, x_addrs, xmap, dsize, xsize, lsize)
5060  use, intrinsic :: iso_c_binding, only: c_ptr, c_f_pointer
5061  type(c_ptr), intent(in) :: d_addrs(:)
5062  type(c_ptr), intent(in) :: x_addrs(:)
5063  type (xmap_type), intent(inout) :: xmap
5064  integer, intent(in) :: dsize, xsize, lsize
5065 
5066  integer :: i, p, buffer_pos, msgsize
5067  integer :: from_pe, to_pe, pos, n, l, count
5068  integer :: ibegin, istart, iend, start_pos
5069  type (comm_type), pointer, save :: comm =>null()
5070  real(r8_kind) :: recv_buffer(xmap%put1%recvsize*lsize)
5071  real(r8_kind) :: send_buffer(xmap%put1%sendsize*lsize)
5072  real(r8_kind) :: unpack_buffer(xmap%put1%recvsize)
5073 
5074  real(r8_kind), pointer :: d(:)
5075  real(r8_kind), pointer :: x(:)
5076  integer :: lll
5077 
5078  call mpp_clock_begin(id_put_1_to_xgrid_order_1)
5079 
5080  !--- pre-post receiving
5081  comm => xmap%put1
5082  do p = 1, comm%nrecv
5083  msgsize = comm%recv(p)%count*lsize
5084  from_pe = comm%recv(p)%pe
5085  buffer_pos = comm%recv(p)%buffer_pos*lsize
5086  call mpp_recv(recv_buffer(buffer_pos+1), glen=msgsize, from_pe = from_pe, block=.false., tag=comm_tag_7)
5087  enddo
5088 
5089  !--- send the data
5090  buffer_pos = 0
5091  do p = 1, comm%nsend
5092  msgsize = comm%send(p)%count*lsize
5093  to_pe = comm%send(p)%pe
5094  pos = buffer_pos
5095  do l = 1, lsize
5096  call c_f_pointer(d_addrs(l), d, shape=[dsize])
5097  do n = 1, comm%send(p)%count
5098  pos = pos + 1
5099  lll = comm%send(p)%i(n)
5100  send_buffer(pos) = d(lll)
5101  enddo
5102  enddo
5103  call mpp_send(send_buffer(buffer_pos+1), plen=msgsize, to_pe = to_pe, tag=comm_tag_7 )
5104  buffer_pos = buffer_pos + msgsize
5105  enddo
5106 
5107  call mpp_sync_self(check=event_recv)
5108 
5109  !--- unpack the buffer
5110  if( lsize == 1) then
5111  call c_f_pointer(x_addrs(1), x, shape=[xsize])
5112  do l=1,xmap%size_put1
5113  x(l) = recv_buffer(xmap%x1_put(l)%pos)
5114  end do
5115  else
5116  start_pos = 0
5117 !$OMP parallel do default(none) shared(lsize,xsize,x_addrs,comm,recv_buffer,xmap) &
5118 !$OMP private(x,count,ibegin,istart,iend,pos,unpack_buffer)
5119  do l = 1, lsize
5120  call c_f_pointer(x_addrs(l), x, shape=[xsize])
5121  do p = 1, comm%nrecv
5122  count = comm%recv(p)%count
5123  ibegin = comm%recv(p)%buffer_pos*lsize + 1
5124  istart = ibegin + (l-1)*count
5125  iend = istart + count - 1
5126  pos = comm%recv(p)%buffer_pos
5127  do n = istart, iend
5128  pos = pos + 1
5129  unpack_buffer(pos) = recv_buffer(n)
5130  enddo
5131  enddo
5132  do i=1,xmap%size_put1
5133  x(i) = unpack_buffer(xmap%x1_put(i)%pos)
5134  end do
5135  enddo
5136  endif
5137 
5138  call mpp_sync_self()
5139 
5140  call mpp_clock_end(id_put_1_to_xgrid_order_1)
5141 
5142 end subroutine put_1_to_xgrid_ug_order_1
5143 
5144 !#######################################################################
5145 
5146 subroutine put_2_to_xgrid_ug(d, grid, x, xmap)
5147 type (grid_type), intent(in) :: grid
5148 real(r8_kind), dimension(grid%ls_me:grid%le_me, grid%km), intent(in) :: d
5149 real(r8_kind), dimension(:), intent(inout) :: x
5150 type (xmap_type), intent(in) :: xmap
5151 
5152  integer :: l
5153  call mpp_clock_begin(id_put_2_to_xgrid)
5154 
5155  do l=grid%first,grid%last
5156  x(l) = d(xmap%x2(l)%l,xmap%x2(l)%k)
5157  end do
5158 
5159  call mpp_clock_end(id_put_2_to_xgrid)
5160 end subroutine put_2_to_xgrid_ug
5161 
5162 
5163 subroutine get_1_from_xgrid_ug(d_addrs, x_addrs, xmap, isize, xsize, lsize)
5164  use, intrinsic :: iso_c_binding, only: c_ptr, c_f_pointer
5165  type(c_ptr), intent(in) :: d_addrs(:)
5166  type(c_ptr), intent(in) :: x_addrs(:)
5167  type (xmap_type), intent(inout) :: xmap
5168  integer, intent(in) :: isize, xsize, lsize
5169 
5170  real(r8_kind), dimension(xmap%size), target :: dg(xmap%size, lsize)
5171  integer :: i, j, l, p, n, m
5172  integer :: msgsize, buffer_pos, pos
5173  integer :: istart, iend, count
5174  real(r8_kind) , pointer, save :: dgp =>null()
5175  type (grid_type) , pointer, save :: grid1 =>null()
5176  type (comm_type) , pointer, save :: comm =>null()
5177  type(overlap_type), pointer, save :: send => null()
5178  type(overlap_type), pointer, save :: recv => null()
5179  real(r8_kind) :: recv_buffer(xmap%get1%recvsize*lsize*3)
5180  real(r8_kind) :: send_buffer(xmap%get1%sendsize*lsize*3)
5181  real(r8_kind), pointer :: d(:)
5182  real(r8_kind), pointer :: x(:)
5183 
5184  call mpp_clock_begin(id_get_1_from_xgrid)
5185 
5186  comm => xmap%get1
5187  grid1 => xmap%grids(1)
5188 
5189  do p = 1, comm%nrecv
5190  recv => comm%recv(p)
5191  msgsize = recv%count*lsize
5192  buffer_pos = recv%buffer_pos*lsize
5193  call mpp_recv(recv_buffer(buffer_pos+1), glen=msgsize, from_pe = recv%pe, block=.false., tag=comm_tag_9)
5194  enddo
5195 
5196  dg = 0.0_r8_kind;
5197 !$OMP parallel do default(none) shared(lsize,xsize,xmap,dg,x_addrs) private(dgp,x)
5198  do l = 1, lsize
5199  call c_f_pointer(x_addrs(l), x, shape=[xsize])
5200  do i=1,xmap%size
5201  dgp => dg(xmap%x1(i)%pos,l)
5202  dgp = dgp + xmap%x1(i)%area*x(i)
5203  enddo
5204  enddo
5205 
5206 
5207  !--- send the data
5208  buffer_pos = 0
5209  istart = 1
5210  do p = 1, comm%nsend
5211  send => comm%send(p)
5212  msgsize = send%count*lsize
5213  pos = buffer_pos
5214  istart = send%buffer_pos+1
5215  iend = istart + send%count - 1
5216  do l = 1, lsize
5217  do n = istart, iend
5218  pos = pos + 1
5219  send_buffer(pos) = dg(n,l)
5220  enddo
5221  enddo
5222  call mpp_send(send_buffer(buffer_pos+1), plen=msgsize, to_pe = send%pe, tag=comm_tag_9 )
5223  buffer_pos = buffer_pos + msgsize
5224  istart = iend + 1
5225  enddo
5226 
5227  call mpp_sync_self(check=event_recv)
5228 
5229  !--- unpack the buffer
5230  do l = 1, lsize
5231  call c_f_pointer(d_addrs(l), d, shape=[isize])
5232  d = 0.0_r8_kind
5233  enddo
5234  !--- To bitwise reproduce old results, first copy the data onto its own pe.
5235 
5236  do p = 1, comm%nrecv
5237  recv => comm%recv(p)
5238  count = recv%count
5239  buffer_pos = recv%buffer_pos*lsize
5240  if( recv%pe == xmap%me ) then
5241 !$OMP parallel do default(none) shared(lsize,isize,recv,recv_buffer,buffer_pos,d_addrs,count) &
5242 !$OMP private(d,i,pos)
5243  do l = 1, lsize
5244  pos = buffer_pos + (l-1)*count
5245  call c_f_pointer(d_addrs(l), d, shape=[isize])
5246  do n = 1,count
5247  i = recv%i(n)
5248  pos = pos + 1
5249  d(i) = recv_buffer(pos)
5250  enddo
5251  enddo
5252  exit
5253  endif
5254  enddo
5255 
5256  pos = 0
5257  do m = 1, comm%nrecv
5258  p = comm%unpack_ind(m)
5259  recv => comm%recv(p)
5260  if( recv%pe == xmap%me ) then
5261  cycle
5262  endif
5263  buffer_pos = recv%buffer_pos*lsize
5264 !$OMP parallel do default(none) shared(lsize,isize,recv,recv_buffer,buffer_pos,d_addrs) &
5265 !$OMP private(d,i,j,pos)
5266  do l = 1, lsize
5267  pos = buffer_pos + (l-1)*recv%count
5268  call c_f_pointer(d_addrs(l), d, shape=[isize])
5269  do n = 1, recv%count
5270  i = recv%i(n)
5271  pos = pos + 1
5272  d(i) = d(i) + recv_buffer(pos)
5273  enddo
5274  enddo
5275  enddo
5276 
5277  !
5278  ! normalize with side 1 grid cell areas
5279  !
5280 !$OMP parallel do default(none) shared(lsize,isize,d_addrs,grid1) private(d)
5281  do l = 1, lsize
5282  call c_f_pointer(d_addrs(l), d, shape=[isize])
5283  d = d * grid1%area_inv(:,1)
5284  enddo
5285  call mpp_sync_self()
5286  call mpp_clock_end(id_get_1_from_xgrid)
5287 
5288 end subroutine get_1_from_xgrid_ug
5289 
5290 !#######################################################################
5291 
5292 subroutine get_1_from_xgrid_ug_repro(d_addrs, x_addrs, xmap, xsize, lsize)
5293  use, intrinsic :: iso_c_binding, only: c_ptr, c_f_pointer
5294  type(c_ptr), intent(in) :: d_addrs(:)
5295  type(c_ptr), intent(in) :: x_addrs(:)
5296  type (xmap_type), intent(inout) :: xmap
5297  integer, intent(in) :: xsize, lsize
5298 
5299  integer :: g, i, j, k, p, l, n, l2, l3
5300  integer :: msgsize, buffer_pos, pos
5301  type (grid_type), pointer, save :: grid =>null()
5302  type(comm_type), pointer, save :: comm => null()
5303  type(overlap_type), pointer, save :: send => null()
5304  type(overlap_type), pointer, save :: recv => null()
5305  integer, dimension(0:xmap%npes-1) :: pl, ml
5306  real(r8_kind) :: recv_buffer(xmap%recv_count_repro_tot*lsize)
5307  real(r8_kind) :: send_buffer(xmap%send_count_repro_tot*lsize)
5308  real(r8_kind), pointer :: d(:)
5309  real(r8_kind), pointer :: x(:)
5310  real(r8_kind), pointer, contiguous :: tmpptr(:)
5311  integer :: shape_d(1)
5312 
5313  call mpp_clock_begin(id_get_1_from_xgrid_repro)
5314  shape_d = [xmap%grids(1)%le_me-xmap%grids(1)%ls_me+1]
5315  comm => xmap%get1_repro
5316  !--- pre-post receiving
5317  do p = 1, comm%nrecv
5318  recv => comm%recv(p)
5319  msgsize = recv%count*lsize
5320  buffer_pos = recv%buffer_pos*lsize
5321  call mpp_recv(recv_buffer(buffer_pos+1), glen=msgsize, from_pe = recv%pe, block=.false., tag=comm_tag_10)
5322  n = recv%pe -xmap%root_pe
5323  pl(n) = buffer_pos
5324  ml(n) = recv%count
5325  enddo
5326 
5327  !pack the data
5328  send_buffer(:) = 0.0_r8_kind
5329 !$OMP parallel do default(none) shared(lsize,xsize,x_addrs,comm,xmap,send_buffer) &
5330 !$OMP private(x,i,j,g,l2,pos,send)
5331  do p = 1, comm%nsend
5332  pos = comm%send(p)%buffer_pos*lsize
5333  send => comm%send(p)
5334  do l = 1,lsize
5335  call c_f_pointer(x_addrs(l), x, shape=[xsize])
5336  do n = 1, send%count
5337  i = send%i(n)
5338  j = send%j(n)
5339  g = send%g(n)
5340  l2 = send%xloc(n)
5341  pos = pos + 1
5342  do k =1, xmap%grids(g)%km
5343  if(xmap%grids(g)%frac_area(i,j,k)/=0.0_r8_kind) then
5344  l2 = l2+1
5345  send_buffer(pos) = send_buffer(pos) + xmap%x1(l2)%area *x(l2)
5346  endif
5347  enddo
5348  enddo
5349  enddo
5350  enddo
5351 
5352  do p =1, comm%nsend
5353  buffer_pos = comm%send(p)%buffer_pos*lsize
5354  msgsize = comm%send(p)%count*lsize
5355  call mpp_send(send_buffer(buffer_pos+1), plen=msgsize, to_pe=comm%send(p)%pe, tag=comm_tag_10)
5356  enddo
5357 
5358  do l = 1, lsize
5359  call c_f_pointer(d_addrs(l), tmpptr, shape=shape_d)
5360  d(xmap%grids(1)%ls_me:xmap%grids(1)%le_me) => tmpptr
5361  d = 0
5362  enddo
5363 
5364  call mpp_sync_self(check=event_recv)
5365 
5366 !$OMP parallel do default(none) shared(lsize,shape_d,d_addrs,xmap,recv_buffer,pl,ml) &
5367 !$OMP private(d,tmpptr,grid,i,j,p,pos)
5368  do l = 1, lsize
5369  call c_f_pointer(d_addrs(l), tmpptr, shape=shape_d)
5370  d(xmap%grids(1)%ls_me:xmap%grids(1)%le_me) => tmpptr
5371  do g=2,size(xmap%grids(:))
5372  grid => xmap%grids(g)
5373  do l3=1,grid%size_repro ! index into side1 grid's patterns
5374  i = grid%x_repro(l3)%l1
5375  p = grid%x_repro(l3)%pe-xmap%root_pe
5376  pos = pl(p) + (l-1)*ml(p) + grid%x_repro(l3)%recv_pos
5377  d(i) = d(i) + recv_buffer(pos)
5378  end do
5379  end do
5380  ! normalize with side 1 grid cell areas
5381  d = d * xmap%grids(1)%area_inv(:,1)
5382  enddo
5383 
5384  call mpp_sync_self()
5385 
5386  call mpp_clock_end(id_get_1_from_xgrid_repro)
5387 
5388 end subroutine get_1_from_xgrid_ug_repro
5389 
5390 !#######################################################################
5391 
5392 subroutine get_2_from_xgrid_ug(d, grid, x, xmap)
5393 type (grid_type), intent(in) :: grid
5394 real(r8_kind), dimension(grid%ls_me:grid%le_me, grid%km), intent(out) :: d
5395 real(r8_kind), dimension(:), intent(in) :: x
5396 type (xmap_type), intent(in) :: xmap
5397 
5398  integer :: l, k
5399 
5400  call mpp_clock_begin(id_get_2_from_xgrid)
5401 
5402  d = 0.0_r8_kind
5403  do l=grid%first_get,grid%last_get
5404  d(xmap%x2_get(l)%l,xmap%x2_get(l)%k) = &
5405  d(xmap%x2_get(l)%l,xmap%x2_get(l)%k) + xmap%x2_get(l)%area*x(xmap%x2_get(l)%pos)
5406  end do
5407  !
5408  ! normalize with side 2 grid cell areas
5409  !
5410  do k=1,size(d,2)
5411  d(:,k) = d(:,k) * grid%area_inv(:,1)
5412  end do
5413 
5414  call mpp_clock_end(id_get_2_from_xgrid)
5415 
5416 end subroutine get_2_from_xgrid_ug
5417 
5418 !######################################################################
5419 !> @return logical in_box_me
5420 logical function in_box_me(i, j, grid)
5421  integer, intent(in) :: i, j
5422  type (grid_type), intent(in) :: grid
5423  integer :: g
5424 
5425  if(grid%is_ug) then
5426  g = (j-1)*grid%ni + i
5427  in_box_me = (g>=grid%gs_me) .and. (g<=grid%ge_me)
5428  else
5429  in_box_me = (i>=grid%is_me) .and. (i<=grid%ie_me) .and. (j>=grid%js_me) .and. (j<=grid%je_me)
5430  endif
5431 
5432 end function in_box_me
5433 
5434 !######################################################################
5435 !> @return logical in_box_nbr
5436 logical function in_box_nbr(i, j, grid, p)
5437  integer, intent(in) :: i, j, p
5438  type (grid_type), intent(in) :: grid
5439  integer :: g
5440 
5441  if(grid%is_ug) then
5442  g = (j-1)*grid%ni + i
5443  in_box_nbr = (g>=grid%gs(p)) .and. (g<=grid%ge(p))
5444  else
5445  in_box_nbr = (i>=grid%is(p)) .and. (i<=grid%ie(p)) .and. (j>=grid%js(p)) .and. (j<=grid%je(p))
5446  endif
5447 
5448 end function in_box_nbr
5449 
5450 end module xgrid_mod
5451 !> @}
5452 ! close documentation grouping
5453 
Register a diagnostic field for a given module.
Send data over to output fields.
Close a netcdf or domain file opened with open_file or open_virtual_file.
Definition: fms2_io.F90:233
Opens a NetCDF dataset on disk and initializes the file object.
Definition: fms2_io.F90:188
Read data from a defined field in a file.
Definition: fms2_io.F90:364
integer function, public check_nml_error(IOSTAT, NML_NAME)
Checks the iostat argument that is returned after reading a namelist and determines if the error code...
Definition: fms.F90:523
subroutine, public write_version_number(version, tag, unit)
Prints to the log file (or a specified unit) the version id string and tag name.
Definition: fms.F90:701
subroutine, public error_mesg(routine, message, level)
Print notes, warnings and error messages; terminates program for warning and error messages....
Definition: fms.F90:441
integer function, public get_mosaic_xgrid_size(fileobj)
return exchange grid size of mosaic xgrid file.
Definition: mosaic2.F90:118
subroutine, public get_mosaic_contact(fileobj, tile1, tile2, istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2)
Get contact information from mosaic_file Example usage: call get_mosaic_contact(mosaic_file,...
Definition: mosaic2.F90:222
integer function, public get_mosaic_ntiles(fileobj)
Get number of tiles in the mosaic_file.
Definition: mosaic2.F90:134
subroutine, public get_mosaic_tile_grid(grid_file, fileobj, domain, tile_count)
Gets the name of a mosaic tile grid file.
Definition: mosaic2.F90:428
integer function, public get_mosaic_ncontacts(fileobj)
Get number of contacts in the mosaic_file.
Definition: mosaic2.F90:150
subroutine, public get_mosaic_grid_sizes(fileobj, nx, ny)
Get grid size of each tile from mosaic_file.
Definition: mosaic2.F90:172
integer function mpp_get_domain_npes(domain)
Set user stack size.
integer function, dimension(size(domain%tile_id(:))) mpp_get_tile_id(domain)
Returns the tile_id on current pe.
integer function mpp_get_current_ntile(domain)
Returns number of tile on current pe.
integer function mpp_get_ntile_count(domain)
Returns number of tiles in mosaic.
subroutine mpp_compute_extent(isg, ieg, ndivs, ibegin, iend, extent)
Computes extents for a grid decomposition with the given indices and divisions.
subroutine mpp_get_tile_list(domain, tiles)
Return the tile_id on current pelist. one-tile-per-pe is assumed.
logical function mpp_domain_is_initialized(domain)
Set user stack size.
subroutine mpp_get_domain_pelist(domain, pelist)
Set user stack size.
integer function mpp_get_domain_root_pe(domain)
Set user stack size.
Broadcasts domain to every pe. Only useful outside the context of it's own pelist.
Deallocate given 1D or 2D domain.
Set up a domain decomposition.
These routines retrieve the axis specifications associated with the compute domains....
Retrieve the entire array of compute domain extents associated with a decomposition.
These routines retrieve the axis specifications associated with the data domains. The domain is a der...
These routines retrieve the axis specifications associated with the global domains....
Global sum of domain-decomposed arrays. mpp_global_sum is used to get the sum of a domain-decomposed...
Modifies the extents (compute, data and global) of a given domain.
Passes data from a structured grid to an unstructured grid Example usage:
Reorganization of distributed global arrays. mpp_redistribute is used to reorganize a distributed ar...
Performs halo updates for a given domain.
One dimensional domain used to manage shared data access between pes.
The domain2D type contains all the necessary information to define the global, compute and data domai...
Domain information for managing data on unstructured grids.
subroutine mpp_sync_self(pelist, check, request, msg_size, msg_type)
This is to check if current PE's outstanding puts are complete but we can't use shmem_fence because w...
integer function stdout()
This function returns the current standard fortran unit numbers for output.
Definition: mpp_util.inc:42
subroutine mpp_set_current_pelist(pelist, no_sync)
Set context pelist.
Definition: mpp_util.inc:514
integer function stdlog()
This function returns the current standard fortran unit numbers for log messages. Log messages,...
Definition: mpp_util.inc:58
integer function mpp_npes()
Returns processor count for current pelist.
Definition: mpp_util.inc:420
integer function mpp_pe()
Returns processor ID.
Definition: mpp_util.inc:406
subroutine mpp_sync(pelist, do_self)
Synchronize PEs in list.
integer function mpp_clock_id(name, flags, grain)
Return an ID for a new or existing clock.
Definition: mpp_util.inc:736
Scatter a vector across all PEs.
Definition: mpp.F90:824
Reduction operations. Find the max of scalar a from the PEs in pelist result is also automatically br...
Definition: mpp.F90:568
Reduction operations. Find the min of scalar a from the PEs in pelist result is also automatically br...
Definition: mpp.F90:590
Receive data from another PE.
Definition: mpp.F90:999
Send data to a receiving PE.
Definition: mpp.F90:1066
Reduction operation.
Definition: mpp.F90:627
Holds stocks amounts per PE values.
subroutine, public get_time(Time, seconds, days, ticks, err_msg)
Returns days and seconds ( < 86400 ) corresponding to a time. err_msg should be checked for any error...
Type to represent amounts of time. Implemented as seconds and days to allow for larger intervals.
subroutine get_area_elements_fms2_io(fileobj, name, get_area_data)
Read the area elements from NetCDF file.
Definition: xgrid.F90:1451
integer function, public xgrid_count(xmap)
Returns current size of exchange grid variables.
Definition: xgrid.F90:3229
subroutine, public some(xmap, some_arr, grid_id)
Returns logical associating exchange grid cells with given side two grid.
Definition: xgrid.F90:3460
subroutine regen(xmap)
Regenerate/Update the xmap.
Definition: xgrid.F90:2930
integer nsubset
Number of processors to read exchange grid information. Those processors that read the exchange grid ...
Definition: xgrid.F90:159
subroutine put_side1_to_xgrid(d, grid_id, x, xmap, remap_method, complete)
Scatters data to exchange grid.
Definition: xgrid.F90:3238
integer function get_nest_contact_fms2_io(fileobj, tile_nest_out, tile_parent_out, is_nest_out, ie_nest_out, js_nest_out, je_nest_out, is_parent_out, ie_parent_out, js_parent_out, je_parent_out)
currently we are assuming there is only one nest region
Definition: xgrid.F90:2111
subroutine, public get_ocean_model_area_elements(domain, grid_file)
Read Ocean area element data from netCDF file.
Definition: xgrid.F90:1474
subroutine, public set_frac_area_ug(f, grid_id, xmap)
Changes sub-grid portion areas and/or number.
Definition: xgrid.F90:3195
real(r8_kind) function, dimension(3) conservation_check_ug_side1(d, grid_id, xmap, remap_method)
conservation_check_ug - returns three numbers which are the global sum of a variable (1) on its home ...
Definition: xgrid.F90:4209
subroutine get_side1_from_xgrid(d, grid_id, x, xmap, complete)
Definition: xgrid.F90:3356
subroutine stock_move_3d(from, to, grid_index, stock_data3d, xmap, delta_t, from_side, to_side, radius, verbose, ier)
this version takes rank 3 data, it can be used to compute the flux on anything but the first grid,...
Definition: xgrid.F90:4480
real(r8_kind), dimension(:,:), allocatable, public area_atm_sphere
Area elements based on a the spherical model used by the ICE layer.
Definition: xgrid.F90:177
logical function in_box_me(i, j, grid)
Definition: xgrid.F90:5423
logical function in_box(i, j, is, ie, js, je)
Definition: xgrid.F90:508
integer remapping_method
xgrid nml
Definition: xgrid.F90:172
subroutine get_grid_version2(grid, grid_id, grid_file)
read the center point of the grid from version 1 grid file. only the grid at the side 1 is needed,...
Definition: xgrid.F90:1363
subroutine get_side2_from_xgrid(d, grid_id, x, xmap)
Definition: xgrid.F90:3434
real(r8_kind) function, dimension(3) conservation_check_ug_side2(d, grid_id, xmap, remap_method)
conservation_check_ug - returns three numbers which are the global sum of a variable (1) on its home ...
Definition: xgrid.F90:4282
real(r8_kind) function, dimension(is:ie, js:je) grad_merid_latlon(d, lat, is, ie, js, je, isd, jsd)
This function is used to calculate the gradient along meridinal direction. Maybe need to setup a limi...
Definition: xgrid.F90:4430
logical make_exchange_reproduce
Set to .true. to make xgrid_mod reproduce answers on different numbers of PEs. This option has a cons...
Definition: xgrid.F90:151
character(len=64) interp_method
Exchange grid interpolation method. It has two options: "first_order", "second_order".
Definition: xgrid.F90:154
integer, parameter version2
mosaic grid file
Definition: xgrid.F90:148
subroutine, public setup_xmap(xmap, grid_ids, grid_domains, grid_file, atm_grid, lnd_ug_domain)
Sets up exchange grid connectivity using grid specification file and processor domain decomposition.
Definition: xgrid.F90:1507
subroutine get_grid_version1(grid, grid_id, grid_file)
read the center point of the grid from version 1 grid file. only the grid at the side 1 is needed,...
Definition: xgrid.F90:1295
subroutine put_side1_to_xgrid_ug(d, grid_id, x, xmap, complete)
Currently only support first order.
Definition: xgrid.F90:4927
subroutine put_side2_to_xgrid(d, grid_id, x, xmap)
Scatters data to exchange grid.
Definition: xgrid.F90:3331
subroutine set_frac_area_sg(f, grid_id, xmap)
Changes sub-grid portion areas and/or number.
Definition: xgrid.F90:3163
logical function in_box_nbr(i, j, grid, p)
Definition: xgrid.F90:5439
integer, parameter version1
grid spec file
Definition: xgrid.F90:147
real(r8_kind) function, dimension(3) conservation_check_side2(d, grid_id, xmap, remap_method)
conservation_check - returns three numbers which are the global sum of a variable (1) on its home mod...
Definition: xgrid.F90:4153
real(r8_kind) function, dimension(3) conservation_check_side1(d, grid_id, xmap, remap_method)
conservation_check - returns three numbers which are the global sum of a variable (1) on its home mod...
Definition: xgrid.F90:4106
subroutine, public xgrid_init(remap_method)
Initialize the xgrid_mod.
Definition: xgrid.F90:519
real(r8_kind), dimension(:,:), allocatable, public area_atm_model
Area elements used inside each model.
Definition: xgrid.F90:175
real(r8_kind) function, dimension(is:ie, js:je) grad_zonal_latlon(d, lon, lat, is, ie, js, je, isd, jsd)
This function is used to calculate the gradient along zonal direction. Maybe need to setup a limit fo...
Definition: xgrid.F90:4390
subroutine, public get_xmap_grid_area(id, xmap, area)
This routine is used to get the grid area of component model with id.
Definition: xgrid.F90:4362
Returns three numbers which are the global sum of a variable.
Definition: xgrid.F90:248
For an unstructured grid, returns three numbers which are the global sum of a variable (1) on its hom...
Definition: xgrid.F90:257
Sums data from exchange grid to model grid.
Definition: xgrid.F90:201
get_from_xgrid for unstructured grids.
Definition: xgrid.F90:219
Scatters data from model grid onto exchange grid.
Definition: xgrid.F90:189
put_to_xgrid for unstructured grids.
Definition: xgrid.F90:210
Sets sub-grid area and numbering in the given exchange grid.
Definition: xgrid.F90:226
Private type used for exchange grid communication.
Definition: xgrid.F90:399
Type to hold pointers for grid boxes.
Definition: xgrid.F90:284
Private type to hold all data needed from given grid for an exchange grid.
Definition: xgrid.F90:300
Private type for overlap exchange grid data.
Definition: xgrid.F90:384
Private type for exchange grid data.
Definition: xgrid.F90:364
Private type for exchange grid data.
Definition: xgrid.F90:376
Private type for cell indices and data in the exchange grid.
Definition: xgrid.F90:265
Type for an exchange grid, holds pointers to included grids and any necessary data.
Definition: xgrid.F90:409
Get the current pelist. The two flavors of this subroutine differ in the type of their comm/commID ar...
Definition: mpp.F90:433