45#include "../base/base_uses.f90"
76 LOGICAL,
PRIVATE,
PARAMETER :: debug_this_module = .false.
77 CHARACTER(len=*),
PARAMETER,
PRIVATE :: modulen =
'realspace_grid_types'
82 INTEGER :: distribution_layout(3) = -1
83 REAL(kind=
dp) :: memory_factor = 0.0_dp
84 LOGICAL :: lock_distribution = .false.
86 REAL(kind=
dp) :: halo_reduction_factor = 1.0_dp
93 INTEGER :: ref_count = 0
95 INTEGER(int_8) :: ngpts = 0_int_8
96 INTEGER,
DIMENSION(3) :: npts = 0
97 INTEGER,
DIMENSION(3) :: lb = 0
98 INTEGER,
DIMENSION(3) :: ub = 0
100 INTEGER :: border = 0
102 INTEGER,
DIMENSION(3) :: perd = -1
103 REAL(kind=
dp),
DIMENSION(3, 3) :: dh = 0.0_dp
104 REAL(kind=
dp),
DIMENSION(3, 3) :: dh_inv = 0.0_dp
105 LOGICAL :: orthorhombic = .true.
107 LOGICAL :: parallel = .true.
108 LOGICAL :: distributed = .true.
112 INTEGER :: my_pos = -1
113 INTEGER :: group_size = 0
114 INTEGER,
DIMENSION(3) :: group_dim = -1
115 INTEGER,
DIMENSION(3) :: group_coor = -1
116 INTEGER,
DIMENSION(3) :: neighbours = -1
119 INTEGER,
DIMENSION(:, :),
ALLOCATABLE :: lb_global
120 INTEGER,
DIMENSION(:, :),
ALLOCATABLE :: ub_global
122 INTEGER,
DIMENSION(:, :),
ALLOCATABLE :: rank2coord
123 INTEGER,
DIMENSION(:, :, :),
ALLOCATABLE :: coord2rank
125 INTEGER,
DIMENSION(:),
ALLOCATABLE :: x2coord
126 INTEGER,
DIMENSION(:),
ALLOCATABLE :: y2coord
127 INTEGER,
DIMENSION(:),
ALLOCATABLE :: z2coord
129 INTEGER :: my_virtual_pos = -1
130 INTEGER,
DIMENSION(3) :: virtual_group_coor = -1
132 INTEGER,
DIMENSION(:),
ALLOCATABLE :: virtual2real, real2virtual
140 INTEGER :: ngpts_local = -1
141 INTEGER,
DIMENSION(3) :: npts_local = -1
142 INTEGER,
DIMENSION(3) :: lb_local = -1
143 INTEGER,
DIMENSION(3) :: ub_local = -1
144 INTEGER,
DIMENSION(3) :: lb_real = -1
145 INTEGER,
DIMENSION(3) :: ub_real = -1
147 INTEGER,
DIMENSION(:),
ALLOCATABLE :: px, py, pz
149 REAL(kind=
dp),
DIMENSION(:, :, :),
CONTIGUOUS,
POINTER :: r => null()
174 INTEGER,
INTENT(IN) :: rank_in
175 INTEGER,
DIMENSION(3),
INTENT(IN) :: shift
180 coord =
modulo(rs_desc%rank2coord(:, rank_in) + shift, rs_desc%group_dim)
181 rank_out = rs_desc%coord2rank(coord(1), coord(2), coord(3))
205 INTEGER,
INTENT(IN),
OPTIONAL :: border_points
207 CHARACTER(LEN=*),
PARAMETER :: routinen =
'rs_grid_create_descriptor'
209 INTEGER :: border_size, dir, handle, i, j, k, l, &
210 lb(2), min_npts_real, n_slices(3), &
211 n_slices_tmp(3), nmin
213 REAL(kind=
dp) :: ratio, ratio_best, volume, volume_dist
215 CALL timeset(routinen, handle)
217 IF (
PRESENT(border_points))
THEN
218 border_size = border_points
225 CALL pw_grid%para%group%sync()
231 desc%dh_inv = pw_grid%dh_inv
232 desc%orthorhombic = pw_grid%orthorhombic
238 desc%npts = pw_grid%npts
239 desc%ngpts = product(int(desc%npts, kind=
int_8))
240 desc%lb = pw_grid%bounds(1, :)
241 desc%ub = pw_grid%bounds(2, :)
242 desc%border = border_size
243 IF (border_size == 0)
THEN
248 desc%parallel = .false.
249 desc%distributed = .false.
258 desc%group_size = pw_grid%para%group%num_pe
259 desc%npts = pw_grid%npts
260 desc%ngpts = product(int(desc%npts, kind=
int_8))
261 desc%lb = pw_grid%bounds(1, :)
262 desc%ub = pw_grid%bounds(2, :)
265 IF (border_size == 0)
THEN
266 nmin = (input_settings%nsmax + 1)/2
267 nmin = max(0, nint(nmin*input_settings%halo_reduction_factor))
276 IF (border_size > 0)
THEN
277 CALL cp_abort(__location__, &
278 "An explicit border size > 0 is not yet working for "// &
279 "replicated realspace grids. Request DISTRIBUTION_TYPE "// &
280 "distributed for RS_GRID explicitly.")
286 ratio_best = -huge(ratio_best)
289 DO k = 1, min(desc%npts(3), desc%group_size)
290 DO j = 1, min(desc%npts(2), desc%group_size)
291 i = min(desc%npts(1), desc%group_size/(j*k))
292 n_slices_tmp = [i, j, k]
295 IF (product(n_slices_tmp) /= desc%group_size) cycle
299 IF (.NOT. all(pack(n_slices_tmp == input_settings%distribution_layout, &
300 [-1, -1, -1] /= input_settings%distribution_layout) &
307 IF (n_slices_tmp(dir) > 1)
THEN
308 DO l = 0, n_slices_tmp(dir) - 1
309 lb =
get_limit(desc%npts(dir), n_slices_tmp(dir), l)
310 IF (lb(2) - lb(1) + 1 + 2*nmin > desc%npts(dir)) overlap = .true.
320 ratio = product(real(desc%npts, kind=
dp)/n_slices_tmp)/ &
321 product(real(desc%npts, kind=
dp)/n_slices_tmp + &
322 merge([0.0_dp, 0.0_dp, 0.0_dp], 2*[1.06_dp*nmin, 1.05_dp*nmin, 1.03_dp*nmin], n_slices_tmp == [1, 1, 1]))
323 IF (ratio > ratio_best)
THEN
325 n_slices = n_slices_tmp
334 volume = product(real(desc%npts, kind=
dp))
335 volume_dist = product(real(desc%npts, kind=
dp)/n_slices + &
336 merge([0, 0, 0], 2*[nmin, nmin, nmin], n_slices == [1, 1, 1]))
337 IF (volume < volume_dist*input_settings%memory_factor)
THEN
344 desc%group_dim(:) = n_slices(:)
345 CALL desc%group%from_dup(pw_grid%para%group)
346 desc%group_size = desc%group%num_pe
347 desc%my_pos = desc%group%mepos
349 IF (all(n_slices == 1))
THEN
352 desc%border = border_size
353 IF (border_size == 0)
THEN
358 desc%distributed = .false.
359 desc%parallel = .true.
360 desc%group_coor(:) = 0
361 desc%my_virtual_pos = 0
363 ALLOCATE (desc%virtual2real(0:desc%group_size - 1))
364 ALLOCATE (desc%real2virtual(0:desc%group_size - 1))
366 DO i = 0, desc%group_size - 1
367 desc%virtual2real(i) = i
368 desc%real2virtual(i) = i
373 IF (border_size == 0)
THEN
376 IF (n_slices(dir) > 1) desc%perd(dir) = 0
384 desc%parallel = .true.
385 desc%distributed = .true.
388 ALLOCATE (desc%rank2coord(3, 0:desc%group_size - 1))
389 ALLOCATE (desc%coord2rank(0:desc%group_dim(1) - 1, 0:desc%group_dim(2) - 1, 0:desc%group_dim(3) - 1))
390 ALLOCATE (desc%lb_global(3, 0:desc%group_size - 1))
391 ALLOCATE (desc%ub_global(3, 0:desc%group_size - 1))
392 ALLOCATE (desc%x2coord(desc%lb(1):desc%ub(1)))
393 ALLOCATE (desc%y2coord(desc%lb(2):desc%ub(2)))
394 ALLOCATE (desc%z2coord(desc%lb(3):desc%ub(3)))
396 DO i = 0, desc%group_size - 1
398 desc%rank2coord(1, i) = i/(desc%group_dim(2)*desc%group_dim(3))
399 desc%rank2coord(2, i) =
modulo(i, desc%group_dim(2)*desc%group_dim(3)) &
401 desc%rank2coord(3, i) =
modulo(i, desc%group_dim(3))
403 IF (i == desc%my_pos)
THEN
404 desc%group_coor = desc%rank2coord(:, i)
407 desc%coord2rank(desc%rank2coord(1, i), desc%rank2coord(2, i), desc%rank2coord(3, i)) = i
409 desc%lb_global(:, i) = desc%lb
410 desc%ub_global(:, i) = desc%ub
412 IF (desc%group_dim(dir) > 1)
THEN
413 lb =
get_limit(desc%npts(dir), desc%group_dim(dir), desc%rank2coord(dir, i))
414 desc%lb_global(dir, i) = lb(1) + desc%lb(dir) - 1
415 desc%ub_global(dir, i) = lb(2) + desc%lb(dir) - 1
422 DO l = 0, desc%group_dim(dir) - 1
423 IF (desc%group_dim(dir) > 1)
THEN
424 lb =
get_limit(desc%npts(dir), desc%group_dim(dir), l)
425 lb = lb + desc%lb(dir) - 1
432 desc%x2coord(lb(1):lb(2)) = l
434 desc%y2coord(lb(1):lb(2)) = l
436 desc%z2coord(lb(1):lb(2)) = l
443 desc%neighbours(dir) = 0
444 IF ((n_slices(dir) > 1) .OR. (border_size > 0))
THEN
445 min_npts_real = huge(0)
446 DO l = 0, n_slices(dir) - 1
447 lb =
get_limit(desc%npts(dir), n_slices(dir), l)
448 min_npts_real = min(lb(2) - lb(1) + 1, min_npts_real)
450 desc%neighbours(dir) = (desc%border + min_npts_real - 1)/min_npts_real
454 ALLOCATE (desc%virtual2real(0:desc%group_size - 1))
455 ALLOCATE (desc%real2virtual(0:desc%group_size - 1))
457 DO i = 0, desc%group_size - 1
458 desc%virtual2real(i) = i
459 desc%real2virtual(i) = i
462 desc%my_virtual_pos = desc%real2virtual(desc%my_pos)
463 desc%virtual_group_coor(:) = desc%rank2coord(:, desc%my_virtual_pos)
468 CALL timestop(handle)
482 CHARACTER(LEN=*),
PARAMETER :: routinen =
'rs_grid_create'
486 CALL timeset(routinen, handle)
496 rs%lb_local = rs%lb_real - desc%border*(1 - desc%perd)
497 rs%ub_local = rs%ub_real + desc%border*(1 - desc%perd)
498 rs%npts_local = rs%ub_local - rs%lb_local + 1
499 rs%ngpts_local = product(rs%npts_local)
502 IF (all(rs%desc%group_dim == 1))
THEN
507 rs%lb_local = rs%lb_real - desc%border*(1 - desc%perd)
508 rs%ub_local = rs%ub_real + desc%border*(1 - desc%perd)
509 rs%npts_local = rs%ub_local - rs%lb_local + 1
510 rs%ngpts_local = product(rs%npts_local)
514 rs%lb_real = desc%lb_global(:, desc%my_virtual_pos)
515 rs%ub_real = desc%ub_global(:, desc%my_virtual_pos)
516 rs%lb_local = rs%lb_real - desc%border*(1 - desc%perd)
517 rs%ub_local = rs%ub_real + desc%border*(1 - desc%perd)
518 rs%npts_local = rs%ub_local - rs%lb_local + 1
519 rs%ngpts_local = product(rs%npts_local)
523 rs%r(rs%lb_local(1):rs%ub_local(1), &
524 rs%lb_local(2):rs%ub_local(2), &
525 rs%lb_local(3):rs%ub_local(3)) => rs%buffer%host_buffer
527 ALLOCATE (rs%px(desc%npts(1)))
528 ALLOCATE (rs%py(desc%npts(2)))
529 ALLOCATE (rs%pz(desc%npts(3)))
531 CALL timestop(handle)
554 INTEGER,
DIMENSION(:),
INTENT(IN) :: real2virtual
558 desc%real2virtual(:) = real2virtual
560 DO i = 0, desc%group_size - 1
561 desc%virtual2real(desc%real2virtual(i)) = i
564 desc%my_virtual_pos = desc%real2virtual(desc%my_pos)
566 IF (.NOT. all(desc%group_dim == 1))
THEN
567 desc%virtual_group_coor(:) = desc%rank2coord(:, desc%my_virtual_pos)
580 INTEGER,
INTENT(in) :: iounit
582 INTEGER :: dir, i, nn
583 REAL(kind=
dp) :: pp(3)
585 IF (rs%desc%parallel)
THEN
587 WRITE (iounit,
'(/,A,T71,I10)') &
588 " RS_GRID| Information for grid number ", rs%desc%pw%id_nr
590 WRITE (iounit,
'(A,I3,T30,2I8,T62,A,T71,I10)')
" RS_GRID| Bounds ", &
591 i, rs%desc%lb(i), rs%desc%ub(i),
"Points:", rs%desc%npts(i)
593 IF (.NOT. rs%desc%distributed)
THEN
594 WRITE (iounit,
'(A)')
" RS_GRID| Real space fully replicated"
595 WRITE (iounit,
'(A,T71,I10)') &
596 " RS_GRID| Group size ", rs%desc%group_dim(2)
599 IF (rs%desc%perd(dir) /= 1)
THEN
600 WRITE (iounit,
'(A,T71,I3,A)') &
601 " RS_GRID| Real space distribution over ", rs%desc%group_dim(dir),
" groups"
602 WRITE (iounit,
'(A,T71,I10)') &
603 " RS_GRID| Real space distribution along direction ", dir
604 WRITE (iounit,
'(A,T71,I10)') &
605 " RS_GRID| Border size ", rs%desc%border
610 IF (rs%desc%distributed)
THEN
612 IF (rs%desc%perd(dir) /= 1)
THEN
613 nn = rs%npts_local(dir)
614 CALL rs%desc%group%sum(nn)
615 pp(1) = real(nn, kind=
dp)/real(product(rs%desc%group_dim), kind=
dp)
616 nn = rs%npts_local(dir)
617 CALL rs%desc%group%max(nn)
618 pp(2) = real(nn, kind=
dp)
619 nn = rs%npts_local(dir)
620 CALL rs%desc%group%min(nn)
621 pp(3) = real(nn, kind=
dp)
623 WRITE (iounit,
'(A,T48,A)')
" RS_GRID| Distribution", &
625 WRITE (iounit,
'(A,T45,F12.1,2I12)')
" RS_GRID| Planes ", &
626 pp(1), nint(pp(2)), nint(pp(3))
634 WRITE (iounit,
'(/,A,T71,I10)') &
635 " RS_GRID| Information for grid number ", rs%desc%pw%id_nr
637 WRITE (iounit,
'(A,I3,T30,2I8,T62,A,T71,I10)')
" RS_GRID| Bounds ", &
638 i, rs%desc%lb(i), rs%desc%ub(i),
"Points:", rs%desc%npts(i)
655 CHARACTER(len=*),
PARAMETER :: routinen =
'transfer_rs2pw'
657 INTEGER :: handle, handle2, i
659 CALL timeset(routinen, handle2)
660 CALL timeset(routinen//
"_"//trim(adjustl(
cp_to_string(ceiling(pw%pw_grid%cutoff/10)*10))), handle)
662 IF (.NOT.
ASSOCIATED(rs%desc%pw, pw%pw_grid))
THEN
663 cpabort(
"Different rs and pw indentifiers")
666 IF (rs%desc%distributed)
THEN
667 CALL transfer_rs2pw_distributed(rs, pw)
668 ELSE IF (rs%desc%parallel)
THEN
669 CALL transfer_rs2pw_replicated(rs, pw)
671 IF (rs%desc%border == 0)
THEN
672 CALL dcopy(
SIZE(rs%r), rs%r, 1, pw%array, 1)
674 cpassert(lbound(pw%array, 3) == rs%lb_real(3))
676 DO i = rs%lb_real(3), rs%ub_real(3)
677 pw%array(:, :, i) = rs%r(rs%lb_real(1):rs%ub_real(1), &
678 rs%lb_real(2):rs%ub_real(2), i)
684 CALL timestop(handle)
685 CALL timestop(handle2)
699 CHARACTER(len=*),
PARAMETER :: routinen =
'transfer_pw2rs'
701 INTEGER :: handle, handle2, i, im, j, jm, k, km
703 CALL timeset(routinen, handle2)
704 CALL timeset(routinen//
"_"//trim(adjustl(
cp_to_string(ceiling(pw%pw_grid%cutoff/10)*10))), handle)
706 IF (.NOT.
ASSOCIATED(rs%desc%pw, pw%pw_grid))
THEN
707 cpabort(
"Different rs and pw indentifiers")
710 IF (rs%desc%distributed)
THEN
711 CALL transfer_pw2rs_distributed(rs, pw)
712 ELSE IF (rs%desc%parallel)
THEN
713 CALL transfer_pw2rs_replicated(rs, pw)
715 IF (rs%desc%border == 0)
THEN
716 CALL dcopy(
SIZE(rs%r), pw%array, 1, rs%r, 1)
721 DO k = rs%lb_local(3), rs%ub_local(3)
722 IF (k < rs%lb_real(3))
THEN
723 km = k + rs%desc%npts(3)
724 ELSE IF (k > rs%ub_real(3))
THEN
725 km = k - rs%desc%npts(3)
729 DO j = rs%lb_local(2), rs%ub_local(2)
730 IF (j < rs%lb_real(2))
THEN
731 jm = j + rs%desc%npts(2)
732 ELSE IF (j > rs%ub_real(2))
THEN
733 jm = j - rs%desc%npts(2)
737 DO i = rs%lb_local(1), rs%ub_local(1)
738 IF (i < rs%lb_real(1))
THEN
739 im = i + rs%desc%npts(1)
740 ELSE IF (i > rs%ub_real(1))
THEN
741 im = i - rs%desc%npts(1)
745 rs%r(i, j, k) = pw%array(im, jm, km)
753 CALL timestop(handle)
754 CALL timestop(handle2)
763 SUBROUTINE transfer_rs2pw_replicated(rs, pw)
767 INTEGER :: dest, ii, ip, ix, iy, iz, nma, nn, s(3), &
769 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: rcount
770 INTEGER,
DIMENSION(3) :: lb, ub
771 INTEGER,
DIMENSION(:, :, :, :),
POINTER :: bounds_by_rank
772 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: recvbuf, sendbuf, swaparray
775 bounds_by_rank => pw%pw_grid%para%bo
776 associate(np => pw%pw_grid%para%group%num_pe, bo => bounds_by_rank(:, :, :, 1), &
777 pbo => pw%pw_grid%bounds, group => pw%pw_grid%para%group, mepos => pw%pw_grid%para%group%mepos, &
779 ALLOCATE (rcount(0:np - 1))
781 rcount(ip - 1) = product(bo(2, :, ip) - bo(1, :, ip) + 1)
783 nma = maxval(rcount(0:np - 1))
784 ALLOCATE (sendbuf(nma), recvbuf(nma))
785 sendbuf = 1.0e99_dp; recvbuf = 1.0e99_dp
790 dest =
modulo(mepos + 1, np)
791 source =
modulo(mepos - 1, np)
796 lb = pbo(1, :) + bo(1, :,
modulo(mepos - ip, np) + 1) - 1
797 ub = pbo(1, :) + bo(2, :,
modulo(mepos - ip, np) + 1) - 1
806 ii = (iz - lb(3))*s(1)*s(2) + (ix - lb(1)) + 1
808 sendbuf(ii) = sendbuf(ii) + grid(ix, iy, iz)
814 CALL group%sendrecv(sendbuf, dest, recvbuf, source, 13)
815 CALL move_alloc(sendbuf, swaparray)
816 CALL move_alloc(recvbuf, sendbuf)
817 CALL move_alloc(swaparray, recvbuf)
822 CALL dcopy(nn, sendbuf, 1, pw%array, 1)
828 END SUBROUTINE transfer_rs2pw_replicated
835 SUBROUTINE transfer_pw2rs_replicated(rs, pw)
837 TYPE(pw_r3d_rs_type),
INTENT(IN) :: pw
839 INTEGER :: dest, i, ii, im, ip, ix, iy, iz, j, jm, &
840 k, km, nma, nn, source
841 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: rcount
842 INTEGER,
DIMENSION(3) :: lb, ub
843 INTEGER,
DIMENSION(:, :, :, :),
POINTER :: bounds_by_rank
844 REAL(kind=dp),
ALLOCATABLE,
DIMENSION(:) :: recvbuf, sendbuf, swaparray
845 TYPE(mp_request_type),
DIMENSION(2) :: req
848 bounds_by_rank => pw%pw_grid%para%bo
849 associate(np => pw%pw_grid%para%group%num_pe, bo => bounds_by_rank(:, :, :, 1), &
850 pbo => pw%pw_grid%bounds, group => pw%pw_grid%para%group, mepos => pw%pw_grid%para%group%mepos, &
852 ALLOCATE (rcount(0:np - 1))
854 rcount(ip - 1) = product(bo(2, :, ip) - bo(1, :, ip) + 1)
856 nma = maxval(rcount(0:np - 1))
857 ALLOCATE (sendbuf(nma), recvbuf(nma))
858 sendbuf = 1.0e99_dp; recvbuf = 1.0e99_dp
864 CALL dcopy(nn, pw%array, 1, sendbuf, 1)
866 dest =
modulo(mepos + 1, np)
867 source =
modulo(mepos - 1, np)
871 IF (ip /= np - 1)
THEN
872 CALL group%isendrecv(sendbuf, dest, recvbuf, source, &
875 lb = pbo(1, :) + bo(1, :,
modulo(mepos - ip, np) + 1) - 1
876 ub = pbo(1, :) + bo(2, :,
modulo(mepos - ip, np) + 1) - 1
884 grid(ix, iy, iz) = sendbuf(ii)
888 IF (ip /= np - 1)
THEN
891 CALL move_alloc(sendbuf, swaparray)
892 CALL move_alloc(recvbuf, sendbuf)
893 CALL move_alloc(swaparray, recvbuf)
895 IF (rs%desc%border > 0)
THEN
899 DO k = rs%lb_local(3), rs%ub_local(3)
900 IF (k < rs%lb_real(3))
THEN
901 km = k + rs%desc%npts(3)
902 ELSE IF (k > rs%ub_real(3))
THEN
903 km = k - rs%desc%npts(3)
907 DO j = rs%lb_local(2), rs%ub_local(2)
908 IF (j < rs%lb_real(2))
THEN
909 jm = j + rs%desc%npts(2)
910 ELSE IF (j > rs%ub_real(2))
THEN
911 jm = j - rs%desc%npts(2)
915 DO i = rs%lb_local(1), rs%ub_local(1)
916 IF (i < rs%lb_real(1))
THEN
917 im = i + rs%desc%npts(1)
918 ELSE IF (i > rs%ub_real(1))
THEN
919 im = i - rs%desc%npts(1)
923 rs%r(i, j, k) = rs%r(im, jm, km)
935 END SUBROUTINE transfer_pw2rs_replicated
959 SUBROUTINE transfer_rs2pw_distributed(rs, pw)
961 TYPE(pw_r3d_rs_type),
INTENT(IN) :: pw
963 CHARACTER(LEN=200) :: error_string
964 INTEGER :: completed, dest_down, dest_up, i, idir, j, k, lb, my_id, my_pw_rank, my_rs_rank, &
965 n_shifts, nn, num_threads, position, source_down, source_up, ub, x, y, z
966 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: dshifts, recv_disps, recv_sizes, &
967 send_disps, send_sizes, ushifts
968 INTEGER,
ALLOCATABLE,
DIMENSION(:, :) :: bounds, recv_tasks, send_tasks
969 INTEGER,
DIMENSION(2) :: neighbours, pos
970 INTEGER,
DIMENSION(3) :: coords, lb_recv, lb_recv_down, lb_recv_up, lb_send, lb_send_down, &
971 lb_send_up, ub_recv, ub_recv_down, ub_recv_up, ub_send, ub_send_down, ub_send_up
972 LOGICAL,
DIMENSION(3) :: halo_swapped
973 REAL(kind=dp) :: pw_sum, rs_sum
974 REAL(kind=dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: recv_buf_3d_down, recv_buf_3d_up, &
975 send_buf_3d_down, send_buf_3d_up
976 TYPE(cp_1d_r_p_type),
ALLOCATABLE,
DIMENSION(:) :: recv_bufs, send_bufs
977 TYPE(mp_request_type),
ALLOCATABLE,
DIMENSION(:) :: recv_reqs, send_reqs
978 TYPE(mp_request_type),
DIMENSION(4) :: req
984 IF (debug_this_module)
THEN
985 rs_sum = accurate_sum(rs%r)*abs(det_3x3(rs%desc%dh))
986 CALL rs%desc%group%sum(rs_sum)
989 halo_swapped = .false.
996 IF (rs%desc%perd(idir) /= 1)
THEN
998 ALLOCATE (dshifts(0:rs%desc%neighbours(idir)))
999 ALLOCATE (ushifts(0:rs%desc%neighbours(idir)))
1005 DO n_shifts = 1, min(rs%desc%neighbours(idir), rs%desc%group_dim(idir) - 1)
1009 position =
modulo(rs%desc%virtual_group_coor(idir) - n_shifts, rs%desc%group_dim(idir))
1010 neighbours = get_limit(rs%desc%npts(idir), rs%desc%group_dim(idir), position)
1011 dshifts(n_shifts) = dshifts(n_shifts - 1) + (neighbours(2) - neighbours(1) + 1)
1013 position =
modulo(rs%desc%virtual_group_coor(idir) + n_shifts, rs%desc%group_dim(idir))
1014 neighbours = get_limit(rs%desc%npts(idir), rs%desc%group_dim(idir), position)
1015 ushifts(n_shifts) = ushifts(n_shifts - 1) + (neighbours(2) - neighbours(1) + 1)
1021 CALL cart_shift(rs, idir, -1*n_shifts, source_down, dest_down)
1023 lb_send_down(:) = rs%lb_local(:)
1024 lb_recv_down(:) = rs%lb_local(:)
1025 ub_recv_down(:) = rs%ub_local(:)
1026 ub_send_down(:) = rs%ub_local(:)
1028 IF (dshifts(n_shifts - 1) <= rs%desc%border)
THEN
1029 ub_send_down(idir) = lb_send_down(idir) + rs%desc%border - 1 - dshifts(n_shifts - 1)
1030 lb_send_down(idir) = max(lb_send_down(idir), &
1031 lb_send_down(idir) + rs%desc%border - dshifts(n_shifts))
1033 ub_recv_down(idir) = ub_recv_down(idir) - rs%desc%border
1034 lb_recv_down(idir) = max(lb_recv_down(idir) + rs%desc%border, &
1035 ub_recv_down(idir) - rs%desc%border + 1 + ushifts(n_shifts - 1))
1037 lb_send_down(idir) = 0
1038 ub_send_down(idir) = -1
1039 lb_recv_down(idir) = 0
1040 ub_recv_down(idir) = -1
1044 IF (halo_swapped(i))
THEN
1045 lb_send_down(i) = rs%lb_real(i)
1046 ub_send_down(i) = rs%ub_real(i)
1047 lb_recv_down(i) = rs%lb_real(i)
1048 ub_recv_down(i) = rs%ub_real(i)
1053 ALLOCATE (recv_buf_3d_down(lb_recv_down(1):ub_recv_down(1), &
1054 lb_recv_down(2):ub_recv_down(2), lb_recv_down(3):ub_recv_down(3)))
1055 CALL rs%desc%group%irecv(recv_buf_3d_down, source_down, req(1))
1058 nn = product(ub_send_down - lb_send_down + 1)
1059 ALLOCATE (send_buf_3d_down(lb_send_down(1):ub_send_down(1), &
1060 lb_send_down(2):ub_send_down(2), lb_send_down(3):ub_send_down(3)))
1067 IF (my_id < num_threads)
THEN
1068 lb = lb_send_down(3) + ((ub_send_down(3) - lb_send_down(3) + 1)*my_id)/num_threads
1069 ub = lb_send_down(3) + ((ub_send_down(3) - lb_send_down(3) + 1)*(my_id + 1))/num_threads - 1
1071 send_buf_3d_down(lb_send_down(1):ub_send_down(1), lb_send_down(2):ub_send_down(2), &
1072 lb:ub) = rs%r(lb_send_down(1):ub_send_down(1), &
1073 lb_send_down(2):ub_send_down(2), lb:ub)
1077 CALL rs%desc%group%isend(send_buf_3d_down, dest_down, req(3))
1080 CALL cart_shift(rs, idir, n_shifts, source_up, dest_up)
1082 lb_send_up(:) = rs%lb_local(:)
1083 lb_recv_up(:) = rs%lb_local(:)
1084 ub_recv_up(:) = rs%ub_local(:)
1085 ub_send_up(:) = rs%ub_local(:)
1087 IF (ushifts(n_shifts - 1) <= rs%desc%border)
THEN
1089 lb_send_up(idir) = ub_send_up(idir) - rs%desc%border + 1 + ushifts(n_shifts - 1)
1090 ub_send_up(idir) = min(ub_send_up(idir), &
1091 ub_send_up(idir) - rs%desc%border + ushifts(n_shifts))
1093 lb_recv_up(idir) = lb_recv_up(idir) + rs%desc%border
1094 ub_recv_up(idir) = min(ub_recv_up(idir) - rs%desc%border, &
1095 lb_recv_up(idir) + rs%desc%border - 1 - dshifts(n_shifts - 1))
1097 lb_send_up(idir) = 0
1098 ub_send_up(idir) = -1
1099 lb_recv_up(idir) = 0
1100 ub_recv_up(idir) = -1
1104 IF (halo_swapped(i))
THEN
1105 lb_send_up(i) = rs%lb_real(i)
1106 ub_send_up(i) = rs%ub_real(i)
1107 lb_recv_up(i) = rs%lb_real(i)
1108 ub_recv_up(i) = rs%ub_real(i)
1113 ALLOCATE (recv_buf_3d_up(lb_recv_up(1):ub_recv_up(1), &
1114 lb_recv_up(2):ub_recv_up(2), lb_recv_up(3):ub_recv_up(3)))
1115 CALL rs%desc%group%irecv(recv_buf_3d_up, source_up, req(2))
1118 nn = product(ub_send_up - lb_send_up + 1)
1119 ALLOCATE (send_buf_3d_up(lb_send_up(1):ub_send_up(1), &
1120 lb_send_up(2):ub_send_up(2), lb_send_up(3):ub_send_up(3)))
1127 IF (my_id < num_threads)
THEN
1128 lb = lb_send_up(3) + ((ub_send_up(3) - lb_send_up(3) + 1)*my_id)/num_threads
1129 ub = lb_send_up(3) + ((ub_send_up(3) - lb_send_up(3) + 1)*(my_id + 1))/num_threads - 1
1131 send_buf_3d_up(lb_send_up(1):ub_send_up(1), lb_send_up(2):ub_send_up(2), &
1132 lb:ub) = rs%r(lb_send_up(1):ub_send_up(1), &
1133 lb_send_up(2):ub_send_up(2), lb:ub)
1137 CALL rs%desc%group%isend(send_buf_3d_up, dest_up, req(4))
1143 CALL mp_waitany(req(1:2), completed)
1145 IF (completed == 1)
THEN
1148 IF (ub_recv_down(idir) >= lb_recv_down(idir))
THEN
1155 IF (my_id < num_threads)
THEN
1156 lb = lb_recv_down(3) + ((ub_recv_down(3) - lb_recv_down(3) + 1)*my_id)/num_threads
1157 ub = lb_recv_down(3) + ((ub_recv_down(3) - lb_recv_down(3) + 1)*(my_id + 1))/num_threads - 1
1159 rs%r(lb_recv_down(1):ub_recv_down(1), &
1160 lb_recv_down(2):ub_recv_down(2), lb:ub) = &
1161 rs%r(lb_recv_down(1):ub_recv_down(1), &
1162 lb_recv_down(2):ub_recv_down(2), lb:ub) + &
1163 recv_buf_3d_down(:, :, lb:ub)
1167 DEALLOCATE (recv_buf_3d_down)
1171 IF (ub_recv_up(idir) >= lb_recv_up(idir))
THEN
1178 IF (my_id < num_threads)
THEN
1179 lb = lb_recv_up(3) + ((ub_recv_up(3) - lb_recv_up(3) + 1)*my_id)/num_threads
1180 ub = lb_recv_up(3) + ((ub_recv_up(3) - lb_recv_up(3) + 1)*(my_id + 1))/num_threads - 1
1182 rs%r(lb_recv_up(1):ub_recv_up(1), &
1183 lb_recv_up(2):ub_recv_up(2), lb:ub) = &
1184 rs%r(lb_recv_up(1):ub_recv_up(1), &
1185 lb_recv_up(2):ub_recv_up(2), lb:ub) + &
1186 recv_buf_3d_up(:, :, lb:ub)
1190 DEALLOCATE (recv_buf_3d_up)
1197 CALL mp_waitall(req(3:4))
1199 DEALLOCATE (send_buf_3d_down)
1200 DEALLOCATE (send_buf_3d_up)
1203 DEALLOCATE (dshifts)
1204 DEALLOCATE (ushifts)
1208 halo_swapped(idir) = .true.
1213 ALLOCATE (bounds(0:pw%pw_grid%para%group%num_pe - 1, 1:4))
1216 DO i = 0, pw%pw_grid%para%group%num_pe - 1
1217 bounds(i, 1:2) = pw%pw_grid%para%bo(1:2, 1, i, 1)
1218 bounds(i, 3:4) = pw%pw_grid%para%bo(1:2, 2, i, 1)
1219 bounds(i, 1:2) = bounds(i, 1:2) - pw%pw_grid%npts(1)/2 - 1
1220 bounds(i, 3:4) = bounds(i, 3:4) - pw%pw_grid%npts(2)/2 - 1
1223 ALLOCATE (send_tasks(0:pw%pw_grid%para%group%num_pe - 1, 1:6))
1224 ALLOCATE (send_sizes(0:pw%pw_grid%para%group%num_pe - 1))
1225 ALLOCATE (send_disps(0:pw%pw_grid%para%group%num_pe - 1))
1226 ALLOCATE (recv_tasks(0:pw%pw_grid%para%group%num_pe - 1, 1:6))
1227 ALLOCATE (recv_sizes(0:pw%pw_grid%para%group%num_pe - 1))
1228 ALLOCATE (recv_disps(0:pw%pw_grid%para%group%num_pe - 1))
1229 send_tasks(:, 1) = 1
1230 send_tasks(:, 2) = 0
1231 send_tasks(:, 3) = 1
1232 send_tasks(:, 4) = 0
1233 send_tasks(:, 5) = 1
1234 send_tasks(:, 6) = 0
1238 my_rs_rank = rs%desc%my_pos
1239 my_pw_rank = pw%pw_grid%para%group%mepos
1250 DO i = 0, rs%desc%group_size - 1
1252 coords(:) = rs%desc%rank2coord(:, rs%desc%real2virtual(i))
1256 pos(:) = get_limit(rs%desc%npts(idir), rs%desc%group_dim(idir), coords(idir))
1257 pos(:) = pos(:) - rs%desc%npts(idir)/2 - 1
1258 lb_send(idir) = pos(1)
1259 ub_send(idir) = pos(2)
1262 IF (lb_send(1) > bounds(my_rs_rank, 2)) cycle
1263 IF (ub_send(1) < bounds(my_rs_rank, 1)) cycle
1264 IF (lb_send(2) > bounds(my_rs_rank, 4)) cycle
1265 IF (ub_send(2) < bounds(my_rs_rank, 3)) cycle
1267 recv_tasks(i, 1) = max(lb_send(1), bounds(my_rs_rank, 1))
1268 recv_tasks(i, 2) = min(ub_send(1), bounds(my_rs_rank, 2))
1269 recv_tasks(i, 3) = max(lb_send(2), bounds(my_rs_rank, 3))
1270 recv_tasks(i, 4) = min(ub_send(2), bounds(my_rs_rank, 4))
1271 recv_tasks(i, 5) = lb_send(3)
1272 recv_tasks(i, 6) = ub_send(3)
1273 recv_sizes(i) = (recv_tasks(i, 2) - recv_tasks(i, 1) + 1)* &
1274 (recv_tasks(i, 4) - recv_tasks(i, 3) + 1)*(recv_tasks(i, 6) - recv_tasks(i, 5) + 1)
1279 coords(:) = rs%desc%rank2coord(:, rs%desc%real2virtual(my_rs_rank))
1281 pos(:) = get_limit(rs%desc%npts(idir), rs%desc%group_dim(idir), coords(idir))
1282 pos(:) = pos(:) - rs%desc%npts(idir)/2 - 1
1283 lb_send(idir) = pos(1)
1284 ub_send(idir) = pos(2)
1287 lb_recv(:) = lb_send(:)
1288 ub_recv(:) = ub_send(:)
1291 DO j = 0, pw%pw_grid%para%group%num_pe - 1
1293 IF (lb_send(1) > bounds(j, 2)) cycle
1294 IF (ub_send(1) < bounds(j, 1)) cycle
1295 IF (lb_send(2) > bounds(j, 4)) cycle
1296 IF (ub_send(2) < bounds(j, 3)) cycle
1298 send_tasks(j, 1) = max(lb_send(1), bounds(j, 1))
1299 send_tasks(j, 2) = min(ub_send(1), bounds(j, 2))
1300 send_tasks(j, 3) = max(lb_send(2), bounds(j, 3))
1301 send_tasks(j, 4) = min(ub_send(2), bounds(j, 4))
1302 send_tasks(j, 5) = lb_send(3)
1303 send_tasks(j, 6) = ub_send(3)
1304 send_sizes(j) = (send_tasks(j, 2) - send_tasks(j, 1) + 1)* &
1305 (send_tasks(j, 4) - send_tasks(j, 3) + 1)*(send_tasks(j, 6) - send_tasks(j, 5) + 1)
1312 DO i = 1, pw%pw_grid%para%group%num_pe - 1
1313 send_disps(i) = send_disps(i - 1) + send_sizes(i - 1)
1314 recv_disps(i) = recv_disps(i - 1) + recv_sizes(i - 1)
1317 cpassert(sum(send_sizes) == product(ub_recv - lb_recv + 1))
1319 ALLOCATE (send_bufs(0:rs%desc%group_size - 1))
1320 ALLOCATE (recv_bufs(0:rs%desc%group_size - 1))
1322 DO i = 0, rs%desc%group_size - 1
1323 IF (send_sizes(i) /= 0)
THEN
1324 ALLOCATE (send_bufs(i)%array(send_sizes(i)))
1326 NULLIFY (send_bufs(i)%array)
1328 IF (recv_sizes(i) /= 0)
THEN
1329 ALLOCATE (recv_bufs(i)%array(recv_sizes(i)))
1331 NULLIFY (recv_bufs(i)%array)
1335 ALLOCATE (recv_reqs(0:rs%desc%group_size - 1))
1336 recv_reqs = mp_request_null
1338 DO i = 0, rs%desc%group_size - 1
1339 IF (recv_sizes(i) /= 0)
THEN
1340 CALL rs%desc%group%irecv(recv_bufs(i)%array, i, recv_reqs(i))
1348 DO i = 0, rs%desc%group_size - 1
1350 DO z = send_tasks(i, 5), send_tasks(i, 6)
1351 DO y = send_tasks(i, 3), send_tasks(i, 4)
1352 DO x = send_tasks(i, 1), send_tasks(i, 2)
1354 send_bufs(i)%array(k) = rs%r(x, y, z)
1361 ALLOCATE (send_reqs(0:rs%desc%group_size - 1))
1362 send_reqs = mp_request_null
1364 DO i = 0, rs%desc%group_size - 1
1365 IF (send_sizes(i) /= 0)
THEN
1366 CALL rs%desc%group%isend(send_bufs(i)%array, i, send_reqs(i))
1372 DO i = 0, rs%desc%group_size - 1
1373 IF (recv_sizes(i) == 0) cycle
1375 CALL mp_waitany(recv_reqs, completed)
1377 DO z = recv_tasks(completed - 1, 5), recv_tasks(completed - 1, 6)
1378 DO y = recv_tasks(completed - 1, 3), recv_tasks(completed - 1, 4)
1379 DO x = recv_tasks(completed - 1, 1), recv_tasks(completed - 1, 2)
1381 pw%array(x, y, z) = recv_bufs(completed - 1)%array(k)
1387 CALL mp_waitall(send_reqs)
1389 DEALLOCATE (recv_reqs)
1390 DEALLOCATE (send_reqs)
1392 DO i = 0, rs%desc%group_size - 1
1393 IF (
ASSOCIATED(send_bufs(i)%array))
THEN
1394 DEALLOCATE (send_bufs(i)%array)
1396 IF (
ASSOCIATED(recv_bufs(i)%array))
THEN
1397 DEALLOCATE (recv_bufs(i)%array)
1401 DEALLOCATE (send_bufs)
1402 DEALLOCATE (recv_bufs)
1403 DEALLOCATE (send_tasks)
1404 DEALLOCATE (send_sizes)
1405 DEALLOCATE (send_disps)
1406 DEALLOCATE (recv_tasks)
1407 DEALLOCATE (recv_sizes)
1408 DEALLOCATE (recv_disps)
1410 IF (debug_this_module)
THEN
1412 pw_sum = pw_integrate_function(pw)
1413 IF (abs(pw_sum - rs_sum)/max(1.0_dp, abs(pw_sum), abs(rs_sum)) > epsilon(rs_sum)*1000)
THEN
1414 WRITE (error_string,
'(A,6(1X,I4.4),3F25.16)')
"rs_pw_transfer_distributed", &
1415 rs%desc%npts, rs%desc%group_dim, pw_sum, rs_sum, abs(pw_sum - rs_sum)
1416 CALL cp_abort(__location__, &
1417 error_string//
" Please report this bug ... quick workaround: use "// &
1418 "DISTRIBUTION_TYPE REPLICATED")
1422 END SUBROUTINE transfer_rs2pw_distributed
1446 SUBROUTINE transfer_pw2rs_distributed(rs, pw)
1448 TYPE(pw_r3d_rs_type),
INTENT(IN) :: pw
1450 INTEGER :: completed, dest_down, dest_up, i, idir, j, k, lb, my_id, my_pw_rank, my_rs_rank, &
1451 n_shifts, nn, num_threads, position, source_down, source_up, ub, x, y, z
1452 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: dshifts, recv_disps, recv_sizes, &
1453 send_disps, send_sizes, ushifts
1454 INTEGER,
ALLOCATABLE,
DIMENSION(:, :) :: bounds, recv_tasks, send_tasks
1455 INTEGER,
DIMENSION(2) :: neighbours, pos
1456 INTEGER,
DIMENSION(3) :: coords, lb_recv, lb_recv_down, lb_recv_up, lb_send, lb_send_down, &
1457 lb_send_up, ub_recv, ub_recv_down, ub_recv_up, ub_send, ub_send_down, ub_send_up
1458 LOGICAL,
DIMENSION(3) :: halo_swapped
1459 REAL(kind=dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: recv_buf_3d_down, recv_buf_3d_up, &
1460 send_buf_3d_down, send_buf_3d_up
1461 TYPE(cp_1d_r_p_type),
ALLOCATABLE,
DIMENSION(:) :: recv_bufs, send_bufs
1462 TYPE(mp_request_type),
ALLOCATABLE,
DIMENSION(:) :: recv_reqs, send_reqs
1463 TYPE(mp_request_type),
DIMENSION(4) :: req
1472 ALLOCATE (bounds(0:pw%pw_grid%para%group%num_pe - 1, 1:4))
1474 DO i = 0, pw%pw_grid%para%group%num_pe - 1
1475 bounds(i, 1:2) = pw%pw_grid%para%bo(1:2, 1, i, 1)
1476 bounds(i, 3:4) = pw%pw_grid%para%bo(1:2, 2, i, 1)
1477 bounds(i, 1:2) = bounds(i, 1:2) - pw%pw_grid%npts(1)/2 - 1
1478 bounds(i, 3:4) = bounds(i, 3:4) - pw%pw_grid%npts(2)/2 - 1
1481 ALLOCATE (send_tasks(0:pw%pw_grid%para%group%num_pe - 1, 1:6))
1482 ALLOCATE (send_sizes(0:pw%pw_grid%para%group%num_pe - 1))
1483 ALLOCATE (send_disps(0:pw%pw_grid%para%group%num_pe - 1))
1484 ALLOCATE (recv_tasks(0:pw%pw_grid%para%group%num_pe - 1, 1:6))
1485 ALLOCATE (recv_sizes(0:pw%pw_grid%para%group%num_pe - 1))
1486 ALLOCATE (recv_disps(0:pw%pw_grid%para%group%num_pe - 1))
1489 send_tasks(:, 1) = 1
1490 send_tasks(:, 2) = 0
1491 send_tasks(:, 3) = 1
1492 send_tasks(:, 4) = 0
1493 send_tasks(:, 5) = 1
1494 send_tasks(:, 6) = 0
1498 recv_tasks(:, 1) = 1
1499 recv_tasks(:, 2) = 0
1500 send_tasks(:, 3) = 1
1501 send_tasks(:, 4) = 0
1502 send_tasks(:, 5) = 1
1503 send_tasks(:, 6) = 0
1506 my_rs_rank = rs%desc%my_pos
1507 my_pw_rank = pw%pw_grid%para%group%mepos
1520 DO i = 0, pw%pw_grid%para%group%num_pe - 1
1522 coords(:) = rs%desc%rank2coord(:, rs%desc%real2virtual(i))
1526 pos(:) = get_limit(rs%desc%npts(idir), rs%desc%group_dim(idir), coords(idir))
1527 pos(:) = pos(:) - rs%desc%npts(idir)/2 - 1
1528 lb_send(idir) = pos(1)
1529 ub_send(idir) = pos(2)
1532 IF (ub_send(1) < bounds(my_rs_rank, 1)) cycle
1533 IF (lb_send(1) > bounds(my_rs_rank, 2)) cycle
1534 IF (ub_send(2) < bounds(my_rs_rank, 3)) cycle
1535 IF (lb_send(2) > bounds(my_rs_rank, 4)) cycle
1537 send_tasks(i, 1) = max(lb_send(1), bounds(my_rs_rank, 1))
1538 send_tasks(i, 2) = min(ub_send(1), bounds(my_rs_rank, 2))
1539 send_tasks(i, 3) = max(lb_send(2), bounds(my_rs_rank, 3))
1540 send_tasks(i, 4) = min(ub_send(2), bounds(my_rs_rank, 4))
1541 send_tasks(i, 5) = lb_send(3)
1542 send_tasks(i, 6) = ub_send(3)
1543 send_sizes(i) = (send_tasks(i, 2) - send_tasks(i, 1) + 1)* &
1544 (send_tasks(i, 4) - send_tasks(i, 3) + 1)*(send_tasks(i, 6) - send_tasks(i, 5) + 1)
1549 coords(:) = rs%desc%rank2coord(:, rs%desc%real2virtual(my_rs_rank))
1551 pos(:) = get_limit(rs%desc%npts(idir), rs%desc%group_dim(idir), coords(idir))
1552 pos(:) = pos(:) - rs%desc%npts(idir)/2 - 1
1553 lb_send(idir) = pos(1)
1554 ub_send(idir) = pos(2)
1557 lb_recv(:) = lb_send(:)
1558 ub_recv(:) = ub_send(:)
1562 DO j = 0, pw%pw_grid%para%group%num_pe - 1
1564 IF (ub_send(1) < bounds(j, 1)) cycle
1565 IF (lb_send(1) > bounds(j, 2)) cycle
1566 IF (ub_send(2) < bounds(j, 3)) cycle
1567 IF (lb_send(2) > bounds(j, 4)) cycle
1569 recv_tasks(j, 1) = max(lb_send(1), bounds(j, 1))
1570 recv_tasks(j, 2) = min(ub_send(1), bounds(j, 2))
1571 recv_tasks(j, 3) = max(lb_send(2), bounds(j, 3))
1572 recv_tasks(j, 4) = min(ub_send(2), bounds(j, 4))
1573 recv_tasks(j, 5) = lb_send(3)
1574 recv_tasks(j, 6) = ub_send(3)
1575 recv_sizes(j) = (recv_tasks(j, 2) - recv_tasks(j, 1) + 1)* &
1576 (recv_tasks(j, 4) - recv_tasks(j, 3) + 1)*(recv_tasks(j, 6) - recv_tasks(j, 5) + 1)
1583 DO i = 1, pw%pw_grid%para%group%num_pe - 1
1584 send_disps(i) = send_disps(i - 1) + send_sizes(i - 1)
1585 recv_disps(i) = recv_disps(i - 1) + recv_sizes(i - 1)
1588 cpassert(sum(recv_sizes) == product(ub_recv - lb_recv + 1))
1590 ALLOCATE (send_bufs(0:rs%desc%group_size - 1))
1591 ALLOCATE (recv_bufs(0:rs%desc%group_size - 1))
1593 DO i = 0, rs%desc%group_size - 1
1594 IF (send_sizes(i) /= 0)
THEN
1595 ALLOCATE (send_bufs(i)%array(send_sizes(i)))
1597 NULLIFY (send_bufs(i)%array)
1599 IF (recv_sizes(i) /= 0)
THEN
1600 ALLOCATE (recv_bufs(i)%array(recv_sizes(i)))
1602 NULLIFY (recv_bufs(i)%array)
1606 ALLOCATE (recv_reqs(0:rs%desc%group_size - 1))
1607 recv_reqs = mp_request_null
1609 DO i = 0, rs%desc%group_size - 1
1610 IF (recv_sizes(i) /= 0)
THEN
1611 CALL rs%desc%group%irecv(recv_bufs(i)%array, i, recv_reqs(i))
1619 DO i = 0, rs%desc%group_size - 1
1621 DO z = send_tasks(i, 5), send_tasks(i, 6)
1622 DO y = send_tasks(i, 3), send_tasks(i, 4)
1623 DO x = send_tasks(i, 1), send_tasks(i, 2)
1625 send_bufs(i)%array(k) = pw%array(x, y, z)
1632 ALLOCATE (send_reqs(0:rs%desc%group_size - 1))
1633 send_reqs = mp_request_null
1635 DO i = 0, rs%desc%group_size - 1
1636 IF (send_sizes(i) /= 0)
THEN
1637 CALL rs%desc%group%isend(send_bufs(i)%array, i, send_reqs(i))
1644 DO i = 0, rs%desc%group_size - 1
1645 IF (recv_sizes(i) == 0) cycle
1647 CALL mp_waitany(recv_reqs, completed)
1649 DO z = recv_tasks(completed - 1, 5), recv_tasks(completed - 1, 6)
1650 DO y = recv_tasks(completed - 1, 3), recv_tasks(completed - 1, 4)
1651 DO x = recv_tasks(completed - 1, 1), recv_tasks(completed - 1, 2)
1653 rs%r(x, y, z) = recv_bufs(completed - 1)%array(k)
1659 CALL mp_waitall(send_reqs)
1661 DEALLOCATE (recv_reqs)
1662 DEALLOCATE (send_reqs)
1664 DO i = 0, rs%desc%group_size - 1
1665 IF (
ASSOCIATED(send_bufs(i)%array))
THEN
1666 DEALLOCATE (send_bufs(i)%array)
1668 IF (
ASSOCIATED(recv_bufs(i)%array))
THEN
1669 DEALLOCATE (recv_bufs(i)%array)
1673 DEALLOCATE (send_bufs)
1674 DEALLOCATE (recv_bufs)
1675 DEALLOCATE (send_tasks)
1676 DEALLOCATE (send_sizes)
1677 DEALLOCATE (send_disps)
1678 DEALLOCATE (recv_tasks)
1679 DEALLOCATE (recv_sizes)
1680 DEALLOCATE (recv_disps)
1683 halo_swapped = .false.
1687 IF (rs%desc%perd(idir) /= 1)
THEN
1689 ALLOCATE (dshifts(0:rs%desc%neighbours(idir)))
1690 ALLOCATE (ushifts(0:rs%desc%neighbours(idir)))
1694 DO n_shifts = 1, rs%desc%neighbours(idir)
1699 position =
modulo(rs%desc%virtual_group_coor(idir) - n_shifts, rs%desc%group_dim(idir))
1700 neighbours = get_limit(rs%desc%npts(idir), rs%desc%group_dim(idir), position)
1701 dshifts(n_shifts) = dshifts(n_shifts - 1) + (neighbours(2) - neighbours(1) + 1)
1703 position =
modulo(rs%desc%virtual_group_coor(idir) + n_shifts, rs%desc%group_dim(idir))
1704 neighbours = get_limit(rs%desc%npts(idir), rs%desc%group_dim(idir), position)
1705 ushifts(n_shifts) = ushifts(n_shifts - 1) + (neighbours(2) - neighbours(1) + 1)
1711 CALL cart_shift(rs, idir, -1*n_shifts, source_down, dest_down)
1713 lb_send_down(:) = rs%lb_local(:)
1714 ub_send_down(:) = rs%ub_local(:)
1715 lb_recv_down(:) = rs%lb_local(:)
1716 ub_recv_down(:) = rs%ub_local(:)
1718 IF (dshifts(n_shifts - 1) <= rs%desc%border)
THEN
1719 lb_send_down(idir) = lb_send_down(idir) + rs%desc%border
1720 ub_send_down(idir) = min(ub_send_down(idir) - rs%desc%border, &
1721 lb_send_down(idir) + rs%desc%border - 1 - dshifts(n_shifts - 1))
1723 lb_recv_down(idir) = ub_recv_down(idir) - rs%desc%border + 1 + ushifts(n_shifts - 1)
1724 ub_recv_down(idir) = min(ub_recv_down(idir), &
1725 ub_recv_down(idir) - rs%desc%border + ushifts(n_shifts))
1727 lb_send_down(idir) = 0
1728 ub_send_down(idir) = -1
1729 lb_recv_down(idir) = 0
1730 ub_recv_down(idir) = -1
1734 IF (.NOT. (halo_swapped(i) .OR. i == idir))
THEN
1735 lb_send_down(i) = rs%lb_real(i)
1736 ub_send_down(i) = rs%ub_real(i)
1737 lb_recv_down(i) = rs%lb_real(i)
1738 ub_recv_down(i) = rs%ub_real(i)
1743 nn = product(ub_recv_down - lb_recv_down + 1)
1744 ALLOCATE (recv_buf_3d_down(lb_recv_down(1):ub_recv_down(1), &
1745 lb_recv_down(2):ub_recv_down(2), lb_recv_down(3):ub_recv_down(3)))
1748 CALL rs%desc%group%irecv(recv_buf_3d_down, source_down, req(1))
1751 nn = product(ub_send_down - lb_send_down + 1)
1752 ALLOCATE (send_buf_3d_down(lb_send_down(1):ub_send_down(1), &
1753 lb_send_down(2):ub_send_down(2), lb_send_down(3):ub_send_down(3)))
1760 IF (my_id < num_threads)
THEN
1761 lb = lb_send_down(3) + ((ub_send_down(3) - lb_send_down(3) + 1)*my_id)/num_threads
1762 ub = lb_send_down(3) + ((ub_send_down(3) - lb_send_down(3) + 1)*(my_id + 1))/num_threads - 1
1764 send_buf_3d_down(lb_send_down(1):ub_send_down(1), lb_send_down(2):ub_send_down(2), &
1765 lb:ub) = rs%r(lb_send_down(1):ub_send_down(1), &
1766 lb_send_down(2):ub_send_down(2), lb:ub)
1770 CALL rs%desc%group%isend(send_buf_3d_down, dest_down, req(3))
1774 CALL cart_shift(rs, idir, n_shifts, source_up, dest_up)
1776 lb_send_up(:) = rs%lb_local(:)
1777 ub_send_up(:) = rs%ub_local(:)
1778 lb_recv_up(:) = rs%lb_local(:)
1779 ub_recv_up(:) = rs%ub_local(:)
1781 IF (ushifts(n_shifts - 1) <= rs%desc%border)
THEN
1782 ub_send_up(idir) = ub_send_up(idir) - rs%desc%border
1783 lb_send_up(idir) = max(lb_send_up(idir) + rs%desc%border, &
1784 ub_send_up(idir) - rs%desc%border + 1 + ushifts(n_shifts - 1))
1786 ub_recv_up(idir) = lb_recv_up(idir) + rs%desc%border - 1 - dshifts(n_shifts - 1)
1787 lb_recv_up(idir) = max(lb_recv_up(idir), &
1788 lb_recv_up(idir) + rs%desc%border - dshifts(n_shifts))
1790 lb_send_up(idir) = 0
1791 ub_send_up(idir) = -1
1792 lb_recv_up(idir) = 0
1793 ub_recv_up(idir) = -1
1797 IF (.NOT. (halo_swapped(i) .OR. i == idir))
THEN
1798 lb_send_up(i) = rs%lb_real(i)
1799 ub_send_up(i) = rs%ub_real(i)
1800 lb_recv_up(i) = rs%lb_real(i)
1801 ub_recv_up(i) = rs%ub_real(i)
1806 nn = product(ub_recv_up - lb_recv_up + 1)
1807 ALLOCATE (recv_buf_3d_up(lb_recv_up(1):ub_recv_up(1), &
1808 lb_recv_up(2):ub_recv_up(2), lb_recv_up(3):ub_recv_up(3)))
1812 CALL rs%desc%group%irecv(recv_buf_3d_up, source_up, req(2))
1815 nn = product(ub_send_up - lb_send_up + 1)
1816 ALLOCATE (send_buf_3d_up(lb_send_up(1):ub_send_up(1), &
1817 lb_send_up(2):ub_send_up(2), lb_send_up(3):ub_send_up(3)))
1824 IF (my_id < num_threads)
THEN
1825 lb = lb_send_up(3) + ((ub_send_up(3) - lb_send_up(3) + 1)*my_id)/num_threads
1826 ub = lb_send_up(3) + ((ub_send_up(3) - lb_send_up(3) + 1)*(my_id + 1))/num_threads - 1
1828 send_buf_3d_up(lb_send_up(1):ub_send_up(1), lb_send_up(2):ub_send_up(2), &
1829 lb:ub) = rs%r(lb_send_up(1):ub_send_up(1), &
1830 lb_send_up(2):ub_send_up(2), lb:ub)
1834 CALL rs%desc%group%isend(send_buf_3d_up, dest_up, req(4))
1840 CALL mp_waitany(req(1:2), completed)
1842 IF (completed == 1)
THEN
1845 IF (ub_recv_down(idir) >= lb_recv_down(idir))
THEN
1853 IF (my_id < num_threads)
THEN
1854 lb = lb_recv_down(3) + ((ub_recv_down(3) - lb_recv_down(3) + 1)*my_id)/num_threads
1855 ub = lb_recv_down(3) + ((ub_recv_down(3) - lb_recv_down(3) + 1)*(my_id + 1))/num_threads - 1
1857 rs%r(lb_recv_down(1):ub_recv_down(1), lb_recv_down(2):ub_recv_down(2), &
1858 lb:ub) = recv_buf_3d_down(:, :, lb:ub)
1863 DEALLOCATE (recv_buf_3d_down)
1867 IF (ub_recv_up(idir) >= lb_recv_up(idir))
THEN
1875 IF (my_id < num_threads)
THEN
1876 lb = lb_recv_up(3) + ((ub_recv_up(3) - lb_recv_up(3) + 1)*my_id)/num_threads
1877 ub = lb_recv_up(3) + ((ub_recv_up(3) - lb_recv_up(3) + 1)*(my_id + 1))/num_threads - 1
1879 rs%r(lb_recv_up(1):ub_recv_up(1), lb_recv_up(2):ub_recv_up(2), &
1880 lb:ub) = recv_buf_3d_up(:, :, lb:ub)
1885 DEALLOCATE (recv_buf_3d_up)
1889 CALL mp_waitall(req(3:4))
1891 DEALLOCATE (send_buf_3d_down)
1892 DEALLOCATE (send_buf_3d_up)
1895 DEALLOCATE (ushifts)
1896 DEALLOCATE (dshifts)
1899 halo_swapped(idir) = .true.
1903 END SUBROUTINE transfer_pw2rs_distributed
1916 CHARACTER(len=*),
PARAMETER :: routinen =
'rs_grid_zero'
1918 INTEGER :: handle, i, j, k, l(3), u(3)
1920 CALL timeset(routinen, handle)
1921 l(1) = lbound(rs%r, 1); l(2) = lbound(rs%r, 2); l(3) = lbound(rs%r, 3)
1922 u(1) = ubound(rs%r, 1); u(2) = ubound(rs%r, 2); u(3) = ubound(rs%r, 3)
1929 rs%r(i, j, k) = 0.0_dp
1934 CALL timestop(handle)
1951 REAL(dp),
INTENT(IN) :: scalar
1953 CHARACTER(len=*),
PARAMETER :: routinen =
'rs_grid_mult_and_add'
1955 INTEGER :: handle, i, j, k, l(3), u(3)
1959 CALL timeset(routinen, handle)
1960 IF (scalar /= 0.0_dp)
THEN
1961 l(1) = lbound(rs1%r, 1); l(2) = lbound(rs1%r, 2); l(3) = lbound(rs1%r, 3)
1962 u(1) = ubound(rs1%r, 1); u(2) = ubound(rs1%r, 2); u(3) = ubound(rs1%r, 3)
1969 rs1%r(i, j, k) = rs1%r(i, j, k) + scalar*rs2%r(i, j, k)*rs3%r(i, j, k)
1975 CALL timestop(handle)
1989 TYPE(pw_grid_type),
INTENT(IN),
TARGET :: pw_grid
1992 cpassert(
ASSOCIATED(rs%desc%pw, pw_grid))
1993 rs%desc%dh = pw_grid%dh
1994 rs%desc%dh_inv = pw_grid%dh_inv
2008 cpassert(rs_desc%ref_count > 0)
2009 rs_desc%ref_count = rs_desc%ref_count + 1
2027 IF (
ALLOCATED(rs_grid%px))
DEALLOCATE (rs_grid%px)
2028 IF (
ALLOCATED(rs_grid%py))
DEALLOCATE (rs_grid%py)
2029 IF (
ALLOCATED(rs_grid%pz))
DEALLOCATE (rs_grid%pz)
2042 IF (
ASSOCIATED(rs_desc))
THEN
2043 cpassert(rs_desc%ref_count > 0)
2044 rs_desc%ref_count = rs_desc%ref_count - 1
2045 IF (rs_desc%ref_count == 0)
THEN
2047 CALL pw_grid_release(rs_desc%pw)
2049 IF (rs_desc%parallel)
THEN
2051 CALL rs_desc%group%free()
2053 DEALLOCATE (rs_desc%virtual2real)
2054 DEALLOCATE (rs_desc%real2virtual)
2057 IF (rs_desc%distributed)
THEN
2058 DEALLOCATE (rs_desc%rank2coord)
2059 DEALLOCATE (rs_desc%coord2rank)
2060 DEALLOCATE (rs_desc%lb_global)
2061 DEALLOCATE (rs_desc%ub_global)
2062 DEALLOCATE (rs_desc%x2coord)
2063 DEALLOCATE (rs_desc%y2coord)
2064 DEALLOCATE (rs_desc%z2coord)
2067 DEALLOCATE (rs_desc)
2085 PURE SUBROUTINE cart_shift(rs_grid, dir, disp, source, dest)
2088 INTEGER,
INTENT(IN) :: dir, disp
2089 INTEGER,
INTENT(OUT) :: source, dest
2091 INTEGER,
DIMENSION(3) :: shift_coords
2093 shift_coords = rs_grid%desc%virtual_group_coor
2094 shift_coords(dir) =
modulo(shift_coords(dir) + disp, rs_grid%desc%group_dim(dir))
2095 dest = rs_grid%desc%virtual2real(rs_grid%desc%coord2rank(shift_coords(1), shift_coords(2), shift_coords(3)))
2096 shift_coords = rs_grid%desc%virtual_group_coor
2097 shift_coords(dir) =
modulo(shift_coords(dir) - disp, rs_grid%desc%group_dim(dir))
2098 source = rs_grid%desc%virtual2real(rs_grid%desc%coord2rank(shift_coords(1), shift_coords(2), shift_coords(3)))
2100 END SUBROUTINE cart_shift
2112 INTEGER :: max_ngpts
2114 CHARACTER(len=*),
PARAMETER :: routinen =
'rs_grid_max_ngpts'
2116 INTEGER :: handle, i
2117 INTEGER,
DIMENSION(3) :: lb, ub
2119 CALL timeset(routinen, handle)
2122 IF ((desc%pw%para%mode == pw_mode_local) .OR. &
2123 (all(desc%group_dim == 1)))
THEN
2124 cpassert(product(int(desc%npts, kind=int_8)) < huge(1))
2125 max_ngpts = product(desc%npts)
2127 DO i = 0, desc%group_size - 1
2128 lb = desc%lb_global(:, i)
2129 ub = desc%ub_global(:, i)
2130 lb = lb - desc%border*(1 - desc%perd)
2131 ub = ub + desc%border*(1 - desc%perd)
2132 cpassert(product(int(ub - lb + 1, kind=int_8)) < huge(1))
2133 max_ngpts = max(max_ngpts, product(ub - lb + 1))
2137 CALL timestop(handle)
2153 REAL(kind=dp),
DIMENSION(3, 3),
INTENT(IN) :: h_inv
2154 REAL(kind=dp),
DIMENSION(3),
INTENT(IN) :: ra
2155 INTEGER,
INTENT(IN),
OPTIONAL :: offset, group_size, my_pos
2157 INTEGER :: dir, lb(3), location(3), tp(3), ub(3)
2161 IF (.NOT. all(rs_grid%desc%perd == 1))
THEN
2164 tp(dir) = floor(dot_product(h_inv(dir, :), ra)*rs_grid%desc%npts(dir))
2165 tp(dir) =
modulo(tp(dir), rs_grid%desc%npts(dir))
2166 IF (rs_grid%desc%perd(dir) /= 1)
THEN
2167 lb(dir) = rs_grid%lb_local(dir) + rs_grid%desc%border
2168 ub(dir) = rs_grid%ub_local(dir) - rs_grid%desc%border
2170 lb(dir) = rs_grid%lb_local(dir)
2171 ub(dir) = rs_grid%ub_local(dir)
2174 location(dir) = tp(dir) + rs_grid%desc%lb(dir)
2176 IF (all(lb(:) <= location(:)) .AND. all(location(:) <= ub(:)))
THEN
2180 IF (
PRESENT(offset) .AND.
PRESENT(group_size) .AND.
PRESENT(my_pos))
THEN
2182 IF (
modulo(offset, group_size) == my_pos) res = .true.
static GRID_HOST_DEVICE int modulo(int a, int m)
Equivalent of Fortran's MODULO, which always return a positive number. https://gcc....
various utilities that regard array of different kinds: output, allocation,... maybe it is not a good...
various routines to log and control the output. The idea is that decisions about where to log should ...
sums arrays of real/complex numbers with much reduced round-off as compared to a naive implementation...
Defines the basic variable types.
integer, parameter, public int_8
integer, parameter, public dp
Machine interface based on Fortran 2003 and POSIX.
subroutine, public m_memory(mem)
Returns the total amount of memory [bytes] in use, if known, zero otherwise.
Collection of simple mathematical functions and subroutines.
Interface to the message passing library MPI.
type(mp_comm_type), parameter, public mp_comm_null
subroutine, public mp_waitany(requests, completed)
waits for completion of any of the given requests
type(mp_request_type), parameter, public mp_request_null
Fortran API for the offload package, which is written in C.
subroutine, public offload_free_buffer(buffer)
Deallocates given buffer.
subroutine, public offload_create_buffer(length, buffer)
Allocates a buffer of given length, ie. number of elements.
integer, parameter, public pw_mode_local
This module defines the grid data type and some basic operations on it.
subroutine, public pw_grid_release(pw_grid)
releases the given pw grid
subroutine, public pw_grid_retain(pw_grid)
retains the given pw grid
subroutine, public rs_grid_print(rs, iounit)
Print information on grids to output.
integer, parameter, public rsgrid_replicated
subroutine, public rs_grid_create(rs, desc)
...
subroutine, public rs_grid_create_descriptor(desc, pw_grid, input_settings, border_points)
Determine the setup of real space grids - this is divided up into the creation of a descriptor and th...
pure integer function, public rs_grid_locate_rank(rs_desc, rank_in, shift)
returns the 1D rank of the task which is a cartesian shift away from 1D rank rank_in only possible if...
subroutine, public transfer_pw2rs(rs, pw)
...
integer, parameter, public rsgrid_automatic
pure subroutine, public rs_grid_reorder_ranks(desc, real2virtual)
Defines a new ordering of ranks on this realspace grid, recalculating the data bounds and reallocatin...
subroutine, public rs_grid_mult_and_add(rs1, rs2, rs3, scalar)
rs1(i) = rs1(i) + rs2(i)*rs3(i)
subroutine, public rs_grid_set_box(pw_grid, rs)
Set box matrix info for real space grid This is needed for variable cell simulations.
subroutine, public rs_grid_retain_descriptor(rs_desc)
retains the given rs grid descriptor (see doc/ReferenceCounting.html)
subroutine, public rs_grid_release_descriptor(rs_desc)
releases the given rs grid descriptor (see doc/ReferenceCounting.html)
integer function, public rs_grid_max_ngpts(desc)
returns the maximum number of points in the local grid of any process to account for the case where t...
integer, parameter, public rsgrid_distributed
pure logical function, public map_gaussian_here(rs_grid, h_inv, ra, offset, group_size, my_pos)
...
subroutine, public transfer_rs2pw(rs, pw)
...
subroutine, public rs_grid_release(rs_grid)
releases the given rs grid (see doc/ReferenceCounting.html)
subroutine, public rs_grid_zero(rs)
Initialize grid to zero.
All kind of helpful little routines.
pure integer function, dimension(2), public get_limit(m, n, me)
divide m entries into n parts, return size of part me
void offload_free_buffer(offload_buffer *buffer)
Deallocate given buffer.
represent a pointer to a 1d array