18 #include "fms_switches.h"
24 module drifters_comm_mod
29 #define _TYPE_DOMAIN2D integer
35 use mpp_mod,
only : mpp_root_pe
37 use mpp_mod,
only : comm_tag_1, comm_tag_2, comm_tag_3, comm_tag_4
41 use mpp_domains_mod,
only : north, south, east, west, cyclic_global_domain
42 use mpp_domains_mod,
only : north_east, south_east, south_west, north_west
44 #define _TYPE_DOMAIN2D type(domain2d)
45 #define _NULL_PE NULL_PE
49 use drifters_core_mod,
only: drifters_core_type, drifters_core_remove_and_add, drifters_core_set_positions
54 public :: drifters_comm_type, drifters_comm_new, drifters_comm_del, drifters_comm_set_pe_neighbors
55 public :: drifters_comm_set_domain, drifters_comm_update, drifters_comm_gather
59 type :: drifters_comm_type
84 end type drifters_comm_type
92 subroutine drifters_comm_new(self)
93 type(drifters_comm_type) :: self
95 self%xcmin = -huge(1.); self%xcmax = +huge(1.)
96 self%ycmin = -huge(1.); self%ycmax = +huge(1.)
98 self%xdmin = -huge(1.); self%xdmax = +huge(1.)
99 self%ydmin = -huge(1.); self%ydmax = +huge(1.)
101 self%xgmin = -huge(1.); self%xgmax = +huge(1.)
102 self%ygmin = -huge(1.); self%ygmax = +huge(1.)
104 self%xperiodic = .false.; self%yperiodic = .false.
110 self%pe_NE = _null_pe
111 self%pe_SE = _null_pe
112 self%pe_SW = _null_pe
113 self%pe_NW = _null_pe
119 end subroutine drifters_comm_new
123 subroutine drifters_comm_del(self)
124 type(drifters_comm_type) :: self
127 call drifters_comm_new(self)
129 end subroutine drifters_comm_del
133 subroutine drifters_comm_set_data_bounds(self, xmin, ymin, xmax, ymax)
135 type(drifters_comm_type) :: self
136 real,
intent(in) :: xmin, ymin, xmax, ymax
138 self%xdmin = max(xmin, self%xdmin)
139 self%xdmax = min(xmax, self%xdmax)
140 self%ydmin = max(ymin, self%ydmin)
141 self%ydmax = min(ymax, self%ydmax)
143 end subroutine drifters_comm_set_data_bounds
147 subroutine drifters_comm_set_comp_bounds(self, xmin, ymin, xmax, ymax)
149 type(drifters_comm_type) :: self
150 real,
intent(in) :: xmin, ymin, xmax, ymax
152 self%xcmin = max(xmin, self%xcmin)
153 self%xcmax = min(xmax, self%xcmax)
154 self%ycmin = max(ymin, self%ycmin)
155 self%ycmax = min(ymax, self%ycmax)
157 end subroutine drifters_comm_set_comp_bounds
161 subroutine drifters_comm_set_pe_neighbors(self, domain)
163 type(drifters_comm_type) :: self
164 _type_domain2d,
intent(inout) :: domain
169 integer :: pe_N, pe_S, pe_E, pe_W, pe_NE, pe_SE, pe_SW, pe_NW
180 if(pe_n /= self%pe_N .and. self%pe_N == _null_pe)
then
182 else if(pe_n /= self%pe_N )
then
183 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: NORTH PE changed!.')
185 if(pe_ne /= self%pe_NE .and. self%pe_NE == _null_pe)
then
187 else if(pe_ne /= self%pe_NE)
then
188 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: NORTH-EAST PE changed!.')
190 if(pe_e /= self%pe_E .and. self%pe_E == _null_pe)
then
192 else if(pe_e /= self%pe_E )
then
193 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: EAST PE changed!.')
195 if(pe_se /= self%pe_SE .and. self%pe_SE == _null_pe)
then
197 else if(pe_se /= self%pe_SE)
then
198 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: SOUTH-EAST PE changed!.')
200 if(pe_s /= self%pe_S .and. self%pe_S == _null_pe)
then
202 else if(pe_s /= self%pe_S )
then
203 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: SOUTH PE changed!.')
205 if(pe_sw /= self%pe_SW .and. self%pe_SW == _null_pe)
then
207 else if(pe_sw /= self%pe_SW)
then
208 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: SOUTH-WEST PE changed!.')
210 if(pe_w /= self%pe_W .and. self%pe_W == _null_pe)
then
212 else if(pe_w /= self%pe_W )
then
213 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: WEST PE changed!.')
215 if(pe_nw /= self%pe_NW .and. self%pe_NW == _null_pe)
then
217 else if(pe_nw /= self%pe_NW)
then
218 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: NORTH-WEST PE changed!.')
224 end subroutine drifters_comm_set_pe_neighbors
230 subroutine drifters_comm_set_domain(self, domain, x, y, backoff_x, backoff_y)
234 type(drifters_comm_type) :: self
235 _type_domain2d,
intent(inout) :: domain
236 real,
intent(in) :: x(:)
237 real,
intent(in) :: y(:)
238 integer,
intent(in) :: backoff_x
239 integer,
intent(in) :: backoff_y
250 integer nx, ny, hx, hy, bckf_x, bckf_y, halox, haloy
251 real dx, dy, xdmin, xdmax, ydmin, ydmax
256 ibnds = lbound(x); isc = ibnds(1)
257 ibnds = ubound(x); iec = ibnds(1) - 1
258 ibnds = lbound(y); jsc = ibnds(1)
259 ibnds = ubound(y); jec = ibnds(1) - 1
264 self%xcmin = max(x(isc), self%xcmin)
265 self%xcmax = min(x(iec), self%xcmax)
266 self%ycmin = max(y(jsc), self%ycmin)
267 self%ycmax = min(y(jec), self%ycmax)
273 isd = 1; ied =
size(x); jsd = 1; jed =
size(y)
278 hx = max(ied-iec, isc-isd)
279 hy = max(jed-jec, jsc-jsd)
280 bckf_x = min(backoff_x, hx)
281 bckf_y = min(backoff_y, hy)
283 halox = max(0, hx - bckf_x)
284 haloy = max(0, hy - bckf_y)
288 xdmin = self%xcmin - dx*halox
290 xdmin = x(isd+bckf_x)
295 xdmax = self%xcmax + dx*halox
297 xdmax = x(ied-bckf_x)
302 ydmin = self%ycmin - dy*haloy
304 ydmin = y(jsd+bckf_y)
309 ydmax = self%ycmax + dy*haloy
311 ydmax = y(jed-bckf_y)
314 self%xdmin = max(xdmin, self%xdmin)
315 self%ydmin = max(ydmin, self%ydmin)
316 self%xdmax = min(xdmax, self%xdmax)
317 self%ydmax = min(ydmax, self%ydmax)
319 call drifters_comm_set_pe_neighbors(self, domain)
321 end subroutine drifters_comm_set_domain
325 subroutine drifters_comm_update(self, drfts, new_positions, &
326 & comm, remove, max_add_remove)
331 type(drifters_comm_type) :: self
332 type(drifters_core_type) :: drfts
333 real,
intent(inout) :: new_positions(:,:)
334 integer,
intent(in),
optional :: comm
335 logical,
intent(in),
optional :: remove(:)
336 integer,
intent(in),
optional :: max_add_remove
341 drfts%positions(:, 1:drfts%np) = new_positions(:, 1:drfts%np)
346 integer nd, np, nar_est, ip, neigh_pe, irem, pe, npes, ntuples
347 integer ntuples_tot, ndata, mycomm
351 integer,
allocatable :: iadd(:)
352 integer,
allocatable :: table_recv(:), table_send(:)
353 real ,
allocatable :: data_recv(:,:), data_send(:,:)
354 integer,
allocatable :: indices_to_remove(:)
355 integer,
allocatable :: ids_to_add(:)
356 real ,
allocatable :: positions_to_add(:,:)
357 real :: x, y, xold, yold
358 character(len=128) :: ermsg, notemsg
359 logical :: is_present
360 integer :: id, j, k, m, n, el
361 logical :: crossed_W, crossed_E, crossed_S, crossed_N
362 logical :: was_in_compute_domain, left_domain
364 mycomm = mpi_comm_world
365 if(
present(comm) ) mycomm = comm
368 np =
size(new_positions,2)
369 if(np > 0 .and. nd < 2)
call mpp_error( fatal, &
370 &
'drifters_comm_update: number of dimensions must be 2 or higher.' )
373 if(
present(max_add_remove)) nar_est = max(1, max_add_remove)
379 allocate(iadd(self%pe_beg:self%pe_end))
380 allocate(table_recv(self%pe_beg:self%pe_end))
381 allocate(table_send(self%pe_beg:self%pe_end))
382 allocate(data_recv(nar_est*(1+nd), self%pe_beg:self%pe_end))
383 allocate(data_send(nar_est*(1+nd), self%pe_beg:self%pe_end))
384 allocate(indices_to_remove(nar_est))
394 x = new_positions(1, ip)
395 y = new_positions(2, ip)
396 xold = drfts%positions(1, ip)
397 yold = drfts%positions(2, ip)
399 if( xold<self%xcmin .or. xold>self%xcmax .or. &
400 & yold<self%ycmin .or. yold>self%ycmax )
then
401 was_in_compute_domain = .false.
403 was_in_compute_domain = .true.
412 if( was_in_compute_domain .and. &
413 & (x<self%xcmin) .and. (xold>self%xcmin) ) crossed_w = .true.
414 if( was_in_compute_domain .and. &
415 & (x>self%xcmax) .and. (xold<self%xcmax) ) crossed_e = .true.
416 if( was_in_compute_domain .and. &
417 & (y<self%ycmin) .and. (yold>self%ycmin) ) crossed_s = .true.
418 if( was_in_compute_domain .and. &
419 & (y>self%ycmax) .and. (yold<self%ycmax) ) crossed_n = .true.
422 if(crossed_n .and. .not. crossed_e .and. .not. crossed_w) neigh_pe = self%pe_N
423 if(crossed_n .and. crossed_e ) neigh_pe = self%pe_NE
424 if(crossed_e .and. .not. crossed_n .and. .not. crossed_s) neigh_pe = self%pe_E
425 if(crossed_s .and. crossed_e ) neigh_pe = self%pe_SE
426 if(crossed_s .and. .not. crossed_e .and. .not. crossed_w) neigh_pe = self%pe_S
427 if(crossed_s .and. crossed_w ) neigh_pe = self%pe_SW
428 if(crossed_w .and. .not. crossed_s .and. .not. crossed_n) neigh_pe = self%pe_W
429 if(crossed_n .and. crossed_w ) neigh_pe = self%pe_NW
431 if(neigh_pe /= _null_pe)
then
432 iadd(neigh_pe) = iadd(neigh_pe) + 1
433 if(iadd(neigh_pe) > nar_est)
then
434 write(notemsg,
'(a,i4,a,i4,a)')
'drifters_comm_update: exceeded nar_est (', &
435 & iadd(neigh_pe),
'>',nar_est,
').'
438 table_send(neigh_pe) = table_send(neigh_pe) + 1
439 k = ( iadd(neigh_pe)-1 )*(1+nd) + 1
440 data_send(k , neigh_pe) = drfts%ids(ip)
441 data_send(k+1:k+nd, neigh_pe) = new_positions(:,ip)
446 left_domain = .false.
447 if( (x<self%xdmin .and. (self%pe_W/=pe)) .or. &
448 & (x>self%xdmax .and. (self%pe_E/=pe)) .or. &
449 & (y<self%ydmin .and. (self%pe_S/=pe)) .or. &
450 & (y>self%ydmax .and. (self%pe_N/=pe)) )
then
456 if(
present(remove))
then
457 if(remove(ip)) left_domain = .true.
462 if(irem > nar_est)
then
463 write(notemsg,
'(a,i4,a,i4,a)')
'drifters_comm_update: exceeded nar_est (',&
464 & irem,
'>',nar_est,
').'
467 indices_to_remove(irem) = ip
474 call drifters_core_set_positions(drfts, new_positions, ermsg)
475 if(ermsg/=
'')
call mpp_error( fatal, ermsg)
489 do m = self%pe_beg, self%pe_end
491 call mpi_scatter (table_send , 1, mpi_integer, &
492 & table_recv(m), 1, mpi_integer, &
496 do k = self%pe_beg, self%pe_end
497 call mpp_send(table_send(k), plen=1, to_pe=k, tag=comm_tag_1)
500 call mpp_recv(table_recv(m), glen=1, from_pe=m, tag=comm_tag_1)
507 do m = self%pe_beg, self%pe_end
508 ntuples = table_send(m)
509 ndata = ntuples*(nd+1)
512 call mpi_scatter (data_send , nar_est*(1+nd), mpi_real8, &
513 & data_recv(1,m), nar_est*(1+nd), mpi_real8, &
517 do k = self%pe_beg, self%pe_end
518 call mpp_send(data_send(1,k), plen=nar_est*(1+nd), to_pe=k, tag=comm_tag_2)
521 call mpp_recv(data_recv(1,m), glen=nar_est*(1+nd), from_pe=m, tag=comm_tag_2)
527 do m = self%pe_beg, self%pe_end
528 ntuples_tot = ntuples_tot + table_recv(m)
531 allocate(positions_to_add(nd, ntuples_tot))
532 allocate( ids_to_add( ntuples_tot))
536 do m = self%pe_beg, self%pe_end
538 do n = 1, table_recv(m)
540 el = (n-1)*(nd+1) + 1
541 id = int(data_recv(el, m))
547 if(id == drfts%ids(j))
then
549 write(notemsg,
'(a,i4,a)')
'Drifter ', id,
' already advected (will not be added).'
554 if(.not. is_present)
then
558 positions_to_add(1:nd, k) = data_recv(el+1:el+nd, m)
565 if(irem > 0 .or. k > 0)
then
566 write(notemsg,
'(i4,a,i4,a)') irem,
' drifter(s) will be removed, ', k,
' will be added'
571 call drifters_core_remove_and_add(drfts, indices_to_remove(1:irem), &
572 & ids_to_add(1:k), positions_to_add(:,1:k), ermsg)
573 if(ermsg/=
'')
call mpp_error( fatal, ermsg)
580 deallocate(ids_to_add)
581 deallocate(positions_to_add)
584 deallocate(table_recv)
585 deallocate(table_send)
586 deallocate(data_recv)
587 deallocate(data_send)
588 deallocate(indices_to_remove)
593 end subroutine drifters_comm_update
596 subroutine drifters_comm_gather(self, drfts, dinp, &
597 & lons, lats, do_save_lonlat, &
604 use drifters_input_mod,
only : drifters_input_type, drifters_input_save
606 type(drifters_comm_type) :: self
607 type(drifters_core_type) :: drfts
608 type(drifters_input_type) :: dinp
609 real,
intent(in) :: lons(:), lats(:)
610 logical,
intent(in) :: do_save_lonlat
611 character(len=*),
intent(in) :: filename
612 integer,
intent(in),
optional :: root
613 integer,
intent(in),
optional :: mycomm
615 character(len=128) :: ermesg
620 dinp%ids(1:drfts%np) = drfts%ids(1:drfts%np)
621 dinp%positions(:, 1:drfts%np) = drfts%positions(:, 1:drfts%np)
623 if(do_save_lonlat)
then
625 call drifters_input_save(dinp, filename=filename, &
626 & geolon=lons, geolat=lats, ermesg=ermesg)
630 call drifters_input_save(dinp, filename=filename, ermesg=ermesg)
638 integer :: npf, ip, comm, root_pe, pe, npes, nd, np, npdim, npmax, ier, nptot
639 integer :: i, j, k, kk
640 integer,
allocatable :: nps(:)
642 real,
allocatable :: lons0(:), lats0(:), recvbuf(:,:)
643 real :: com_data(drfts%nd+3, drfts%np)
645 comm = mpi_comm_world
646 if(
present(mycomm)) comm = mycomm
648 root_pe = mpp_root_pe()
649 if(
present(root)) root_pe = root
658 allocate(nps(self%pe_beg:self%pe_end))
665 x = drfts%positions(1, ip)
666 y = drfts%positions(2, ip)
667 if( x <= self%xcmax .and. x >= self%xcmin .and. &
668 & y <= self%ycmax .and. y >= self%ycmin)
then
670 com_data(1 , npf) = real(drfts%ids(ip))
671 com_data(1+1:1+nd, npf) = drfts%positions(:, ip)
672 com_data( 2+nd, npf) = lons(ip)
673 com_data( 3+nd, npf) = lats(ip)
679 call mpi_gather(npf, 1, mpi_int, &
681 & root_pe, comm, ier)
684 call mpp_send(npf, plen=1, to_pe=root_pe, tag=comm_tag_3)
686 do i = self%pe_beg, self%pe_end
687 call mpp_recv(nps(i), glen=1, from_pe=i, tag=comm_tag_3)
697 allocate(recvbuf(npmax*(nd+3), self%pe_beg:self%pe_end))
702 call mpi_gather( com_data , npf*(nd+3), mpi_real8, &
703 & recvbuf, npmax*(nd+3), mpi_real8, &
704 & root_pe, comm, ier)
707 if(npf > 0)
call mpp_send(com_data(1,1), plen=npf*(nd+3), to_pe=root_pe, tag=comm_tag_4)
709 do i = self%pe_beg, self%pe_end
710 if(nps(i) > 0)
call mpp_recv(recvbuf(1, i), glen=nps(i)*(nd+3), from_pe=i, tag=comm_tag_4)
716 if(pe == root_pe)
then
719 if(nptot /=
size(dinp%ids))
then
720 deallocate(dinp%ids , stat=ier)
721 deallocate(dinp%positions, stat=ier)
722 allocate(dinp%ids(nptot))
723 allocate(dinp%positions(nd, nptot))
725 dinp%positions = -huge(1.)
728 allocate(lons0(nptot), lats0(nptot))
735 do i = self%pe_beg, self%pe_end
738 dinp%ids(j) = int(recvbuf(kk+1 , i))
739 dinp%positions(1:nd, j) = recvbuf(kk+1+1:kk+1+nd, i)
740 lons0(j) = recvbuf(kk+2+nd, i)
741 lats0(j) = recvbuf(kk+3+nd, i)
746 if(do_save_lonlat)
then
748 call drifters_input_save(dinp, filename=filename, &
749 & geolon=lons0, geolat=lats0, ermesg=ermesg)
753 call drifters_input_save(dinp, filename=filename, ermesg=ermesg)
757 deallocate(lons0, lats0)
764 deallocate(nps , stat=ier)
765 deallocate(recvbuf, stat=ier)
770 end subroutine drifters_comm_gather
773 end module drifters_comm_mod
Set up a domain decomposition.
These routines retrieve the axis specifications associated with the compute domains....
These routines retrieve the axis specifications associated with the data domains. The domain is a der...
Retrieve layout associated with a domain decomposition The 1D version of this call returns the number...
Retrieve PE number of a neighboring domain.
The domain2D type contains all the necessary information to define the global, compute and data domai...
subroutine mpp_sync_self(pelist, check, request, msg_size, msg_type)
This is to check if current PE's outstanding puts are complete but we can't use shmem_fence because w...
integer function mpp_npes()
Returns processor count for current pelist.
integer function mpp_pe()
Returns processor ID.
Receive data from another PE.
Send data to a receiving PE.