1 !***********************************************************************
2 !* GNU Lesser General Public License
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
6 !* FMS is free software: you can redistribute it and/or modify it under
7 !* the terms of the GNU Lesser General Public License as published by
8 !* the Free Software Foundation, either version 3 of the License, or (at
9 !* your option) any later version.
11 !* FMS is distributed in the hope that it will be useful, but WITHOUT
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 !* You should have received a copy of the GNU Lesser General Public
17 !* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
18 !***********************************************************************
19 #include "fms_switches.h"
21 !> @defgroup drifters_comm_mod drifters_comm_mod
23 !> @brief Routines and types to update drifter positions across processor domains
25 module drifters_comm_mod
29 #define _TYPE_DOMAIN2D integer
34 use mpp_mod, only : NULL_PE, FATAL, NOTE, mpp_error, mpp_pe, mpp_npes
35 use mpp_mod, only : mpp_root_pe
36 use mpp_mod, only : mpp_send, mpp_recv, mpp_sync_self
37 use mpp_mod, only : COMM_TAG_1, COMM_TAG_2, COMM_TAG_3, COMM_TAG_4
38 use mpp_domains_mod, only : domain2D
39 use mpp_domains_mod, only : mpp_get_neighbor_pe, mpp_define_domains, mpp_get_layout
40 use mpp_domains_mod, only : mpp_get_compute_domain, mpp_get_data_domain
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
57 !> Type for drifter communication between PE's
58 !> @ingroup drifters_comm_mod
59 type :: drifters_comm_type
60 real :: xcmin !< compute domain
61 real :: xcmax !< compute domain
62 real :: ycmin !< compute domain
63 real :: ycmax !< compute domain
64 real :: xdmin !< data domain
65 real :: xdmax !< data domain
66 real :: ydmin !< data domain
67 real :: ydmax !< data domain
68 real :: xgmin !< global valid min/max
69 real :: xgmax !< global valid min/max
70 real :: ygmin !< global valid min/max
71 real :: ygmax !< global valid min/max
72 logical :: xperiodic !< x/y period (can be be nearly infinite)
73 logical :: yperiodic !< x/y period (can be be nearly infinite)
74 integer :: pe_N !< neighbor domains
75 integer :: pe_S !< neighbor domains
76 integer :: pe_E !< neighbor domains
77 integer :: pe_W !< neighbor domains
78 integer :: pe_NE !< neighbor domains
79 integer :: pe_SE !< neighbor domains
80 integer :: pe_SW !< neighbor domains
81 integer :: pe_NW !< neighbor domains
82 integer :: pe_beg !< starting/ending pe, set this to a value /= 0 if running concurrently
83 integer :: pe_end !< starting/ending pe, set this to a value /= 0 if running concurrently
84 end type drifters_comm_type
88 !> @addtogroup drifters_comm_mod
90 !===============================================================================
91 !> @brief Initializes default values for @ref drifters_comm_type in self
92 subroutine drifters_comm_new(self)
93 type(drifters_comm_type) :: self !< A new @ref drifters_comm_type
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
121 !===============================================================================
122 !> @brief Reset data in a given @ref drifters_comm_type to defaults
123 subroutine drifters_comm_del(self)
124 type(drifters_comm_type) :: self !< A @ref drifters_comm_type to reset
126 ! nothing to deallocate
127 call drifters_comm_new(self)
129 end subroutine drifters_comm_del
131 !===============================================================================
132 !> @brief Set data domain bounds.
133 subroutine drifters_comm_set_data_bounds(self, xmin, ymin, xmax, ymax)
134 ! Set data domain bounds.
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
145 !===============================================================================
146 !> @brief Set compute domain bounds.
147 subroutine drifters_comm_set_comp_bounds(self, xmin, ymin, xmax, ymax)
148 ! Set compute domain bounds.
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
159 !===============================================================================
160 !> @brief Set neighboring pe numbers.
161 subroutine drifters_comm_set_pe_neighbors(self, domain)
162 ! Set neighboring pe numbers.
163 type(drifters_comm_type) :: self !< Drifters communication type to set pe numbers for
164 _TYPE_DOMAIN2D, intent(inout) :: domain !< domain to get neighboring PE's from
169 integer :: pe_N, pe_S, pe_E, pe_W, pe_NE, pe_SE, pe_SW, pe_NW
171 call mpp_get_neighbor_pe(domain, NORTH , pe_N )
172 call mpp_get_neighbor_pe(domain, NORTH_EAST, pe_NE)
173 call mpp_get_neighbor_pe(domain, EAST , pe_E )
174 call mpp_get_neighbor_pe(domain, SOUTH_EAST, pe_SE)
175 call mpp_get_neighbor_pe(domain, SOUTH , pe_S )
176 call mpp_get_neighbor_pe(domain, SOUTH_WEST, pe_SW)
177 call mpp_get_neighbor_pe(domain, WEST , pe_W )
178 call mpp_get_neighbor_pe(domain, NORTH_WEST, 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!.')
222 ! end of parallel code
224 end subroutine drifters_comm_set_pe_neighbors
226 !===============================================================================
227 !> @brief Set boundaries of domain and compute neighbors. This method can be called
228 !! multiple times; the data domain will just be the intersection (overlap) of
229 !! all domains (e.g domain_u, domain_v, etc).
230 subroutine drifters_comm_set_domain(self, domain, x, y, backoff_x, backoff_y)
231 ! Set boundaries of domain and compute neighbors. This method can be called
232 ! multiple times; the data domain will just be the intersection (overlap) of
233 ! all domains (e.g domain_u, domain_v, etc).
234 type(drifters_comm_type) :: self
235 _TYPE_DOMAIN2D, intent(inout) :: domain
236 real, intent(in) :: x(:) !< global axes
237 real, intent(in) :: y(:) !< global axes
238 integer, intent(in) :: backoff_x !< >=0, data domain is reduced by "backoff_x,y" indices in x, resp. y
239 integer, intent(in) :: backoff_y !< >=0, data domain is reduced by "backoff_x,y" indices in x, resp. y
241 ! compute/data domain start/end indices
242 integer :: isc !< compute domain start/end indices
243 integer :: iec !< compute domain start/end indices
244 integer :: jsc !< compute domain start/end indices
245 integer :: jec !< compute domain start/end indices
246 integer :: isd !< data domain start/end indices
247 integer :: ied !< data domain start/end indices
248 integer :: jsd !< data domain start/end indices
249 integer :: jed !< data domain start/end indices
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
261 call mpp_get_compute_domain( domain, isc, iec, jsc, jec )
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)
275 call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
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
323 !===============================================================================
324 !> Updates drifter communication
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 !< MPI communicator
335 logical, intent(in), optional :: remove(:) !< Set to True for particles that should be removed
336 integer, intent(in), optional :: max_add_remove !< max no of particles to 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)
378 ! assume pe list is contiguous, self%pe_beg...self%pe_end
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.
406 ! check if drifters crossed compute domain boundary
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,').'
436 call mpp_error( FATAL, notemsg)
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)
444 ! check if drifters left data domain
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
454 ! remove if particle was tagged as such
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,').'
465 call mpp_error( FATAL, notemsg)
467 indices_to_remove(irem) = ip
473 ! update drifters' positions (remove whatever needs to be removed later)
474 call drifters_core_set_positions(drfts, new_positions, ermsg)
475 if(ermsg/='') call mpp_error( FATAL, ermsg)
477 ! fill in table_recv from table_send. table_send contains the
478 ! number of tuples that will be sent to another pe. table_recv
479 ! will contain the number of tuples to be received. The indices
480 ! of table_send refer to the pe where the tuples should be sent to;
481 ! the indices of table_recv refer to the pe number
482 ! (self%pe_beg..self%pe_end) from
483 ! which the tuple should be received from.
485 ! table_send(to_pe) = ntuples; table_recv(from_pe) = ntuples
487 ! the following is a transpose operation
488 ! table_send(m)[pe] -> table_recv(pe)[m]
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)
504 ! communicate new positions. data_send is an array of size n*(nd+1) times npes.
505 ! Each column j of data_send contains the tuple (id, x, y, ..) to be sent to pe=j.
506 ! Inversely, data_recv's column j contains tuples (id, x, y,..) received from pe=j.
507 do m = self%pe_beg, self%pe_end
508 ntuples = table_send(m)
509 ndata = ntuples*(nd+1)
510 ! should be able to send ndata?
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)
525 ! total number of tuples will determine size of ids_to_add/positions_to_add
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))
534 ! fill positions_to_add and ids_to_add.
536 do m = self%pe_beg, self%pe_end
537 ! get ids/positions coming from all pes
538 do n = 1, table_recv(m)
539 ! iterate over all ids/positions coming from pe=m
540 el = (n-1)*(nd+1) + 1
541 id = int(data_recv(el, m))
542 ! only add if id not already present in drfts
543 ! this can happen if a drifter meanders about
544 ! the compute domain boundary
547 if(id == drfts%ids(j)) then
549 write(notemsg, '(a,i4,a)') 'Drifter ', id, ' already advected (will not be added).'
550 call mpp_error(NOTE, notemsg)
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'
567 call mpp_error(NOTE, notemsg)
568 !!$ if(k>0) print *,'positions to add ', positions_to_add(:,1:k)
569 !!$ if(irem>0) print *,'ids to remove: ', indices_to_remove(1:irem)
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)
576 ! make sure unbuffered mpp_isend call returned before deallocating
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)
591 ! end of parallel code
593 end subroutine drifters_comm_update
595 !===============================================================================
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 !< root pe
613 integer, intent(in), optional :: mycomm !< MPI communicator
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 :: 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))
661 ! npf= number of drifters in compute domain
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 data(1 , npf) = real(drfts%ids(ip))
671 data(1+1:1+nd, npf) = drfts%positions(:, ip)
672 data( 2+nd, npf) = lons(ip)
673 data( 3+nd, npf) = lats(ip)
677 ! gather number of drifters
679 call mpi_gather(npf, 1, MPI_INT, &
681 & root_pe, comm, ier)
682 !!if(ier/=0) ermesg = 'drifters_write_restart: ERROR while gathering "npf"'
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)
692 ! Now we know the max number of drifters to expect from each PE, so allocate
693 ! recvbuf (first dim will be zero on all PEs except root).
695 ! allocate recvbuf to receive all the data on root PE, strided by npmax*(nd+3)
697 allocate(recvbuf(npmax*(nd+3), self%pe_beg:self%pe_end))
700 ! Each PE sends data to recvbuf on root_pe.
702 call mpi_gather( data , npf*(nd+3), MPI_REAL8, &
703 & recvbuf, npmax*(nd+3), MPI_REAL8, &
704 & root_pe, comm, ier)
705 !!if(ier/=0) ermesg = 'drifters_write_restart: ERROR while gathering "data"'
707 if(npf > 0) call mpp_send(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)
715 ! Set positions and ids
716 if(pe == root_pe) then
718 nptot = sum(nps) ! total number of drifters, across al PEs
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))
730 ! Set the new positions/ids in dinp, on PE=root. Also set
731 ! lons/lats, these arrays will hold garbage if x1, y1, etc. were
732 ! not passed as subroutine arguments, that's ok 'cause we won't
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)
768 ! _end of parallel code
770 end subroutine drifters_comm_gather
773 end module drifters_comm_mod
775 !===============================================================================
776 !===============================================================================