37 USE iso_c_binding,
ONLY: c_f_pointer,&
64#include "../base/base_uses.f90"
73 INTEGER :: grid_tag = 0
74 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'pw_grids'
82 MODULE PROCEDURE pw_grid_create_local
83 MODULE PROCEDURE pw_grid_create_extended
96 SUBROUTINE pw_grid_create_local(pw_grid, bounds)
99 INTEGER,
DIMENSION(2, 3),
INTENT(IN) :: bounds
101 INTEGER,
DIMENSION(2) :: rs_dims
103 cpassert(.NOT.
ASSOCIATED(pw_grid))
105 pw_grid%bounds = bounds
106 pw_grid%bounds_local = bounds
107 pw_grid%npts = bounds(2, :) - bounds(1, :) + 1
108 pw_grid%npts_local = pw_grid%npts
109 pw_grid%ngpts = product(int(pw_grid%npts, kind=
int_8))
110 pw_grid%ngpts_cut = pw_grid%ngpts
111 pw_grid%ngpts_local = product(pw_grid%npts)
112 pw_grid%ngpts_cut_local = pw_grid%ngpts_local
115 pw_grid%reference = 0
116 pw_grid%ref_count = 1
118 NULLIFY (pw_grid%gsq)
119 NULLIFY (pw_grid%g_hatmap)
120 NULLIFY (pw_grid%gidx)
121 NULLIFY (pw_grid%grays)
124 grid_tag = grid_tag + 1
125 pw_grid%id_nr = grid_tag
129 CALL pw_grid%para%group%create(
mp_comm_self, 2, rs_dims)
130 IF (pw_grid%para%group%num_pe > 1)
THEN
136 END SUBROUTINE pw_grid_create_local
154 IF (grida%id_nr == gridb%id_nr)
THEN
184 ngpts_cut, dr, cutoff, orthorhombic, gvectors, gsquare)
187 INTEGER,
INTENT(OUT),
OPTIONAL :: id_nr, mode
188 REAL(
dp),
INTENT(OUT),
OPTIONAL :: vol, dvol
189 INTEGER,
DIMENSION(3),
INTENT(OUT),
OPTIONAL :: npts
190 INTEGER(int_8),
INTENT(OUT),
OPTIONAL :: ngpts, ngpts_cut
191 REAL(
dp),
DIMENSION(3),
INTENT(OUT),
OPTIONAL :: dr
192 REAL(
dp),
INTENT(OUT),
OPTIONAL :: cutoff
193 LOGICAL,
INTENT(OUT),
OPTIONAL :: orthorhombic
194 REAL(
dp),
DIMENSION(:, :),
OPTIONAL,
POINTER :: gvectors
195 REAL(
dp),
DIMENSION(:),
OPTIONAL,
POINTER :: gsquare
197 cpassert(pw_grid%ref_count > 0)
199 IF (
PRESENT(id_nr)) id_nr = pw_grid%id_nr
200 IF (
PRESENT(mode)) mode = pw_grid%para%mode
201 IF (
PRESENT(vol)) vol = pw_grid%vol
202 IF (
PRESENT(dvol)) dvol = pw_grid%dvol
203 IF (
PRESENT(npts)) npts(1:3) = pw_grid%npts(1:3)
204 IF (
PRESENT(ngpts)) ngpts = pw_grid%ngpts
205 IF (
PRESENT(ngpts_cut)) ngpts_cut = pw_grid%ngpts_cut
206 IF (
PRESENT(dr)) dr = pw_grid%dr
207 IF (
PRESENT(cutoff)) cutoff = pw_grid%cutoff
208 IF (
PRESENT(orthorhombic)) orthorhombic = pw_grid%orthorhombic
209 IF (
PRESENT(gvectors)) gvectors => pw_grid%g
210 IF (
PRESENT(gsquare)) gsquare => pw_grid%gsq
226 SUBROUTINE set_pw_grid_info(pw_grid, grid_span, npts, bounds, cutoff, spherical)
229 INTEGER,
INTENT(in),
OPTIONAL :: grid_span
230 INTEGER,
DIMENSION(3),
INTENT(IN),
OPTIONAL :: npts
231 INTEGER,
DIMENSION(2, 3),
INTENT(IN),
OPTIONAL :: bounds
232 REAL(kind=
dp),
INTENT(IN),
OPTIONAL :: cutoff
233 LOGICAL,
INTENT(IN),
OPTIONAL :: spherical
235 cpassert(pw_grid%ref_count > 0)
237 IF (
PRESENT(grid_span))
THEN
238 pw_grid%grid_span = grid_span
240 IF (
PRESENT(bounds) .AND.
PRESENT(npts))
THEN
241 pw_grid%bounds = bounds
243 cpassert(all(npts == bounds(2, :) - bounds(1, :) + 1))
244 ELSE IF (
PRESENT(bounds))
THEN
245 pw_grid%bounds = bounds
246 pw_grid%npts = bounds(2, :) - bounds(1, :) + 1
247 ELSE IF (
PRESENT(npts))
THEN
251 IF (
PRESENT(cutoff))
THEN
252 pw_grid%cutoff = cutoff
253 IF (
PRESENT(spherical))
THEN
254 pw_grid%spherical = spherical
256 pw_grid%spherical = .false.
260 END SUBROUTINE set_pw_grid_info
285 SUBROUTINE pw_grid_create_extended(pw_grid, mp_comm, cell_hmat, grid_span, cutoff, bounds, bounds_local, npts, &
286 spherical, odd, fft_usage, ncommensurate, icommensurate, blocked, ref_grid, &
290 REAL(KIND=
dp),
DIMENSION(3, 3),
INTENT(IN) :: cell_hmat
293 INTEGER,
INTENT(in),
OPTIONAL :: grid_span
294 REAL(kind=
dp),
INTENT(IN),
OPTIONAL :: cutoff
295 INTEGER,
DIMENSION(2, 3),
INTENT(IN),
OPTIONAL :: bounds, bounds_local
296 INTEGER,
DIMENSION(3),
INTENT(IN),
OPTIONAL :: npts
297 LOGICAL,
INTENT(in),
OPTIONAL :: spherical, odd, fft_usage
298 INTEGER,
INTENT(in),
OPTIONAL :: ncommensurate, icommensurate, blocked
300 INTEGER,
DIMENSION(2),
INTENT(in),
OPTIONAL :: rs_dims
301 INTEGER,
INTENT(in),
OPTIONAL :: iounit
303 CHARACTER(len=*),
PARAMETER :: routineN =
'pw_grid_setup'
305 INTEGER :: handle, my_icommensurate, &
307 INTEGER,
DIMENSION(3) :: n
308 LOGICAL :: my_fft_usage, my_odd, my_spherical
309 REAL(KIND=
dp) :: cell_deth, my_cutoff
310 REAL(KIND=
dp),
DIMENSION(3, 3) :: cell_h_inv
312 CALL timeset(routinen, handle)
314 cpassert(.NOT.
ASSOCIATED(pw_grid))
317 pw_grid%cutoff = 0.0_dp
320 pw_grid%reference = 0
321 pw_grid%ref_count = 1
323 NULLIFY (pw_grid%gsq)
324 NULLIFY (pw_grid%g_hatmap)
325 NULLIFY (pw_grid%gidx)
326 NULLIFY (pw_grid%grays)
329 grid_tag = grid_tag + 1
330 pw_grid%id_nr = grid_tag
333 IF (mp_comm%num_pe > 1)
THEN
339 cell_deth = abs(
det_3x3(cell_hmat))
340 IF (cell_deth < 1.0e-10_dp)
THEN
341 CALL cp_abort(__location__, &
342 "An invalid set of cell vectors was specified. "// &
343 "The determinant det(h) is too small")
345 cell_h_inv =
inv_3x3(cell_hmat)
347 IF (
PRESENT(grid_span))
THEN
348 CALL set_pw_grid_info(pw_grid, grid_span=grid_span)
351 IF (
PRESENT(spherical))
THEN
352 my_spherical = spherical
354 my_spherical = .false.
357 IF (
PRESENT(odd))
THEN
363 IF (
PRESENT(fft_usage))
THEN
364 my_fft_usage = fft_usage
366 my_fft_usage = .false.
369 IF (
PRESENT(ncommensurate))
THEN
370 my_ncommensurate = ncommensurate
371 IF (
PRESENT(icommensurate))
THEN
372 my_icommensurate = icommensurate
374 my_icommensurate = min(1, ncommensurate)
381 IF (
PRESENT(bounds))
THEN
382 IF (
PRESENT(cutoff))
THEN
383 CALL set_pw_grid_info(pw_grid, bounds=bounds, cutoff=cutoff, &
384 spherical=my_spherical)
386 n = bounds(2, :) - bounds(1, :) + 1
388 my_cutoff = 0.5_dp*my_cutoff*my_cutoff
389 CALL set_pw_grid_info(pw_grid, bounds=bounds, cutoff=my_cutoff, &
390 spherical=my_spherical)
392 ELSE IF (
PRESENT(npts))
THEN
394 IF (
PRESENT(cutoff))
THEN
398 my_cutoff = 0.5_dp*my_cutoff*my_cutoff
400 IF (my_fft_usage)
THEN
402 spherical=my_spherical, odd=my_odd, fft_usage=my_fft_usage, &
403 ncommensurate=my_ncommensurate, icommensurate=my_icommensurate, &
404 ref_grid=ref_grid, n_orig=n)
406 CALL set_pw_grid_info(pw_grid, npts=n, cutoff=my_cutoff, &
407 spherical=my_spherical)
408 ELSE IF (
PRESENT(cutoff))
THEN
410 spherical=my_spherical, odd=my_odd, fft_usage=my_fft_usage, &
411 ncommensurate=my_ncommensurate, icommensurate=my_icommensurate, &
413 CALL set_pw_grid_info(pw_grid, npts=n, cutoff=cutoff, &
414 spherical=my_spherical)
416 cpabort(
"BOUNDS, NPTS or CUTOFF have to be specified")
419 CALL pw_grid_setup_internal(cell_hmat, cell_h_inv, cell_deth, pw_grid, mp_comm, bounds_local=bounds_local, &
420 blocked=blocked, ref_grid=ref_grid, rs_dims=rs_dims, iounit=iounit)
422#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
423 CALL pw_grid_create_ghatmap(pw_grid)
426 CALL timestop(handle)
428 END SUBROUTINE pw_grid_create_extended
430#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
436 SUBROUTINE pw_grid_create_ghatmap(pw_grid)
440 CHARACTER(len=*),
PARAMETER :: routinen =
'pw_grid_create_ghatmap'
442 INTEGER :: gpt, handle, l, m, mn, n
444 CALL timeset(routinen, handle)
447 cpassert(pw_grid%ref_count > 0)
451 associate(g_hat => pw_grid%g_hat, g_hatmap => pw_grid%g_hatmap, pmapl => pw_grid%mapl%pos, &
452 pmapm => pw_grid%mapm%pos, pmapn => pw_grid%mapn%pos, nmapl => pw_grid%mapl%neg, &
453 nmapm => pw_grid%mapm%neg, nmapn => pw_grid%mapn%neg, ngpts =>
SIZE(pw_grid%gsq), &
454 npts => pw_grid%npts, yzq => pw_grid%para%yzq)
460 l = pmapl(g_hat(1, gpt))
461 m = pmapm(g_hat(2, gpt))
462 n = pmapn(g_hat(3, gpt))
465 g_hatmap(gpt, 1) = l + npts(1)*(m + npts(2)*n)
469 l = nmapl(g_hat(1, gpt))
470 m = nmapm(g_hat(2, gpt))
471 n = nmapn(g_hat(3, gpt))
474 g_hatmap(gpt, 2) = l + npts(1)*(m + npts(2)*n)
479 l = pmapl(g_hat(1, gpt))
480 m = pmapm(g_hat(2, gpt)) + 1
481 n = pmapn(g_hat(3, gpt)) + 1
485 g_hatmap(gpt, 1) = l + npts(1)*mn
489 l = nmapl(g_hat(1, gpt))
490 m = nmapm(g_hat(2, gpt)) + 1
491 n = nmapn(g_hat(3, gpt)) + 1
495 g_hatmap(gpt, 2) = l + npts(1)*mn
501 CALL timestop(handle)
503 END SUBROUTINE pw_grid_create_ghatmap
533 SUBROUTINE pw_grid_setup_internal(cell_hmat, cell_h_inv, cell_deth, pw_grid, mp_comm, bounds_local, &
534 blocked, ref_grid, rs_dims, iounit)
535 REAL(kind=dp),
DIMENSION(3, 3),
INTENT(IN) :: cell_hmat, cell_h_inv
536 REAL(kind=dp),
INTENT(IN) :: cell_deth
537 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
539 CLASS(mp_comm_type),
INTENT(IN) :: mp_comm
540 INTEGER,
DIMENSION(2, 3),
INTENT(IN),
OPTIONAL :: bounds_local
541 INTEGER,
INTENT(in),
OPTIONAL :: blocked
542 TYPE(pw_grid_type),
INTENT(in),
OPTIONAL :: ref_grid
543 INTEGER,
DIMENSION(2),
INTENT(in),
OPTIONAL :: rs_dims
544 INTEGER,
INTENT(in),
OPTIONAL :: iounit
546 CHARACTER(len=*),
PARAMETER :: routineN =
'pw_grid_setup_internal'
548 INTEGER :: handle, n(3)
549 INTEGER,
ALLOCATABLE,
DIMENSION(:, :) :: yz_mask
550 REAL(KIND=dp) :: ecut
554 CALL timeset(routinen, handle)
556 cpassert(pw_grid%ref_count > 0)
559 IF (
PRESENT(ref_grid))
THEN
560 pw_grid%reference = ref_grid%id_nr
563 IF (pw_grid%spherical)
THEN
564 ecut = pw_grid%cutoff
569 n(:) = pw_grid%npts(:)
575 ALLOCATE (yz_mask(n(2), n(3)))
576 CALL pw_grid_count(cell_h_inv, pw_grid, mp_comm, ecut, yz_mask)
579 IF (
PRESENT(ref_grid))
THEN
580 cpassert(pw_grid%para%mode == ref_grid%para%mode)
581 cpassert(pw_grid%grid_span == ref_grid%grid_span)
582 cpassert(pw_grid%spherical .EQV. ref_grid%spherical)
586 CALL pw_grid_distribute(pw_grid, mp_comm, yz_mask, bounds_local=bounds_local, ref_grid=ref_grid, blocked=blocked, &
590 CALL pw_grid_allocate(pw_grid, pw_grid%ngpts_cut_local, &
594 CALL pw_grid_assign(cell_h_inv, pw_grid, ecut)
597 CALL pw_grid_sort(pw_grid, ref_grid)
599 CALL pw_grid_remap(pw_grid, yz_mask)
603 CALL cell2grid(cell_hmat, cell_h_inv, cell_deth, pw_grid)
608 IF (
PRESENT(iounit))
THEN
609 CALL pw_grid_print(pw_grid, iounit)
612 CALL timestop(handle)
614 END SUBROUTINE pw_grid_setup_internal
625 SUBROUTINE cell2grid(cell_hmat, cell_h_inv, cell_deth, pw_grid)
626 REAL(KIND=dp),
DIMENSION(3, 3),
INTENT(IN) :: cell_hmat, cell_h_inv
627 REAL(KIND=dp),
INTENT(IN) :: cell_deth
628 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
630 pw_grid%vol = abs(cell_deth)
631 pw_grid%dvol = pw_grid%vol/real(pw_grid%ngpts, kind=dp)
632 pw_grid%dr(1) = sqrt(sum(cell_hmat(:, 1)**2)) &
633 /real(pw_grid%npts(1), kind=dp)
634 pw_grid%dr(2) = sqrt(sum(cell_hmat(:, 2)**2)) &
635 /real(pw_grid%npts(2), kind=dp)
636 pw_grid%dr(3) = sqrt(sum(cell_hmat(:, 3)**2)) &
637 /real(pw_grid%npts(3), kind=dp)
638 pw_grid%dh(:, 1) = cell_hmat(:, 1)/real(pw_grid%npts(1), kind=dp)
639 pw_grid%dh(:, 2) = cell_hmat(:, 2)/real(pw_grid%npts(2), kind=dp)
640 pw_grid%dh(:, 3) = cell_hmat(:, 3)/real(pw_grid%npts(3), kind=dp)
641 pw_grid%dh_inv(1, :) = cell_h_inv(1, :)*real(pw_grid%npts(1), kind=dp)
642 pw_grid%dh_inv(2, :) = cell_h_inv(2, :)*real(pw_grid%npts(2), kind=dp)
643 pw_grid%dh_inv(3, :) = cell_h_inv(3, :)*real(pw_grid%npts(3), kind=dp)
645 IF ((cell_hmat(1, 2) == 0.0_dp) .AND. (cell_hmat(1, 3) == 0.0_dp) .AND. &
646 (cell_hmat(2, 1) == 0.0_dp) .AND. (cell_hmat(2, 3) == 0.0_dp) .AND. &
647 (cell_hmat(3, 1) == 0.0_dp) .AND. (cell_hmat(3, 2) == 0.0_dp))
THEN
648 pw_grid%orthorhombic = .true.
650 pw_grid%orthorhombic = .false.
652 END SUBROUTINE cell2grid
660 SUBROUTINE pw_grid_print(pw_grid, info)
662 TYPE(pw_grid_type),
INTENT(IN) :: pw_grid
663 INTEGER,
INTENT(IN) :: info
666 INTEGER(KIND=int_8) :: n(3)
667 REAL(KIND=dp) :: rv(3, 3)
674 IF (pw_grid%para%mode == pw_mode_local)
THEN
676 WRITE (info,
'(/,A,T71,I10)') &
677 " PW_GRID| Information for grid number ", pw_grid%id_nr
678 IF (pw_grid%reference > 0)
THEN
679 WRITE (info,
'(A,T71,I10)') &
680 " PW_GRID| Number of the reference grid ", pw_grid%reference
682 WRITE (info,
'(" PW_GRID| Cutoff [a.u.]",T71,f10.1)') pw_grid%cutoff
683 IF (pw_grid%spherical)
THEN
684 WRITE (info,
'(A,T78,A)')
" PW_GRID| spherical cutoff: ",
"YES"
685 WRITE (info,
'(A,T71,I10)')
" PW_GRID| Grid points within cutoff", &
688 WRITE (info,
'(A,T78,A)')
" PW_GRID| spherical cutoff: ",
" NO"
691 WRITE (info,
'(A,I3,T30,2I8,T62,A,T71,I10)')
" PW_GRID| Bounds ", &
692 i, pw_grid%bounds(1, i), pw_grid%bounds(2, i), &
693 "Points:", pw_grid%npts(i)
695 WRITE (info,
'(A,G12.4,T50,A,T67,F14.4)') &
696 " PW_GRID| Volume element (a.u.^3)", &
697 pw_grid%dvol,
" Volume (a.u.^3) :", pw_grid%vol
698 IF (pw_grid%grid_span == halfspace)
THEN
699 WRITE (info,
'(A,T72,A)')
" PW_GRID| Grid span",
"HALFSPACE"
701 WRITE (info,
'(A,T72,A)')
" PW_GRID| Grid span",
"FULLSPACE"
706 n(1) = pw_grid%ngpts_cut_local
707 n(2) = pw_grid%ngpts_local
708 CALL pw_grid%para%group%sum(n(1:2))
709 n(3) = sum(pw_grid%para%nyzray)
710 rv(:, 1) = real(n, kind=dp)/real(pw_grid%para%group%num_pe, kind=dp)
711 n(1) = pw_grid%ngpts_cut_local
712 n(2) = pw_grid%ngpts_local
713 CALL pw_grid%para%group%max(n(1:2))
714 n(3) = maxval(pw_grid%para%nyzray)
715 rv(:, 2) = real(n, kind=dp)
716 n(1) = pw_grid%ngpts_cut_local
717 n(2) = pw_grid%ngpts_local
718 CALL pw_grid%para%group%min(n(1:2))
719 n(3) = minval(pw_grid%para%nyzray)
720 rv(:, 3) = real(n, kind=dp)
723 WRITE (info,
'(/,A,T71,I10)') &
724 " PW_GRID| Information for grid number ", pw_grid%id_nr
725 IF (pw_grid%reference > 0)
THEN
726 WRITE (info,
'(A,T71,I10)') &
727 " PW_GRID| Number of the reference grid ", pw_grid%reference
729 WRITE (info,
'(A,T60,I10,A)') &
730 " PW_GRID| Grid distributed over ", pw_grid%para%group%num_pe, &
732 WRITE (info,
'(A,T71,2I5)') &
733 " PW_GRID| Real space group dimensions ", pw_grid%para%group%num_pe_cart
734 IF (pw_grid%para%blocked)
THEN
735 WRITE (info,
'(A,T78,A)')
" PW_GRID| the grid is blocked: ",
"YES"
737 WRITE (info,
'(A,T78,A)')
" PW_GRID| the grid is blocked: ",
" NO"
739 WRITE (info,
'(" PW_GRID| Cutoff [a.u.]",T71,f10.1)') pw_grid%cutoff
740 IF (pw_grid%spherical)
THEN
741 WRITE (info,
'(A,T78,A)')
" PW_GRID| spherical cutoff: ",
"YES"
742 WRITE (info,
'(A,T71,I10)')
" PW_GRID| Grid points within cutoff", &
745 WRITE (info,
'(A,T78,A)')
" PW_GRID| spherical cutoff: ",
" NO"
748 WRITE (info,
'(A,I3,T30,2I8,T62,A,T71,I10)')
" PW_GRID| Bounds ", &
749 i, pw_grid%bounds(1, i), pw_grid%bounds(2, i), &
750 "Points:", pw_grid%npts(i)
752 WRITE (info,
'(A,G12.4,T50,A,T67,F14.4)') &
753 " PW_GRID| Volume element (a.u.^3)", &
754 pw_grid%dvol,
" Volume (a.u.^3) :", pw_grid%vol
755 IF (pw_grid%grid_span == halfspace)
THEN
756 WRITE (info,
'(A,T72,A)')
" PW_GRID| Grid span",
"HALFSPACE"
758 WRITE (info,
'(A,T72,A)')
" PW_GRID| Grid span",
"FULLSPACE"
760 WRITE (info,
'(A,T48,A)')
" PW_GRID| Distribution", &
762 WRITE (info,
'(A,T45,F12.1,2I12)')
" PW_GRID| G-Vectors", &
763 rv(1, 1), nint(rv(1, 2)), nint(rv(1, 3))
764 WRITE (info,
'(A,T45,F12.1,2I12)')
" PW_GRID| G-Rays ", &
765 rv(3, 1), nint(rv(3, 2)), nint(rv(3, 3))
766 WRITE (info,
'(A,T45,F12.1,2I12)')
" PW_GRID| Real Space Points", &
767 rv(2, 1), nint(rv(2, 2)), nint(rv(2, 3))
771 END SUBROUTINE pw_grid_print
788 SUBROUTINE pw_grid_distribute(pw_grid, mp_comm, yz_mask, bounds_local, ref_grid, blocked, rs_dims)
790 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
792 CLASS(mp_comm_type),
INTENT(IN) :: mp_comm
793 INTEGER,
DIMENSION(:, :),
INTENT(INOUT) :: yz_mask
794 INTEGER,
DIMENSION(2, 3),
INTENT(IN),
OPTIONAL :: bounds_local
795 TYPE(pw_grid_type),
INTENT(IN),
OPTIONAL :: ref_grid
796 INTEGER,
INTENT(IN),
OPTIONAL :: blocked
797 INTEGER,
DIMENSION(2),
INTENT(in),
OPTIONAL :: rs_dims
799 CHARACTER(len=*),
PARAMETER :: routineN =
'pw_grid_distribute'
801 INTEGER :: blocked_local, coor(2), gmax, handle, i, &
802 i1, i2, ip, ipl, ipp, itmp, j, l, lby, &
803 lbz, lo(2), m, n, np, ns, nx, ny, nz, &
805 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: pemap
806 INTEGER,
ALLOCATABLE,
DIMENSION(:, :) :: yz_index
807 INTEGER,
ALLOCATABLE,
DIMENSION(:, :, :) :: axis_dist_all
808 INTEGER,
DIMENSION(2) :: my_rs_dims
809 INTEGER,
DIMENSION(2, 3) :: axis_dist
814 CALL timeset(routinen, handle)
816 lby = pw_grid%bounds(1, 2)
817 lbz = pw_grid%bounds(1, 3)
819 pw_grid%ngpts = product(int(pw_grid%npts, kind=int_8))
822 IF (
PRESENT(rs_dims))
THEN
826 IF (
PRESENT(blocked))
THEN
827 blocked_local = blocked
832 pw_grid%para%blocked = .false.
834 IF (pw_grid%para%mode == pw_mode_local)
THEN
836 pw_grid%para%ray_distribution = .false.
838 pw_grid%bounds_local = pw_grid%bounds
839 pw_grid%npts_local = pw_grid%npts
840 cpassert(pw_grid%ngpts_cut < huge(pw_grid%ngpts_cut_local))
841 pw_grid%ngpts_cut_local = int(pw_grid%ngpts_cut)
842 cpassert(pw_grid%ngpts < huge(pw_grid%ngpts_local))
843 pw_grid%ngpts_local = int(pw_grid%ngpts)
845 CALL pw_grid%para%group%create(mp_comm, 2, my_rs_dims)
847 ALLOCATE (pw_grid%para%bo(2, 3, 0:0, 3))
849 pw_grid%para%bo(1, 1:3, 0, i) = 1
850 pw_grid%para%bo(2, 1:3, 0, i) = pw_grid%npts(1:3)
870 IF (any(my_rs_dims <= 0))
THEN
871 IF (all(my_rs_dims <= 0))
THEN
874 IF (my_rs_dims(1) > 0)
THEN
875 my_rs_dims(2) = np/my_rs_dims(1)
877 my_rs_dims(1) = np/my_rs_dims(2)
882 IF (product(my_rs_dims) .NE. np) my_rs_dims = [0, 0]
884 IF (all(my_rs_dims == [1, np])) my_rs_dims = [0, 0]
887 IF (all(my_rs_dims == [0, 0]))
THEN
891 CALL mp_dims_create(np, my_rs_dims)
893 IF (my_rs_dims(1) > my_rs_dims(2))
THEN
895 my_rs_dims(1) = my_rs_dims(2)
899 IF (my_rs_dims(1) == 1)
THEN
901 my_rs_dims(1) = my_rs_dims(2)
910 SELECT CASE (blocked_local)
916 IF (all(my_rs_dims == [np, 1]))
THEN
926 CALL pw_grid%para%group%create(mp_comm, 2, my_rs_dims)
928 IF (
PRESENT(bounds_local))
THEN
929 pw_grid%bounds_local = bounds_local
931 lo = get_limit(nx, pw_grid%para%group%num_pe_cart(1), &
932 pw_grid%para%group%mepos_cart(1))
933 pw_grid%bounds_local(:, 1) = lo + pw_grid%bounds(1, 1) - 1
934 lo = get_limit(ny, pw_grid%para%group%num_pe_cart(2), &
935 pw_grid%para%group%mepos_cart(2))
936 pw_grid%bounds_local(:, 2) = lo + pw_grid%bounds(1, 2) - 1
937 pw_grid%bounds_local(:, 3) = pw_grid%bounds(:, 3)
940 pw_grid%npts_local(:) = pw_grid%bounds_local(2, :) &
941 - pw_grid%bounds_local(1, :) + 1
944 ALLOCATE (pw_grid%para%bo(2, 3, 0:np - 1, 3))
945 rsd = pw_grid%para%group%num_pe_cart
947 IF (
PRESENT(bounds_local))
THEN
950 axis_dist(:, i) = bounds_local(:, i) - pw_grid%bounds(1, i) + 1
952 ALLOCATE (axis_dist_all(2, 3, np))
953 CALL pw_grid%para%group%allgather(axis_dist, axis_dist_all)
955 CALL pw_grid%para%group%coords(ip, coor)
957 pw_grid%para%bo(1:2, 1, ip, 1) = axis_dist_all(1:2, 1, ip + 1)
958 pw_grid%para%bo(1:2, 2, ip, 1) = axis_dist_all(1:2, 2, ip + 1)
959 pw_grid%para%bo(1, 3, ip, 1) = 1
960 pw_grid%para%bo(2, 3, ip, 1) = nz
962 pw_grid%para%bo(1:2, 1, ip, 2) = axis_dist_all(1:2, 1, ip + 1)
963 pw_grid%para%bo(1, 2, ip, 2) = 1
964 pw_grid%para%bo(2, 2, ip, 2) = ny
965 pw_grid%para%bo(1:2, 3, ip, 2) = get_limit(nz, rsd(2), coor(2))
967 pw_grid%para%bo(1, 1, ip, 3) = 1
968 pw_grid%para%bo(2, 1, ip, 3) = nx
969 pw_grid%para%bo(1:2, 2, ip, 3) = get_limit(ny, rsd(1), coor(1))
970 pw_grid%para%bo(1:2, 3, ip, 3) = get_limit(nz, rsd(2), coor(2))
972 DEALLOCATE (axis_dist_all)
975 CALL pw_grid%para%group%coords(ip, coor)
977 pw_grid%para%bo(1:2, 1, ip, 1) = get_limit(nx, rsd(1), coor(1))
978 pw_grid%para%bo(1:2, 2, ip, 1) = get_limit(ny, rsd(2), coor(2))
979 pw_grid%para%bo(1, 3, ip, 1) = 1
980 pw_grid%para%bo(2, 3, ip, 1) = nz
982 pw_grid%para%bo(1:2, 1, ip, 2) = get_limit(nx, rsd(1), coor(1))
983 pw_grid%para%bo(1, 2, ip, 2) = 1
984 pw_grid%para%bo(2, 2, ip, 2) = ny
985 pw_grid%para%bo(1:2, 3, ip, 2) = get_limit(nz, rsd(2), coor(2))
987 pw_grid%para%bo(1, 1, ip, 3) = 1
988 pw_grid%para%bo(2, 1, ip, 3) = nx
989 pw_grid%para%bo(1:2, 2, ip, 3) = get_limit(ny, rsd(1), coor(1))
990 pw_grid%para%bo(1:2, 3, ip, 3) = get_limit(nz, rsd(2), coor(2))
994 pw_grid%ngpts_cut_local = 0
996 ALLOCATE (pw_grid%para%nyzray(0:np - 1))
998 ALLOCATE (pw_grid%para%yzq(ny, nz))
1000 IF (pw_grid%spherical .OR. pw_grid%grid_span == halfspace &
1001 .OR. .NOT. blocking)
THEN
1003 pw_grid%para%ray_distribution = .true.
1005 pw_grid%para%yzq = -1
1006 IF (
PRESENT(ref_grid))
THEN
1008 CALL pre_tag(pw_grid, yz_mask, ref_grid)
1015 i1 =
SIZE(yz_mask, 1)
1016 i2 =
SIZE(yz_mask, 2)
1017 ALLOCATE (yz_index(2, i1*i2))
1018 CALL order_mask(yz_mask, yz_index)
1020 lo(1) = yz_index(1, i)
1021 lo(2) = yz_index(2, i)
1022 IF (lo(1)*lo(2) == 0) cycle
1023 gmax = yz_mask(lo(1), lo(2))
1024 IF (gmax == 0) cycle
1025 yz_mask(lo(1), lo(2)) = 0
1026 ip = mod(i - 1, 2*np)
1027 IF (ip > np - 1) ip = 2*np - ip - 1
1028 IF (ip == pw_grid%para%group%mepos)
THEN
1029 pw_grid%ngpts_cut_local = pw_grid%ngpts_cut_local + gmax
1031 pw_grid%para%yzq(lo(1), lo(2)) = ip
1032 IF (pw_grid%grid_span == halfspace)
THEN
1033 m = -lo(1) - 2*lby + 2
1034 n = -lo(2) - 2*lbz + 2
1035 pw_grid%para%yzq(m, n) = ip
1040 DEALLOCATE (yz_index)
1043 pw_grid%para%nyzray = 0
1046 ip = pw_grid%para%yzq(j, i)
1047 IF (ip >= 0) pw_grid%para%nyzray(ip) = &
1048 pw_grid%para%nyzray(ip) + 1
1053 ns = maxval(pw_grid%para%nyzray(0:np - 1))
1054 ALLOCATE (pw_grid%para%yzp(2, ns, 0:np - 1))
1057 pw_grid%para%nyzray = 0
1060 ip = pw_grid%para%yzq(j, i)
1062 pw_grid%para%nyzray(ip) = &
1063 pw_grid%para%nyzray(ip) + 1
1064 ns = pw_grid%para%nyzray(ip)
1065 pw_grid%para%yzp(1, ns, ip) = j
1066 pw_grid%para%yzp(2, ns, ip) = i
1067 IF (ip == pw_grid%para%group%mepos)
THEN
1068 pw_grid%para%yzq(j, i) = ns
1070 pw_grid%para%yzq(j, i) = -1
1073 pw_grid%para%yzq(j, i) = -2
1078 pw_grid%ngpts_local = product(pw_grid%npts_local)
1085 pw_grid%para%blocked = .true.
1086 pw_grid%para%ray_distribution = .false.
1089 m = pw_grid%para%bo(2, 2, ip, 3) - &
1090 pw_grid%para%bo(1, 2, ip, 3) + 1
1091 n = pw_grid%para%bo(2, 3, ip, 3) - &
1092 pw_grid%para%bo(1, 3, ip, 3) + 1
1093 pw_grid%para%nyzray(ip) = n*m
1096 ipl = pw_grid%para%group%mepos
1097 l = pw_grid%para%bo(2, 1, ipl, 3) - &
1098 pw_grid%para%bo(1, 1, ipl, 3) + 1
1099 m = pw_grid%para%bo(2, 2, ipl, 3) - &
1100 pw_grid%para%bo(1, 2, ipl, 3) + 1
1101 n = pw_grid%para%bo(2, 3, ipl, 3) - &
1102 pw_grid%para%bo(1, 3, ipl, 3) + 1
1103 pw_grid%ngpts_cut_local = l*m*n
1104 pw_grid%ngpts_local = pw_grid%ngpts_cut_local
1106 pw_grid%para%yzq = 0
1107 ny = pw_grid%para%bo(2, 2, ipl, 3) - &
1108 pw_grid%para%bo(1, 2, ipl, 3) + 1
1109 DO n = pw_grid%para%bo(1, 3, ipl, 3), &
1110 pw_grid%para%bo(2, 3, ipl, 3)
1111 i = n - pw_grid%para%bo(1, 3, ipl, 3)
1112 DO m = pw_grid%para%bo(1, 2, ipl, 3), &
1113 pw_grid%para%bo(2, 2, ipl, 3)
1114 j = m - pw_grid%para%bo(1, 2, ipl, 3) + 1
1115 pw_grid%para%yzq(m, n) = j + i*ny
1120 ns = maxval(pw_grid%para%nyzray(0:np - 1))
1121 ALLOCATE (pw_grid%para%yzp(2, ns, 0:np - 1))
1122 pw_grid%para%yzp = 0
1124 ALLOCATE (pemap(0:np - 1))
1126 pemap(pw_grid%para%group%mepos) = pw_grid%para%group%mepos
1127 CALL pw_grid%para%group%sum(pemap)
1132 DO n = pw_grid%para%bo(1, 3, ipp, 3), &
1133 pw_grid%para%bo(2, 3, ipp, 3)
1134 i = n - pw_grid%bounds(1, 3) + 1
1135 DO m = pw_grid%para%bo(1, 2, ipp, 3), &
1136 pw_grid%para%bo(2, 2, ipp, 3)
1137 j = m - pw_grid%bounds(1, 2) + 1
1139 pw_grid%para%yzp(1, ns, ip) = j
1140 pw_grid%para%yzp(2, ns, ip) = i
1143 cpassert(ns == pw_grid%para%nyzray(ip))
1154 IF (pw_grid%para%mode .EQ. pw_mode_distributed)
THEN
1155 ALLOCATE (pw_grid%para%pos_of_x(pw_grid%bounds(1, 1):pw_grid%bounds(2, 1)))
1156 pw_grid%para%pos_of_x = 0
1157 pw_grid%para%pos_of_x(pw_grid%bounds_local(1, 1):pw_grid%bounds_local(2, 1)) = pw_grid%para%group%mepos
1158 CALL pw_grid%para%group%sum(pw_grid%para%pos_of_x)
1161 ALLOCATE (pw_grid%para%pos_of_x(pw_grid%bounds(1, 1):pw_grid%bounds(2, 1)))
1162 pw_grid%para%pos_of_x = 0
1165 CALL timestop(handle)
1167 END SUBROUTINE pw_grid_distribute
1177 SUBROUTINE pre_tag(pw_grid, yz_mask, ref_grid)
1179 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
1180 INTEGER,
DIMENSION(:, :),
INTENT(INOUT) :: yz_mask
1181 TYPE(pw_grid_type),
INTENT(IN) :: ref_grid
1183 INTEGER :: gmax, ig, ip, lby, lbz, my, mz, ny, nz, &
1184 uby, ubz, y, yp, z, zp
1186 ny = ref_grid%npts(2)
1187 nz = ref_grid%npts(3)
1188 lby = pw_grid%bounds(1, 2)
1189 lbz = pw_grid%bounds(1, 3)
1190 uby = pw_grid%bounds(2, 2)
1191 ubz = pw_grid%bounds(2, 3)
1192 my =
SIZE(yz_mask, 1)
1193 mz =
SIZE(yz_mask, 2)
1196 DO ip = 0, ref_grid%para%group%num_pe - 1
1197 DO ig = 1, ref_grid%para%nyzray(ip)
1200 y = ref_grid%para%yzp(1, ig, ip) - 1
1201 IF (y >= ny/2) y = y - ny
1202 z = ref_grid%para%yzp(2, ig, ip) - 1
1203 IF (z >= nz/2) z = z - nz
1205 IF (y < lby .OR. y > uby .OR. z < lbz .OR. z > ubz) cycle
1210 IF (pw_grid%grid_span == halfspace)
THEN
1215 IF (yp < 1 .OR. yp > my .OR. zp < 1 .OR. zp > mz) cycle
1216 gmax = max(yz_mask(y, z), yz_mask(yp, zp))
1217 IF (gmax == 0) cycle
1220 pw_grid%para%yzq(y, z) = ip
1221 pw_grid%para%yzq(yp, zp) = ip
1223 gmax = yz_mask(y, z)
1224 IF (gmax == 0) cycle
1226 pw_grid%para%yzq(y, z) = ip
1228 IF (ip == pw_grid%para%group%mepos)
THEN
1229 pw_grid%ngpts_cut_local = pw_grid%ngpts_cut_local + gmax
1234 END SUBROUTINE pre_tag
1241 PURE SUBROUTINE order_mask(yz_mask, yz_index)
1243 INTEGER,
DIMENSION(:, :),
INTENT(IN) :: yz_mask
1244 INTEGER,
DIMENSION(:, :),
INTENT(OUT) :: yz_index
1246 INTEGER :: i1, i2, ic, icount, ii, im, jc, jj
1254 i1 =
SIZE(yz_mask, 1)
1255 i2 =
SIZE(yz_mask, 2)
1263 IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2)
THEN
1264 IF (yz_mask(ii, jj) /= 0)
THEN
1265 yz_index(1, icount) = ii
1266 yz_index(2, icount) = jj
1270 DO im = 1, max(ic + 1, jc + 1)
1272 DO jj = jc - im, jc + im
1273 IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2)
THEN
1274 IF (yz_mask(ii, jj) /= 0)
THEN
1275 yz_index(1, icount) = ii
1276 yz_index(2, icount) = jj
1282 DO jj = jc - im, jc + im
1283 IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2)
THEN
1284 IF (yz_mask(ii, jj) /= 0)
THEN
1285 yz_index(1, icount) = ii
1286 yz_index(2, icount) = jj
1292 DO ii = ic - im + 1, ic + im - 1
1293 IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2)
THEN
1294 IF (yz_mask(ii, jj) /= 0)
THEN
1295 yz_index(1, icount) = ii
1296 yz_index(2, icount) = jj
1302 DO ii = ic - im + 1, ic + im - 1
1303 IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2)
THEN
1304 IF (yz_mask(ii, jj) /= 0)
THEN
1305 yz_index(1, icount) = ii
1306 yz_index(2, icount) = jj
1313 END SUBROUTINE order_mask
1325 PURE SUBROUTINE pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1327 REAL(KIND=dp),
DIMENSION(3, 3),
INTENT(IN) :: h_inv
1328 REAL(KIND=dp),
INTENT(OUT) :: length_x, length_y, length_z, length
1329 INTEGER,
INTENT(IN) :: l, m, n
1332 = real(l, dp)*h_inv(1, 1) &
1333 + real(m, dp)*h_inv(2, 1) &
1334 + real(n, dp)*h_inv(3, 1)
1336 = real(l, dp)*h_inv(1, 2) &
1337 + real(m, dp)*h_inv(2, 2) &
1338 + real(n, dp)*h_inv(3, 2)
1340 = real(l, dp)*h_inv(1, 3) &
1341 + real(m, dp)*h_inv(2, 3) &
1342 + real(n, dp)*h_inv(3, 3)
1345 IF (l == 0 .AND. m == 0 .AND. n == 0)
THEN
1351 length_x = length_x*twopi
1352 length_y = length_y*twopi
1353 length_z = length_z*twopi
1355 length = length_x**2 + length_y**2 + length_z**2
1371 SUBROUTINE pw_grid_count(h_inv, pw_grid, mp_comm, cutoff, yz_mask)
1373 REAL(KIND=dp),
DIMENSION(3, 3) :: h_inv
1374 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
1376 CLASS(mp_comm_type),
INTENT(IN) :: mp_comm
1377 REAL(KIND=dp),
INTENT(IN) :: cutoff
1378 INTEGER,
DIMENSION(:, :),
INTENT(OUT) :: yz_mask
1380 INTEGER :: l, m, mm, n, n_upperlimit, nlim(2), nn
1381 INTEGER(KIND=int_8) :: gpt
1382 REAL(KIND=dp) :: length, length_x, length_y, length_z
1384 associate(bounds => pw_grid%bounds)
1386 IF (pw_grid%grid_span == halfspace)
THEN
1388 ELSE IF (pw_grid%grid_span == fullspace)
THEN
1389 n_upperlimit = bounds(2, 3)
1391 cpabort(
"No type set for the grid")
1396 IF (pw_grid%para%mode == pw_mode_local)
THEN
1397 nlim(1) = bounds(1, 3)
1398 nlim(2) = n_upperlimit
1399 ELSE IF (pw_grid%para%mode == pw_mode_distributed)
THEN
1400 n = n_upperlimit - bounds(1, 3) + 1
1401 nlim = get_limit(n, mp_comm%num_pe, mp_comm%mepos)
1402 nlim = nlim + bounds(1, 3) - 1
1404 cpabort(
"para % mode not specified")
1408 DO n = nlim(1), nlim(2)
1409 nn = n - bounds(1, 3) + 1
1410 DO m = bounds(1, 2), bounds(2, 2)
1411 mm = m - bounds(1, 2) + 1
1412 DO l = bounds(1, 1), bounds(2, 1)
1413 IF (pw_grid%grid_span == halfspace .AND. n == 0)
THEN
1414 IF ((m == 0 .AND. l > 0) .OR. (m > 0)) cycle
1417 CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1419 IF (0.5_dp*length <= cutoff)
THEN
1421 yz_mask(mm, nn) = yz_mask(mm, nn) + 1
1430 IF (pw_grid%para%mode == pw_mode_distributed)
THEN
1431 CALL mp_comm%sum(gpt)
1432 CALL mp_comm%sum(yz_mask)
1434 pw_grid%ngpts_cut = gpt
1436 END SUBROUTINE pw_grid_count
1448 SUBROUTINE pw_grid_assign(h_inv, pw_grid, cutoff)
1450 REAL(KIND=dp),
DIMENSION(3, 3) :: h_inv
1451 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
1452 REAL(kind=dp),
INTENT(IN) :: cutoff
1454 CHARACTER(len=*),
PARAMETER :: routinen =
'pw_grid_assign'
1456 INTEGER :: gpt, handle, i, ip, l, lby, lbz, ll, m, &
1457 mm, n, n_upperlimit, nn
1458 INTEGER(KIND=int_8) :: gpt_global
1459 INTEGER,
DIMENSION(2, 3) :: bol, bounds
1460 REAL(kind=dp) :: length, length_x, length_y, length_z
1462 CALL timeset(routinen, handle)
1464 bounds = pw_grid%bounds
1465 lby = pw_grid%bounds(1, 2)
1466 lbz = pw_grid%bounds(1, 3)
1468 IF (pw_grid%grid_span == halfspace)
THEN
1470 ELSE IF (pw_grid%grid_span == fullspace)
THEN
1471 n_upperlimit = bounds(2, 3)
1473 cpabort(
"No type set for the grid")
1477 IF (pw_grid%para%mode == pw_mode_local)
THEN
1479 DO n = bounds(1, 3), n_upperlimit
1480 DO m = bounds(1, 2), bounds(2, 2)
1481 DO l = bounds(1, 1), bounds(2, 1)
1482 IF (pw_grid%grid_span == halfspace .AND. n == 0)
THEN
1483 IF ((m == 0 .AND. l > 0) .OR. (m > 0)) cycle
1486 CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1488 IF (0.5_dp*length <= cutoff)
THEN
1490 pw_grid%g(1, gpt) = length_x
1491 pw_grid%g(2, gpt) = length_y
1492 pw_grid%g(3, gpt) = length_z
1493 pw_grid%gsq(gpt) = length
1494 pw_grid%g_hat(1, gpt) = l
1495 pw_grid%g_hat(2, gpt) = m
1496 pw_grid%g_hat(3, gpt) = n
1505 IF (pw_grid%para%ray_distribution)
THEN
1508 ip = pw_grid%para%group%mepos
1509 DO i = 1, pw_grid%para%nyzray(ip)
1510 n = pw_grid%para%yzp(2, i, ip) + lbz - 1
1511 m = pw_grid%para%yzp(1, i, ip) + lby - 1
1512 IF (n > n_upperlimit) cycle
1513 DO l = bounds(1, 1), bounds(2, 1)
1514 IF (pw_grid%grid_span == halfspace .AND. n == 0)
THEN
1515 IF ((m == 0 .AND. l > 0) .OR. (m > 0)) cycle
1518 CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1520 IF (0.5_dp*length <= cutoff)
THEN
1522 pw_grid%g(1, gpt) = length_x
1523 pw_grid%g(2, gpt) = length_y
1524 pw_grid%g(3, gpt) = length_z
1525 pw_grid%gsq(gpt) = length
1526 pw_grid%g_hat(1, gpt) = l
1527 pw_grid%g_hat(2, gpt) = m
1528 pw_grid%g_hat(3, gpt) = n
1536 bol = pw_grid%para%bo(:, :, pw_grid%para%group%mepos, 3)
1538 DO n = bounds(1, 3), bounds(2, 3)
1540 nn = n + pw_grid%npts(3) + 1
1544 IF (nn < bol(1, 3) .OR. nn > bol(2, 3)) cycle
1545 DO m = bounds(1, 2), bounds(2, 2)
1547 mm = m + pw_grid%npts(2) + 1
1551 IF (mm < bol(1, 2) .OR. mm > bol(2, 2)) cycle
1552 DO l = bounds(1, 1), bounds(2, 1)
1554 ll = l + pw_grid%npts(1) + 1
1558 IF (ll < bol(1, 1) .OR. ll > bol(2, 1)) cycle
1560 CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1563 pw_grid%g(1, gpt) = length_x
1564 pw_grid%g(2, gpt) = length_y
1565 pw_grid%g(3, gpt) = length_z
1566 pw_grid%gsq(gpt) = length
1567 pw_grid%g_hat(1, gpt) = l
1568 pw_grid%g_hat(2, gpt) = m
1569 pw_grid%g_hat(3, gpt) = n
1580 cpassert(pw_grid%ngpts_cut_local == gpt)
1581 IF (pw_grid%para%mode == pw_mode_distributed)
THEN
1583 CALL pw_grid%para%group%sum(gpt_global)
1584 cpassert(pw_grid%ngpts_cut == gpt_global)
1587 pw_grid%have_g0 = .false.
1588 pw_grid%first_gne0 = 1
1589 DO gpt = 1, pw_grid%ngpts_cut_local
1590 IF (all(pw_grid%g_hat(:, gpt) == 0))
THEN
1591 pw_grid%have_g0 = .true.
1592 pw_grid%first_gne0 = 2
1597 CALL pw_grid_set_maps(pw_grid%grid_span, pw_grid%g_hat, &
1598 pw_grid%mapl, pw_grid%mapm, pw_grid%mapn, pw_grid%npts)
1600 CALL timestop(handle)
1602 END SUBROUTINE pw_grid_assign
1619 SUBROUTINE pw_grid_set_maps(grid_span, g_hat, mapl, mapm, mapn, npts)
1621 INTEGER,
INTENT(IN) :: grid_span
1622 INTEGER,
DIMENSION(:, :),
INTENT(IN) :: g_hat
1623 TYPE(map_pn),
INTENT(INOUT) :: mapl, mapm, mapn
1624 INTEGER,
DIMENSION(:),
INTENT(IN) :: npts
1626 INTEGER :: gpt, l, m, n, ng
1635 mapl%pos(l) = l + npts(1)
1640 mapm%pos(m) = m + npts(2)
1645 mapn%pos(n) = n + npts(3)
1652 IF (grid_span == halfspace)
THEN
1657 mapl%neg(l) = npts(1) - l
1662 mapm%neg(m) = npts(2) - m
1667 mapn%neg(n) = npts(3) - n
1674 END SUBROUTINE pw_grid_set_maps
1688 SUBROUTINE pw_grid_allocate(pw_grid, ng, bounds)
1691 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
1692 INTEGER,
INTENT(IN) :: ng
1693 INTEGER,
DIMENSION(:, :),
INTENT(IN) :: bounds
1695 CHARACTER(len=*),
PARAMETER :: routineN =
'pw_grid_allocate'
1698#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
1699 INTEGER(KIND=C_SIZE_T) :: length
1700 TYPE(c_ptr) :: cptr_g_hatmap
1706 CALL timeset(routinen, handle)
1708 ALLOCATE (pw_grid%g(3, ng))
1709 ALLOCATE (pw_grid%gsq(ng))
1710 ALLOCATE (pw_grid%g_hat(3, ng))
1713 IF (pw_grid%grid_span == halfspace) nmaps = 2
1714#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
1717 length = int(int_size*max(ng, 1)*max(nmaps, 1), kind=c_size_t)
1718 stat = offload_malloc_pinned_mem(cptr_g_hatmap, length)
1720 CALL c_f_pointer(cptr_g_hatmap, pw_grid%g_hatmap, (/max(ng, 1), max(nmaps, 1)/))
1722 ALLOCATE (pw_grid%g_hatmap(1, 1))
1725 IF (pw_grid%para%mode == pw_mode_distributed)
THEN
1726 ALLOCATE (pw_grid%grays(pw_grid%npts(1), &
1727 pw_grid%para%nyzray(pw_grid%para%group%mepos)))
1730 ALLOCATE (pw_grid%mapl%pos(bounds(1, 1):bounds(2, 1)))
1731 ALLOCATE (pw_grid%mapl%neg(bounds(1, 1):bounds(2, 1)))
1732 ALLOCATE (pw_grid%mapm%pos(bounds(1, 2):bounds(2, 2)))
1733 ALLOCATE (pw_grid%mapm%neg(bounds(1, 2):bounds(2, 2)))
1734 ALLOCATE (pw_grid%mapn%pos(bounds(1, 3):bounds(2, 3)))
1735 ALLOCATE (pw_grid%mapn%neg(bounds(1, 3):bounds(2, 3)))
1737 CALL timestop(handle)
1739 END SUBROUTINE pw_grid_allocate
1760 SUBROUTINE pw_grid_sort(pw_grid, ref_grid)
1763 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
1764 TYPE(pw_grid_type),
INTENT(IN),
OPTIONAL :: ref_grid
1766 CHARACTER(len=*),
PARAMETER :: routineN =
'pw_grid_sort'
1768 INTEGER :: handle, i, ig, ih, ip, is, it, ng, ngr
1769 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: idx
1770 INTEGER,
ALLOCATABLE,
DIMENSION(:, :) :: int_tmp
1772 REAL(KIND=dp) :: gig, gigr
1773 REAL(KIND=dp),
ALLOCATABLE,
DIMENSION(:, :) :: real_tmp
1775 CALL timeset(routinen, handle)
1777 ng =
SIZE(pw_grid%gsq)
1781 CALL sort(pw_grid%gsq, ng, idx)
1783 CALL sort_shells(pw_grid%gsq, pw_grid%g_hat, idx)
1785 ALLOCATE (real_tmp(3, ng))
1787 real_tmp(1, i) = pw_grid%g(1, idx(i))
1788 real_tmp(2, i) = pw_grid%g(2, idx(i))
1789 real_tmp(3, i) = pw_grid%g(3, idx(i))
1792 pw_grid%g(1, i) = real_tmp(1, i)
1793 pw_grid%g(2, i) = real_tmp(2, i)
1794 pw_grid%g(3, i) = real_tmp(3, i)
1796 DEALLOCATE (real_tmp)
1798 ALLOCATE (int_tmp(3, ng))
1800 int_tmp(1, i) = pw_grid%g_hat(1, idx(i))
1801 int_tmp(2, i) = pw_grid%g_hat(2, idx(i))
1802 int_tmp(3, i) = pw_grid%g_hat(3, idx(i))
1805 pw_grid%g_hat(1, i) = int_tmp(1, i)
1806 pw_grid%g_hat(2, i) = int_tmp(2, i)
1807 pw_grid%g_hat(3, i) = int_tmp(3, i)
1809 DEALLOCATE (int_tmp)
1814 IF (
PRESENT(ref_grid))
THEN
1815 ngr =
SIZE(ref_grid%gsq)
1817 IF (pw_grid%spherical)
THEN
1818 IF (.NOT. all(pw_grid%g_hat(1:3, 1:ngr) &
1819 == ref_grid%g_hat(1:3, 1:ngr)))
THEN
1820 cpabort(
"G space sorting not compatible")
1823 ALLOCATE (pw_grid%gidx(1:ngr))
1828 IF (.NOT. all(pw_grid%g_hat(1:3, ig) &
1829 == ref_grid%g_hat(1:3, ig)))
EXIT
1830 pw_grid%gidx(ig) = ig
1838 gig = pw_grid%gsq(ig)
1839 gigr = max(1._dp, gig)
1841 DO ih = is + 1,
SIZE(ref_grid%gsq)
1842 IF (abs(gig - ref_grid%gsq(ih))/gigr > 1.e-12_dp) cycle
1846 IF (.NOT. g_found)
THEN
1847 WRITE (*,
"(A,I10,F20.10)")
"G-vector", ig, pw_grid%gsq(ig)
1848 cpabort(
"G vector not found")
1851 DO ih = ip + 1,
SIZE(ref_grid%gsq)
1852 IF (abs(gig - ref_grid%gsq(ih))/gigr > 1.e-12_dp) cycle
1853 IF (pw_grid%g_hat(1, ig) /= ref_grid%g_hat(1, ih)) cycle
1854 IF (pw_grid%g_hat(2, ig) /= ref_grid%g_hat(2, ih)) cycle
1855 IF (pw_grid%g_hat(3, ig) /= ref_grid%g_hat(3, ih)) cycle
1856 pw_grid%gidx(ig) = ih
1859 IF (pw_grid%gidx(ig) == 0)
THEN
1860 WRITE (*,
"(A,2I10)")
" G-Shell ", is + 1, ip + 1
1861 WRITE (*,
"(A,I10,3I6,F20.10)") &
1862 " G-vector", ig, pw_grid%g_hat(1:3, ig), pw_grid%gsq(ig)
1863 DO ih = 1,
SIZE(ref_grid%gsq)
1864 IF (pw_grid%g_hat(1, ig) /= ref_grid%g_hat(1, ih)) cycle
1865 IF (pw_grid%g_hat(2, ig) /= ref_grid%g_hat(2, ih)) cycle
1866 IF (pw_grid%g_hat(3, ig) /= ref_grid%g_hat(3, ih)) cycle
1867 WRITE (*,
"(A,I10,3I6,F20.10)") &
1868 " G-vector", ih, ref_grid%g_hat(1:3, ih), ref_grid%gsq(ih)
1870 cpabort(
"G vector not found")
1878 gig = ref_grid%gsq(ig)
1879 gigr = max(1._dp, gig)
1882 IF (abs(pw_grid%gsq(ih) - gig)/gigr > 1.e-12_dp) cycle
1886 IF (.NOT. g_found)
THEN
1887 WRITE (*,
"(A,I10,F20.10)")
"G-vector", ig, ref_grid%gsq(ig)
1888 cpabort(
"G vector not found")
1892 IF (abs(pw_grid%gsq(ih) - gig)/gigr > 1.e-12_dp) cycle
1893 IF (pw_grid%g_hat(1, ih) /= ref_grid%g_hat(1, ig)) cycle
1894 IF (pw_grid%g_hat(2, ih) /= ref_grid%g_hat(2, ig)) cycle
1895 IF (pw_grid%g_hat(3, ih) /= ref_grid%g_hat(3, ig)) cycle
1896 pw_grid%gidx(ig) = ih
1899 IF (pw_grid%gidx(ig) == 0)
THEN
1900 WRITE (*,
"(A,2I10)")
" G-Shell ", is + 1, ip + 1
1901 WRITE (*,
"(A,I10,3I6,F20.10)") &
1902 " G-vector", ig, ref_grid%g_hat(1:3, ig), ref_grid%gsq(ig)
1904 IF (pw_grid%g_hat(1, ih) /= ref_grid%g_hat(1, ig)) cycle
1905 IF (pw_grid%g_hat(2, ih) /= ref_grid%g_hat(2, ig)) cycle
1906 IF (pw_grid%g_hat(3, ih) /= ref_grid%g_hat(3, ig)) cycle
1907 WRITE (*,
"(A,I10,3I6,F20.10)") &
1908 " G-vector", ih, pw_grid%g_hat(1:3, ih), pw_grid%gsq(ih)
1910 cpabort(
"G vector not found")
1916 IF (any(pw_grid%gidx == 0))
THEN
1917 cpabort(
"G space sorting not compatible")
1923 IF (pw_grid%have_g0)
THEN
1924 IF (pw_grid%gsq(1) /= 0.0_dp)
THEN
1925 cpabort(
"G = 0 not in first position")
1929 CALL timestop(handle)
1931 END SUBROUTINE pw_grid_sort
1939 SUBROUTINE sort_shells(gsq, g_hat, idx)
1942 REAL(KIND=dp),
DIMENSION(:),
INTENT(IN) :: gsq
1943 INTEGER,
DIMENSION(:, :),
INTENT(IN) :: g_hat
1944 INTEGER,
DIMENSION(:),
INTENT(INOUT) :: idx
1946 CHARACTER(len=*),
PARAMETER :: routineN =
'sort_shells'
1947 REAL(KIND=dp),
PARAMETER :: small = 5.e-16_dp
1949 INTEGER :: handle, ig, ng, s1, s2
1950 REAL(KIND=dp) :: s_begin
1952 CALL timeset(routinen, handle)
1963 IF (abs(gsq(ig) - s_begin) < small)
THEN
1966 CALL redist(g_hat, idx, s1, s2)
1972 CALL redist(g_hat, idx, s1, s2)
1974 CALL timestop(handle)
1976 END SUBROUTINE sort_shells
1985 SUBROUTINE redist(g_hat, idx, s1, s2)
1988 INTEGER,
DIMENSION(:, :),
INTENT(IN) :: g_hat
1989 INTEGER,
DIMENSION(:),
INTENT(INOUT) :: idx
1990 INTEGER,
INTENT(IN) :: s1, s2
1992 INTEGER :: i, ii, n1, n2, n3, ns
1993 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: indl
1994 REAL(KIND=dp),
ALLOCATABLE,
DIMENSION(:) :: slen
1996 IF (s2 <= s1)
RETURN
2006 slen(i - s1 + 1) = 1000.0_dp*real(n1, dp) + &
2007 REAL(n2, dp) + 0.001_dp*
REAL(n3, dp)
2009 CALL sort(slen, ns, indl)
2011 ii = indl(i) + s1 - 1
2014 idx(s1:s2) = indl(1:ns)
2019 END SUBROUTINE redist
2029 SUBROUTINE pw_grid_remap(pw_grid, yz)
2032 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
2033 INTEGER,
DIMENSION(:, :),
INTENT(OUT) :: yz
2035 CHARACTER(len=*),
PARAMETER :: routineN =
'pw_grid_remap'
2037 INTEGER :: gpt, handle, i, ip, is, j, m, n
2039 IF (pw_grid%para%mode == pw_mode_local)
RETURN
2041 CALL timeset(routinen, handle)
2043 associate(ny => pw_grid%npts(2), nz => pw_grid%npts(3), posm => pw_grid%mapm%pos, posn => pw_grid%mapn%pos, &
2044 negm => pw_grid%mapm%neg, negn => pw_grid%mapn%neg)
2047 pw_grid%para%yzp = 0
2048 pw_grid%para%yzq = 0
2050 DO gpt = 1,
SIZE(pw_grid%gsq)
2051 m = posm(pw_grid%g_hat(2, gpt)) + 1
2052 n = posn(pw_grid%g_hat(3, gpt)) + 1
2053 yz(m, n) = yz(m, n) + 1
2055 IF (pw_grid%grid_span == halfspace)
THEN
2056 DO gpt = 1,
SIZE(pw_grid%gsq)
2057 m = negm(pw_grid%g_hat(2, gpt)) + 1
2058 n = negn(pw_grid%g_hat(3, gpt)) + 1
2059 yz(m, n) = yz(m, n) + 1
2063 ip = pw_grid%para%group%mepos
2067 IF (yz(j, i) > 0)
THEN
2069 pw_grid%para%yzp(1, is, ip) = j
2070 pw_grid%para%yzp(2, is, ip) = i
2071 pw_grid%para%yzq(j, i) = is
2077 cpassert(is == pw_grid%para%nyzray(ip))
2078 CALL pw_grid%para%group%sum(pw_grid%para%yzp)
2080 CALL timestop(handle)
2082 END SUBROUTINE pw_grid_remap
2099 REAL(kind=dp),
DIMENSION(3, 3),
INTENT(IN) :: cell_hmat
2100 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
2103 REAL(kind=dp) :: cell_deth, l, m, n
2104 REAL(kind=dp),
DIMENSION(3, 3) :: cell_h_inv
2105 REAL(kind=dp),
DIMENSION(:, :),
POINTER :: g
2107 cell_deth = abs(det_3x3(cell_hmat))
2108 IF (cell_deth < 1.0e-10_dp)
THEN
2109 CALL cp_abort(__location__, &
2110 "An invalid set of cell vectors was specified. "// &
2111 "The determinant det(h) is too small")
2113 cell_h_inv = inv_3x3(cell_hmat)
2117 CALL cell2grid(cell_hmat, cell_h_inv, cell_deth, pw_grid)
2119 DO gpt = 1,
SIZE(g, 2)
2121 l = twopi*real(pw_grid%g_hat(1, gpt), kind=dp)
2122 m = twopi*real(pw_grid%g_hat(2, gpt), kind=dp)
2123 n = twopi*real(pw_grid%g_hat(3, gpt), kind=dp)
2125 g(1, gpt) = l*cell_h_inv(1, 1) + m*cell_h_inv(2, 1) + n*cell_h_inv(3, 1)
2126 g(2, gpt) = l*cell_h_inv(1, 2) + m*cell_h_inv(2, 2) + n*cell_h_inv(3, 2)
2127 g(3, gpt) = l*cell_h_inv(1, 3) + m*cell_h_inv(2, 3) + n*cell_h_inv(3, 3)
2129 pw_grid%gsq(gpt) = g(1, gpt)*g(1, gpt) &
2130 + g(2, gpt)*g(2, gpt) &
2131 + g(3, gpt)*g(3, gpt)
2147 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
2149 cpassert(pw_grid%ref_count > 0)
2150 pw_grid%ref_count = pw_grid%ref_count + 1
2164 TYPE(pw_grid_type),
POINTER :: pw_grid
2166#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
2167 INTEGER,
POINTER :: dummy_ptr
2171 IF (
ASSOCIATED(pw_grid))
THEN
2172 cpassert(pw_grid%ref_count > 0)
2173 pw_grid%ref_count = pw_grid%ref_count - 1
2174 IF (pw_grid%ref_count == 0)
THEN
2175 IF (
ASSOCIATED(pw_grid%gidx))
THEN
2176 DEALLOCATE (pw_grid%gidx)
2178 IF (
ASSOCIATED(pw_grid%g))
THEN
2179 DEALLOCATE (pw_grid%g)
2181 IF (
ASSOCIATED(pw_grid%gsq))
THEN
2182 DEALLOCATE (pw_grid%gsq)
2184 IF (
ALLOCATED(pw_grid%g_hat))
THEN
2185 DEALLOCATE (pw_grid%g_hat)
2187 IF (
ASSOCIATED(pw_grid%g_hatmap))
THEN
2188#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
2189 dummy_ptr => pw_grid%g_hatmap(1, 1)
2190 stat = offload_free_pinned_mem(c_loc(dummy_ptr))
2193 DEALLOCATE (pw_grid%g_hatmap)
2196 IF (
ASSOCIATED(pw_grid%grays))
THEN
2197 DEALLOCATE (pw_grid%grays)
2199 IF (
ALLOCATED(pw_grid%mapl%pos))
THEN
2200 DEALLOCATE (pw_grid%mapl%pos)
2202 IF (
ALLOCATED(pw_grid%mapm%pos))
THEN
2203 DEALLOCATE (pw_grid%mapm%pos)
2205 IF (
ALLOCATED(pw_grid%mapn%pos))
THEN
2206 DEALLOCATE (pw_grid%mapn%pos)
2208 IF (
ALLOCATED(pw_grid%mapl%neg))
THEN
2209 DEALLOCATE (pw_grid%mapl%neg)
2211 IF (
ALLOCATED(pw_grid%mapm%neg))
THEN
2212 DEALLOCATE (pw_grid%mapm%neg)
2214 IF (
ALLOCATED(pw_grid%mapn%neg))
THEN
2215 DEALLOCATE (pw_grid%mapn%neg)
2217 IF (
ALLOCATED(pw_grid%para%bo))
THEN
2218 DEALLOCATE (pw_grid%para%bo)
2220 IF (pw_grid%para%mode == pw_mode_distributed)
THEN
2221 IF (
ALLOCATED(pw_grid%para%yzp))
THEN
2222 DEALLOCATE (pw_grid%para%yzp)
2224 IF (
ALLOCATED(pw_grid%para%yzq))
THEN
2225 DEALLOCATE (pw_grid%para%yzq)
2227 IF (
ALLOCATED(pw_grid%para%nyzray))
THEN
2228 DEALLOCATE (pw_grid%para%nyzray)
2232 CALL pw_grid%para%group%free()
2233 IF (
ALLOCATED(pw_grid%para%pos_of_x))
THEN
2234 DEALLOCATE (pw_grid%para%pos_of_x)
2237 IF (
ASSOCIATED(pw_grid))
THEN
2238 DEALLOCATE (pw_grid)
Defines the basic variable types.
integer, parameter, public int_8
integer, parameter, public dp
integer, parameter, public int_size
Definition of mathematical constants and functions.
real(kind=dp), parameter, public twopi
Collection of simple mathematical functions and subroutines.
pure real(kind=dp) function, dimension(3, 3), public inv_3x3(a)
Returns the inverse of the 3 x 3 matrix a.
Interface to the message passing library MPI.
subroutine, public mp_dims_create(nodes, dims)
wrapper to MPI_Dims_create
type(mp_comm_type), parameter, public mp_comm_self
Fortran API for the offload package, which is written in C.
subroutine, public offload_activate_chosen_device()
Activates the device selected via offload_set_chosen_device()
integer function, public offload_free_pinned_mem(buffer)
free pinned memory
integer function, public offload_malloc_pinned_mem(buffer, length)
allocate pinned memory.
This module returns additional info on PW grids.
real(kind=dp) function, public pw_find_cutoff(npts, h_inv)
Given a grid and a box, calculate the corresponding cutoff *** This routine calculates the cutoff in ...
integer function, dimension(2, 3), public pw_grid_bounds_from_n(npts)
returns the bounds that distribute n points evenly around 0
integer function, dimension(3), public pw_grid_init_setup(hmat, cutoff, spherical, odd, fft_usage, ncommensurate, icommensurate, ref_grid, n_orig)
...
integer, parameter, public halfspace
integer, parameter, public pw_mode_local
integer, parameter, public fullspace
integer, parameter, public pw_mode_distributed
This module defines the grid data type and some basic operations on it.
logical function, public pw_grid_compare(grida, gridb)
Check if two pw_grids are equal.
integer, parameter, public do_pw_grid_blocked_false
subroutine, public pw_grid_release(pw_grid)
releases the given pw grid
integer, parameter, public do_pw_grid_blocked_true
subroutine, public pw_grid_retain(pw_grid)
retains the given pw grid
integer, parameter, public do_pw_grid_blocked_free
subroutine, public get_pw_grid_info(pw_grid, id_nr, mode, vol, dvol, npts, ngpts, ngpts_cut, dr, cutoff, orthorhombic, gvectors, gsquare)
Access to information stored in the pw_grid_type.
subroutine, public pw_grid_change(cell_hmat, pw_grid)
Recalculate the g-vectors after a change of the box.
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_activate_chosen_device(void)
Activates the device selected via offload_set_chosen_device()