4 !***********************************************************************
5 !* GNU Lesser General Public License
7 !* This file
is part of the GFDL Flexible Modeling System (FMS).
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.
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
19 !* You should have
received a copy of the GNU Lesser General Public
20 !* License along with FMS. If
not, see <http:
21 !***********************************************************************
24 isize_in,jsize_in,ksize_in,isize_out,jsize_out,ksize_out) RESULT(
d_comm)
33 integer, intent(in) :: isize_out
34 integer, intent(in) :: jsize_out
35 integer, intent(in) :: ksize_out
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.
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. 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.
' ) 65 if( ke == 0 )call mpp_error( FATAL, 'MPP_REDISTRIBUTE_INIT_COMM: either
domain_in or
domain_out must be native.
' ) 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.
' ) 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.
' ) 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) 82 domain_id = set_domain_id(domain_in%id,ke+list_size) 85 d_comm =>get_comm(domain_id,l_addrs_in(1),l_addrs_out(1)) 87 if(d_comm%initialized)return ! Found existing field/domain communicator 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 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)) 107 d_comm%sendis=0; d_comm%sendie=0 108 d_comm%sendjs=0; d_comm%sendje=0; 110 d_comm%S_do_buf=.false. 112 ioff = domain_in%x(1)%data%begin 113 joff = domain_in%y(1)%data%begin 114 mytile = domain_in%tile_id(1) 116 call mpp_get_compute_domain( domain_in, isc, iec, jsc, jec ) 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 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 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 154 d_comm%recvis=0; d_comm%recvie=0 155 d_comm%recvjs=0; d_comm%recvje=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 161 mytile = domain_out%tile_id(1) 162 call mpp_get_compute_domain( domain_out, isc, iec, jsc, jec ) 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 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) 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 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.
' ) 196 DEALLOCATE(slist_addr,isL,jsL) 198 d_comm%initialized = .true. 200 end function mpp_redistribute_init_comm 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 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 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 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. 241 call mpp_get_domain_shift(domain, ishift, jshift, position=position) 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.
' ) 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 255 call mpp_error(FATAL,'MPP_GLOBAL_FIELD_INIT_COMM: incoming
field array must match either compute domain or data domain.
') 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) 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 267 d_comm%gf_ioff=ioff; d_comm%gf_joff=joff 269 !fill off-domains (note loops begin at an offset of 1) 271 lsize = size(domain%x(1)%list(:)) 273 allocate(d_comm%cto_pe(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 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)) 285 d_comm%recvis=0; d_comm%recvie=0 286 d_comm%recvjs=0; d_comm%recvje=0; 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 300 lsize = size(domain%y(1)%list(:)) 302 allocate(d_comm%cto_pe(0:lsize-1)) 305 lpos = mod(domain%y(1)%pos+lsize-list,lsize) 306 d_comm%cto_pe(list) = domain%y(1)%list(lpos)%pe 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)) 314 d_comm%recvis=0; d_comm%recvie=0 315 d_comm%recvjs=0; d_comm%recvje=0; 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 329 nlist = size(domain%list(:)) 330 tile_id = domain%tile_id(1) 334 if( domain%list(list)%tile_id(1) .NE. tile_id ) cycle 339 allocate(d_comm%cto_pe(0:lsize-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 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)) 354 d_comm%recvis=0; d_comm%recvie=0 355 d_comm%recvjs=0; d_comm%recvje=0; 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 372 d_comm%Slist_size = lsize 373 d_comm%Rlist_size = lsize 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)) 382 d_comm%sendis=0; d_comm%sendie=0 383 d_comm%sendjs=0; d_comm%sendje=0; 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 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 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 404 d_comm%isizeR=0; d_comm%jsizeR=0 405 d_comm%sendisR=0; d_comm%sendjsR=0 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(:))/) ) 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.
' ) 419 DEALLOCATE(slist_addr,isL,jsL) 421 d_comm%initialized = .true. 423 end function mpp_global_field_init_comm 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.
442 call free_comm(domain_id,l_addr,l_addr2)
443 end subroutine mpp_redistribute_free_comm
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 455 integer :: update_flags 456 integer(LONG_KIND) :: domain_id 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 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.
479 if(PRESENT(l_addr2))then
487 call
mpp_error(FATAL,
'FREE_COMM: attempt to remove nonexistent domains communicator key')
489 call deallocate_comm(
d_comm(dc_idx))
493 end subroutine free_comm
496 function get_comm(domain_id,l_addr,l_addr2)
500 type(DomainCommunicator2D), pointer :: get_comm
510 if(PRESENT(l_addr2))then
521 call
mpp_error(FATAL,
'GET_COMM: Maximum number of domains exceeded')
528 call
mpp_error(FATAL,
'GET_COMM: Maximum number of memory addresses exceeded')
533 if(PRESENT(l_addr2))then
536 call
mpp_error(FATAL,
'GET_COMM: Maximum number of 2nd memory addresses exceeded')
543 call
mpp_error(FATAL,
'GET_COMM: Maximum number of fields exceeded')
546 if(PRESENT(l_addr2))a_key = a_key + ADDR2_BASE*int(
addrs2_idx(a2_idx),KIND(8))
549 if(dc_idx /= -1)call
mpp_error(FATAL,
'GET_COMM: attempt to insert existing key')
553 if(PRESENT(l_addr2))then
561 end function get_comm
564 function push_key(sorted,idx,n_idx,
insert,key,ival)
566 integer, intent(inout),
dimension(-1:) :: idx ! Start -1 to simplify first call logic in get_comm
567 integer, intent(inout) :: n_idx
575 sorted(
i+1) = sorted(
i)
582 end function push_key
585 subroutine pop_key(sorted,idx,n_idx,key_idx)
587 integer, intent(inout),
dimension(-1:) :: idx ! Start -1 to simplify first call logic in get_comm
588 integer, intent(inout) :: n_idx
594 sorted(
i) = sorted(
i+1)
597 sorted(n_idx) = -9999
600 end subroutine pop_key
603 function find_key(key,sorted,
insert) RESULT(
n)
604 ! The algorithm used here requires monotonic keys w/
out repetition.
611 n_key =
size(sorted(:))
613 n = -1 ! value
not in list
614 if(n_key == 0)return ! first call
616 if(key < sorted(1))then
618 elseif(key > sorted(n_key))then
622 if(key == sorted(1))then
624 elseif(key == sorted(n_key))then
632 if(key == sorted(
n))then
634 elseif(key > sorted(
n))then
635 if(key < sorted(
n+1))then
641 if(key > sorted(
n-1))then
647 if(
n==1 .or.
n==n_key)exit
649 if(not_found)
n = -1 ! value
not in list
650 end function find_key
653 subroutine deallocate_comm(
d_comm)
654 type(DomainCommunicator2D), intent(inout) ::
d_comm 695 end subroutine deallocate_comm
698 function set_domain_id(d_id,
ksize,flags,gtype, position, whalo, ehalo, shalo, nhalo)
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
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
717 set_domain_id=set_domain_id+GT_BASE*
int(2**4*2**whalo, KIND(d_id))
719 set_domain_id=set_domain_id-GT_BASE*
int(2**4*2**(-whalo), KIND(d_id))
722 if(present(ehalo)) then
724 set_domain_id=set_domain_id+GT_BASE*
int(2**4*2**ehalo, KIND(d_id))
726 set_domain_id=set_domain_id-GT_BASE*
int(2**4*2**(-ehalo), KIND(d_id))
729 if(present(shalo)) then
731 set_domain_id=set_domain_id+GT_BASE*
int(2**4*2**shalo, KIND(d_id))
733 set_domain_id=set_domain_id-GT_BASE*
int(2**4*2**(-shalo), KIND(d_id))
736 if(present(nhalo)) then
738 set_domain_id=set_domain_id+GT_BASE*
int(2**4*2**nhalo, KIND(d_id))
740 set_domain_id=set_domain_id-GT_BASE*
int(2**4*2**(-nhalo), KIND(d_id))
743 end function set_domain_id
746 !
####################################################################### ************************************************************************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
************************************************************************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
integer, parameter, public no
*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
************************************************************************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
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, 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
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
************************************************************************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
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
logical function received(this, seqno)
integer, save, private isc
************************************************************************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
************************************************************************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
*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
l_size ! loop over number of fields ke do je do ie to js
integer, dimension(-1:max_dom_ids), save ids_idx