19 #include "fms_switches.h" 22 #include <fms_platform.h> 26 #define _TYPE_DOMAIN2D integer 34 use mpp_mod,
only : comm_tag_1, comm_tag_2, comm_tag_3, comm_tag_4
38 use mpp_domains_mod,
only : north, south, east, west, cyclic_global_domain
39 use mpp_domains_mod,
only : north_east, south_east, south_west, north_west
41 #define _TYPE_DOMAIN2D type(domain2d) 42 #define _NULL_PE NULL_PE 65 logical :: xperiodic, yperiodic
67 integer :: pe_n, pe_s, pe_e, pe_w, pe_ne, pe_se, pe_sw, pe_nw
69 integer :: pe_beg, pe_end
78 self%xcmin = -huge(1.); self%xcmax = +huge(1.)
79 self%ycmin = -huge(1.); self%ycmax = +huge(1.)
81 self%xdmin = -huge(1.); self%xdmax = +huge(1.)
82 self%ydmin = -huge(1.); self%ydmax = +huge(1.)
84 self%xgmin = -huge(1.); self%xgmax = +huge(1.)
85 self%ygmin = -huge(1.); self%ygmax = +huge(1.)
87 self%xperiodic = .false.; self%yperiodic = .false.
116 type(drifters_comm_type) :: self
117 real,
intent(in) :: xmin, ymin, xmax, ymax
119 self%xdmin =
max(xmin, self%xdmin)
120 self%xdmax =
min(xmax, self%xdmax)
121 self%ydmin =
max(ymin, self%ydmin)
122 self%ydmax =
min(ymax, self%ydmax)
129 type(drifters_comm_type) :: self
130 real,
intent(in) :: xmin, ymin, xmax, ymax
132 self%xcmin =
max(xmin, self%xcmin)
133 self%xcmax =
min(xmax, self%xcmax)
134 self%ycmin =
max(ymin, self%ycmin)
135 self%ycmax =
min(ymax, self%ycmax)
143 _type_domain2d,
intent(inout) :: domain
148 integer :: pe_n, pe_s, pe_e, pe_w, pe_ne, pe_se, pe_sw, pe_nw
159 if(pe_n /= self%pe_N .and. self%pe_N == _null_pe)
then 161 else if(pe_n /= self%pe_N )
then 162 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: NORTH PE changed!.')
164 if(pe_ne /= self%pe_NE .and. self%pe_NE == _null_pe)
then 166 else if(pe_ne /= self%pe_NE)
then 167 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: NORTH-EAST PE changed!.')
169 if(pe_e /= self%pe_E .and. self%pe_E == _null_pe)
then 171 else if(pe_e /= self%pe_E )
then 172 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: EAST PE changed!.')
174 if(pe_se /= self%pe_SE .and. self%pe_SE == _null_pe)
then 176 else if(pe_se /= self%pe_SE)
then 177 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: SOUTH-EAST PE changed!.')
179 if(pe_s /= self%pe_S .and. self%pe_S == _null_pe)
then 181 else if(pe_s /= self%pe_S )
then 182 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: SOUTH PE changed!.')
184 if(pe_sw /= self%pe_SW .and. self%pe_SW == _null_pe)
then 186 else if(pe_sw /= self%pe_SW)
then 187 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: SOUTH-WEST PE changed!.')
189 if(pe_w /= self%pe_W .and. self%pe_W == _null_pe)
then 191 else if(pe_w /= self%pe_W )
then 192 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: WEST PE changed!.')
194 if(pe_nw /= self%pe_NW .and. self%pe_NW == _null_pe)
then 196 else if(pe_nw /= self%pe_NW)
then 197 call mpp_error( fatal,
'drifters_comm_set_pe_neighbors: NORTH-WEST PE changed!.')
211 _type_domain2d,
intent(inout) :: domain
212 real,
intent(in) :: x(:), y(:)
213 integer,
intent(in) :: backoff_x, backoff_y
216 integer isc, iec, jsc, jec
217 integer isd, ied, jsd, jed
218 integer nx, ny, hx, hy, bckf_x, bckf_y, halox, haloy
219 real dx, dy, xdmin, xdmax, ydmin, ydmax
224 ibnds = lbound(x); isc = ibnds(1)
225 ibnds = ubound(x); iec = ibnds(1) - 1
226 ibnds = lbound(y); jsc = ibnds(1)
227 ibnds = ubound(y); jec = ibnds(1) - 1
232 self%xcmin =
max(x(isc), self%xcmin)
233 self%xcmax =
min(x(iec), self%xcmax)
234 self%ycmin =
max(y(jsc), self%ycmin)
235 self%ycmax =
min(y(jec), self%ycmax)
241 isd = 1; ied =
size(x); jsd = 1; jed =
size(y)
246 hx =
max(ied-iec, isc-isd)
247 hy =
max(jed-jec, jsc-jsd)
248 bckf_x =
min(backoff_x, hx)
249 bckf_y =
min(backoff_y, hy)
251 halox =
max(0, hx - bckf_x)
252 haloy =
max(0, hy - bckf_y)
256 xdmin = self%xcmin - dx*halox
258 xdmin = x(isd+bckf_x)
263 xdmax = self%xcmax + dx*halox
265 xdmax = x(ied-bckf_x)
270 ydmin = self%ycmin - dy*haloy
272 ydmin = y(jsd+bckf_y)
277 ydmax = self%ycmax + dy*haloy
279 ydmax = y(jed-bckf_y)
282 self%xdmin =
max(xdmin, self%xdmin)
283 self%ydmin =
max(ydmin, self%ydmin)
284 self%xdmax =
min(xdmax, self%xdmax)
285 self%ydmax =
min(ydmax, self%ydmax)
293 & comm, remove, max_add_remove)
297 real,
intent(inout) :: new_positions(:,:)
298 integer,
intent(in),
optional :: comm
299 logical,
intent(in),
optional :: remove(:)
300 integer,
intent(in),
optional :: max_add_remove
305 drfts%positions(:, 1:drfts%np) = new_positions(:, 1:drfts%np)
314 integer nd, np, nar_est, ip, neigh_pe, irem, pe, npes, ntuples
315 integer ntuples_tot, ndata, mycomm
319 integer,
allocatable :: iadd(:)
320 integer,
allocatable :: table_recv(:), table_send(:)
321 real ,
allocatable :: data_recv(:,:), data_send(:,:)
322 integer,
allocatable :: indices_to_remove(:)
323 integer,
allocatable :: ids_to_add(:)
324 real ,
allocatable :: positions_to_add(:,:)
325 real :: x, y, xold, yold
326 character(len=128) :: ermsg, notemsg
327 logical :: is_present
328 integer :: id, j, k, m, n, el
329 logical :: crossed_w, crossed_e, crossed_s, crossed_n
330 logical :: was_in_compute_domain, left_domain
332 mycomm = mpi_comm_world
333 if(
present(comm) ) mycomm = comm
336 np =
size(new_positions,2)
337 if(np > 0 .and. nd < 2)
call mpp_error( fatal, &
338 &
'drifters_comm_update: number of dimensions must be 2 or higher.' )
341 if(
present(max_add_remove)) nar_est =
max(1, max_add_remove)
347 allocate(iadd(self%pe_beg:self%pe_end))
348 allocate(table_recv(self%pe_beg:self%pe_end))
349 allocate(table_send(self%pe_beg:self%pe_end))
350 allocate(data_recv(nar_est*(1+nd), self%pe_beg:self%pe_end))
351 allocate(data_send(nar_est*(1+nd), self%pe_beg:self%pe_end))
352 allocate(indices_to_remove(nar_est))
362 x = new_positions(1, ip)
363 y = new_positions(2, ip)
364 xold = drfts%positions(1, ip)
365 yold = drfts%positions(2, ip)
367 if( xold<self%xcmin .or. xold>self%xcmax .or. &
368 & yold<self%ycmin .or. yold>self%ycmax )
then 369 was_in_compute_domain = .false.
371 was_in_compute_domain = .true.
380 if( was_in_compute_domain .and. &
381 & (x<self%xcmin) .and. (xold>self%xcmin) ) crossed_w = .true.
382 if( was_in_compute_domain .and. &
383 & (x>self%xcmax) .and. (xold<self%xcmax) ) crossed_e = .true.
384 if( was_in_compute_domain .and. &
385 & (y<self%ycmin) .and. (yold>self%ycmin) ) crossed_s = .true.
386 if( was_in_compute_domain .and. &
387 & (y>self%ycmax) .and. (yold<self%ycmax) ) crossed_n = .true.
390 if(crossed_n .and. .not. crossed_e .and. .not. crossed_w) neigh_pe = self%pe_N
391 if(crossed_n .and. crossed_e ) neigh_pe = self%pe_NE
392 if(crossed_e .and. .not. crossed_n .and. .not. crossed_s) neigh_pe = self%pe_E
393 if(crossed_s .and. crossed_e ) neigh_pe = self%pe_SE
394 if(crossed_s .and. .not. crossed_e .and. .not. crossed_w) neigh_pe = self%pe_S
395 if(crossed_s .and. crossed_w ) neigh_pe = self%pe_SW
396 if(crossed_w .and. .not. crossed_s .and. .not. crossed_n) neigh_pe = self%pe_W
397 if(crossed_n .and. crossed_w ) neigh_pe = self%pe_NW
399 if(neigh_pe /= _null_pe)
then 400 iadd(neigh_pe) = iadd(neigh_pe) + 1
401 if(iadd(neigh_pe) > nar_est)
then 402 write(notemsg,
'(a,i4,a,i4,a)')
'drifters_comm_update: exceeded nar_est (', &
403 & iadd(neigh_pe),
'>',nar_est,
').' 406 table_send(neigh_pe) = table_send(neigh_pe) + 1
407 k = ( iadd(neigh_pe)-1 )*(1+nd) + 1
408 data_send(k , neigh_pe) = drfts%ids(ip)
409 data_send(k+1:k+nd, neigh_pe) = new_positions(:,ip)
414 left_domain = .false.
415 if( (x<self%xdmin .and. (self%pe_W/=pe)) .or. &
416 & (x>self%xdmax .and. (self%pe_E/=pe)) .or. &
417 & (y<self%ydmin .and. (self%pe_S/=pe)) .or. &
418 & (y>self%ydmax .and. (self%pe_N/=pe)) )
then 424 if(
present(remove))
then 425 if(remove(ip)) left_domain = .true.
430 if(irem > nar_est)
then 431 write(notemsg,
'(a,i4,a,i4,a)')
'drifters_comm_update: exceeded nar_est (',&
432 & irem,
'>',nar_est,
').' 435 indices_to_remove(irem) = ip
443 if(ermsg/=
'')
call mpp_error( fatal, ermsg)
457 do m = self%pe_beg, self%pe_end
459 call mpi_scatter (table_send , 1, mpi_integer, &
460 & table_recv(m), 1, mpi_integer, &
464 do k = self%pe_beg, self%pe_end
465 call mpp_send(table_send(k), plen=1, to_pe=k, tag=comm_tag_1)
468 call mpp_recv(table_recv(m), glen=1, from_pe=m, tag=comm_tag_1)
475 do m = self%pe_beg, self%pe_end
476 ntuples = table_send(m)
477 ndata = ntuples*(nd+1)
480 call mpi_scatter (data_send , nar_est*(1+nd), mpi_real8, &
481 & data_recv(1,m), nar_est*(1+nd), mpi_real8, &
485 do k = self%pe_beg, self%pe_end
486 call mpp_send(data_send(1,k), plen=nar_est*(1+nd), to_pe=k, tag=comm_tag_2)
489 call mpp_recv(data_recv(1,m), glen=nar_est*(1+nd), from_pe=m, tag=comm_tag_2)
495 do m = self%pe_beg, self%pe_end
496 ntuples_tot = ntuples_tot + table_recv(m)
499 allocate(positions_to_add(nd, ntuples_tot))
500 allocate( ids_to_add( ntuples_tot))
504 do m = self%pe_beg, self%pe_end
506 do n = 1, table_recv(m)
508 el = (n-1)*(nd+1) + 1
509 id = int(data_recv(el, m))
515 if(id == drfts%ids(j))
then 517 write(notemsg,
'(a,i4,a)')
'Drifter ', id,
' already advected (will not be added).' 522 if(.not. is_present)
then 526 positions_to_add(1:nd, k) = data_recv(el+1:el+nd, m)
533 if(irem > 0 .or. k > 0)
then 534 write(notemsg,
'(i4,a,i4,a)') irem,
' drifter(s) will be removed, ', k,
' will be added' 540 & ids_to_add(1:k), positions_to_add(:,1:k), ermsg)
541 if(ermsg/=
'')
call mpp_error( fatal, ermsg)
548 deallocate(ids_to_add)
549 deallocate(positions_to_add)
552 deallocate(table_recv)
553 deallocate(table_send)
554 deallocate(data_recv)
555 deallocate(data_send)
556 deallocate(indices_to_remove)
565 & lons, lats, do_save_lonlat, &
574 real,
intent(in) :: lons(:), lats(:)
575 logical,
intent(in) :: do_save_lonlat
576 character(len=*),
intent(in) :: filename
577 integer,
intent(in),
optional :: root
578 integer,
intent(in),
optional :: mycomm
580 character(len=128) :: ermesg
585 dinp%ids(1:drfts%np) = drfts%ids(1:drfts%np)
586 dinp%positions(:, 1:drfts%np) = drfts%positions(:, 1:drfts%np)
588 if(do_save_lonlat)
then 591 & geolon=lons, geolat=lats, ermesg=ermesg)
603 integer :: npf, ip, comm, root_pe, pe, npes, nd, np, npdim, npmax, ier, nptot
604 integer :: i, j, k, kk
605 integer,
allocatable :: nps(:)
607 real,
allocatable :: lons0(:), lats0(:), recvbuf(:,:)
608 real :: data(drfts%nd+3, drfts%np)
611 comm = mpi_comm_world
612 if(
present(mycomm)) comm = mycomm
614 root_pe = mpp_root_pe()
615 if(
present(root)) root_pe = root
624 allocate(nps(self%pe_beg:self%pe_end))
631 x = drfts%positions(1, ip)
632 y = drfts%positions(2, ip)
633 if( x <= self%xcmax .and. x >= self%xcmin .and. &
634 & y <= self%ycmax .and. y >= self%ycmin)
then 636 data(1 , npf) =
real(drfts%ids(ip))
637 data(1+1:1+nd, npf) = drfts%positions(:, ip)
638 data( 2+nd, npf) = lons(ip)
639 data( 3+nd, npf) = lats(ip)
645 call mpi_gather(npf, 1, mpi_int, &
647 & root_pe, comm, ier)
650 call mpp_send(npf, plen=1, to_pe=root_pe, tag=comm_tag_3)
652 do i = self%pe_beg, self%pe_end
653 call mpp_recv(nps(i), glen=1, from_pe=i, tag=comm_tag_3)
663 allocate(recvbuf(npmax*(nd+3), self%pe_beg:self%pe_end))
668 call mpi_gather(
data , npf*(nd+3), mpi_real8, &
669 & recvbuf, npmax*(nd+3), mpi_real8, &
670 & root_pe, comm, ier)
673 if(npf > 0)
call mpp_send(
data(1,1), plen=npf*(nd+3), to_pe=root_pe, tag=comm_tag_4)
675 do i = self%pe_beg, self%pe_end
676 if(nps(i) > 0)
call mpp_recv(recvbuf(1, i), glen=nps(i)*(nd+3), from_pe=i, tag=comm_tag_4)
682 if(pe == root_pe)
then 685 if(nptot /=
size(dinp%ids))
then 686 deallocate(dinp%ids , stat=ier)
687 deallocate(dinp%positions, stat=ier)
688 allocate(dinp%ids(nptot))
689 allocate(dinp%positions(nd, nptot))
691 dinp%positions = -huge(1.)
694 allocate(lons0(nptot), lats0(nptot))
701 do i = self%pe_beg, self%pe_end
704 dinp%ids(j) = int(recvbuf(kk+1 , i))
705 dinp%positions(1:nd, j) = recvbuf(kk+1+1:kk+1+nd, i)
706 lons0(j) = recvbuf(kk+2+nd, i)
707 lats0(j) = recvbuf(kk+3+nd, i)
712 if(do_save_lonlat)
then 715 & geolon=lons0, geolat=lats0, ermesg=ermesg)
723 deallocate(lons0, lats0)
730 deallocate(nps , stat=ier)
731 deallocate(recvbuf, stat=ier)
743 #ifdef _TEST_DRIFTERS_COMM 759 integer,
parameter :: nd=2, npmax = 4
760 integer :: nx, ny, halox, haloy, layout(2), i, j,
npes, pe, it, nt
761 _type_domain2d :: domain
764 real,
parameter :: xmin=0., xmax=1., ymin=0., ymax=1.
765 real :: dx, dy, u0, v0, dt, lx, ly
766 real,
allocatable :: x(:), y(:)
767 character(len=128) :: ermsg =
'' 768 integer :: ids(npmax)
769 real :: positions(nd, npmax), velocity(nd, npmax)
773 namelist /drifters_comm_nml/ nx, ny, halox, haloy, u0, v0, dt, nt
790 #ifdef INTERNAL_FILE_NML 793 open(unit=1, file=
'input.nml', form=
'formatted')
794 read(1, drifters_comm_nml)
796 if(mpp_pe()==0)
write(*,drifters_comm_nml)
804 allocate(x(nx), y(ny))
805 x = xmin + (/ ( i*dx, i=0, nx-1) /)
806 y = ymin + (/ ( j*dy, j=0, ny-1) /)
809 call mpp_domains_init
814 if(mpp_pe()==0) print *,
'LAYOUT: ', layout
816 & xflags=cyclic_global_domain, yflags=cyclic_global_domain)
827 if(ermsg /=
'') print *,ermsg
830 ids = (/ (i+100*pe, i=1,npmax) /)
832 if(ermsg /=
'') print *,ermsg
836 positions(:, 1) = (/ (drfts_com%xcmin + drfts_com%xcmax)/2., &
837 & (drfts_com%ycmin + drfts_com%ycmax)/2. /)
840 if(ermsg /=
'') print *,ermsg
844 velocity(:,1) = (/u0, v0/)
846 positions(:,1:drfts%np) = xmin + &
847 & modulo(drfts%positions(:,1:drfts%np) + dt*velocity(:,1:drfts%np)-xmin, xmax-xmin)
851 if(drfts%np > 0)
then 853 print
'(a,i6,a,i3,a,i3,a, i3, a,2f10.6)',
'PE: ',pe,
' it=', it,
' np=', drfts%np,
' ip=', i, &
854 &
' x,y=', drfts%positions(1,i), drfts%positions(2,i)
863 if(ermsg /=
'') print *,ermsg
865 call mpp_domains_exit
subroutine drifters_comm_set_comp_bounds(self, xmin, ymin, xmax, ymax)
subroutine drifters_core_set_ids(self, ids, ermesg)
subroutine, public drifters_comm_update(self, drfts, new_positions, comm, remove, max_add_remove)
subroutine, public drifters_core_set_positions(self, positions, ermesg)
subroutine, public drifters_core_new(self, nd, npdim, ermesg)
subroutine, public drifters_comm_new(self)
subroutine, public drifters_core_remove_and_add(self, indices_to_remove_in, ids_to_add, positions_to_add, ermesg)
character(len=input_str_length), dimension(:), allocatable, target, public input_nml_file
subroutine, public drifters_comm_set_pe_neighbors(self, domain)
subroutine, public drifters_comm_set_domain(self, domain, x, y, backoff_x, backoff_y)
subroutine drifters_comm_set_data_bounds(self, xmin, ymin, xmax, ymax)
subroutine, public drifters_comm_del(self)
subroutine, public drifters_comm_gather(self, drfts, dinp, lons, lats, do_save_lonlat, filename, root, mycomm)
subroutine, public drifters_core_del(self, ermesg)