19 #include "fms_switches.h"
25 module drifters_comm_mod
30 #define _TYPE_DOMAIN2D integer
36 use mpp_mod,
only : mpp_root_pe
38 use mpp_mod,
only : comm_tag_1, comm_tag_2, comm_tag_3, comm_tag_4
42 use mpp_domains_mod,
only : north, south, east, west, cyclic_global_domain
43 use mpp_domains_mod,
only : north_east, south_east, south_west, north_west
45 #define _TYPE_DOMAIN2D type(domain2d)
46 #define _NULL_PE NULL_PE
50 use drifters_core_mod,
only: drifters_core_type, drifters_core_remove_and_add, drifters_core_set_positions
55 public :: drifters_comm_type, drifters_comm_new, drifters_comm_del, drifters_comm_set_pe_neighbors
56 public :: drifters_comm_set_domain, drifters_comm_update, drifters_comm_gather
60 type :: drifters_comm_type
85 end type drifters_comm_type
93 subroutine drifters_comm_new(self)
94 type(drifters_comm_type) :: self
96 self%xcmin = -huge(1.); self%xcmax = +huge(1.)
97 self%ycmin = -huge(1.); self%ycmax = +huge(1.)
99 self%xdmin = -huge(1.); self%xdmax = +huge(1.)
100 self%ydmin = -huge(1.); self%ydmax = +huge(1.)
102 self%xgmin = -huge(1.); self%xgmax = +huge(1.)
103 self%ygmin = -huge(1.); self%ygmax = +huge(1.)
105 self%xperiodic = .false.; self%yperiodic = .false.
111 self%pe_NE = _null_pe
112 self%pe_SE = _null_pe
113 self%pe_SW = _null_pe
114 self%pe_NW = _null_pe
120 end subroutine drifters_comm_new
124 subroutine drifters_comm_del(self)
125 type(drifters_comm_type) :: self
128 call drifters_comm_new(self)
130 end subroutine drifters_comm_del
134 subroutine drifters_comm_set_data_bounds(self, xmin, ymin, xmax, ymax)
136 type(drifters_comm_type) :: self
137 real,
intent(in) :: xmin, ymin, xmax, ymax
139 self%xdmin = max(xmin, self%xdmin)
140 self%xdmax = min(xmax, self%xdmax)
141 self%ydmin = max(ymin, self%ydmin)
142 self%ydmax = min(ymax, self%ydmax)
144 end subroutine drifters_comm_set_data_bounds
148 subroutine drifters_comm_set_comp_bounds(self, xmin, ymin, xmax, ymax)
150 type(drifters_comm_type) :: self
151 real,
intent(in) :: xmin, ymin, xmax, ymax
153 self%xcmin = max(xmin, self%xcmin)
154 self%xcmax = min(xmax, self%xcmax)
155 self%ycmin = max(ymin, self%ycmin)
156 self%ycmax = min(ymax, self%ycmax)
158 end subroutine drifters_comm_set_comp_bounds
162 subroutine drifters_comm_set_pe_neighbors(self, domain)
164 type(drifters_comm_type) :: self
165 _type_domain2d,
intent(inout) :: domain
170 integer :: pe_N, pe_S, pe_E, pe_W, pe_NE, pe_SE, pe_SW, pe_NW
181 if(pe_n /= self%pe_N .and. self%pe_N == _null_pe)
then
183 else if(pe_n /= self%pe_N )
then
184 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: NORTH PE changed!.')
186 if(pe_ne /= self%pe_NE .and. self%pe_NE == _null_pe)
then
188 else if(pe_ne /= self%pe_NE)
then
189 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: NORTH-EAST PE changed!.')
191 if(pe_e /= self%pe_E .and. self%pe_E == _null_pe)
then
193 else if(pe_e /= self%pe_E )
then
194 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: EAST PE changed!.')
196 if(pe_se /= self%pe_SE .and. self%pe_SE == _null_pe)
then
198 else if(pe_se /= self%pe_SE)
then
199 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: SOUTH-EAST PE changed!.')
201 if(pe_s /= self%pe_S .and. self%pe_S == _null_pe)
then
203 else if(pe_s /= self%pe_S )
then
204 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: SOUTH PE changed!.')
206 if(pe_sw /= self%pe_SW .and. self%pe_SW == _null_pe)
then
208 else if(pe_sw /= self%pe_SW)
then
209 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: SOUTH-WEST PE changed!.')
211 if(pe_w /= self%pe_W .and. self%pe_W == _null_pe)
then
213 else if(pe_w /= self%pe_W )
then
214 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: WEST PE changed!.')
216 if(pe_nw /= self%pe_NW .and. self%pe_NW == _null_pe)
then
218 else if(pe_nw /= self%pe_NW)
then
219 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: NORTH-WEST PE changed!.')
225 end subroutine drifters_comm_set_pe_neighbors
231 subroutine drifters_comm_set_domain(self, domain, x, y, backoff_x, backoff_y)
235 type(drifters_comm_type) :: self
236 _type_domain2d,
intent(inout) :: domain
237 real,
intent(in) :: x(:)
238 real,
intent(in) :: y(:)
239 integer,
intent(in) :: backoff_x
240 integer,
intent(in) :: backoff_y
251 integer nx, ny, hx, hy, bckf_x, bckf_y, halox, haloy
252 real dx, dy, xdmin, xdmax, ydmin, ydmax
257 ibnds = lbound(x); isc = ibnds(1)
258 ibnds = ubound(x); iec = ibnds(1) - 1
259 ibnds = lbound(y); jsc = ibnds(1)
260 ibnds = ubound(y); jec = ibnds(1) - 1
265 self%xcmin = max(x(isc), self%xcmin)
266 self%xcmax = min(x(iec), self%xcmax)
267 self%ycmin = max(y(jsc), self%ycmin)
268 self%ycmax = min(y(jec), self%ycmax)
274 isd = 1; ied =
size(x); jsd = 1; jed =
size(y)
279 hx = max(ied-iec, isc-isd)
280 hy = max(jed-jec, jsc-jsd)
281 bckf_x = min(backoff_x, hx)
282 bckf_y = min(backoff_y, hy)
284 halox = max(0, hx - bckf_x)
285 haloy = max(0, hy - bckf_y)
289 xdmin = self%xcmin - dx*halox
291 xdmin = x(isd+bckf_x)
296 xdmax = self%xcmax + dx*halox
298 xdmax = x(ied-bckf_x)
303 ydmin = self%ycmin - dy*haloy
305 ydmin = y(jsd+bckf_y)
310 ydmax = self%ycmax + dy*haloy
312 ydmax = y(jed-bckf_y)
315 self%xdmin = max(xdmin, self%xdmin)
316 self%ydmin = max(ydmin, self%ydmin)
317 self%xdmax = min(xdmax, self%xdmax)
318 self%ydmax = min(ydmax, self%ydmax)
320 call drifters_comm_set_pe_neighbors(self, domain)
322 end subroutine drifters_comm_set_domain
326 subroutine drifters_comm_update(self, drfts, new_positions, &
327 & comm, remove, max_add_remove)
332 type(drifters_comm_type) :: self
333 type(drifters_core_type) :: drfts
334 real,
intent(inout) :: new_positions(:,:)
335 integer,
intent(in),
optional :: comm
336 logical,
intent(in),
optional :: remove(:)
337 integer,
intent(in),
optional :: max_add_remove
342 drfts%positions(:, 1:drfts%np) = new_positions(:, 1:drfts%np)
347 integer nd, np, nar_est, ip, neigh_pe, irem, pe, npes, ntuples
348 integer ntuples_tot, ndata, mycomm
352 integer,
allocatable :: iadd(:)
353 integer,
allocatable :: table_recv(:), table_send(:)
354 real ,
allocatable :: data_recv(:,:), data_send(:,:)
355 integer,
allocatable :: indices_to_remove(:)
356 integer,
allocatable :: ids_to_add(:)
357 real ,
allocatable :: positions_to_add(:,:)
358 real :: x, y, xold, yold
359 character(len=128) :: ermsg, notemsg
360 logical :: is_present
361 integer :: id, j, k, m, n, el
362 logical :: crossed_W, crossed_E, crossed_S, crossed_N
363 logical :: was_in_compute_domain, left_domain
365 mycomm = mpi_comm_world
366 if(
present(comm) ) mycomm = comm
369 np =
size(new_positions,2)
370 if(np > 0 .and. nd < 2)
call mpp_error( fatal, &
371 &
'drifters_comm_update: number of dimensions must be 2 or higher.' )
374 if(
present(max_add_remove)) nar_est = max(1, max_add_remove)
380 allocate(iadd(self%pe_beg:self%pe_end))
381 allocate(table_recv(self%pe_beg:self%pe_end))
382 allocate(table_send(self%pe_beg:self%pe_end))
383 allocate(data_recv(nar_est*(1+nd), self%pe_beg:self%pe_end))
384 allocate(data_send(nar_est*(1+nd), self%pe_beg:self%pe_end))
385 allocate(indices_to_remove(nar_est))
395 x = new_positions(1, ip)
396 y = new_positions(2, ip)
397 xold = drfts%positions(1, ip)
398 yold = drfts%positions(2, ip)
400 if( xold<self%xcmin .or. xold>self%xcmax .or. &
401 & yold<self%ycmin .or. yold>self%ycmax )
then
402 was_in_compute_domain = .false.
404 was_in_compute_domain = .true.
413 if( was_in_compute_domain .and. &
414 & (x<self%xcmin) .and. (xold>self%xcmin) ) crossed_w = .true.
415 if( was_in_compute_domain .and. &
416 & (x>self%xcmax) .and. (xold<self%xcmax) ) crossed_e = .true.
417 if( was_in_compute_domain .and. &
418 & (y<self%ycmin) .and. (yold>self%ycmin) ) crossed_s = .true.
419 if( was_in_compute_domain .and. &
420 & (y>self%ycmax) .and. (yold<self%ycmax) ) crossed_n = .true.
423 if(crossed_n .and. .not. crossed_e .and. .not. crossed_w) neigh_pe = self%pe_N
424 if(crossed_n .and. crossed_e ) neigh_pe = self%pe_NE
425 if(crossed_e .and. .not. crossed_n .and. .not. crossed_s) neigh_pe = self%pe_E
426 if(crossed_s .and. crossed_e ) neigh_pe = self%pe_SE
427 if(crossed_s .and. .not. crossed_e .and. .not. crossed_w) neigh_pe = self%pe_S
428 if(crossed_s .and. crossed_w ) neigh_pe = self%pe_SW
429 if(crossed_w .and. .not. crossed_s .and. .not. crossed_n) neigh_pe = self%pe_W
430 if(crossed_n .and. crossed_w ) neigh_pe = self%pe_NW
432 if(neigh_pe /= _null_pe)
then
433 iadd(neigh_pe) = iadd(neigh_pe) + 1
434 if(iadd(neigh_pe) > nar_est)
then
435 write(notemsg,
'(a,i4,a,i4,a)')
'drifters_comm_update: exceeded nar_est (', &
436 & iadd(neigh_pe),
'>',nar_est,
').'
439 table_send(neigh_pe) = table_send(neigh_pe) + 1
440 k = ( iadd(neigh_pe)-1 )*(1+nd) + 1
441 data_send(k , neigh_pe) = drfts%ids(ip)
442 data_send(k+1:k+nd, neigh_pe) = new_positions(:,ip)
447 left_domain = .false.
448 if( (x<self%xdmin .and. (self%pe_W/=pe)) .or. &
449 & (x>self%xdmax .and. (self%pe_E/=pe)) .or. &
450 & (y<self%ydmin .and. (self%pe_S/=pe)) .or. &
451 & (y>self%ydmax .and. (self%pe_N/=pe)) )
then
457 if(
present(remove))
then
458 if(remove(ip)) left_domain = .true.
463 if(irem > nar_est)
then
464 write(notemsg,
'(a,i4,a,i4,a)')
'drifters_comm_update: exceeded nar_est (',&
465 & irem,
'>',nar_est,
').'
468 indices_to_remove(irem) = ip
475 call drifters_core_set_positions(drfts, new_positions, ermsg)
476 if(ermsg/=
'')
call mpp_error( fatal, ermsg)
490 do m = self%pe_beg, self%pe_end
492 call mpi_scatter (table_send , 1, mpi_integer, &
493 & table_recv(m), 1, mpi_integer, &
497 do k = self%pe_beg, self%pe_end
498 call mpp_send(table_send(k), plen=1, to_pe=k, tag=comm_tag_1)
501 call mpp_recv(table_recv(m), glen=1, from_pe=m, tag=comm_tag_1)
508 do m = self%pe_beg, self%pe_end
509 ntuples = table_send(m)
510 ndata = ntuples*(nd+1)
513 call mpi_scatter (data_send , nar_est*(1+nd), mpi_real8, &
514 & data_recv(1,m), nar_est*(1+nd), mpi_real8, &
518 do k = self%pe_beg, self%pe_end
519 call mpp_send(data_send(1,k), plen=nar_est*(1+nd), to_pe=k, tag=comm_tag_2)
522 call mpp_recv(data_recv(1,m), glen=nar_est*(1+nd), from_pe=m, tag=comm_tag_2)
528 do m = self%pe_beg, self%pe_end
529 ntuples_tot = ntuples_tot + table_recv(m)
532 allocate(positions_to_add(nd, ntuples_tot))
533 allocate( ids_to_add( ntuples_tot))
537 do m = self%pe_beg, self%pe_end
539 do n = 1, table_recv(m)
541 el = (n-1)*(nd+1) + 1
542 id = int(data_recv(el, m))
548 if(id == drfts%ids(j))
then
550 write(notemsg,
'(a,i4,a)')
'Drifter ', id,
' already advected (will not be added).'
555 if(.not. is_present)
then
559 positions_to_add(1:nd, k) = data_recv(el+1:el+nd, m)
566 if(irem > 0 .or. k > 0)
then
567 write(notemsg,
'(i4,a,i4,a)') irem,
' drifter(s) will be removed, ', k,
' will be added'
572 call drifters_core_remove_and_add(drfts, indices_to_remove(1:irem), &
573 & ids_to_add(1:k), positions_to_add(:,1:k), ermsg)
574 if(ermsg/=
'')
call mpp_error( fatal, ermsg)
581 deallocate(ids_to_add)
582 deallocate(positions_to_add)
585 deallocate(table_recv)
586 deallocate(table_send)
587 deallocate(data_recv)
588 deallocate(data_send)
589 deallocate(indices_to_remove)
594 end subroutine drifters_comm_update
597 subroutine drifters_comm_gather(self, drfts, dinp, &
598 & lons, lats, do_save_lonlat, &
605 use drifters_input_mod,
only : drifters_input_type, drifters_input_save
607 type(drifters_comm_type) :: self
608 type(drifters_core_type) :: drfts
609 type(drifters_input_type) :: dinp
610 real,
intent(in) :: lons(:), lats(:)
611 logical,
intent(in) :: do_save_lonlat
612 character(len=*),
intent(in) :: filename
613 integer,
intent(in),
optional :: root
614 integer,
intent(in),
optional :: mycomm
616 character(len=128) :: ermesg
621 dinp%ids(1:drfts%np) = drfts%ids(1:drfts%np)
622 dinp%positions(:, 1:drfts%np) = drfts%positions(:, 1:drfts%np)
624 if(do_save_lonlat)
then
626 call drifters_input_save(dinp, filename=filename, &
627 & geolon=lons, geolat=lats, ermesg=ermesg)
631 call drifters_input_save(dinp, filename=filename, ermesg=ermesg)
639 integer :: npf, ip, comm, root_pe, pe, npes, nd, np, npdim, npmax, ier, nptot
640 integer :: i, j, k, kk
641 integer,
allocatable :: nps(:)
643 real,
allocatable :: lons0(:), lats0(:), recvbuf(:,:)
644 real :: com_data(drfts%nd+3, drfts%np)
646 comm = mpi_comm_world
647 if(
present(mycomm)) comm = mycomm
649 root_pe = mpp_root_pe()
650 if(
present(root)) root_pe = root
659 allocate(nps(self%pe_beg:self%pe_end))
666 x = drfts%positions(1, ip)
667 y = drfts%positions(2, ip)
668 if( x <= self%xcmax .and. x >= self%xcmin .and. &
669 & y <= self%ycmax .and. y >= self%ycmin)
then
671 com_data(1 , npf) = real(drfts%ids(ip))
672 com_data(1+1:1+nd, npf) = drfts%positions(:, ip)
673 com_data( 2+nd, npf) = lons(ip)
674 com_data( 3+nd, npf) = lats(ip)
680 call mpi_gather(npf, 1, mpi_int, &
682 & root_pe, comm, ier)
685 call mpp_send(npf, plen=1, to_pe=root_pe, tag=comm_tag_3)
687 do i = self%pe_beg, self%pe_end
688 call mpp_recv(nps(i), glen=1, from_pe=i, tag=comm_tag_3)
698 allocate(recvbuf(npmax*(nd+3), self%pe_beg:self%pe_end))
703 call mpi_gather( com_data , npf*(nd+3), mpi_real8, &
704 & recvbuf, npmax*(nd+3), mpi_real8, &
705 & root_pe, comm, ier)
708 if(npf > 0)
call mpp_send(com_data(1,1), plen=npf*(nd+3), to_pe=root_pe, tag=comm_tag_4)
710 do i = self%pe_beg, self%pe_end
711 if(nps(i) > 0)
call mpp_recv(recvbuf(1, i), glen=nps(i)*(nd+3), from_pe=i, tag=comm_tag_4)
717 if(pe == root_pe)
then
720 if(nptot /=
size(dinp%ids))
then
721 deallocate(dinp%ids , stat=ier)
722 deallocate(dinp%positions, stat=ier)
723 allocate(dinp%ids(nptot))
724 allocate(dinp%positions(nd, nptot))
726 dinp%positions = -huge(1.)
729 allocate(lons0(nptot), lats0(nptot))
736 do i = self%pe_beg, self%pe_end
739 dinp%ids(j) = int(recvbuf(kk+1 , i))
740 dinp%positions(1:nd, j) = recvbuf(kk+1+1:kk+1+nd, i)
741 lons0(j) = recvbuf(kk+2+nd, i)
742 lats0(j) = recvbuf(kk+3+nd, i)
747 if(do_save_lonlat)
then
749 call drifters_input_save(dinp, filename=filename, &
750 & geolon=lons0, geolat=lats0, ermesg=ermesg)
754 call drifters_input_save(dinp, filename=filename, ermesg=ermesg)
758 deallocate(lons0, lats0)
765 deallocate(nps , stat=ier)
766 deallocate(recvbuf, stat=ier)
771 end subroutine drifters_comm_gather
774 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.
Recieve data from another PE.
Send data to a receiving PE.