FV3 Bundle
mpp_domains_comm.inc
Go to the documentation of this file.
1 ! -*-f90-*-
2 
3 
4 !***********************************************************************
5 !* GNU Lesser General Public License
6 !*
7 !* This file is part of the GFDL Flexible Modeling System (FMS).
8 !*
9 !* FMS is free software: you can redistribute it and/or modify it under
10 !* the terms of the GNU Lesser General Public License as published by
11 !* the Free Software Foundation, either version 3 of the License, or (at
12 !* your option) any later version.
13 !*
14 !* FMS is distributed in the hope that it will be useful, but WITHOUT
15 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 !* for more details.
18 !*
19 !* You should have received a copy of the GNU Lesser General Public
20 !* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
21 !***********************************************************************
22 
23  function mpp_redistribute_init_comm(domain_in,l_addrs_in, domain_out,l_addrs_out, &
24  isize_in,jsize_in,ksize_in,isize_out,jsize_out,ksize_out) RESULT(d_comm)
25  type(DomainCommunicator2D), pointer :: d_comm
26  type(domain2D),target, intent(in) :: domain_in
27  integer(LONG_KIND), intent(in) :: l_addrs_in(:)
28  type(domain2D),target, intent(in) :: domain_out
29  integer(LONG_KIND), intent(in) :: l_addrs_out(:)
30  integer, intent(in) :: isize_in
31  integer, intent(in) :: jsize_in
32  integer, intent(in) :: ksize_in
33  integer, intent(in) :: isize_out
34  integer, intent(in) :: jsize_out
35  integer, intent(in) :: ksize_out
36 
37  integer(LONG_KIND) :: domain_id
38  integer :: m, list
39  integer :: is, ie, js, je, ke, ioff, joff, list_size
40  integer :: isc, iec, jsc, jec, mytile
42  integer, allocatable,dimension(:) :: isL, jsL
43  integer(LONG_KIND),allocatable,dimension(:,:) :: slist_addr
44  character(len=8) :: text
45 
46 
47  ! This test determines whether input fields are from allocated memory (LOC gets global
48  ! address) or "static" memory (need shmem_ptr). This probably needs to be generalized
49  ! to determine appropriate mechanism for each incoming address.
50 
51  ! "Concurrent" run mode may leave field_in or field_out unassociated if pe does not
52  ! contain in/out data. Use of STATIC option for ocean complicates this as ocean component
53  ! always defined. Field_out is always a boundary structure and so is always allocated or
54  ! not depending on whether it's used. If field out is defined (>0), then it is used otherwise
55  ! field in must be defined.
56 
57 !fix ke
58  ke = 0
59  if( domain_in%pe /= NULL_PE )ke = ksize_in
60  if( domain_out%pe /= NULL_PE )then
61  if( ke /= 0 .AND. ke /= ksize_out ) &
62  call mpp_error( FATAL, 'MPP_REDISTRIBUTE_INIT_COMM: mismatch between field_in and field_out.' )
63  ke = ksize_out
64  end if
65  if( ke == 0 )call mpp_error( FATAL, 'MPP_REDISTRIBUTE_INIT_COMM: either domain_in or domain_out must be native.' )
66 !check sizes
67  if( domain_in%pe /= NULL_PE )then
68  if( isize_in /= domain_in%x(1)%data%size .OR. jsize_in /= domain_in%y(1)%data%size ) &
69  call mpp_error( FATAL, 'MPP_REDISTRIBUTE_INIT_COMM: field_in must be on data domain of domain_in.' )
70  end if
71  if( domain_out%pe /= NULL_PE )then
72  if( isize_out /= domain_out%x(1)%data%size .OR. jsize_out /= domain_out%y(1)%data%size ) &
73  call mpp_error( FATAL, 'MPP_REDISTRIBUTE_INIT_COMM: field_out must be on data domain of domain_out.' )
74  end if
75 
76 
77  ! Create unique domain identifier
78  list_size = size(l_addrs_in(:))
79  if(l_addrs_out(1) > 0)then
80  domain_id = set_domain_id(domain_out%id,ke+list_size)
81  else
82  domain_id = set_domain_id(domain_in%id,ke+list_size)
83  endif
84 
85  d_comm =>get_comm(domain_id,l_addrs_in(1),l_addrs_out(1))
86 
87  if(d_comm%initialized)return ! Found existing field/domain communicator
88 
89  d_comm%l_addr = l_addrs_in(1)
90  d_comm%domain_in =>domain_in
91  d_comm%Slist_size = size(domain_out%list(:))
92  d_comm%isize_in = isize_in
93  d_comm%jsize_in = jsize_in
94  d_comm%ke = ke
95 
96 !send
97  lsize = d_comm%Slist_size-1
98  allocate(d_comm%sendis(1,0:lsize), d_comm%sendie(1,0:lsize), &
99  d_comm%sendjs(1,0:lsize), d_comm%sendje(1,0:lsize), &
100  d_comm%S_msize(0:lsize),isL(0:lsize),jsL(0:lsize))
101  allocate(slist_addr(list_size,0:lsize))
102  allocate(d_comm%cto_pe(0:lsize), d_comm%S_do_buf(0:lsize))
103 
104  isL=0;jsL=0
105  slist_addr = -9999
106  d_comm%cto_pe=-1
107  d_comm%sendis=0; d_comm%sendie=0
108  d_comm%sendjs=0; d_comm%sendje=0;
109  d_comm%S_msize=0
110  d_comm%S_do_buf=.false.
111 
112  ioff = domain_in%x(1)%data%begin
113  joff = domain_in%y(1)%data%begin
114  mytile = domain_in%tile_id(1)
115 
116  call mpp_get_compute_domain( domain_in, isc, iec, jsc, jec )
117  do list = 0,lsize
118  m = mod( domain_out%pos+list+lsize+1, lsize+1 )
119  if( mytile .NE. domain_out%list(m)%tile_id(1) ) cycle
120  d_comm%cto_pe(list) = domain_out%list(m)%pe
121  to_pe = d_comm%cto_pe(list)
122  is = domain_out%list(m)%x(1)%compute%begin
123  ie = domain_out%list(m)%x(1)%compute%end
124  js = domain_out%list(m)%y(1)%compute%begin
125  je = domain_out%list(m)%y(1)%compute%end
126  is = max(is,isc); ie = min(ie,iec)
127  js = max(js,jsc); je = min(je,jec)
128  if( ie >= is .AND. je >= js )then
129  d_comm%S_do_buf(list) = .true.
130  d_comm%sendis(1,list)=is; d_comm%sendie(1,list)=ie
131  d_comm%sendjs(1,list)=js; d_comm%sendje(1,list)=je
132  d_comm%S_msize(list) = (ie-is+1)*(je-js+1)*ke
133  isL(list) = is-ioff+1; jsL(list) = js-joff+1
134  end if
135  end do
136 
137  call mpp_sync_self()
138 !recv
139  d_comm%domain_out =>domain_out
140  d_comm%Rlist_size = size(domain_in%list(:))
141  d_comm%isize_out = isize_out
142  d_comm%jsize_out = jsize_out
143 
144  rsize = d_comm%Rlist_size-1
145  allocate(d_comm%recvis(1,0:rsize), d_comm%recvie(1,0:rsize), &
146  d_comm%recvjs(1,0:rsize), d_comm%recvje(1,0:rsize), &
147  d_comm%R_msize(0:rsize))
148  allocate(d_comm%cfrom_pe(0:rsize), d_comm%R_do_buf(0:rsize))
149  allocate(d_comm%isizeR(0:rsize), d_comm%jsizeR(0:rsize))
150  allocate(d_comm%sendisR(1,0:rsize), d_comm%sendjsR(1,0:rsize))
151  allocate(d_comm%rem_addrl(list_size,0:rsize))
152  d_comm%rem_addrl=-9999
153  d_comm%cfrom_pe=-1
154  d_comm%recvis=0; d_comm%recvie=0
155  d_comm%recvjs=0; d_comm%recvje=0;
156  d_comm%R_msize=0
157  d_comm%R_do_buf=.false.
158  d_comm%isizeR=0; d_comm%jsizeR=0
159  d_comm%sendisR=0; d_comm%sendjsR=0
160 
161  mytile = domain_out%tile_id(1)
162  call mpp_get_compute_domain( domain_out, isc, iec, jsc, jec )
163  do list = 0,rsize
164  m = mod( domain_in%pos+rsize+1-list, rsize+1 )
165  if( mytile .NE. domain_in%list(m)%tile_id(1) ) cycle
166  d_comm%cfrom_pe(list) = domain_in%list(m)%pe
167  from_pe = d_comm%cfrom_pe(list)
168  is = domain_in%list(m)%x(1)%compute%begin
169  ie = domain_in%list(m)%x(1)%compute%end
170  js = domain_in%list(m)%y(1)%compute%begin
171  je = domain_in%list(m)%y(1)%compute%end
172  is = max(is,isc); ie = min(ie,iec)
173  js = max(js,jsc); je = min(je,jec)
174  if( ie >= is .AND. je >= js )then
175  d_comm%R_do_buf(list) = .true.
176  d_comm%recvis(1,list)=is; d_comm%recvie(1,list)=ie
177  d_comm%recvjs(1,list)=js; d_comm%recvje(1,list)=je
178  d_comm%R_msize(list) = (ie-is+1)*(je-js+1)*ke
179  end if
180  end do
181 
182  d_comm%isize_max = isize_in; call mpp_max(d_comm%isize_max)
183  d_comm%jsize_max = jsize_in; call mpp_max(d_comm%jsize_max)
184 
185  ! Handles case where S_msize and/or R_msize are 0 size array
186  msgsize = ( MAXVAL( (/0,sum(d_comm%S_msize(:))/) ) + MAXVAL( (/0,sum(d_comm%R_msize(:))/) ) ) * list_size
187  if(msgsize>0)then
188  mpp_domains_stack_hwm = max( mpp_domains_stack_hwm, msgsize )
189  if( mpp_domains_stack_hwm.GT.mpp_domains_stack_size )then
190  write( text,'(i8)' )mpp_domains_stack_hwm
191  call mpp_error( FATAL, 'MPP_REDISTRIBUTE_INIT_COMM: mpp_domains_stack overflow, call mpp_domains_set_stack_size(' &
192  //trim(text)//') from all PEs.' )
193  end if
194  end if
195 
196  DEALLOCATE(slist_addr,isL,jsL)
197 
198  d_comm%initialized = .true.
199 
200  end function mpp_redistribute_init_comm
201 
202 
203  function mpp_global_field_init_comm(domain,l_addr,isize_g,jsize_g,isize_l, &
204  jsize_l, ksize,l_addr2,flags, position) RESULT(d_comm)
205  type(DomainCommunicator2D), pointer :: d_comm
206  type(domain2D),target, intent(in) :: domain
207  integer(LONG_KIND), intent(in) :: l_addr
208  integer, intent(in) :: isize_g
209  integer, intent(in) :: jsize_g
210  integer, intent(in) :: isize_l
211  integer, intent(in) :: jsize_l
212  integer, intent(in) :: ksize
213  integer(LONG_KIND),optional,intent(in) :: l_addr2
214  integer, optional, intent(in) :: flags
215  integer, optional, intent(in) :: position
216 
217  integer(LONG_KIND) :: domain_id
218  integer :: n, lpos, rpos, list, nlist, tile_id
219  integer :: update_flags
220  logical :: xonly, yonly
221  integer :: is, ie, js, je, ioff, joff, ishift, jshift
222  integer :: lsize,msgsize,from_pe
223  integer, allocatable,dimension(:) :: isL, jsL
224  integer(LONG_KIND),allocatable,dimension(:,:) :: slist_addr
225  integer(LONG_KIND),save ,dimension(2) :: rem_addr
226  character(len=8) :: text
227 
228  if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_GLOBAL_FIELD: must first call mpp_domains_init.' )
229  update_flags=XUPDATE+YUPDATE; xonly = .FALSE.; yonly = .FALSE.
230  if( PRESENT(flags) )then
231  update_flags = flags
232  xonly = BTEST(flags,EAST)
233  yonly = BTEST(flags,SOUTH)
234  if( .NOT.xonly .AND. .NOT.yonly )call mpp_error( WARNING, &
235  'MPP_GLOBAL_FIELD: you must have flags=XUPDATE, YUPDATE or XUPDATE+YUPDATE' )
236  if(xonly .AND. yonly) then
237  xonly = .false.; yonly = .false.
238  endif
239  end if
240 
241  call mpp_get_domain_shift(domain, ishift, jshift, position=position)
242 
243  if( isize_g /= (domain%x(1)%global%size+ishift) .OR. jsize_g /= (domain%y(1)%global%size+jshift) ) &
244  call mpp_error( FATAL, 'MPP_GLOBAL_FIELD_INIT_COMM: incoming arrays do not match domain.' )
245 
246  if( isize_l == (domain%x(1)%compute%size+ishift) .AND. jsize_l == (domain%y(1)%compute%size+jshift) )then
247 !local is on compute domain
248  ioff = -domain%x(1)%compute%begin + 1
249  joff = -domain%y(1)%compute%begin + 1
250  elseif( isize_l == (domain%x(1)%memory%size+ishift) .AND. jsize_l == (domain%y(1)%memory%size+jshift) )then
251 !local is on data domain
252  ioff = -domain%x(1)%data%begin + 1
253  joff = -domain%y(1)%data%begin + 1
254  else
255  call mpp_error(FATAL,'MPP_GLOBAL_FIELD_INIT_COMM: incoming field array must match either compute domain or data domain.')
256  endif
257 
258  ! Create unique domain identifier
259  domain_id=set_domain_id(domain%id,ksize,update_flags, position=position)
260  d_comm =>get_comm(domain_id,l_addr,l_addr2)
261 
262  if(d_comm%initialized)return ! Found existing field/domain communicator
263  d_comm%domain => domain
264  d_comm%isize_in = isize_l; d_comm%isize_out = isize_g
265  d_comm%jsize_in = jsize_l; d_comm%jsize_out = jsize_g
266  d_comm%ke = ksize
267  d_comm%gf_ioff=ioff; d_comm%gf_joff=joff
268 
269 !fill off-domains (note loops begin at an offset of 1)
270  if( xonly )then
271  lsize = size(domain%x(1)%list(:))
272 !send
273  allocate(d_comm%cto_pe(0:lsize-1))
274  d_comm%cto_pe=-1
275  do list = 0,lsize-1
276  lpos = mod(domain%x(1)%pos+lsize-list,lsize)
277  d_comm%cto_pe(list) = domain%x(1)%list(lpos)%pe
278  end do
279 !recv
280  allocate(d_comm%cfrom_pe(0:lsize-1))
281  allocate(d_comm%recvis(1,0:lsize-1), d_comm%recvie(1,0:lsize-1), &
282  d_comm%recvjs(1,0:lsize-1), d_comm%recvje(1,0:lsize-1), &
283  d_comm%R_msize(0:lsize-1))
284  d_comm%cfrom_pe=-1
285  d_comm%recvis=0; d_comm%recvie=0
286  d_comm%recvjs=0; d_comm%recvje=0;
287  d_comm%R_msize=0
288  do list = 0,lsize-1
289  rpos = mod(domain%x(1)%pos+list,lsize)
290  from_pe = domain%x(1)%list(rpos)%pe
291  d_comm%cfrom_pe(list) = from_pe
292  is = domain%list(from_pe)%x(1)%compute%begin; ie = domain%list(from_pe)%x(1)%compute%end+ishift
293  js = domain%y(1)%compute%begin; je = domain%y(1)%compute%end+jshift
294  d_comm%recvis(1,list)=is; d_comm%recvie(1,list)=ie
295  d_comm%recvjs(1,list)=js; d_comm%recvje(1,list)=je
296  d_comm%R_msize(list) = (ie-is+1) * (je-js+1) * ksize
297  end do
298 
299  elseif( yonly )then
300  lsize = size(domain%y(1)%list(:))
301 !send
302  allocate(d_comm%cto_pe(0:lsize-1))
303  d_comm%cto_pe=-1
304  do list = 0,lsize
305  lpos = mod(domain%y(1)%pos+lsize-list,lsize)
306  d_comm%cto_pe(list) = domain%y(1)%list(lpos)%pe
307  end do
308 !recv
309  allocate(d_comm%cfrom_pe(0:lsize-1))
310  allocate(d_comm%recvis(1,0:lsize-1), d_comm%recvie(1,0:lsize-1), &
311  d_comm%recvjs(1,0:lsize-1), d_comm%recvje(1,0:lsize-1), &
312  d_comm%R_msize(0:lsize-1))
313  d_comm%cfrom_pe=-1
314  d_comm%recvis=0; d_comm%recvie=0
315  d_comm%recvjs=0; d_comm%recvje=0;
316  d_comm%R_msize=0
317  do list = 0,lsize-1
318  rpos = mod(domain%y(1)%pos+list,lsize)
319  from_pe = domain%y(1)%list(rpos)%pe
320  d_comm%cfrom_pe(list) = from_pe
321  is = domain%x(1)%compute%begin; ie = domain%x(1)%compute%end+ishift
322  js = domain%list(from_pe)%y(1)%compute%begin; je = domain%list(from_pe)%y(1)%compute%end+jshift
323  d_comm%recvis(1,list)=is; d_comm%recvie(1,list)=ie
324  d_comm%recvjs(1,list)=js; d_comm%recvje(1,list)=je
325  d_comm%R_msize(list) = (ie-is+1) * (je-js+1) * ksize
326  end do
327 
328  else
329  nlist = size(domain%list(:))
330  tile_id = domain%tile_id(1)
331 
332  lsize = 0
333  do list = 0,nlist-1
334  if( domain%list(list)%tile_id(1) .NE. tile_id ) cycle
335  lsize = lsize+1
336  end do
337 
338  !send
339  allocate(d_comm%cto_pe(0:lsize-1))
340  d_comm%cto_pe=-1
341  n = 0
342  do list = 0,nlist-1
343  lpos = mod(domain%pos+nlist-list,nlist)
344  if( domain%list(lpos)%tile_id(1) .NE. tile_id ) cycle
345  d_comm%cto_pe(n) = domain%list(lpos)%pe
346  n = n + 1
347  end do
348  !recv
349  allocate(d_comm%cfrom_pe(0:lsize-1))
350  allocate(d_comm%recvis(1,0:lsize-1), d_comm%recvie(1,0:lsize-1), &
351  d_comm%recvjs(1,0:lsize-1), d_comm%recvje(1,0:lsize-1), &
352  d_comm%R_msize(0:lsize-1))
353  d_comm%cfrom_pe=-1
354  d_comm%recvis=0; d_comm%recvie=0
355  d_comm%recvjs=0; d_comm%recvje=0;
356  d_comm%R_msize=0
357  n = 0
358  do list = 0,nlist-1
359  rpos = mod(domain%pos+list,nlist)
360  if( domain%list(rpos)%tile_id(1) .NE. tile_id ) cycle
361  d_comm%cfrom_pe(n) = domain%list(rpos)%pe
362  is = domain%list(rpos)%x(1)%compute%begin; ie = domain%list(rpos)%x(1)%compute%end+ishift
363  js = domain%list(rpos)%y(1)%compute%begin; je = domain%list(rpos)%y(1)%compute%end+jshift
364  d_comm%recvis(1,n)=is; d_comm%recvie(1,n)=ie
365  d_comm%recvjs(1,n)=js; d_comm%recvje(1,n)=je
366  d_comm%R_msize(n) = (je-js+1) * (ie-is+1) * ksize
367  n = n+1
368  end do
369 
370  endif
371 
372  d_comm%Slist_size = lsize
373  d_comm%Rlist_size = lsize
374 
375 !send
376  allocate(d_comm%sendis(1,0:lsize-1), d_comm%sendie(1,0:lsize-1), &
377  d_comm%sendjs(1,0:lsize-1), d_comm%sendje(1,0:lsize-1), &
378  d_comm%S_msize(0:lsize-1),isL(0:lsize-1),jsL(0:lsize-1))
379  allocate(slist_addr(2,0:lsize-1))
380  isL=0; jsL=0
381  slist_addr = -9999
382  d_comm%sendis=0; d_comm%sendie=0
383  d_comm%sendjs=0; d_comm%sendje=0;
384  d_comm%S_msize=0
385  do list = 0,lsize-1
386  is=domain%x(1)%compute%begin; ie=domain%x(1)%compute%end+ishift
387  js=domain%y(1)%compute%begin; je=domain%y(1)%compute%end+jshift
388  d_comm%sendis(1,list)=is; d_comm%sendie(1,list)=ie
389  d_comm%sendjs(1,list)=js; d_comm%sendje(1,list)=je
390  d_comm%S_msize(list) = (je-js+1) * (ie-is+1) * ksize
391  isL(list) = ioff+domain%x(1)%compute%begin; jsL(list) = joff+domain%y(1)%compute%begin
392  end do
393 
394 !recv
395  allocate(d_comm%isizeR(0:lsize-1), d_comm%jsizeR(0:lsize-1))
396  allocate(d_comm%sendisR(1,0:lsize-1), d_comm%sendjsR(1,0:lsize-1))
397  if(.not.PRESENT(l_addr2))then
398  allocate(d_comm%rem_addr(0:lsize-1))
399  d_comm%rem_addr=-9999
400  else
401  allocate(d_comm%rem_addrx(0:lsize-1),d_comm%rem_addry(0:lsize-1))
402  d_comm%rem_addrx=-9999; d_comm%rem_addry=-9999
403  endif
404  d_comm%isizeR=0; d_comm%jsizeR=0
405  d_comm%sendisR=0; d_comm%sendjsR=0
406  rem_addr = -9999
407 
408  ! Handles case where S_msize and/or R_msize are 0 size array
409  msgsize = MAXVAL( (/0,sum(d_comm%S_msize(:))/) ) + MAXVAL( (/0,sum(d_comm%R_msize(:))/) )
410  if(msgsize>0)then
411  mpp_domains_stack_hwm = max( mpp_domains_stack_hwm, msgsize )
412  if( mpp_domains_stack_hwm.GT.mpp_domains_stack_size )then
413  write( text,'(i8)' )mpp_domains_stack_hwm
414  call mpp_error( FATAL, 'MPP_GLOBAL_FIELD_INIT_COMM: mpp_domains_stack overflow, call mpp_domains_set_stack_size(' &
415  //trim(text)//') from all PEs.' )
416  end if
417  end if
418 
419  DEALLOCATE(slist_addr,isL,jsL)
420 
421  d_comm%initialized = .true.
422 
423  end function mpp_global_field_init_comm
424 
425 
426  subroutine mpp_redistribute_free_comm(domain_in,l_addr,domain_out,l_addr2,ksize,lsize)
427  ! Since initialization of the d_comm type is expensive, freeing should be a rare
428  ! event. Thus no attempt is made to salvage freed d_comm's.
429  type(domain2D), intent(in) :: domain_in
430  integer(LONG_KIND), intent(in) :: l_addr
431  type(domain2D), intent(in) :: domain_out
432  integer(LONG_KIND), intent(in) :: l_addr2
433  integer, intent(in) :: ksize,lsize
434 
435  integer(LONG_KIND) :: domain_id
436 
437  if(l_addr2 > 0)then
438  domain_id = set_domain_id(domain_out%id,ksize+lsize)
439  else
440  domain_id = set_domain_id(domain_in%id,ksize+lsize)
441  endif
442  call free_comm(domain_id,l_addr,l_addr2)
443  end subroutine mpp_redistribute_free_comm
444 
445 
446  subroutine mpp_global_field_free_comm(domain,l_addr,ksize,l_addr2,flags)
447  ! Since initialization of the d_comm type is expensive, freeing should be a rare
448  ! event. Thus no attempt is made to salvage freed d_comm's.
449  type(domain2D), intent(in) :: domain
450  integer(LONG_KIND), intent(in) :: l_addr
451  integer, intent(in) :: ksize
452  integer(LONG_KIND),optional,intent(in) :: l_addr2
453  integer, optional,intent(in) :: flags
454 
455  integer :: update_flags
456  integer(LONG_KIND) :: domain_id
457 
458  update_flags=0; if(PRESENT(flags))update_flags=flags
459  domain_id=set_domain_id(domain%id,ksize,update_flags)
460  call free_comm(domain_id,l_addr,l_addr2)
461  end subroutine mpp_global_field_free_comm
462 
463 
464  subroutine free_comm(domain_id,l_addr,l_addr2)
465  ! Since initialization of the d_comm type is expensive, freeing should be a rare
466  ! event. Thus no attempt is made to salvage freed d_comm's.
467  integer(LONG_KIND), intent(in) :: domain_id
468  integer(LONG_KIND), intent(in) :: l_addr
469  integer(LONG_KIND),optional,intent(in) :: l_addr2
470 
471  integer(LONG_KIND) :: dc_key,a_key
472  integer :: dc_idx,a_idx,i_idx,insert,insert_a,insert_i
473  integer :: a2_idx,insert_a2
474 
475 
476  i_idx = find_key(domain_id,ids_sorted(1:n_ids),insert_i)
477  a_idx = find_key(l_addr,addrs_sorted(1:a_sort_len),insert_a)
478  a_key = int(addrs_idx(a_idx),KIND(LONG_KIND))
479  if(PRESENT(l_addr2))then
480  a2_idx = find_key(l_addr2,addrs2_sorted(1:a2_sort_len),insert_a2)
481  a_key = a_key + ADDR2_BASE*int(addrs2_idx(a2_idx),KIND(LONG_KIND))
482  endif
483  dc_key = DOMAIN_ID_BASE*int(ids_idx(i_idx),KIND(LONG_KIND)) + a_key
484  dc_idx = find_key(dc_key,dcKey_sorted(1:dc_sort_len),insert)
485 
486  if(dc_idx < 0)then
487  call mpp_error(FATAL,'FREE_COMM: attempt to remove nonexistent domains communicator key')
488  endif
489  call deallocate_comm(d_comm(dc_idx))
490  call pop_key(dcKey_sorted,d_comm_idx,dc_sort_len,dc_idx)
491  call pop_key(addrs_sorted,addrs_idx,a_sort_len,a_idx)
492  if(PRESENT(l_addr2))call pop_key(addrs2_sorted,addrs2_idx,a2_sort_len,a2_idx)
493  end subroutine free_comm
494 
495 
496  function get_comm(domain_id,l_addr,l_addr2)
497  integer(LONG_KIND),intent(in) :: domain_id
498  integer(LONG_KIND),intent(in) :: l_addr
499  integer(LONG_KIND),intent(in),optional :: l_addr2
500  type(DomainCommunicator2D), pointer :: get_comm
501 
502  integer(LONG_KIND) :: dc_key,a_key
503  integer :: i,dc_idx,a_idx,i_idx,insert,insert_a,insert_i
504  integer :: a2_idx,insert_a2
505 
506  if(.not.ALLOCATED(d_comm))ALLOCATE(d_comm(MAX_FIELDS))
507  i_idx = find_key(domain_id,ids_sorted(1:n_ids),insert_i)
508  a_idx = find_key(l_addr,addrs_sorted(1:a_sort_len),insert_a)
509  a_key = int(addrs_idx(a_idx),KIND(LONG_KIND))
510  if(PRESENT(l_addr2))then
511  a2_idx = find_key(l_addr2,addrs2_sorted(1:a2_sort_len),insert_a2)
512  a_key = a_key + ADDR2_BASE*int(addrs2_idx(a2_idx),KIND(LONG_KIND))
513  endif
514  dc_key = DOMAIN_ID_BASE*int(ids_idx(i_idx),KIND(LONG_KIND)) + a_key
515  dc_idx = find_key(dc_key,dcKey_sorted(1:dc_sort_len),insert)
516  if(dc_idx > 0)then
517  get_comm =>d_comm(d_comm_idx(dc_idx))
518  else
519  if(i_idx<0)then
520  if(n_ids == MAX_DOM_IDS)then
521  call mpp_error(FATAL,'GET_COMM: Maximum number of domains exceeded')
522  endif
523  n_ids = n_ids+1
524  i_idx = push_key(ids_sorted,ids_idx,i_sort_len,insert_i,domain_id,n_ids)
525  endif
526  if(a_idx<0)then
527  if(n_addrs == MAX_ADDRS)then
528  call mpp_error(FATAL,'GET_COMM: Maximum number of memory addresses exceeded')
529  endif
530  n_addrs = n_addrs + 1
531  a_idx = push_key(addrs_sorted,addrs_idx,a_sort_len,insert_a,l_addr,n_addrs)
532  endif
533  if(PRESENT(l_addr2))then
534  if(a2_idx<0)then
535  if(n_addrs2 == MAX_ADDRS2)then
536  call mpp_error(FATAL,'GET_COMM: Maximum number of 2nd memory addresses exceeded')
537  endif
538  n_addrs2 = n_addrs2 + 1
539  a2_idx = push_key(addrs2_sorted,addrs2_idx,a2_sort_len,insert_a2,l_addr2,n_addrs2)
540  endif
541  endif
542  if(n_comm == MAX_FIELDS)then
543  call mpp_error(FATAL,'GET_COMM: Maximum number of fields exceeded')
544  endif
545  a_key = int(addrs_idx(a_idx),KIND(8))
546  if(PRESENT(l_addr2))a_key = a_key + ADDR2_BASE*int(addrs2_idx(a2_idx),KIND(8))
547  dc_key = DOMAIN_ID_BASE*int(ids_idx(i_idx),KIND(LONG_KIND)) + a_key
548  dc_idx = find_key(dc_key,dcKey_sorted(1:dc_sort_len),insert)
549  if(dc_idx /= -1)call mpp_error(FATAL,'GET_COMM: attempt to insert existing key')
550  n_comm = n_comm + 1
551  i = push_key(dcKey_sorted,d_comm_idx,dc_sort_len,insert,dc_key,n_comm)
553  if(PRESENT(l_addr2))then
554  d_comm(n_comm)%l_addrx = l_addr
555  d_comm(n_comm)%l_addry = l_addr2
556  else
557  d_comm(n_comm)%l_addr = l_addr
558  endif
559  get_comm =>d_comm(n_comm)
560  endif
561  end function get_comm
562 
563 
564  function push_key(sorted,idx,n_idx,insert,key,ival)
565  integer(LONG_KIND),intent(inout),dimension(:) :: sorted
566  integer, intent(inout),dimension(-1:) :: idx ! Start -1 to simplify first call logic in get_comm
567  integer, intent(inout) :: n_idx
568  integer, intent(in) :: insert
569  integer(LONG_KIND),intent(in) :: key
570  integer, intent(in) :: ival
571 
572  integer :: push_key,i
573 
574  do i=n_idx,insert,-1
575  sorted(i+1) = sorted(i)
576  idx(i+1) = idx(i)
577  end do
578  sorted(insert) = key
579  n_idx = n_idx + 1
580  idx(insert) = ival
581  push_key = insert
582  end function push_key
583 
584 
585  subroutine pop_key(sorted,idx,n_idx,key_idx)
586  integer(LONG_KIND),intent(inout),dimension(:) :: sorted
587  integer, intent(inout),dimension(-1:) :: idx ! Start -1 to simplify first call logic in get_comm
588  integer, intent(inout) :: n_idx
589  integer, intent(in) :: key_idx
590 
591  integer :: i
592 
593  do i=key_idx,n_idx-1
594  sorted(i) = sorted(i+1)
595  idx(i) = idx(i+1)
596  end do
597  sorted(n_idx) = -9999
598  idx(n_idx) = -9999
599  n_idx = n_idx - 1
600  end subroutine pop_key
601 
602 
603  function find_key(key,sorted,insert) RESULT(n)
604  ! The algorithm used here requires monotonic keys w/out repetition.
605  integer(LONG_KIND),intent(in) :: key ! new address to be found in list
606  integer(LONG_KIND),dimension(:),intent(in) :: sorted ! list of sorted local addrs
607  integer, intent(out) :: insert
608  integer :: n, n_max, n_min, n_key
609  logical :: not_found
610 
611  n_key = size(sorted(:))
612  insert = 1
613  n = -1 ! value not in list
614  if(n_key == 0)return ! first call
615 
616  if(key < sorted(1))then
617  insert = 1; return
618  elseif(key > sorted(n_key))then
619  insert = n_key+1; return
620  endif
621 
622  if(key == sorted(1))then
623  n = 1; return
624  elseif(key == sorted(n_key))then
625  n = n_key; return
626  endif
627 
628  not_found = .true.
629  n = n_key/2 + 1
630  n_min=1; n_max=n_key
631  do while(not_found)
632  if(key == sorted(n))then
633  not_found = .false.
634  elseif(key > sorted(n))then
635  if(key < sorted(n+1))then
636  insert = n+1; exit
637  endif
638  n_min = n
639  n = (n+1+n_max)/2
640  else
641  if(key > sorted(n-1))then
642  insert = n; exit
643  endif
644  n_max = n
645  n = (n+n_min)/2
646  endif
647  if(n==1 .or. n==n_key)exit
648  end do
649  if(not_found)n = -1 ! value not in list
650  end function find_key
651 
652 
653  subroutine deallocate_comm(d_comm)
654  type(DomainCommunicator2D), intent(inout) :: d_comm
655 
656  d_comm%domain =>NULL()
657  d_comm%domain_in =>NULL()
659 
660  d_comm%initialized=.false.
661  d_comm%id=-9999
662  d_comm%l_addr =-9999
663  d_comm%l_addrx =-9999
664  d_comm%l_addry =-9999
665 
666  if( _ALLOCATED(d_comm%sendis) ) DEALLOCATE(d_comm%sendis); !!d_comm%sendis =>NULL()
667  if( _ALLOCATED(d_comm%sendie) ) DEALLOCATE(d_comm%sendie); !!d_comm%sendie =>NULL()
668  if( _ALLOCATED(d_comm%sendjs) ) DEALLOCATE(d_comm%sendjs); !!d_comm%sendjs =>NULL()
669  if( _ALLOCATED(d_comm%sendje) ) DEALLOCATE(d_comm%sendje); !!d_comm%sendje =>NULL()
670  if( _ALLOCATED(d_comm%S_msize) ) DEALLOCATE(d_comm%S_msize); !!d_comm%S_msize =>NULL()
671  if( _ALLOCATED(d_comm%S_do_buf) ) DEALLOCATE(d_comm%S_do_buf); !!d_comm%S_do_buf =>NULL()
672  if( _ALLOCATED(d_comm%cto_pe) ) DEALLOCATE(d_comm%cto_pe); !!d_comm%cto_pe =>NULL()
673  if( _ALLOCATED(d_comm%recvis) ) DEALLOCATE(d_comm%recvis); !!d_comm%recvis =>NULL()
674  if( _ALLOCATED(d_comm%recvie) ) DEALLOCATE(d_comm%recvie); !!d_comm%recvie =>NULL()
675  if( _ALLOCATED(d_comm%recvjs) ) DEALLOCATE(d_comm%recvjs); !!d_comm%recvjs =>NULL()
676  if( _ALLOCATED(d_comm%recvje) ) DEALLOCATE(d_comm%recvje); !!d_comm%recvje =>NULL()
677  if( _ALLOCATED(d_comm%R_msize) ) DEALLOCATE(d_comm%R_msize); !!d_comm%R_msize =>NULL()
678  if( _ALLOCATED(d_comm%R_do_buf) ) DEALLOCATE(d_comm%R_do_buf); !!d_comm%R_do_buf =>NULL()
679  if( _ALLOCATED(d_comm%cfrom_pe) ) DEALLOCATE(d_comm%cfrom_pe); !!d_comm%cfrom_pe =>NULL()
680  d_comm%Slist_size=0; d_comm%Rlist_size=0
681  d_comm%isize=0; d_comm%jsize=0; d_comm%ke=0
682  d_comm%isize_in=0; d_comm%jsize_in=0
683  d_comm%isize_out=0; d_comm%jsize_out=0
684  d_comm%isize_max=0; d_comm%jsize_max=0
685  d_comm%gf_ioff=0; d_comm%gf_joff=0
686  ! Remote data
687  if( _ALLOCATED(d_comm%isizeR) ) DEALLOCATE(d_comm%isizeR); !!dd_comm%isizeR =>NULL()
688  if( _ALLOCATED(d_comm%jsizeR) ) DEALLOCATE(d_comm%jsizeR); !!dd_comm%jsizeR =>NULL()
689  if( _ALLOCATED(d_comm%sendisR) ) DEALLOCATE(d_comm%sendisR); !!dd_comm%sendisR =>NULL()
690  if( _ALLOCATED(d_comm%sendjsR) ) DEALLOCATE(d_comm%sendjsR); !!dd_comm%sendjsR =>NULL()
691  if( _ALLOCATED(d_comm%rem_addr) ) DEALLOCATE(d_comm%rem_addr); !!dd_comm%rem_addr =>NULL()
692  if( _ALLOCATED(d_comm%rem_addrx) )DEALLOCATE(d_comm%rem_addrx); !!dd_comm%rem_addrx =>NULL()
693  if( _ALLOCATED(d_comm%rem_addry) )DEALLOCATE(d_comm%rem_addry); !!dd_comm%rem_addry =>NULL()
694  if( _ALLOCATED(d_comm%rem_addrl) )DEALLOCATE(d_comm%rem_addrl); !!dd_comm%rem_addrl =>NULL()
695  end subroutine deallocate_comm
696 
697 
698  function set_domain_id(d_id,ksize,flags,gtype, position, whalo, ehalo, shalo, nhalo)
699  integer(LONG_KIND), intent(in) :: d_id
700  integer , intent(in) :: ksize
701  integer , optional, intent(in) :: flags
702  integer , optional, intent(in) :: gtype
703  integer , optional, intent(in) :: position
704  integer , optional, intent(in) :: whalo, ehalo, shalo, nhalo
705 
706  integer(LONG_KIND) :: set_domain_id
707 
708  set_domain_id=d_id + KE_BASE*int(ksize,KIND(d_id))
709  if(PRESENT(flags))set_domain_id=set_domain_id+int(flags,KIND(d_id))
710  if(PRESENT(gtype))set_domain_id=set_domain_id+GT_BASE*int(gtype,KIND(d_id)) ! Must be LONG_KIND arithmetic
711  !--- gtype is never been used to set id. we need to add position to calculate id to seperate
712  !--- BGRID and CGRID or scalar variable.
713  if(present(position)) set_domain_id=set_domain_id+GT_BASE*int(2**position, KIND(d_id))
714  !z1l ???? the following calculation may need to be revised
715  if(present(whalo)) then
716  if(whalo>=0) then
717  set_domain_id=set_domain_id+GT_BASE*int(2**4*2**whalo, KIND(d_id))
718  else
719  set_domain_id=set_domain_id-GT_BASE*int(2**4*2**(-whalo), KIND(d_id))
720  endif
721  end if
722  if(present(ehalo)) then
723  if(ehalo>=0) then
724  set_domain_id=set_domain_id+GT_BASE*int(2**4*2**ehalo, KIND(d_id))
725  else
726  set_domain_id=set_domain_id-GT_BASE*int(2**4*2**(-ehalo), KIND(d_id))
727  endif
728  end if
729  if(present(shalo)) then
730  if(shalo>=0) then
731  set_domain_id=set_domain_id+GT_BASE*int(2**4*2**shalo, KIND(d_id))
732  else
733  set_domain_id=set_domain_id-GT_BASE*int(2**4*2**(-shalo), KIND(d_id))
734  endif
735  end if
736  if(present(nhalo)) then
737  if(nhalo>=0) then
738  set_domain_id=set_domain_id+GT_BASE*int(2**4*2**nhalo, KIND(d_id))
739  else
740  set_domain_id=set_domain_id-GT_BASE*int(2**4*2**(-nhalo), KIND(d_id))
741  endif
742  end if
743  end function set_domain_id
744 
745 
746 !#######################################################################
747 
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! MPP_TRANSMIT !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! subroutine MPP_TRANSMIT_(put_data, put_len, to_pe, get_data, get_len, from_pe, block, tag, recv_request, send_request)!a message-passing routine intended to be reminiscent equally of both MPI and SHMEM!put_data and get_data are contiguous MPP_TYPE_ arrays!at each call, your put_data array is put to to_pe 's get_data! your get_data array is got from from_pe 's put_data!i.e we assume that typically(e.g updating halo regions) each PE performs a put _and_ a get!special PE designations:! NULL_PE:to disable a put or a get(e.g at boundaries)! ANY_PE:if remote PE for the put or get is to be unspecific! ALL_PES:broadcast and collect operations(collect not yet implemented)!ideally we would not pass length, but this f77-style call performs better(arrays passed by address, not descriptor)!further, this permits< length > contiguous words from an array of any rank to be passed(avoiding f90 rank conformance check)!caller is responsible for completion checks(mpp_sync_self) before and after integer, intent(in) ::put_len, to_pe, get_len, from_pe MPP_TYPE_, intent(in) ::put_data(*) MPP_TYPE_, intent(out) ::get_data(*) logical, intent(in), optional ::block integer, intent(in), optional ::tag integer, intent(out), optional ::recv_request, send_request logical ::block_comm integer ::i MPP_TYPE_, allocatable, save ::local_data(:) !local copy used by non-parallel code(no SHMEM or MPI) integer ::comm_tag integer ::rsize if(.NOT.module_is_initialized) call mpp_error(FATAL, 'MPP_TRANSMIT:You must first call mpp_init.') if(to_pe.EQ.NULL_PE .AND. from_pe.EQ.NULL_PE) return block_comm=.true. if(PRESENT(block)) block_comm=block if(debug) then call SYSTEM_CLOCK(tick) write(stdout_unit,'(a, i18, a, i6, a, 2i6, 2i8)')&'T=', tick, ' PE=', pe, ' MPP_TRANSMIT begin:to_pe, from_pe, put_len, get_len=', to_pe, from_pe, put_len, get_len end if comm_tag=DEFAULT_TAG if(present(tag)) comm_tag=tag!do put first and then get if(to_pe.GE.0 .AND. to_pe.LT.npes) then!use non-blocking sends if(debug .and.(current_clock.NE.0)) call SYSTEM_CLOCK(start_tick)!z1l:truly non-blocking send.! if(request(to_pe).NE.MPI_REQUEST_NULL) then !only one message from pe-> to_pe in queue *PE waiting for to_pe ! call error else get_len so only do gets but you cannot have a pure get with MPI call a get means do a wait to ensure put on remote PE is complete error call increase mpp_nml request_multiply call MPP_TRANSMIT get_len end if return end subroutine MPP_TRANSMIT_ ! MPP_BROADCAST ! subroutine but that doesn t allow !broadcast to a subset of PEs This version will
type(ext_fieldtype), dimension(:), pointer, save, private field
*f90 *************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************subroutine MPP_UPDATE_NEST_FINE_2D_(field, nest_domain, wbuffer, ebuffer, sbuffer, nbuffer, &flags, complete, position, extra_halo, name, tile_count) MPP_TYPE_, intent(in) ::field(:,:) type(nest_domain_type), intent(inout) ::nest_domain MPP_TYPE_, intent(inout) ::wbuffer(:,:) MPP_TYPE_, intent(inout) ::ebuffer(:,:) MPP_TYPE_, intent(inout) ::sbuffer(:,:) MPP_TYPE_, intent(inout) ::nbuffer(:,:) integer, intent(in), optional ::flags logical, intent(in), optional ::complete integer, intent(in), optional ::position integer, intent(in), optional ::extra_halo character(len= *), intent(in), optional ::name integer, intent(in), optional ::tile_count MPP_TYPE_ ::field3D(size(field, 1), size(field, 2), 1) MPP_TYPE_ ::wbuffer3D(size(wbuffer, 1), size(wbuffer, 2), 1) MPP_TYPE_ ::ebuffer3D(size(ebuffer, 1), size(ebuffer, 2), 1) MPP_TYPE_ ::sbuffer3D(size(sbuffer, 1), size(sbuffer, 2), 1) MPP_TYPE_ ::nbuffer3D(size(nbuffer, 1), size(nbuffer, 2), 1) pointer(ptr, field3D) pointer(ptr_w, wbuffer3D) pointer(ptr_e, ebuffer3D) pointer(ptr_s, sbuffer3D) pointer(ptr_n, nbuffer3D) ptr=LOC(field) ptr_w=LOC(wbuffer) ptr_e=LOC(ebuffer) ptr_s=LOC(sbuffer) ptr_n=LOC(nbuffer) call mpp_update_nest_fine(field3D, nest_domain, wbuffer3D, ebuffer3D, sbuffer3D, nbuffer3D, &flags, complete, position, extra_halo, name, tile_count) returnend subroutine MPP_UPDATE_NEST_FINE_2D_subroutine MPP_UPDATE_NEST_FINE_3D_(field, nest_domain, wbuffer, sbuffer, ebuffer, nbuffer, &flags, complete, position, extra_halo, name, tile_count) MPP_TYPE_, intent(in) ::field(:,:,:) type(nest_domain_type), intent(inout) ::nest_domain MPP_TYPE_, intent(inout) ::wbuffer(:,:,:) MPP_TYPE_, intent(inout) ::ebuffer(:,:,:) MPP_TYPE_, intent(inout) ::sbuffer(:,:,:) MPP_TYPE_, intent(inout) ::nbuffer(:,:,:) integer, intent(in), optional ::flags logical, intent(in), optional ::complete integer, intent(in), optional ::position integer, intent(in), optional ::extra_halo character(len= *), intent(in), optional ::name integer, intent(in), optional ::tile_count MPP_TYPE_ ::d_type type(nestSpec), pointer ::update=> set_mismatch integer ::tile update_position nbuffersz l_size integer
l_size ! loop over number of fields ke do je do i
integer, private je
Definition: fms_io.F90:494
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! MPP_TRANSMIT !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! subroutine MPP_TRANSMIT_(put_data, put_len, to_pe, get_data, get_len, from_pe, block, tag, recv_request, send_request)!a message-passing routine intended to be reminiscent equally of both MPI and SHMEM!put_data and get_data are contiguous MPP_TYPE_ arrays!at each call, your put_data array is put to to_pe 's get_data! your get_data array is got from from_pe 's put_data!i.e we assume that typically(e.g updating halo regions) each PE performs a put _and_ a get!special PE designations:! NULL_PE:to disable a put or a get(e.g at boundaries)! ANY_PE:if remote PE for the put or get is to be unspecific! ALL_PES:broadcast and collect operations(collect not yet implemented)!ideally we would not pass length, but this f77-style call performs better(arrays passed by address, not descriptor)!further, this permits< length > contiguous words from an array of any rank to be passed(avoiding f90 rank conformance check)!caller is responsible for completion checks(mpp_sync_self) before and after integer, intent(in) ::put_len, to_pe, get_len, from_pe MPP_TYPE_, intent(in) ::put_data(*) MPP_TYPE_, intent(out) ::get_data(*) logical, intent(in), optional ::block integer, intent(in), optional ::tag integer, intent(out), optional ::recv_request, send_request logical ::block_comm integer ::i MPP_TYPE_, allocatable, save ::local_data(:) !local copy used by non-parallel code(no SHMEM or MPI) integer ::comm_tag integer ::rsize if(.NOT.module_is_initialized) call mpp_error(FATAL, 'MPP_TRANSMIT:You must first call mpp_init.') if(to_pe.EQ.NULL_PE .AND. from_pe.EQ.NULL_PE) return block_comm=.true. if(PRESENT(block)) block_comm=block if(debug) then call SYSTEM_CLOCK(tick) write(stdout_unit,'(a, i18, a, i6, a, 2i6, 2i8)')&'T=', tick, ' PE=', pe, ' MPP_TRANSMIT begin:to_pe, from_pe, put_len, get_len=', to_pe, from_pe, put_len, get_len end if comm_tag=DEFAULT_TAG if(present(tag)) comm_tag=tag!do put first and then get if(to_pe.GE.0 .AND. to_pe.LT.npes) then!use non-blocking sends if(debug .and.(current_clock.NE.0)) call SYSTEM_CLOCK(start_tick)!z1l:truly non-blocking send.! if(request(to_pe).NE.MPI_REQUEST_NULL) then !only one message from pe-> to_pe in queue *PE waiting for to_pe ! call error else get_len so only do gets but you cannot have a pure get with MPI call a get means do a wait to ensure put on remote PE is complete error call rsize
integer, save, private iec
Definition: oda_core.F90:124
integer, save n_comm
integer, parameter, public no
subroutine, public add(value, cumul, num, wgt)
Definition: tools_func.F90:185
*f90 *************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************subroutine MPP_UPDATE_NEST_FINE_2D_(field, nest_domain, wbuffer, ebuffer, sbuffer, nbuffer, &flags, complete, position, extra_halo, name, tile_count) MPP_TYPE_, intent(in) ::field(:,:) type(nest_domain_type), intent(inout) ::nest_domain MPP_TYPE_, intent(inout) ::wbuffer(:,:) MPP_TYPE_, intent(inout) ::ebuffer(:,:) MPP_TYPE_, intent(inout) ::sbuffer(:,:) MPP_TYPE_, intent(inout) ::nbuffer(:,:) integer, intent(in), optional ::flags logical, intent(in), optional ::complete integer, intent(in), optional ::position integer, intent(in), optional ::extra_halo character(len= *), intent(in), optional ::name integer, intent(in), optional ::tile_count MPP_TYPE_ ::field3D(size(field, 1), size(field, 2), 1) MPP_TYPE_ ::wbuffer3D(size(wbuffer, 1), size(wbuffer, 2), 1) MPP_TYPE_ ::ebuffer3D(size(ebuffer, 1), size(ebuffer, 2), 1) MPP_TYPE_ ::sbuffer3D(size(sbuffer, 1), size(sbuffer, 2), 1) MPP_TYPE_ ::nbuffer3D(size(nbuffer, 1), size(nbuffer, 2), 1) pointer(ptr, field3D) pointer(ptr_w, wbuffer3D) pointer(ptr_e, ebuffer3D) pointer(ptr_s, sbuffer3D) pointer(ptr_n, nbuffer3D) ptr=LOC(field) ptr_w=LOC(wbuffer) ptr_e=LOC(ebuffer) ptr_s=LOC(sbuffer) ptr_n=LOC(nbuffer) call mpp_update_nest_fine(field3D, nest_domain, wbuffer3D, ebuffer3D, sbuffer3D, nbuffer3D, &flags, complete, position, extra_halo, name, tile_count) returnend subroutine MPP_UPDATE_NEST_FINE_2D_subroutine MPP_UPDATE_NEST_FINE_3D_(field, nest_domain, wbuffer, sbuffer, ebuffer, nbuffer, &flags, complete, position, extra_halo, name, tile_count) MPP_TYPE_, intent(in) ::field(:,:,:) type(nest_domain_type), intent(inout) ::nest_domain MPP_TYPE_, intent(inout) ::wbuffer(:,:,:) MPP_TYPE_, intent(inout) ::ebuffer(:,:,:) MPP_TYPE_, intent(inout) ::sbuffer(:,:,:) MPP_TYPE_, intent(inout) ::nbuffer(:,:,:) integer, intent(in), optional ::flags logical, intent(in), optional ::complete integer, intent(in), optional ::position integer, intent(in), optional ::extra_halo character(len= *), intent(in), optional ::name integer, intent(in), optional ::tile_count MPP_TYPE_ ::d_type type(nestSpec), pointer ::update=> set_mismatch integer ::tile update_position nbuffersz ksize
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************subroutine MPP_WRITE_UNLIMITED_AXIS_1D_(unit, field, domain, data, nelems_io) integer, intent(in) ::unit type(fieldtype), intent(inout) ::field type(domain2D), intent(inout) ::domain MPP_TYPE_, intent(inout) ::data(:) integer, intent(in) ::nelems_io(:) ! number of compressed elements from each ! member of the io_domain. It MUST have the ! same order as the io_domain pelist. integer, allocatable ::pelist(:) integer ::i, j, nelems, npes type(domain2d), pointer ::io_domain=> allocatable
subroutine, public copy(self, rhs)
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! MPP_TRANSMIT !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! subroutine MPP_TRANSMIT_(put_data, put_len, to_pe, get_data, get_len, from_pe, block, tag, recv_request, send_request)!a message-passing routine intended to be reminiscent equally of both MPI and SHMEM!put_data and get_data are contiguous MPP_TYPE_ arrays!at each call, your put_data array is put to to_pe 's get_data! your get_data array is got from from_pe 's put_data!i.e we assume that typically(e.g updating halo regions) each PE performs a put _and_ a get!special PE designations:! NULL_PE:to disable a put or a get(e.g at boundaries)! ANY_PE:if remote PE for the put or get is to be unspecific! ALL_PES:broadcast and collect operations(collect not yet implemented)!ideally we would not pass length, but this f77-style call performs better(arrays passed by address, not descriptor)!further, this permits< length > contiguous words from an array of any rank to be passed(avoiding f90 rank conformance check)!caller is responsible for completion checks(mpp_sync_self) before and after integer, intent(in) ::put_len, to_pe, get_len, from_pe MPP_TYPE_, intent(in) ::put_data(*) MPP_TYPE_, intent(out) ::get_data(*) logical, intent(in), optional ::block integer, intent(in), optional ::tag integer, intent(out), optional ::recv_request, send_request logical ::block_comm integer ::i MPP_TYPE_, allocatable, save ::local_data(:) !local copy used by non-parallel code(no SHMEM or MPI) integer ::comm_tag integer ::rsize if(.NOT.module_is_initialized) call mpp_error(FATAL, 'MPP_TRANSMIT:You must first call mpp_init.') if(to_pe.EQ.NULL_PE .AND. from_pe.EQ.NULL_PE) return block_comm=.true. if(PRESENT(block)) block_comm=block if(debug) then call SYSTEM_CLOCK(tick) write(stdout_unit,'(a, i18, a, i6, a, 2i6, 2i8)')&'T=', tick, ' PE=', pe, ' MPP_TRANSMIT begin:to_pe, from_pe, put_len, get_len=', to_pe, from_pe, put_len, get_len end if comm_tag=DEFAULT_TAG if(present(tag)) comm_tag=tag!do put first and then get if(to_pe.GE.0 .AND. to_pe.LT.npes) then!use non-blocking sends if(debug .and.(current_clock.NE.0)) call SYSTEM_CLOCK(start_tick)!z1l:truly non-blocking send.! if(request(to_pe).NE.MPI_REQUEST_NULL) then !only one message from pe-> to_pe in queue *PE waiting for to_pe ! call error else get_len so only do gets but you cannot have a pure get with MPI call a get means do a wait to ensure put on remote PE is complete error call increase mpp_nml request_multiply call MPP_TRANSMIT end
integer, parameter set
character(len=256) text
Definition: mpp_io.F90:1051
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************subroutine MPP_DO_REDISTRIBUTE_3D_(f_in, f_out, d_comm, d_type) integer(LONG_KIND), intent(in) ::f_in(:), f_out(:) type(DomainCommunicator2D), intent(in) ::d_comm MPP_TYPE_, intent(in) ::d_type MPP_TYPE_ ::field_in(d_comm%domain_in%x(1)%data%begin:d_comm%domain_in%x(1)%data%end, &d_comm%domain_in%y(1)%data%begin:d_comm%domain_in%y(1)%data%end, d_comm%ke) pointer(ptr_field_in, field_in) MPP_TYPE_ ::field_out(d_comm%domain_out%x(1)%data%begin:d_comm%domain_out%x(1)%data%end, &d_comm%domain_out%y(1)%data%begin:d_comm%domain_out%y(1)%data%end, d_comm%ke) pointer(ptr_field_out, field_out) type(domain2D), pointer ::domain_in, domain_out integer ::i, j, k, l, n, l_size integer ::is, ie, js, je integer ::ke integer ::list, pos, msgsize integer ::to_pe, from_pe MPP_TYPE_ ::buffer(size(mpp_domains_stack(:))) pointer(ptr, buffer) integer ::buffer_pos, wordlen, errunit!fix ke errunit=stderr() l_size=size(f_out(:)) ! equal to size(f_in(:)) ke=d_comm%ke domain_in=> d_comm domain_in
type(field_mgr_type), dimension(max_fields), private fields
*f90 *************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************! this routine is used to retrieve scalar boundary data for symmetric domain. subroutine MPP_GET_BOUNDARY_2D_(field, domain, ebuffer, sbuffer, wbuffer, nbuffer, flags, &position, complete, tile_count) type(domain2D), intent(in) ::domain MPP_TYPE_, intent(in) ::field(:,:) MPP_TYPE_, intent(inout), optional ::ebuffer(:), sbuffer(:), wbuffer(:), nbuffer(:) integer, intent(in), optional ::flags, position, tile_count logical, intent(in), optional ::complete MPP_TYPE_ ::field3D(size(field, 1), size(field, 2), 1) MPP_TYPE_, allocatable, dimension(:,:) ::ebuffer2D, sbuffer2D, wbuffer2D, nbuffer2D integer ::xcount, ycount integer ::ntile logical ::need_ebuffer, need_sbuffer, need_wbuffer, need_nbuffer integer(LONG_KIND), dimension(MAX_DOMAIN_FIELDS, MAX_TILES), save ::f_addrs=-9999 integer(LONG_KIND), dimension(4, MAX_DOMAIN_FIELDS, MAX_TILES), save ::b_addrs=-9999 integer, save ::bsize(4)=0, isize=0, jsize=0, ksize=0, pos, list=0, l_size=0, upflags integer ::buffer_size(4) integer ::max_ntile, tile, update_position, ishift, jshift logical ::do_update, is_complete, set_mismatch character(len=3) ::text MPP_TYPE_ ::d_type type(overlapSpec), pointer ::bound=> NULL() ntile
integer(long), parameter false
from from_pe
l_size ! loop over number of fields ke do je do ie to je n if(.NOT. d_comm%R_do_buf(list)) cycle from_pe
l_size ! loop over number of fields ke do je do ie to to_pe
integer, parameter m
integer, dimension(-1:max_addrs), save addrs_idx
character(len=128) version
integer(long_kind), dimension(max_addrs2), save addrs2_sorted
l_size ! loop over number of fields ke do je do ie to is
type
Definition: c2f.py:15
integer, parameter, public global
integer(long_kind), dimension(max_addrs), save addrs_sorted
integer, dimension(-1:max_fields), save d_comm_idx
integer, save dc_sort_len
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************subroutine MPP_GLOBAL_FIELD_2D_(domain, local, global, flags, position, tile_count, default_data) type(domain2D), intent(in) ::domain MPP_TYPE_, intent(in) ::local(:,:) MPP_TYPE_, intent(out) ::global(:,:) integer, intent(in), optional ::flags integer, intent(in), optional ::position integer, intent(in), optional ::tile_count MPP_TYPE_, intent(in), optional ::default_data MPP_TYPE_ ::local3D(size(local, 1), size(local, 2), 1) MPP_TYPE_ ::global3D(size(global, 1), size(global, 2), 1) pointer(lptr, local3D) pointer(gptr, global3D) lptr=LOC(local) gptr=LOC(global) call mpp_global_field(domain, local3D, global3D, flags, position, tile_count, default_data) end subroutine MPP_GLOBAL_FIELD_2D_ subroutine MPP_GLOBAL_FIELD_3D_(domain, local, global, flags, position, tile_count, default_data)!get a global field from a local field!local field may be on compute OR data domain type(domain2D), intent(in) ::domain MPP_TYPE_, intent(in) ::local(:,:,:) MPP_TYPE_, intent(out) ::global(:,:,:) integer, intent(in), optional ::flags integer, intent(in), optional ::position integer, intent(in), optional ::tile_count MPP_TYPE_, intent(in), optional ::default_data integer ::ishift, jshift integer ::tile integer ::isize, jsize tile=1;if(PRESENT(tile_count)) tile=tile_count call mpp_get_domain_shift(domain, ishift, jshift, position) ! The alltoallw method requires that local and global be contiguous. ! We presume that `local` is contiguous if it matches the data domain;! `global` is presumed to always be contiguous. ! Ideally we would use the F2015 function IS_CONTIGUOUS() to validate ! contiguity, but it is not yet suppored in many compilers. ! Also worth noting that many of the nD-> conversion also assumes so there many be other issues here isize
integer, save a2_sort_len
integer, private ie
Definition: fms_io.F90:494
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! MPP_TRANSMIT !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! subroutine MPP_TRANSMIT_(put_data, put_len, to_pe, get_data, get_len, from_pe, block, tag, recv_request, send_request)!a message-passing routine intended to be reminiscent equally of both MPI and SHMEM!put_data and get_data are contiguous MPP_TYPE_ arrays!at each call, your put_data array is put to to_pe 's get_data! your get_data array is got from from_pe 's put_data!i.e we assume that typically(e.g updating halo regions) each PE performs a put _and_ a get!special PE designations:! NULL_PE:to disable a put or a get(e.g at boundaries)! ANY_PE:if remote PE for the put or get is to be unspecific! ALL_PES:broadcast and collect operations(collect not yet implemented)!ideally we would not pass length, but this f77-style call performs better(arrays passed by address, not descriptor)!further, this permits< length > contiguous words from an array of any rank to be passed(avoiding f90 rank conformance check)!caller is responsible for completion checks(mpp_sync_self) before and after integer, intent(in) ::put_len, to_pe, get_len, from_pe MPP_TYPE_, intent(in) ::put_data(*) MPP_TYPE_, intent(out) ::get_data(*) logical, intent(in), optional ::block integer, intent(in), optional ::tag integer, intent(out), optional ::recv_request, send_request logical ::block_comm integer ::i MPP_TYPE_, allocatable, save ::local_data(:) !local copy used by non-parallel code(no SHMEM or MPI) integer ::comm_tag integer ::rsize if(.NOT.module_is_initialized) call mpp_error(FATAL, 'MPP_TRANSMIT:You must first call mpp_init.') if(to_pe.EQ.NULL_PE .AND. from_pe.EQ.NULL_PE) return block_comm=.true. if(PRESENT(block)) block_comm=block if(debug) then call SYSTEM_CLOCK(tick) write(stdout_unit,'(a, i18, a, i6, a, 2i6, 2i8)')&'T=', tick, ' PE=', pe, ' MPP_TRANSMIT begin:to_pe, from_pe, put_len, get_len=', to_pe, from_pe, put_len, get_len end if comm_tag=DEFAULT_TAG if(present(tag)) comm_tag=tag!do put first and then get if(to_pe.GE.0 .AND. to_pe.LT.npes) then!use non-blocking sends if(debug .and.(current_clock.NE.0)) call SYSTEM_CLOCK(start_tick)!z1l:truly non-blocking send.! if(request(to_pe).NE.MPI_REQUEST_NULL) then !only one message from pe-> to_pe in queue *PE waiting for to_pe ! call error else get_len so only do gets but you cannot have a pure get with MPI call mpp_error(FATAL, 'MPP_TRANSMIT:you cannot transmit to ANY_PE using MPI.') else if(to_pe.NE.NULL_PE) then !no other valid cases except NULL_PE call mpp_error(FATAL
#define _ALLOCATED
integer, save a_sort_len
l_size ! loop over number of fields ke do je do ie to je msgsize
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************subroutine READ_RECORD_CORE_(unit, field, nwords, data, start, axsiz) integer, intent(in) ::unit type(fieldtype), intent(in) ::field integer, intent(in) ::nwords MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in) ::start(:), axsiz(:) integer(SHORT_KIND) ::i2vals(nwords)!rab used in conjunction with transfer intrinsic to determine size of a variable integer(KIND=1) ::one_byte(8) integer ::word_sz!#ifdef __sgi integer(INT_KIND) ::ivals(nwords) real(FLOAT_KIND) ::rvals(nwords)!#else! integer ::ivals(nwords)! real ::rvals(nwords)!#endif real(DOUBLE_KIND) ::r8vals(nwords) pointer(ptr1, i2vals) pointer(ptr2, ivals) pointer(ptr3, rvals) pointer(ptr4, r8vals) if(mpp_io_stack_size< nwords) call mpp_io_set_stack_size(nwords) call mpp_error(FATAL, 'MPP_READ currently requires use_netCDF option') end subroutine READ_RECORD_CORE_ subroutine READ_RECORD_(unit, field, nwords, data, time_level, domain, position, tile_count, start_in, axsiz_in)!routine that is finally called by all mpp_read routines to perform the read!a non-netCDF record contains:! field ID! a set of 4 coordinates(is:ie, js:je) giving the data subdomain! a timelevel and a timestamp(=NULLTIME if field is static)! 3D real data(stored as 1D)!if you are using direct access I/O, the RECL argument to OPEN must be large enough for the above!in a global direct access file, record position on PE is given by %record.!Treatment of timestamp:! We assume that static fields have been passed without a timestamp.! Here that is converted into a timestamp of NULLTIME.! For non-netCDF fields, field is treated no differently, but is written! with a timestamp of NULLTIME. There is no check in the code to prevent! the user from repeatedly writing a static field. integer, intent(in) ::unit, nwords type(fieldtype), intent(in) ::field MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in), optional ::time_level type(domain2D), intent(in), optional ::domain integer, intent(in), optional ::position, tile_count integer, intent(in), optional ::start_in(:), axsiz_in(:) integer, dimension(size(field%axes(:))) ::start, axsiz integer ::tlevel !, subdomain(4) integer ::i, error, is, ie, js, je, isg, ieg, jsg, jeg type(domain2d), pointer ::io_domain=> id
integer, save i_sort_len
logical function received(this, seqno)
integer, save n_ids
integer, save, private isc
Definition: oda_core.F90:124
#define LONG_KIND
integer, save n_addrs
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************subroutine READ_RECORD_CORE_(unit, field, nwords, data, start, axsiz) integer, intent(in) ::unit type(fieldtype), intent(in) ::field integer, intent(in) ::nwords MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in) ::start(:), axsiz(:) integer(SHORT_KIND) ::i2vals(nwords)!rab used in conjunction with transfer intrinsic to determine size of a variable integer(KIND=1) ::one_byte(8) integer ::word_sz!#ifdef __sgi integer(INT_KIND) ::ivals(nwords) real(FLOAT_KIND) ::rvals(nwords)!#else! integer ::ivals(nwords)! real ::rvals(nwords)!#endif real(DOUBLE_KIND) ::r8vals(nwords) pointer(ptr1, i2vals) pointer(ptr2, ivals) pointer(ptr3, rvals) pointer(ptr4, r8vals) if(mpp_io_stack_size< nwords) call mpp_io_set_stack_size(nwords) call mpp_error(FATAL, 'MPP_READ currently requires use_netCDF option') end subroutine READ_RECORD_CORE_ subroutine READ_RECORD_(unit, field, nwords, data, time_level, domain, position, tile_count, start_in, axsiz_in)!routine that is finally called by all mpp_read routines to perform the read!a non-netCDF record contains:! field ID! a set of 4 coordinates(is:ie, js:je) giving the data subdomain! a timelevel and a timestamp(=NULLTIME if field is static)! 3D real data(stored as 1D)!if you are using direct access I/O, the RECL argument to OPEN must be large enough for the above!in a global direct access file, record position on PE is given by %record.!Treatment of timestamp:! We assume that static fields have been passed without a timestamp.! Here that is converted into a timestamp of NULLTIME.! For non-netCDF fields, field is treated no differently, but is written! with a timestamp of NULLTIME. There is no check in the code to prevent! the user from repeatedly writing a static field. integer, intent(in) ::unit, nwords type(fieldtype), intent(in) ::field MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in), optional ::time_level type(domain2D), intent(in), optional ::domain integer, intent(in), optional ::position, tile_count integer, intent(in), optional ::start_in(:), axsiz_in(:) integer, dimension(size(field%axes(:))) ::start, axsiz integer ::tlevel !, subdomain(4) integer ::i, error, is, ie, js, je, isg, ieg, jsg, jeg type(domain2d), pointer ::io_domain=> tlevel if(PRESENT(start_in) .AND. PRESENT(axsiz_in)) then if(size(start(! the data domain and compute domain must refer to the subdomain being passed ! In this ! since that attempts to gather all data on PE size(field%axes(:)) axsiz(i)
integer, save, private jsc
Definition: oda_core.F90:124
integer, save n_addrs2
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! MPP_TRANSMIT !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! subroutine MPP_TRANSMIT_(put_data, put_len, to_pe, get_data, get_len, from_pe, block, tag, recv_request, send_request)!a message-passing routine intended to be reminiscent equally of both MPI and SHMEM!put_data and get_data are contiguous MPP_TYPE_ arrays!at each call, your put_data array is put to to_pe 's get_data! your get_data array is got from from_pe 's put_data!i.e we assume that typically(e.g updating halo regions) each PE performs a put _and_ a get!special PE designations:! NULL_PE:to disable a put or a get(e.g at boundaries)! ANY_PE:if remote PE for the put or get is to be unspecific! ALL_PES:broadcast and collect operations(collect not yet implemented)!ideally we would not pass length, but this f77-style call performs better(arrays passed by address, not descriptor)!further, this permits< length > contiguous words from an array of any rank to be passed(avoiding f90 rank conformance check)!caller is responsible for completion checks(mpp_sync_self) before and after integer, intent(in) ::put_len, to_pe, get_len, from_pe MPP_TYPE_, intent(in) ::put_data(*) MPP_TYPE_, intent(out) ::get_data(*) logical, intent(in), optional ::block integer, intent(in), optional ::tag integer, intent(out), optional ::recv_request, send_request logical ::block_comm integer ::i MPP_TYPE_, allocatable, save ::local_data(:) !local copy used by non-parallel code(no SHMEM or MPI) integer ::comm_tag integer ::rsize if(.NOT.module_is_initialized) call mpp_error(FATAL, 'MPP_TRANSMIT:You must first call mpp_init.') if(to_pe.EQ.NULL_PE .AND. from_pe.EQ.NULL_PE) return block_comm=.true. if(PRESENT(block)) block_comm=block if(debug) then call SYSTEM_CLOCK(tick) write(stdout_unit,'(a, i18, a, i6, a, 2i6, 2i8)')&'T=', tick, ' PE=', pe, ' MPP_TRANSMIT begin:to_pe, from_pe, put_len, get_len=', to_pe, from_pe, put_len, get_len end if comm_tag=DEFAULT_TAG if(present(tag)) comm_tag=tag!do put first and then get if(to_pe.GE.0 .AND. to_pe.LT.npes) then!use non-blocking sends if(debug .and.(current_clock.NE.0)) call SYSTEM_CLOCK(start_tick)!z1l:truly non-blocking send.! if(request(to_pe).NE.MPI_REQUEST_NULL) then !only one message from pe-> to_pe in queue *PE waiting for to_pe ! call error else get_len so only do gets but you cannot have a pure get with MPI call a get means do a wait to ensure put on remote PE is complete error call increase mpp_nml request_multiply call MPP_TRANSMIT get_len end if return end subroutine MPP_TRANSMIT_ ! MPP_BROADCAST ! subroutine but that doesn t allow !broadcast to a subset of PEs This version and mpp_transmit will remain !backward compatible intent(inout) a
*f90 *************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************subroutine MPP_UPDATE_NEST_FINE_2D_(field, nest_domain, wbuffer, ebuffer, sbuffer, nbuffer, &flags, complete, position, extra_halo, name, tile_count) MPP_TYPE_, intent(in) ::field(:,:) type(nest_domain_type), intent(inout) ::nest_domain MPP_TYPE_, intent(inout) ::wbuffer(:,:) MPP_TYPE_, intent(inout) ::ebuffer(:,:) MPP_TYPE_, intent(inout) ::sbuffer(:,:) MPP_TYPE_, intent(inout) ::nbuffer(:,:) integer, intent(in), optional ::flags logical, intent(in), optional ::complete integer, intent(in), optional ::position integer, intent(in), optional ::extra_halo character(len= *), intent(in), optional ::name integer, intent(in), optional ::tile_count MPP_TYPE_ ::field3D(size(field, 1), size(field, 2), 1) MPP_TYPE_ ::wbuffer3D(size(wbuffer, 1), size(wbuffer, 2), 1) MPP_TYPE_ ::ebuffer3D(size(ebuffer, 1), size(ebuffer, 2), 1) MPP_TYPE_ ::sbuffer3D(size(sbuffer, 1), size(sbuffer, 2), 1) MPP_TYPE_ ::nbuffer3D(size(nbuffer, 1), size(nbuffer, 2), 1) pointer(ptr, field3D) pointer(ptr_w, wbuffer3D) pointer(ptr_e, ebuffer3D) pointer(ptr_s, sbuffer3D) pointer(ptr_n, nbuffer3D) ptr=LOC(field) ptr_w=LOC(wbuffer) ptr_e=LOC(ebuffer) ptr_s=LOC(sbuffer) ptr_n=LOC(nbuffer) call mpp_update_nest_fine(field3D, nest_domain, wbuffer3D, ebuffer3D, sbuffer3D, nbuffer3D, &flags, complete, position, extra_halo, name, tile_count) returnend subroutine MPP_UPDATE_NEST_FINE_2D_subroutine MPP_UPDATE_NEST_FINE_3D_(field, nest_domain, wbuffer, sbuffer, ebuffer, nbuffer, &flags, complete, position, extra_halo, name, tile_count) MPP_TYPE_, intent(in) ::field(:,:,:) type(nest_domain_type), intent(inout) ::nest_domain MPP_TYPE_, intent(inout) ::wbuffer(:,:,:) MPP_TYPE_, intent(inout) ::ebuffer(:,:,:) MPP_TYPE_, intent(inout) ::sbuffer(:,:,:) MPP_TYPE_, intent(inout) ::nbuffer(:,:,:) integer, intent(in), optional ::flags logical, intent(in), optional ::complete integer, intent(in), optional ::position integer, intent(in), optional ::extra_halo character(len= *), intent(in), optional ::name integer, intent(in), optional ::tile_count MPP_TYPE_ ::d_type type(nestSpec), pointer ::update=> dimension(MAX_DOMAIN_FIELDS)
type(domaincommunicator2d), dimension(:), allocatable, target, save d_comm
*f90 *************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If not
integer, save, private jec
Definition: oda_core.F90:124
*f90 *************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************subroutine MPP_UPDATE_NEST_FINE_2D_(field, nest_domain, wbuffer, ebuffer, sbuffer, nbuffer, &flags, complete, position, extra_halo, name, tile_count) MPP_TYPE_, intent(in) ::field(:,:) type(nest_domain_type), intent(inout) ::nest_domain MPP_TYPE_, intent(inout) ::wbuffer(:,:) MPP_TYPE_, intent(inout) ::ebuffer(:,:) MPP_TYPE_, intent(inout) ::sbuffer(:,:) MPP_TYPE_, intent(inout) ::nbuffer(:,:) integer, intent(in), optional ::flags logical, intent(in), optional ::complete integer, intent(in), optional ::position integer, intent(in), optional ::extra_halo character(len= *), intent(in), optional ::name integer, intent(in), optional ::tile_count MPP_TYPE_ ::field3D(size(field, 1), size(field, 2), 1) MPP_TYPE_ ::wbuffer3D(size(wbuffer, 1), size(wbuffer, 2), 1) MPP_TYPE_ ::ebuffer3D(size(ebuffer, 1), size(ebuffer, 2), 1) MPP_TYPE_ ::sbuffer3D(size(sbuffer, 1), size(sbuffer, 2), 1) MPP_TYPE_ ::nbuffer3D(size(nbuffer, 1), size(nbuffer, 2), 1) pointer(ptr, field3D) pointer(ptr_w, wbuffer3D) pointer(ptr_e, ebuffer3D) pointer(ptr_s, sbuffer3D) pointer(ptr_n, nbuffer3D) ptr=LOC(field) ptr_w=LOC(wbuffer) ptr_e=LOC(ebuffer) ptr_s=LOC(sbuffer) ptr_n=LOC(nbuffer) call mpp_update_nest_fine(field3D, nest_domain, wbuffer3D, ebuffer3D, sbuffer3D, nbuffer3D, &flags, complete, position, extra_halo, name, tile_count) returnend subroutine MPP_UPDATE_NEST_FINE_2D_subroutine MPP_UPDATE_NEST_FINE_3D_(field, nest_domain, wbuffer, sbuffer, ebuffer, nbuffer, &flags, complete, position, extra_halo, name, tile_count) MPP_TYPE_, intent(in) ::field(:,:,:) type(nest_domain_type), intent(inout) ::nest_domain MPP_TYPE_, intent(inout) ::wbuffer(:,:,:) MPP_TYPE_, intent(inout) ::ebuffer(:,:,:) MPP_TYPE_, intent(inout) ::sbuffer(:,:,:) MPP_TYPE_, intent(inout) ::nbuffer(:,:,:) integer, intent(in), optional ::flags logical, intent(in), optional ::complete integer, intent(in), optional ::position integer, intent(in), optional ::extra_halo character(len= *), intent(in), optional ::name integer, intent(in), optional ::tile_count MPP_TYPE_ ::d_type type(nestSpec), pointer ::update=> set_mismatch integer ::tile update_position nbuffersz jsize
integer, dimension(-1:max_addrs2), save addrs2_idx
integer(long_kind), dimension(max_dom_ids), save ids_sorted
subroutine insert(k, lp, list, lptr, lnew)
l_size ! loop over number of fields ke do je do ie to js
integer, dimension(-1:max_dom_ids), save ids_idx