FMS  2025.04
Flexible Modeling System
mpp_domains_comm.inc
1 ! -*-f90-*-
2 
3 
4 !***********************************************************************
5 !* Apache License 2.0
6 !*
7 !* This file is part of the GFDL Flexible Modeling System (FMS).
8 !*
9 !* Licensed under the Apache License, Version 2.0 (the "License");
10 !* you may not use this file except in compliance with the License.
11 !* You may obtain a copy of the License at
12 !*
13 !* http://www.apache.org/licenses/LICENSE-2.0
14 !*
15 !* FMS is distributed in the hope that it will be useful, but WITHOUT
16 !* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied;
17 !* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
18 !* PARTICULAR PURPOSE. See the License for the specific language
19 !* governing permissions and limitations under the License.
20 !***********************************************************************
21 
22 !> @file
23 !> @brief Routines for domain communications via @ref domaincommunicator2d
24 
25 !> @addtogroup mpp_domains_mod
26 !> @{
27  function mpp_redistribute_init_comm(domain_in,l_addrs_in, domain_out,l_addrs_out, &
28  isize_in,jsize_in,ksize_in,isize_out,jsize_out,ksize_out) RESULT(d_comm)
29  type(DomainCommunicator2D), pointer :: d_comm
30  type(domain2D),target, intent(in) :: domain_in
31  integer(i8_kind), intent(in) :: l_addrs_in(:)
32  type(domain2D),target, intent(in) :: domain_out
33  integer(i8_kind), intent(in) :: l_addrs_out(:)
34  integer, intent(in) :: isize_in
35  integer, intent(in) :: jsize_in
36  integer, intent(in) :: ksize_in
37  integer, intent(in) :: isize_out
38  integer, intent(in) :: jsize_out
39  integer, intent(in) :: ksize_out
40 
41  integer(i8_kind) :: domain_id
42  integer :: m, list
43  integer :: is, ie, js, je, ke, ioff, joff, list_size
44  integer :: isc, iec, jsc, jec, mytile
45  integer :: lsize,rsize,msgsize,to_pe,from_pe
46  integer, allocatable,dimension(:) :: isL, jsL
47  integer(i8_kind),allocatable,dimension(:,:) :: slist_addr
48  character(len=8) :: text
49 
50 
51  ! This test determines whether input fields are from allocated memory (LOC gets global
52  ! address) or "static" memory (need shmem_ptr). This probably needs to be generalized
53  ! to determine appropriate mechanism for each incoming address.
54 
55  ! "Concurrent" run mode may leave field_in or field_out unassociated if pe does not
56  ! contain in/out data. Use of STATIC option for ocean complicates this as ocean component
57  ! always defined. Field_out is always a boundary structure and so is always allocated or
58  ! not depending on whether it's used. If field out is defined (>0), then it is used otherwise
59  ! field in must be defined.
60 
61 !fix ke
62  ke = 0
63  if( domain_in%pe /= null_pe )ke = ksize_in
64  if( domain_out%pe /= null_pe )then
65  if( ke /= 0 .AND. ke /= ksize_out ) &
66  call mpp_error( fatal, 'MPP_REDISTRIBUTE_INIT_COMM: mismatch between field_in and field_out.' )
67  ke = ksize_out
68  end if
69  if( ke == 0 )call mpp_error( fatal, &
70  & 'MPP_REDISTRIBUTE_INIT_COMM: either domain_in or domain_out must be native.' )
71 !check sizes
72  if( domain_in%pe /= null_pe )then
73  if( isize_in /= domain_in%x(1)%domain_data%size .OR. jsize_in /= domain_in%y(1)%domain_data%size ) &
74  call mpp_error( fatal, 'MPP_REDISTRIBUTE_INIT_COMM: field_in must be on data domain of domain_in.' )
75  end if
76  if( domain_out%pe /= null_pe )then
77  if( isize_out /= domain_out%x(1)%domain_data%size .OR. jsize_out /= domain_out%y(1)%domain_data%size ) &
78  call mpp_error( fatal, 'MPP_REDISTRIBUTE_INIT_COMM: field_out must be on data domain of domain_out.' )
79  end if
80 
81 
82  ! Create unique domain identifier
83  list_size = size(l_addrs_in(:))
84  if(l_addrs_out(1) > 0)then
85  domain_id = set_domain_id(domain_out%id,ke+list_size)
86  else
87  domain_id = set_domain_id(domain_in%id,ke+list_size)
88  endif
89 
90  d_comm =>get_comm(domain_id,l_addrs_in(1),l_addrs_out(1))
91 
92  if(d_comm%initialized)return ! Found existing field/domain communicator
93 
94  d_comm%l_addr = l_addrs_in(1)
95  d_comm%domain_in =>domain_in
96  d_comm%Slist_size = size(domain_out%list(:))
97  d_comm%isize_in = isize_in
98  d_comm%jsize_in = jsize_in
99  d_comm%ke = ke
100 
101 !send
102  lsize = d_comm%Slist_size-1
103  allocate(d_comm%sendis(1,0:lsize), d_comm%sendie(1,0:lsize), &
104  d_comm%sendjs(1,0:lsize), d_comm%sendje(1,0:lsize), &
105  d_comm%S_msize(0:lsize),isl(0:lsize),jsl(0:lsize))
106  allocate(slist_addr(list_size,0:lsize))
107  allocate(d_comm%cto_pe(0:lsize), d_comm%S_do_buf(0:lsize))
108 
109  isl=0;jsl=0
110  slist_addr = -9999
111  d_comm%cto_pe=-1
112  d_comm%sendis=0; d_comm%sendie=0
113  d_comm%sendjs=0; d_comm%sendje=0;
114  d_comm%S_msize=0
115  d_comm%S_do_buf=.false.
116 
117  ioff = domain_in%x(1)%domain_data%begin
118  joff = domain_in%y(1)%domain_data%begin
119  mytile = domain_in%tile_id(1)
120 
121  call mpp_get_compute_domain( domain_in, isc, iec, jsc, jec )
122  do list = 0,lsize
123  m = mod( domain_out%pos+list+lsize+1, lsize+1 )
124  if( mytile .NE. domain_out%list(m)%tile_id(1) ) cycle
125  d_comm%cto_pe(list) = domain_out%list(m)%pe
126  to_pe = d_comm%cto_pe(list)
127  is = domain_out%list(m)%x(1)%compute%begin
128  ie = domain_out%list(m)%x(1)%compute%end
129  js = domain_out%list(m)%y(1)%compute%begin
130  je = domain_out%list(m)%y(1)%compute%end
131  is = max(is,isc); ie = min(ie,iec)
132  js = max(js,jsc); je = min(je,jec)
133  if( ie >= is .AND. je >= js )then
134  d_comm%S_do_buf(list) = .true.
135  d_comm%sendis(1,list)=is; d_comm%sendie(1,list)=ie
136  d_comm%sendjs(1,list)=js; d_comm%sendje(1,list)=je
137  d_comm%S_msize(list) = (ie-is+1)*(je-js+1)*ke
138  isl(list) = is-ioff+1; jsl(list) = js-joff+1
139  end if
140  end do
141 
142  call mpp_sync_self()
143 !recv
144  d_comm%domain_out =>domain_out
145  d_comm%Rlist_size = size(domain_in%list(:))
146  d_comm%isize_out = isize_out
147  d_comm%jsize_out = jsize_out
148 
149  rsize = d_comm%Rlist_size-1
150  allocate(d_comm%recvis(1,0:rsize), d_comm%recvie(1,0:rsize), &
151  d_comm%recvjs(1,0:rsize), d_comm%recvje(1,0:rsize), &
152  d_comm%R_msize(0:rsize))
153  allocate(d_comm%cfrom_pe(0:rsize), d_comm%R_do_buf(0:rsize))
154  allocate(d_comm%isizeR(0:rsize), d_comm%jsizeR(0:rsize))
155  allocate(d_comm%sendisR(1,0:rsize), d_comm%sendjsR(1,0:rsize))
156  allocate(d_comm%rem_addrl(list_size,0:rsize))
157  d_comm%rem_addrl=-9999
158  d_comm%cfrom_pe=-1
159  d_comm%recvis=0; d_comm%recvie=0
160  d_comm%recvjs=0; d_comm%recvje=0;
161  d_comm%R_msize=0
162  d_comm%R_do_buf=.false.
163  d_comm%isizeR=0; d_comm%jsizeR=0
164  d_comm%sendisR=0; d_comm%sendjsR=0
165 
166  mytile = domain_out%tile_id(1)
167  call mpp_get_compute_domain( domain_out, isc, iec, jsc, jec )
168  do list = 0,rsize
169  m = mod( domain_in%pos+rsize+1-list, rsize+1 )
170  if( mytile .NE. domain_in%list(m)%tile_id(1) ) cycle
171  d_comm%cfrom_pe(list) = domain_in%list(m)%pe
172  from_pe = d_comm%cfrom_pe(list)
173  is = domain_in%list(m)%x(1)%compute%begin
174  ie = domain_in%list(m)%x(1)%compute%end
175  js = domain_in%list(m)%y(1)%compute%begin
176  je = domain_in%list(m)%y(1)%compute%end
177  is = max(is,isc); ie = min(ie,iec)
178  js = max(js,jsc); je = min(je,jec)
179  if( ie >= is .AND. je >= js )then
180  d_comm%R_do_buf(list) = .true.
181  d_comm%recvis(1,list)=is; d_comm%recvie(1,list)=ie
182  d_comm%recvjs(1,list)=js; d_comm%recvje(1,list)=je
183  d_comm%R_msize(list) = (ie-is+1)*(je-js+1)*ke
184  end if
185  end do
186 
187  d_comm%isize_max = isize_in; call mpp_max(d_comm%isize_max)
188  d_comm%jsize_max = jsize_in; call mpp_max(d_comm%jsize_max)
189 
190  ! Handles case where S_msize and/or R_msize are 0 size array
191  msgsize = ( maxval( (/0,sum(d_comm%S_msize(:))/) ) + maxval( (/0,sum(d_comm%R_msize(:))/) ) ) * list_size
192  if(msgsize>0)then
193  mpp_domains_stack_hwm = max( mpp_domains_stack_hwm, msgsize )
194  if( mpp_domains_stack_hwm.GT.mpp_domains_stack_size )then
195  write( text,'(i8)' )mpp_domains_stack_hwm
196  call mpp_error( fatal, &
197  & 'MPP_REDISTRIBUTE_INIT_COMM: mpp_domains_stack overflow, call mpp_domains_set_stack_size(' &
198  & //trim(text)//') from all PEs.' )
199  end if
200  end if
201 
202  DEALLOCATE(slist_addr,isl,jsl)
203 
204  d_comm%initialized = .true.
205 
206  end function mpp_redistribute_init_comm
207 
208  !> initializes a @ref DomainCommunicator2D type for use in @ref mpp_global_field
209  function mpp_global_field_init_comm(domain,l_addr,isize_g,jsize_g,isize_l, &
210  jsize_l, ksize,l_addr2,flags, position) RESULT(d_comm)
211  type(domaincommunicator2d), pointer :: d_comm
212  type(domain2d),target, intent(in) :: domain
213  integer(i8_kind), intent(in) :: l_addr
214  integer, intent(in) :: isize_g
215  integer, intent(in) :: jsize_g
216  integer, intent(in) :: isize_l
217  integer, intent(in) :: jsize_l
218  integer, intent(in) :: ksize
219  integer(i8_kind),optional,intent(in) :: l_addr2
220  integer, optional, intent(in) :: flags
221  integer, optional, intent(in) :: position
222 
223  integer(i8_kind) :: domain_id
224  integer :: n, lpos, rpos, list, nlist, tile_id
225  integer :: update_flags
226  logical :: xonly, yonly
227  integer :: is, ie, js, je, ioff, joff, ishift, jshift
228  integer :: lsize,msgsize,from_pe
229  integer, allocatable,dimension(:) :: isl, jsl
230  integer(i8_kind),allocatable,dimension(:,:) :: slist_addr
231  integer(i8_kind),save ,dimension(2) :: rem_addr
232  character(len=8) :: text
233 
234  if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_GLOBAL_FIELD: must first call mpp_domains_init.' )
235  update_flags=xupdate+yupdate; xonly = .false.; yonly = .false.
236  if( PRESENT(flags) )then
237  update_flags = flags
238  xonly = btest(flags,east)
239  yonly = btest(flags,south)
240  if( .NOT.xonly .AND. .NOT.yonly )call mpp_error( warning, &
241  'MPP_GLOBAL_FIELD: you must have flags=XUPDATE, YUPDATE or XUPDATE+YUPDATE' )
242  if(xonly .AND. yonly) then
243  xonly = .false.; yonly = .false.
244  endif
245  end if
246 
247  call mpp_get_domain_shift(domain, ishift, jshift, position=position)
248 
249  if( isize_g /= (domain%x(1)%global%size+ishift) .OR. jsize_g /= (domain%y(1)%global%size+jshift) ) &
250  call mpp_error( fatal, 'MPP_GLOBAL_FIELD_INIT_COMM: incoming arrays do not match domain.' )
251 
252  if( isize_l == (domain%x(1)%compute%size+ishift) .AND. jsize_l == (domain%y(1)%compute%size+jshift) )then
253 !local is on compute domain
254  ioff = -domain%x(1)%compute%begin + 1
255  joff = -domain%y(1)%compute%begin + 1
256  elseif( isize_l == (domain%x(1)%memory%size+ishift) .AND. jsize_l == (domain%y(1)%memory%size+jshift) )then
257 !local is on data domain
258  ioff = -domain%x(1)%domain_data%begin + 1
259  joff = -domain%y(1)%domain_data%begin + 1
260  else
261  call mpp_error(fatal, &
262  & 'MPP_GLOBAL_FIELD_INIT_COMM: incoming field array must match either compute domain or data domain.')
263  endif
264 
265  ! Create unique domain identifier
266  domain_id=set_domain_id(domain%id,ksize,update_flags, position=position)
267  d_comm =>get_comm(domain_id,l_addr,l_addr2)
268 
269  if(d_comm%initialized)return ! Found existing field/domain communicator
270  d_comm%domain => domain
271  d_comm%isize_in = isize_l; d_comm%isize_out = isize_g
272  d_comm%jsize_in = jsize_l; d_comm%jsize_out = jsize_g
273  d_comm%ke = ksize
274  d_comm%gf_ioff=ioff; d_comm%gf_joff=joff
275 
276 !fill off-domains (note loops begin at an offset of 1)
277  if( xonly )then
278  lsize = size(domain%x(1)%list(:))
279 !send
280  allocate(d_comm%cto_pe(0:lsize-1))
281  d_comm%cto_pe=-1
282  do list = 0,lsize-1
283  lpos = mod(domain%x(1)%pos+lsize-list,lsize)
284  d_comm%cto_pe(list) = domain%x(1)%list(lpos)%pe
285  end do
286 !recv
287  allocate(d_comm%cfrom_pe(0:lsize-1))
288  allocate(d_comm%recvis(1,0:lsize-1), d_comm%recvie(1,0:lsize-1), &
289  d_comm%recvjs(1,0:lsize-1), d_comm%recvje(1,0:lsize-1), &
290  d_comm%R_msize(0:lsize-1))
291  d_comm%cfrom_pe=-1
292  d_comm%recvis=0; d_comm%recvie=0
293  d_comm%recvjs=0; d_comm%recvje=0;
294  d_comm%R_msize=0
295  do list = 0,lsize-1
296  rpos = mod(domain%x(1)%pos+list,lsize)
297  from_pe = domain%x(1)%list(rpos)%pe
298  d_comm%cfrom_pe(list) = from_pe
299  is = domain%list(from_pe)%x(1)%compute%begin; ie = domain%list(from_pe)%x(1)%compute%end+ishift
300  js = domain%y(1)%compute%begin; je = domain%y(1)%compute%end+jshift
301  d_comm%recvis(1,list)=is; d_comm%recvie(1,list)=ie
302  d_comm%recvjs(1,list)=js; d_comm%recvje(1,list)=je
303  d_comm%R_msize(list) = (ie-is+1) * (je-js+1) * ksize
304  end do
305 
306  elseif( yonly )then
307  lsize = size(domain%y(1)%list(:))
308 !send
309  allocate(d_comm%cto_pe(0:lsize-1))
310  d_comm%cto_pe=-1
311  do list = 0,lsize
312  lpos = mod(domain%y(1)%pos+lsize-list,lsize)
313  d_comm%cto_pe(list) = domain%y(1)%list(lpos)%pe
314  end do
315 !recv
316  allocate(d_comm%cfrom_pe(0:lsize-1))
317  allocate(d_comm%recvis(1,0:lsize-1), d_comm%recvie(1,0:lsize-1), &
318  d_comm%recvjs(1,0:lsize-1), d_comm%recvje(1,0:lsize-1), &
319  d_comm%R_msize(0:lsize-1))
320  d_comm%cfrom_pe=-1
321  d_comm%recvis=0; d_comm%recvie=0
322  d_comm%recvjs=0; d_comm%recvje=0;
323  d_comm%R_msize=0
324  do list = 0,lsize-1
325  rpos = mod(domain%y(1)%pos+list,lsize)
326  from_pe = domain%y(1)%list(rpos)%pe
327  d_comm%cfrom_pe(list) = from_pe
328  is = domain%x(1)%compute%begin; ie = domain%x(1)%compute%end+ishift
329  js = domain%list(from_pe)%y(1)%compute%begin; je = domain%list(from_pe)%y(1)%compute%end+jshift
330  d_comm%recvis(1,list)=is; d_comm%recvie(1,list)=ie
331  d_comm%recvjs(1,list)=js; d_comm%recvje(1,list)=je
332  d_comm%R_msize(list) = (ie-is+1) * (je-js+1) * ksize
333  end do
334 
335  else
336  nlist = size(domain%list(:))
337  tile_id = domain%tile_id(1)
338 
339  lsize = 0
340  do list = 0,nlist-1
341  if( domain%list(list)%tile_id(1) .NE. tile_id ) cycle
342  lsize = lsize+1
343  end do
344 
345  !send
346  allocate(d_comm%cto_pe(0:lsize-1))
347  d_comm%cto_pe=-1
348  n = 0
349  do list = 0,nlist-1
350  lpos = mod(domain%pos+nlist-list,nlist)
351  if( domain%list(lpos)%tile_id(1) .NE. tile_id ) cycle
352  d_comm%cto_pe(n) = domain%list(lpos)%pe
353  n = n + 1
354  end do
355  !recv
356  allocate(d_comm%cfrom_pe(0:lsize-1))
357  allocate(d_comm%recvis(1,0:lsize-1), d_comm%recvie(1,0:lsize-1), &
358  d_comm%recvjs(1,0:lsize-1), d_comm%recvje(1,0:lsize-1), &
359  d_comm%R_msize(0:lsize-1))
360  d_comm%cfrom_pe=-1
361  d_comm%recvis=0; d_comm%recvie=0
362  d_comm%recvjs=0; d_comm%recvje=0;
363  d_comm%R_msize=0
364  n = 0
365  do list = 0,nlist-1
366  rpos = mod(domain%pos+list,nlist)
367  if( domain%list(rpos)%tile_id(1) .NE. tile_id ) cycle
368  d_comm%cfrom_pe(n) = domain%list(rpos)%pe
369  is = domain%list(rpos)%x(1)%compute%begin; ie = domain%list(rpos)%x(1)%compute%end+ishift
370  js = domain%list(rpos)%y(1)%compute%begin; je = domain%list(rpos)%y(1)%compute%end+jshift
371  d_comm%recvis(1,n)=is; d_comm%recvie(1,n)=ie
372  d_comm%recvjs(1,n)=js; d_comm%recvje(1,n)=je
373  d_comm%R_msize(n) = (je-js+1) * (ie-is+1) * ksize
374  n = n+1
375  end do
376 
377  endif
378 
379  d_comm%Slist_size = lsize
380  d_comm%Rlist_size = lsize
381 
382 !send
383  allocate(d_comm%sendis(1,0:lsize-1), d_comm%sendie(1,0:lsize-1), &
384  d_comm%sendjs(1,0:lsize-1), d_comm%sendje(1,0:lsize-1), &
385  d_comm%S_msize(0:lsize-1),isl(0:lsize-1),jsl(0:lsize-1))
386  allocate(slist_addr(2,0:lsize-1))
387  isl=0; jsl=0
388  slist_addr = -9999
389  d_comm%sendis=0; d_comm%sendie=0
390  d_comm%sendjs=0; d_comm%sendje=0;
391  d_comm%S_msize=0
392  do list = 0,lsize-1
393  is=domain%x(1)%compute%begin; ie=domain%x(1)%compute%end+ishift
394  js=domain%y(1)%compute%begin; je=domain%y(1)%compute%end+jshift
395  d_comm%sendis(1,list)=is; d_comm%sendie(1,list)=ie
396  d_comm%sendjs(1,list)=js; d_comm%sendje(1,list)=je
397  d_comm%S_msize(list) = (je-js+1) * (ie-is+1) * ksize
398  isl(list) = ioff+domain%x(1)%compute%begin; jsl(list) = joff+domain%y(1)%compute%begin
399  end do
400 
401 !recv
402  allocate(d_comm%isizeR(0:lsize-1), d_comm%jsizeR(0:lsize-1))
403  allocate(d_comm%sendisR(1,0:lsize-1), d_comm%sendjsR(1,0:lsize-1))
404  if(.not.PRESENT(l_addr2))then
405  allocate(d_comm%rem_addr(0:lsize-1))
406  d_comm%rem_addr=-9999
407  else
408  allocate(d_comm%rem_addrx(0:lsize-1),d_comm%rem_addry(0:lsize-1))
409  d_comm%rem_addrx=-9999; d_comm%rem_addry=-9999
410  endif
411  d_comm%isizeR=0; d_comm%jsizeR=0
412  d_comm%sendisR=0; d_comm%sendjsR=0
413  rem_addr = -9999
414 
415  ! Handles case where S_msize and/or R_msize are 0 size array
416  msgsize = maxval( (/0,sum(d_comm%S_msize(:))/) ) + maxval( (/0,sum(d_comm%R_msize(:))/) )
417  if(msgsize>0)then
418  mpp_domains_stack_hwm = max( mpp_domains_stack_hwm, msgsize )
419  if( mpp_domains_stack_hwm.GT.mpp_domains_stack_size )then
420  write( text,'(i8)' )mpp_domains_stack_hwm
421  call mpp_error( fatal, &
422  & 'MPP_GLOBAL_FIELD_INIT_COMM: mpp_domains_stack overflow, call mpp_domains_set_stack_size(' &
423  & //trim(text)//') from all PEs.' )
424  end if
425  end if
426 
427  DEALLOCATE(slist_addr,isl,jsl)
428 
429  d_comm%initialized = .true.
430 
431  end function mpp_global_field_init_comm
432 
433 
434  subroutine mpp_redistribute_free_comm(domain_in,l_addr,domain_out,l_addr2,ksize,lsize)
435  ! Since initialization of the d_comm type is expensive, freeing should be a rare
436  ! event. Thus no attempt is made to salvage freed d_comm's.
437  type(domain2d), intent(in) :: domain_in
438  integer(i8_kind), intent(in) :: l_addr
439  type(domain2d), intent(in) :: domain_out
440  integer(i8_kind), intent(in) :: l_addr2
441  integer, intent(in) :: ksize,lsize
442 
443  integer(i8_kind) :: domain_id
444 
445  if(l_addr2 > 0)then
446  domain_id = set_domain_id(domain_out%id,ksize+lsize)
447  else
448  domain_id = set_domain_id(domain_in%id,ksize+lsize)
449  endif
450  call free_comm(domain_id,l_addr,l_addr2)
451  end subroutine mpp_redistribute_free_comm
452 
453 
454  subroutine mpp_global_field_free_comm(domain,l_addr,ksize,l_addr2,flags)
455  ! Since initialization of the d_comm type is expensive, freeing should be a rare
456  ! event. Thus no attempt is made to salvage freed d_comm's.
457  type(domain2d), intent(in) :: domain
458  integer(i8_kind), intent(in) :: l_addr
459  integer, intent(in) :: ksize
460  integer(i8_kind),optional,intent(in) :: l_addr2
461  integer, optional,intent(in) :: flags
462 
463  integer :: update_flags
464  integer(i8_kind) :: domain_id
465 
466  update_flags=0; if(PRESENT(flags))update_flags=flags
467  domain_id=set_domain_id(domain%id,ksize,update_flags)
468  call free_comm(domain_id,l_addr,l_addr2)
469  end subroutine mpp_global_field_free_comm
470 
471 
472  subroutine free_comm(domain_id,l_addr,l_addr2)
473  ! Since initialization of the d_comm type is expensive, freeing should be a rare
474  ! event. Thus no attempt is made to salvage freed d_comm's.
475  integer(i8_kind), intent(in) :: domain_id
476  integer(i8_kind), intent(in) :: l_addr
477  integer(i8_kind),optional,intent(in) :: l_addr2
478 
479  integer(i8_kind) :: dc_key,a_key
480  integer :: dc_idx,a_idx,i_idx,insert,insert_a,insert_i
481  integer :: a2_idx,insert_a2
482 
483 
484  i_idx = find_key(domain_id,ids_sorted(1:n_ids),insert_i)
485  a_idx = find_key(l_addr,addrs_sorted(1:a_sort_len),insert_a)
486  a_key = int(addrs_idx(a_idx),kind(i8_kind))
487  if(PRESENT(l_addr2))then
488  a2_idx = find_key(l_addr2,addrs2_sorted(1:a2_sort_len),insert_a2)
489  a_key = a_key + addr2_base*int(addrs2_idx(a2_idx),kind(i8_kind))
490  endif
491  dc_key = domain_id_base*int(ids_idx(i_idx),kind(i8_kind)) + a_key
492  dc_idx = find_key(dc_key,dckey_sorted(1:dc_sort_len),insert)
493 
494  if(dc_idx < 0)then
495  call mpp_error(fatal,'FREE_COMM: attempt to remove nonexistent domains communicator key')
496  endif
497  call deallocate_comm(d_comm(dc_idx))
498  call pop_key(dckey_sorted,d_comm_idx,dc_sort_len,dc_idx)
499  call pop_key(addrs_sorted,addrs_idx,a_sort_len,a_idx)
500  if(PRESENT(l_addr2))call pop_key(addrs2_sorted,addrs2_idx,a2_sort_len,a2_idx)
501  end subroutine free_comm
502 
503 
504  function get_comm(domain_id,l_addr,l_addr2)
505  integer(i8_kind),intent(in) :: domain_id
506  integer(i8_kind),intent(in) :: l_addr
507  integer(i8_kind),intent(in),optional :: l_addr2
508  type(domaincommunicator2d), pointer :: get_comm
509 
510  integer(i8_kind) :: dc_key,a_key
511  integer :: i,dc_idx,a_idx,i_idx,insert,insert_a,insert_i
512  integer :: a2_idx,insert_a2
513 
514  if(.not.ALLOCATED(d_comm))ALLOCATE(d_comm(max_fields))
515  i_idx = find_key(domain_id,ids_sorted(1:n_ids),insert_i)
516  a_idx = find_key(l_addr,addrs_sorted(1:a_sort_len),insert_a)
517  a_key = int(addrs_idx(a_idx),kind(i8_kind))
518  if(PRESENT(l_addr2))then
519  a2_idx = find_key(l_addr2,addrs2_sorted(1:a2_sort_len),insert_a2)
520  a_key = a_key + addr2_base*int(addrs2_idx(a2_idx),kind(i8_kind))
521  endif
522  dc_key = domain_id_base*int(ids_idx(i_idx),kind(i8_kind)) + a_key
523  dc_idx = find_key(dc_key,dckey_sorted(1:dc_sort_len),insert)
524  if(dc_idx > 0)then
525  get_comm =>d_comm(d_comm_idx(dc_idx))
526  else
527  if(i_idx<0)then
528  if(n_ids == max_dom_ids)then
529  call mpp_error(fatal,'GET_COMM: Maximum number of domains exceeded')
530  endif
531  n_ids = n_ids+1
532  i_idx = push_key(ids_sorted,ids_idx,i_sort_len,insert_i,domain_id,n_ids)
533  endif
534  if(a_idx<0)then
535  if(n_addrs == max_addrs)then
536  call mpp_error(fatal,'GET_COMM: Maximum number of memory addresses exceeded')
537  endif
538  n_addrs = n_addrs + 1
539  a_idx = push_key(addrs_sorted,addrs_idx,a_sort_len,insert_a,l_addr,n_addrs)
540  endif
541  if(PRESENT(l_addr2))then
542  if(a2_idx<0)then
543  if(n_addrs2 == max_addrs2)then
544  call mpp_error(fatal,'GET_COMM: Maximum number of 2nd memory addresses exceeded')
545  endif
546  n_addrs2 = n_addrs2 + 1
547  a2_idx = push_key(addrs2_sorted,addrs2_idx,a2_sort_len,insert_a2,l_addr2,n_addrs2)
548  endif
549  endif
550  if(n_comm == max_fields)then
551  call mpp_error(fatal,'GET_COMM: Maximum number of fields exceeded')
552  endif
553  a_key = int(addrs_idx(a_idx),kind(8))
554  if(PRESENT(l_addr2))a_key = a_key + addr2_base*int(addrs2_idx(a2_idx),kind(8))
555  dc_key = domain_id_base*int(ids_idx(i_idx),kind(i8_kind)) + a_key
556  dc_idx = find_key(dc_key,dckey_sorted(1:dc_sort_len),insert)
557  if(dc_idx /= -1)call mpp_error(fatal,'GET_COMM: attempt to insert existing key')
558  n_comm = n_comm + 1
559  i = push_key(dckey_sorted,d_comm_idx,dc_sort_len,insert,dc_key,n_comm)
560  d_comm_idx(insert) = n_comm
561  if(PRESENT(l_addr2))then
562  d_comm(n_comm)%l_addrx = l_addr
563  d_comm(n_comm)%l_addry = l_addr2
564  else
565  d_comm(n_comm)%l_addr = l_addr
566  endif
567  get_comm =>d_comm(n_comm)
568  endif
569  end function get_comm
570 
571 
572  function push_key(sorted,idx,n_idx,insert,key,ival)
573  integer(i8_kind),intent(inout),dimension(:) :: sorted
574  integer, intent(inout),dimension(-1:) :: idx ! Start -1 to simplify first call logic in get_comm
575  integer, intent(inout) :: n_idx
576  integer, intent(in) :: insert
577  integer(i8_kind),intent(in) :: key
578  integer, intent(in) :: ival
579 
580  integer :: push_key,i
581 
582  do i=n_idx,insert,-1
583  sorted(i+1) = sorted(i)
584  idx(i+1) = idx(i)
585  end do
586  sorted(insert) = key
587  n_idx = n_idx + 1
588  idx(insert) = ival
589  push_key = insert
590  end function push_key
591 
592 
593  subroutine pop_key(sorted,idx,n_idx,key_idx)
594  integer(i8_kind),intent(inout),dimension(:) :: sorted
595  integer, intent(inout),dimension(-1:) :: idx ! Start -1 to simplify first call logic in get_comm
596  integer, intent(inout) :: n_idx
597  integer, intent(in) :: key_idx
598 
599  integer :: i
600 
601  do i=key_idx,n_idx-1
602  sorted(i) = sorted(i+1)
603  idx(i) = idx(i+1)
604  end do
605  sorted(n_idx) = -9999
606  idx(n_idx) = -9999
607  n_idx = n_idx - 1
608  end subroutine pop_key
609 
610 
611  function find_key(key,sorted,insert) RESULT(n)
612  ! The algorithm used here requires monotonic keys w/out repetition.
613  integer(i8_kind),intent(in) :: key ! new address to be found in list
614  integer(i8_kind),dimension(:),intent(in) :: sorted ! list of sorted local addrs
615  integer, intent(out) :: insert
616  integer :: n, n_max, n_min, n_key
617  logical :: not_found
618 
619  n_key = size(sorted(:))
620  insert = 1
621  n = -1 ! value not in list
622  if(n_key == 0)return ! first call
623 
624  if(key < sorted(1))then
625  insert = 1; return
626  elseif(key > sorted(n_key))then
627  insert = n_key+1; return
628  endif
629 
630  if(key == sorted(1))then
631  n = 1; return
632  elseif(key == sorted(n_key))then
633  n = n_key; return
634  endif
635 
636  not_found = .true.
637  n = n_key/2 + 1
638  n_min=1; n_max=n_key
639  do while(not_found)
640  if(key == sorted(n))then
641  not_found = .false.
642  elseif(key > sorted(n))then
643  if(key < sorted(n+1))then
644  insert = n+1; exit
645  endif
646  n_min = n
647  n = (n+1+n_max)/2
648  else
649  if(key > sorted(n-1))then
650  insert = n; exit
651  endif
652  n_max = n
653  n = (n+n_min)/2
654  endif
655  if(n==1 .or. n==n_key)exit
656  end do
657  if(not_found)n = -1 ! value not in list
658  end function find_key
659 
660 
661  subroutine deallocate_comm(d_comm)
662  type(domaincommunicator2d), intent(inout) :: d_comm
663 
664  d_comm%domain =>null()
665  d_comm%domain_in =>null()
666  d_comm%domain_out =>null()
667 
668  d_comm%initialized=.false.
669  d_comm%id=-9999
670  d_comm%l_addr =-9999
671  d_comm%l_addrx =-9999
672  d_comm%l_addry =-9999
673 
674  if( allocated(d_comm%sendis) ) DEALLOCATE(d_comm%sendis); !!d_comm%sendis =>NULL()
675  if( allocated(d_comm%sendie) ) DEALLOCATE(d_comm%sendie); !!d_comm%sendie =>NULL()
676  if( allocated(d_comm%sendjs) ) DEALLOCATE(d_comm%sendjs); !!d_comm%sendjs =>NULL()
677  if( allocated(d_comm%sendje) ) DEALLOCATE(d_comm%sendje); !!d_comm%sendje =>NULL()
678  if( allocated(d_comm%S_msize) ) DEALLOCATE(d_comm%S_msize); !!d_comm%S_msize =>NULL()
679  if( allocated(d_comm%S_do_buf) ) DEALLOCATE(d_comm%S_do_buf); !!d_comm%S_do_buf =>NULL()
680  if( allocated(d_comm%cto_pe) ) DEALLOCATE(d_comm%cto_pe); !!d_comm%cto_pe =>NULL()
681  if( allocated(d_comm%recvis) ) DEALLOCATE(d_comm%recvis); !!d_comm%recvis =>NULL()
682  if( allocated(d_comm%recvie) ) DEALLOCATE(d_comm%recvie); !!d_comm%recvie =>NULL()
683  if( allocated(d_comm%recvjs) ) DEALLOCATE(d_comm%recvjs); !!d_comm%recvjs =>NULL()
684  if( allocated(d_comm%recvje) ) DEALLOCATE(d_comm%recvje); !!d_comm%recvje =>NULL()
685  if( allocated(d_comm%R_msize) ) DEALLOCATE(d_comm%R_msize); !!d_comm%R_msize =>NULL()
686  if( allocated(d_comm%R_do_buf) ) DEALLOCATE(d_comm%R_do_buf); !!d_comm%R_do_buf =>NULL()
687  if( allocated(d_comm%cfrom_pe) ) DEALLOCATE(d_comm%cfrom_pe); !!d_comm%cfrom_pe =>NULL()
688  d_comm%Slist_size=0; d_comm%Rlist_size=0
689  d_comm%isize=0; d_comm%jsize=0; d_comm%ke=0
690  d_comm%isize_in=0; d_comm%jsize_in=0
691  d_comm%isize_out=0; d_comm%jsize_out=0
692  d_comm%isize_max=0; d_comm%jsize_max=0
693  d_comm%gf_ioff=0; d_comm%gf_joff=0
694  ! Remote data
695  if( allocated(d_comm%isizeR) ) DEALLOCATE(d_comm%isizeR); !!dd_comm%isizeR =>NULL()
696  if( allocated(d_comm%jsizeR) ) DEALLOCATE(d_comm%jsizeR); !!dd_comm%jsizeR =>NULL()
697  if( allocated(d_comm%sendisR) ) DEALLOCATE(d_comm%sendisR); !!dd_comm%sendisR =>NULL()
698  if( allocated(d_comm%sendjsR) ) DEALLOCATE(d_comm%sendjsR); !!dd_comm%sendjsR =>NULL()
699  if( allocated(d_comm%rem_addr) ) DEALLOCATE(d_comm%rem_addr); !!dd_comm%rem_addr =>NULL()
700  if( allocated(d_comm%rem_addrx) )DEALLOCATE(d_comm%rem_addrx); !!dd_comm%rem_addrx =>NULL()
701  if( allocated(d_comm%rem_addry) )DEALLOCATE(d_comm%rem_addry); !!dd_comm%rem_addry =>NULL()
702  if( allocated(d_comm%rem_addrl) )DEALLOCATE(d_comm%rem_addrl); !!dd_comm%rem_addrl =>NULL()
703  end subroutine deallocate_comm
704 
705 
706  function set_domain_id(d_id,ksize,flags,gtype, position, whalo, ehalo, shalo, nhalo)
707  integer(i8_kind), intent(in) :: d_id
708  integer , intent(in) :: ksize
709  integer , optional, intent(in) :: flags
710  integer , optional, intent(in) :: gtype
711  integer , optional, intent(in) :: position
712  integer , optional, intent(in) :: whalo, ehalo, shalo, nhalo
713 
714  integer(i8_kind) :: set_domain_id
715 
716  set_domain_id=d_id + ke_base*int(ksize,kind(d_id))
717  if(PRESENT(flags))set_domain_id=set_domain_id+int(flags,kind(d_id))
718  if(PRESENT(gtype))set_domain_id=set_domain_id+gt_base*int(gtype,kind(d_id)) ! Must be i8_kind arithmetic
719  !--- gtype is never been used to set id. we need to add position to calculate id to separate
720  !--- BGRID and CGRID or scalar variable.
721  if(present(position)) set_domain_id=set_domain_id+gt_base*int(2**position, kind(d_id))
722  !z1l ???? the following calculation may need to be revised
723  if(present(whalo)) then
724  if(whalo>=0) then
725  set_domain_id=set_domain_id+gt_base*int(2**4*2**whalo, kind(d_id))
726  else
727  set_domain_id=set_domain_id-gt_base*int(2**4*2**(-whalo), kind(d_id))
728  endif
729  end if
730  if(present(ehalo)) then
731  if(ehalo>=0) then
732  set_domain_id=set_domain_id+gt_base*int(2**4*2**ehalo, kind(d_id))
733  else
734  set_domain_id=set_domain_id-gt_base*int(2**4*2**(-ehalo), kind(d_id))
735  endif
736  end if
737  if(present(shalo)) then
738  if(shalo>=0) then
739  set_domain_id=set_domain_id+gt_base*int(2**4*2**shalo, kind(d_id))
740  else
741  set_domain_id=set_domain_id-gt_base*int(2**4*2**(-shalo), kind(d_id))
742  endif
743  end if
744  if(present(nhalo)) then
745  if(nhalo>=0) then
746  set_domain_id=set_domain_id+gt_base*int(2**4*2**nhalo, kind(d_id))
747  else
748  set_domain_id=set_domain_id-gt_base*int(2**4*2**(-nhalo), kind(d_id))
749  endif
750  end if
751  end function set_domain_id
752 !> @}
type(domaincommunicator2d) function, pointer mpp_global_field_init_comm(domain, l_addr, isize_g, jsize_g, isize_l, jsize_l, ksize, l_addr2, flags, position)
initializes a DomainCommunicator2D type for use in mpp_global_field
subroutine mpp_get_domain_shift(domain, ishift, jshift, position)
Returns the shift value in x and y-direction according to domain position..
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...