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 CALL pw_grid_create_ghatmap(pw_grid)
424 CALL timestop(handle)
426 END SUBROUTINE pw_grid_create_extended
433 SUBROUTINE pw_grid_create_ghatmap(pw_grid)
437 CHARACTER(len=*),
PARAMETER :: routinen =
'pw_grid_create_ghatmap'
439 INTEGER :: gpt, handle, l, m, mn, n
441 CALL timeset(routinen, handle)
444 cpassert(pw_grid%ref_count > 0)
448 associate(g_hat => pw_grid%g_hat, g_hatmap => pw_grid%g_hatmap, pmapl => pw_grid%mapl%pos, &
449 pmapm => pw_grid%mapm%pos, pmapn => pw_grid%mapn%pos, nmapl => pw_grid%mapl%neg, &
450 nmapm => pw_grid%mapm%neg, nmapn => pw_grid%mapn%neg, ngpts =>
SIZE(pw_grid%gsq), &
451 npts => pw_grid%npts, yzq => pw_grid%para%yzq)
456 cpassert(product(int(npts, kind=
int_8)) <= int(huge(0), kind=
int_8))
458 l = pmapl(g_hat(1, gpt))
459 m = pmapm(g_hat(2, gpt))
460 n = pmapn(g_hat(3, gpt))
463 g_hatmap(gpt, 1) = l + npts(1)*(m + npts(2)*n)
467 l = nmapl(g_hat(1, gpt))
468 m = nmapm(g_hat(2, gpt))
469 n = nmapn(g_hat(3, gpt))
472 g_hatmap(gpt, 2) = l + npts(1)*(m + npts(2)*n)
477 l = pmapl(g_hat(1, gpt))
478 m = pmapm(g_hat(2, gpt)) + 1
479 n = pmapn(g_hat(3, gpt)) + 1
483 g_hatmap(gpt, 1) = l + npts(1)*mn
487 l = nmapl(g_hat(1, gpt))
488 m = nmapm(g_hat(2, gpt)) + 1
489 n = nmapn(g_hat(3, gpt)) + 1
493 g_hatmap(gpt, 2) = l + npts(1)*mn
499 CALL timestop(handle)
501 END SUBROUTINE pw_grid_create_ghatmap
530 SUBROUTINE pw_grid_setup_internal(cell_hmat, cell_h_inv, cell_deth, pw_grid, mp_comm, bounds_local, &
531 blocked, ref_grid, rs_dims, iounit)
532 REAL(kind=dp),
DIMENSION(3, 3),
INTENT(IN) :: cell_hmat, cell_h_inv
533 REAL(kind=dp),
INTENT(IN) :: cell_deth
534 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
536 CLASS(mp_comm_type),
INTENT(IN) :: mp_comm
537 INTEGER,
DIMENSION(2, 3),
INTENT(IN),
OPTIONAL :: bounds_local
538 INTEGER,
INTENT(in),
OPTIONAL :: blocked
539 TYPE(pw_grid_type),
INTENT(in),
OPTIONAL :: ref_grid
540 INTEGER,
DIMENSION(2),
INTENT(in),
OPTIONAL :: rs_dims
541 INTEGER,
INTENT(in),
OPTIONAL :: iounit
543 CHARACTER(len=*),
PARAMETER :: routineN =
'pw_grid_setup_internal'
545 INTEGER :: handle, n(3)
546 INTEGER,
ALLOCATABLE,
DIMENSION(:, :) :: yz_mask
547 REAL(KIND=dp) :: ecut
551 CALL timeset(routinen, handle)
553 cpassert(pw_grid%ref_count > 0)
556 IF (
PRESENT(ref_grid))
THEN
557 pw_grid%reference = ref_grid%id_nr
560 IF (pw_grid%spherical)
THEN
561 ecut = pw_grid%cutoff
566 n(:) = pw_grid%npts(:)
572 ALLOCATE (yz_mask(n(2), n(3)))
573 CALL pw_grid_count(cell_h_inv, pw_grid, mp_comm, ecut, yz_mask)
576 IF (
PRESENT(ref_grid))
THEN
577 cpassert(pw_grid%para%mode == ref_grid%para%mode)
578 cpassert(pw_grid%grid_span == ref_grid%grid_span)
579 cpassert(pw_grid%spherical .EQV. ref_grid%spherical)
583 CALL pw_grid_distribute(pw_grid, mp_comm, yz_mask, bounds_local=bounds_local, ref_grid=ref_grid, blocked=blocked, &
587 CALL pw_grid_allocate(pw_grid, pw_grid%ngpts_cut_local, &
591 CALL pw_grid_assign(cell_h_inv, pw_grid, ecut)
594 CALL pw_grid_sort(pw_grid, ref_grid)
596 CALL pw_grid_remap(pw_grid, yz_mask)
600 CALL cell2grid(cell_hmat, cell_h_inv, cell_deth, pw_grid)
605 IF (
PRESENT(iounit))
THEN
606 CALL pw_grid_print(pw_grid, iounit)
609 CALL timestop(handle)
611 END SUBROUTINE pw_grid_setup_internal
622 SUBROUTINE cell2grid(cell_hmat, cell_h_inv, cell_deth, pw_grid)
623 REAL(KIND=dp),
DIMENSION(3, 3),
INTENT(IN) :: cell_hmat, cell_h_inv
624 REAL(KIND=dp),
INTENT(IN) :: cell_deth
625 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
627 pw_grid%vol = abs(cell_deth)
628 pw_grid%dvol = pw_grid%vol/real(pw_grid%ngpts, kind=dp)
629 pw_grid%dr(1) = sqrt(sum(cell_hmat(:, 1)**2)) &
630 /real(pw_grid%npts(1), kind=dp)
631 pw_grid%dr(2) = sqrt(sum(cell_hmat(:, 2)**2)) &
632 /real(pw_grid%npts(2), kind=dp)
633 pw_grid%dr(3) = sqrt(sum(cell_hmat(:, 3)**2)) &
634 /real(pw_grid%npts(3), kind=dp)
635 pw_grid%dh(:, 1) = cell_hmat(:, 1)/real(pw_grid%npts(1), kind=dp)
636 pw_grid%dh(:, 2) = cell_hmat(:, 2)/real(pw_grid%npts(2), kind=dp)
637 pw_grid%dh(:, 3) = cell_hmat(:, 3)/real(pw_grid%npts(3), kind=dp)
638 pw_grid%dh_inv(1, :) = cell_h_inv(1, :)*real(pw_grid%npts(1), kind=dp)
639 pw_grid%dh_inv(2, :) = cell_h_inv(2, :)*real(pw_grid%npts(2), kind=dp)
640 pw_grid%dh_inv(3, :) = cell_h_inv(3, :)*real(pw_grid%npts(3), kind=dp)
642 IF ((cell_hmat(1, 2) == 0.0_dp) .AND. (cell_hmat(1, 3) == 0.0_dp) .AND. &
643 (cell_hmat(2, 1) == 0.0_dp) .AND. (cell_hmat(2, 3) == 0.0_dp) .AND. &
644 (cell_hmat(3, 1) == 0.0_dp) .AND. (cell_hmat(3, 2) == 0.0_dp))
THEN
645 pw_grid%orthorhombic = .true.
647 pw_grid%orthorhombic = .false.
649 END SUBROUTINE cell2grid
657 SUBROUTINE pw_grid_print(pw_grid, info)
659 TYPE(pw_grid_type),
INTENT(IN) :: pw_grid
660 INTEGER,
INTENT(IN) :: info
663 INTEGER(KIND=int_8) :: n(3)
664 REAL(KIND=dp) :: rv(3, 3)
671 IF (pw_grid%para%mode == pw_mode_local)
THEN
673 WRITE (info,
'(/,A,T71,I10)') &
674 " PW_GRID| Information for grid number ", pw_grid%id_nr
675 IF (pw_grid%reference > 0)
THEN
676 WRITE (info,
'(A,T71,I10)') &
677 " PW_GRID| Number of the reference grid ", pw_grid%reference
679 WRITE (info,
'(" PW_GRID| Cutoff [a.u.]",T71,f10.1)') pw_grid%cutoff
680 IF (pw_grid%spherical)
THEN
681 WRITE (info,
'(A,T78,A)')
" PW_GRID| spherical cutoff: ",
"YES"
682 WRITE (info,
'(A,T71,I10)')
" PW_GRID| Grid points within cutoff", &
685 WRITE (info,
'(A,T78,A)')
" PW_GRID| spherical cutoff: ",
" NO"
688 WRITE (info,
'(A,I3,T30,2I8,T62,A,T71,I10)')
" PW_GRID| Bounds ", &
689 i, pw_grid%bounds(1, i), pw_grid%bounds(2, i), &
690 "Points:", pw_grid%npts(i)
692 WRITE (info,
'(A,G12.4,T50,A,T67,F14.4)') &
693 " PW_GRID| Volume element (a.u.^3)", &
694 pw_grid%dvol,
" Volume (a.u.^3) :", pw_grid%vol
695 IF (pw_grid%grid_span == halfspace)
THEN
696 WRITE (info,
'(A,T72,A)')
" PW_GRID| Grid span",
"HALFSPACE"
698 WRITE (info,
'(A,T72,A)')
" PW_GRID| Grid span",
"FULLSPACE"
703 n(1) = pw_grid%ngpts_cut_local
704 n(2) = pw_grid%ngpts_local
705 CALL pw_grid%para%group%sum(n(1:2))
706 n(3) = sum(pw_grid%para%nyzray)
707 rv(:, 1) = real(n, kind=dp)/real(pw_grid%para%group%num_pe, kind=dp)
708 n(1) = pw_grid%ngpts_cut_local
709 n(2) = pw_grid%ngpts_local
710 CALL pw_grid%para%group%max(n(1:2))
711 n(3) = maxval(pw_grid%para%nyzray)
712 rv(:, 2) = real(n, kind=dp)
713 n(1) = pw_grid%ngpts_cut_local
714 n(2) = pw_grid%ngpts_local
715 CALL pw_grid%para%group%min(n(1:2))
716 n(3) = minval(pw_grid%para%nyzray)
717 rv(:, 3) = real(n, kind=dp)
720 WRITE (info,
'(/,A,T71,I10)') &
721 " PW_GRID| Information for grid number ", pw_grid%id_nr
722 IF (pw_grid%reference > 0)
THEN
723 WRITE (info,
'(A,T71,I10)') &
724 " PW_GRID| Number of the reference grid ", pw_grid%reference
726 WRITE (info,
'(A,T60,I10,A)') &
727 " PW_GRID| Grid distributed over ", pw_grid%para%group%num_pe, &
729 WRITE (info,
'(A,T71,2I5)') &
730 " PW_GRID| Real space group dimensions ", pw_grid%para%group%num_pe_cart
731 IF (pw_grid%para%blocked)
THEN
732 WRITE (info,
'(A,T78,A)')
" PW_GRID| the grid is blocked: ",
"YES"
734 WRITE (info,
'(A,T78,A)')
" PW_GRID| the grid is blocked: ",
" NO"
736 WRITE (info,
'(" PW_GRID| Cutoff [a.u.]",T71,f10.1)') pw_grid%cutoff
737 IF (pw_grid%spherical)
THEN
738 WRITE (info,
'(A,T78,A)')
" PW_GRID| spherical cutoff: ",
"YES"
739 WRITE (info,
'(A,T71,I10)')
" PW_GRID| Grid points within cutoff", &
742 WRITE (info,
'(A,T78,A)')
" PW_GRID| spherical cutoff: ",
" NO"
745 WRITE (info,
'(A,I3,T30,2I8,T62,A,T71,I10)')
" PW_GRID| Bounds ", &
746 i, pw_grid%bounds(1, i), pw_grid%bounds(2, i), &
747 "Points:", pw_grid%npts(i)
749 WRITE (info,
'(A,G12.4,T50,A,T67,F14.4)') &
750 " PW_GRID| Volume element (a.u.^3)", &
751 pw_grid%dvol,
" Volume (a.u.^3) :", pw_grid%vol
752 IF (pw_grid%grid_span == halfspace)
THEN
753 WRITE (info,
'(A,T72,A)')
" PW_GRID| Grid span",
"HALFSPACE"
755 WRITE (info,
'(A,T72,A)')
" PW_GRID| Grid span",
"FULLSPACE"
757 WRITE (info,
'(A,T48,A)')
" PW_GRID| Distribution", &
759 WRITE (info,
'(A,T45,F12.1,2I12)')
" PW_GRID| G-Vectors", &
760 rv(1, 1), nint(rv(1, 2)), nint(rv(1, 3))
761 WRITE (info,
'(A,T45,F12.1,2I12)')
" PW_GRID| G-Rays ", &
762 rv(3, 1), nint(rv(3, 2)), nint(rv(3, 3))
763 WRITE (info,
'(A,T45,F12.1,2I12)')
" PW_GRID| Real Space Points", &
764 rv(2, 1), nint(rv(2, 2)), nint(rv(2, 3))
768 END SUBROUTINE pw_grid_print
785 SUBROUTINE pw_grid_distribute(pw_grid, mp_comm, yz_mask, bounds_local, ref_grid, blocked, rs_dims)
787 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
789 CLASS(mp_comm_type),
INTENT(IN) :: mp_comm
790 INTEGER,
DIMENSION(:, :),
INTENT(INOUT) :: yz_mask
791 INTEGER,
DIMENSION(2, 3),
INTENT(IN),
OPTIONAL :: bounds_local
792 TYPE(pw_grid_type),
INTENT(IN),
OPTIONAL :: ref_grid
793 INTEGER,
INTENT(IN),
OPTIONAL :: blocked
794 INTEGER,
DIMENSION(2),
INTENT(in),
OPTIONAL :: rs_dims
796 CHARACTER(len=*),
PARAMETER :: routineN =
'pw_grid_distribute'
798 INTEGER :: blocked_local, coor(2), gmax, handle, i, &
799 i1, i2, ip, ipl, ipp, itmp, j, l, lby, &
800 lbz, lo(2), m, n, np, ns, nx, ny, nz, &
802 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: pemap
803 INTEGER,
ALLOCATABLE,
DIMENSION(:, :) :: yz_index
804 INTEGER,
ALLOCATABLE,
DIMENSION(:, :, :) :: axis_dist_all
805 INTEGER,
DIMENSION(2) :: my_rs_dims
806 INTEGER,
DIMENSION(2, 3) :: axis_dist
811 CALL timeset(routinen, handle)
813 lby = pw_grid%bounds(1, 2)
814 lbz = pw_grid%bounds(1, 3)
816 pw_grid%ngpts = product(int(pw_grid%npts, kind=int_8))
819 IF (
PRESENT(rs_dims))
THEN
823 IF (
PRESENT(blocked))
THEN
824 blocked_local = blocked
829 pw_grid%para%blocked = .false.
831 IF (pw_grid%para%mode == pw_mode_local)
THEN
833 pw_grid%para%ray_distribution = .false.
835 pw_grid%bounds_local = pw_grid%bounds
836 pw_grid%npts_local = pw_grid%npts
837 cpassert(pw_grid%ngpts_cut < huge(pw_grid%ngpts_cut_local))
838 pw_grid%ngpts_cut_local = int(pw_grid%ngpts_cut)
839 cpassert(pw_grid%ngpts < huge(pw_grid%ngpts_local))
840 pw_grid%ngpts_local = int(pw_grid%ngpts)
842 CALL pw_grid%para%group%create(mp_comm, 2, my_rs_dims)
844 ALLOCATE (pw_grid%para%bo(2, 3, 0:0, 3))
846 pw_grid%para%bo(1, 1:3, 0, i) = 1
847 pw_grid%para%bo(2, 1:3, 0, i) = pw_grid%npts(1:3)
867 IF (any(my_rs_dims <= 0))
THEN
868 IF (all(my_rs_dims <= 0))
THEN
871 IF (my_rs_dims(1) > 0)
THEN
872 my_rs_dims(2) = np/my_rs_dims(1)
874 my_rs_dims(1) = np/my_rs_dims(2)
879 IF (product(my_rs_dims) /= np) my_rs_dims = [0, 0]
881 IF (all(my_rs_dims == [1, np])) my_rs_dims = [0, 0]
884 IF (all(my_rs_dims == [0, 0]))
THEN
888 CALL mp_dims_create(np, my_rs_dims)
890 IF (my_rs_dims(1) > my_rs_dims(2))
THEN
892 my_rs_dims(1) = my_rs_dims(2)
896 IF (my_rs_dims(1) == 1)
THEN
898 my_rs_dims(1) = my_rs_dims(2)
907 SELECT CASE (blocked_local)
913 IF (all(my_rs_dims == [np, 1]))
THEN
919 cpabort(
"Unknown PW grid blocking")
923 CALL pw_grid%para%group%create(mp_comm, 2, my_rs_dims)
925 IF (
PRESENT(bounds_local))
THEN
926 pw_grid%bounds_local = bounds_local
928 lo = get_limit(nx, pw_grid%para%group%num_pe_cart(1), &
929 pw_grid%para%group%mepos_cart(1))
930 pw_grid%bounds_local(:, 1) = lo + pw_grid%bounds(1, 1) - 1
931 lo = get_limit(ny, pw_grid%para%group%num_pe_cart(2), &
932 pw_grid%para%group%mepos_cart(2))
933 pw_grid%bounds_local(:, 2) = lo + pw_grid%bounds(1, 2) - 1
934 pw_grid%bounds_local(:, 3) = pw_grid%bounds(:, 3)
937 pw_grid%npts_local(:) = pw_grid%bounds_local(2, :) &
938 - pw_grid%bounds_local(1, :) + 1
941 ALLOCATE (pw_grid%para%bo(2, 3, 0:np - 1, 3))
942 rsd = pw_grid%para%group%num_pe_cart
944 IF (
PRESENT(bounds_local))
THEN
947 axis_dist(:, i) = bounds_local(:, i) - pw_grid%bounds(1, i) + 1
949 ALLOCATE (axis_dist_all(2, 3, np))
950 CALL pw_grid%para%group%allgather(axis_dist, axis_dist_all)
952 CALL pw_grid%para%group%coords(ip, coor)
954 pw_grid%para%bo(1:2, 1, ip, 1) = axis_dist_all(1:2, 1, ip + 1)
955 pw_grid%para%bo(1:2, 2, ip, 1) = axis_dist_all(1:2, 2, ip + 1)
956 pw_grid%para%bo(1, 3, ip, 1) = 1
957 pw_grid%para%bo(2, 3, ip, 1) = nz
959 pw_grid%para%bo(1:2, 1, ip, 2) = axis_dist_all(1:2, 1, ip + 1)
960 pw_grid%para%bo(1, 2, ip, 2) = 1
961 pw_grid%para%bo(2, 2, ip, 2) = ny
962 pw_grid%para%bo(1:2, 3, ip, 2) = get_limit(nz, rsd(2), coor(2))
964 pw_grid%para%bo(1, 1, ip, 3) = 1
965 pw_grid%para%bo(2, 1, ip, 3) = nx
966 pw_grid%para%bo(1:2, 2, ip, 3) = get_limit(ny, rsd(1), coor(1))
967 pw_grid%para%bo(1:2, 3, ip, 3) = get_limit(nz, rsd(2), coor(2))
969 DEALLOCATE (axis_dist_all)
972 CALL pw_grid%para%group%coords(ip, coor)
974 pw_grid%para%bo(1:2, 1, ip, 1) = get_limit(nx, rsd(1), coor(1))
975 pw_grid%para%bo(1:2, 2, ip, 1) = get_limit(ny, rsd(2), coor(2))
976 pw_grid%para%bo(1, 3, ip, 1) = 1
977 pw_grid%para%bo(2, 3, ip, 1) = nz
979 pw_grid%para%bo(1:2, 1, ip, 2) = get_limit(nx, rsd(1), coor(1))
980 pw_grid%para%bo(1, 2, ip, 2) = 1
981 pw_grid%para%bo(2, 2, ip, 2) = ny
982 pw_grid%para%bo(1:2, 3, ip, 2) = get_limit(nz, rsd(2), coor(2))
984 pw_grid%para%bo(1, 1, ip, 3) = 1
985 pw_grid%para%bo(2, 1, ip, 3) = nx
986 pw_grid%para%bo(1:2, 2, ip, 3) = get_limit(ny, rsd(1), coor(1))
987 pw_grid%para%bo(1:2, 3, ip, 3) = get_limit(nz, rsd(2), coor(2))
991 pw_grid%ngpts_cut_local = 0
993 ALLOCATE (pw_grid%para%nyzray(0:np - 1))
995 ALLOCATE (pw_grid%para%yzq(ny, nz))
997 IF (pw_grid%spherical .OR. pw_grid%grid_span == halfspace &
998 .OR. .NOT. blocking)
THEN
1000 pw_grid%para%ray_distribution = .true.
1004 IF (pw_grid%grid_span == halfspace)
THEN
1005 cpassert(pw_grid%bounds(2, 2) <= -pw_grid%bounds(1, 2))
1006 cpassert(pw_grid%bounds(2, 3) <= -pw_grid%bounds(1, 3))
1009 pw_grid%para%yzq = -1
1010 IF (
PRESENT(ref_grid))
THEN
1012 CALL pre_tag(pw_grid, yz_mask, ref_grid)
1019 i1 =
SIZE(yz_mask, 1)
1020 i2 =
SIZE(yz_mask, 2)
1021 ALLOCATE (yz_index(2, i1*i2))
1022 CALL order_mask(yz_mask, yz_index)
1024 lo(1) = yz_index(1, i)
1025 lo(2) = yz_index(2, i)
1026 IF (lo(1)*lo(2) == 0) cycle
1027 gmax = yz_mask(lo(1), lo(2))
1028 IF (gmax == 0) cycle
1029 yz_mask(lo(1), lo(2)) = 0
1030 ip = mod(i - 1, 2*np)
1031 IF (ip > np - 1) ip = 2*np - ip - 1
1032 IF (ip == pw_grid%para%group%mepos)
THEN
1033 pw_grid%ngpts_cut_local = pw_grid%ngpts_cut_local + gmax
1035 pw_grid%para%yzq(lo(1), lo(2)) = ip
1036 IF (pw_grid%grid_span == halfspace)
THEN
1037 m = -lo(1) - 2*lby + 2
1038 n = -lo(2) - 2*lbz + 2
1039 pw_grid%para%yzq(m, n) = ip
1044 DEALLOCATE (yz_index)
1047 pw_grid%para%nyzray = 0
1050 ip = pw_grid%para%yzq(j, i)
1051 IF (ip >= 0) pw_grid%para%nyzray(ip) = &
1052 pw_grid%para%nyzray(ip) + 1
1057 ns = maxval(pw_grid%para%nyzray(0:np - 1))
1058 ALLOCATE (pw_grid%para%yzp(2, ns, 0:np - 1))
1061 pw_grid%para%nyzray = 0
1064 ip = pw_grid%para%yzq(j, i)
1066 pw_grid%para%nyzray(ip) = &
1067 pw_grid%para%nyzray(ip) + 1
1068 ns = pw_grid%para%nyzray(ip)
1069 pw_grid%para%yzp(1, ns, ip) = j
1070 pw_grid%para%yzp(2, ns, ip) = i
1071 IF (ip == pw_grid%para%group%mepos)
THEN
1072 pw_grid%para%yzq(j, i) = ns
1074 pw_grid%para%yzq(j, i) = -1
1077 pw_grid%para%yzq(j, i) = -2
1082 pw_grid%ngpts_local = product(pw_grid%npts_local)
1089 pw_grid%para%blocked = .true.
1090 pw_grid%para%ray_distribution = .false.
1093 m = pw_grid%para%bo(2, 2, ip, 3) - &
1094 pw_grid%para%bo(1, 2, ip, 3) + 1
1095 n = pw_grid%para%bo(2, 3, ip, 3) - &
1096 pw_grid%para%bo(1, 3, ip, 3) + 1
1097 pw_grid%para%nyzray(ip) = n*m
1100 ipl = pw_grid%para%group%mepos
1101 l = pw_grid%para%bo(2, 1, ipl, 3) - &
1102 pw_grid%para%bo(1, 1, ipl, 3) + 1
1103 m = pw_grid%para%bo(2, 2, ipl, 3) - &
1104 pw_grid%para%bo(1, 2, ipl, 3) + 1
1105 n = pw_grid%para%bo(2, 3, ipl, 3) - &
1106 pw_grid%para%bo(1, 3, ipl, 3) + 1
1107 pw_grid%ngpts_cut_local = l*m*n
1108 pw_grid%ngpts_local = pw_grid%ngpts_cut_local
1110 pw_grid%para%yzq = 0
1111 ny = pw_grid%para%bo(2, 2, ipl, 3) - &
1112 pw_grid%para%bo(1, 2, ipl, 3) + 1
1113 DO n = pw_grid%para%bo(1, 3, ipl, 3), &
1114 pw_grid%para%bo(2, 3, ipl, 3)
1115 i = n - pw_grid%para%bo(1, 3, ipl, 3)
1116 DO m = pw_grid%para%bo(1, 2, ipl, 3), &
1117 pw_grid%para%bo(2, 2, ipl, 3)
1118 j = m - pw_grid%para%bo(1, 2, ipl, 3) + 1
1119 pw_grid%para%yzq(m, n) = j + i*ny
1124 ns = maxval(pw_grid%para%nyzray(0:np - 1))
1125 ALLOCATE (pw_grid%para%yzp(2, ns, 0:np - 1))
1126 pw_grid%para%yzp = 0
1128 ALLOCATE (pemap(0:np - 1))
1130 pemap(pw_grid%para%group%mepos) = pw_grid%para%group%mepos
1131 CALL pw_grid%para%group%sum(pemap)
1136 DO n = pw_grid%para%bo(1, 3, ipp, 3), &
1137 pw_grid%para%bo(2, 3, ipp, 3)
1138 i = n - pw_grid%bounds(1, 3) + 1
1139 DO m = pw_grid%para%bo(1, 2, ipp, 3), &
1140 pw_grid%para%bo(2, 2, ipp, 3)
1141 j = m - pw_grid%bounds(1, 2) + 1
1143 pw_grid%para%yzp(1, ns, ip) = j
1144 pw_grid%para%yzp(2, ns, ip) = i
1147 cpassert(ns == pw_grid%para%nyzray(ip))
1158 IF (pw_grid%para%mode == pw_mode_distributed)
THEN
1159 ALLOCATE (pw_grid%para%pos_of_x(pw_grid%bounds(1, 1):pw_grid%bounds(2, 1)))
1160 pw_grid%para%pos_of_x = 0
1161 pw_grid%para%pos_of_x(pw_grid%bounds_local(1, 1):pw_grid%bounds_local(2, 1)) = pw_grid%para%group%mepos
1162 CALL pw_grid%para%group%sum(pw_grid%para%pos_of_x)
1165 ALLOCATE (pw_grid%para%pos_of_x(pw_grid%bounds(1, 1):pw_grid%bounds(2, 1)))
1166 pw_grid%para%pos_of_x = 0
1169 CALL timestop(handle)
1171 END SUBROUTINE pw_grid_distribute
1181 SUBROUTINE pre_tag(pw_grid, yz_mask, ref_grid)
1183 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
1184 INTEGER,
DIMENSION(:, :),
INTENT(INOUT) :: yz_mask
1185 TYPE(pw_grid_type),
INTENT(IN) :: ref_grid
1187 INTEGER :: gmax, ig, ip, lby, lbz, my, mz, ny, nz, &
1188 uby, ubz, y, yp, z, zp
1190 ny = ref_grid%npts(2)
1191 nz = ref_grid%npts(3)
1192 lby = pw_grid%bounds(1, 2)
1193 lbz = pw_grid%bounds(1, 3)
1194 uby = pw_grid%bounds(2, 2)
1195 ubz = pw_grid%bounds(2, 3)
1196 my =
SIZE(yz_mask, 1)
1197 mz =
SIZE(yz_mask, 2)
1200 DO ip = 0, ref_grid%para%group%num_pe - 1
1201 DO ig = 1, ref_grid%para%nyzray(ip)
1204 y = ref_grid%para%yzp(1, ig, ip) - 1
1205 IF (y >= ny/2) y = y - ny
1206 z = ref_grid%para%yzp(2, ig, ip) - 1
1207 IF (z >= nz/2) z = z - nz
1209 IF (y < lby .OR. y > uby .OR. z < lbz .OR. z > ubz) cycle
1214 IF (pw_grid%grid_span == halfspace)
THEN
1219 IF (yp < 1 .OR. yp > my .OR. zp < 1 .OR. zp > mz) cycle
1220 gmax = max(yz_mask(y, z), yz_mask(yp, zp))
1221 IF (gmax == 0) cycle
1224 pw_grid%para%yzq(y, z) = ip
1225 pw_grid%para%yzq(yp, zp) = ip
1227 gmax = yz_mask(y, z)
1228 IF (gmax == 0) cycle
1230 pw_grid%para%yzq(y, z) = ip
1232 IF (ip == pw_grid%para%group%mepos)
THEN
1233 pw_grid%ngpts_cut_local = pw_grid%ngpts_cut_local + gmax
1238 END SUBROUTINE pre_tag
1245 PURE SUBROUTINE order_mask(yz_mask, yz_index)
1247 INTEGER,
DIMENSION(:, :),
INTENT(IN) :: yz_mask
1248 INTEGER,
DIMENSION(:, :),
INTENT(OUT) :: yz_index
1250 INTEGER :: i1, i2, ic, icount, ii, im, jc, jj
1258 i1 =
SIZE(yz_mask, 1)
1259 i2 =
SIZE(yz_mask, 2)
1267 IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2)
THEN
1268 IF (yz_mask(ii, jj) /= 0)
THEN
1269 yz_index(1, icount) = ii
1270 yz_index(2, icount) = jj
1274 DO im = 1, max(ic + 1, jc + 1)
1276 DO jj = jc - im, jc + im
1277 IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2)
THEN
1278 IF (yz_mask(ii, jj) /= 0)
THEN
1279 yz_index(1, icount) = ii
1280 yz_index(2, icount) = jj
1286 DO jj = jc - im, jc + im
1287 IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2)
THEN
1288 IF (yz_mask(ii, jj) /= 0)
THEN
1289 yz_index(1, icount) = ii
1290 yz_index(2, icount) = jj
1296 DO ii = ic - im + 1, ic + im - 1
1297 IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2)
THEN
1298 IF (yz_mask(ii, jj) /= 0)
THEN
1299 yz_index(1, icount) = ii
1300 yz_index(2, icount) = jj
1306 DO ii = ic - im + 1, ic + im - 1
1307 IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2)
THEN
1308 IF (yz_mask(ii, jj) /= 0)
THEN
1309 yz_index(1, icount) = ii
1310 yz_index(2, icount) = jj
1317 END SUBROUTINE order_mask
1329 PURE SUBROUTINE pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1331 REAL(KIND=dp),
DIMENSION(3, 3),
INTENT(IN) :: h_inv
1332 REAL(KIND=dp),
INTENT(OUT) :: length_x, length_y, length_z, length
1333 INTEGER,
INTENT(IN) :: l, m, n
1336 = real(l, dp)*h_inv(1, 1) &
1337 + real(m, dp)*h_inv(2, 1) &
1338 + real(n, dp)*h_inv(3, 1)
1340 = real(l, dp)*h_inv(1, 2) &
1341 + real(m, dp)*h_inv(2, 2) &
1342 + real(n, dp)*h_inv(3, 2)
1344 = real(l, dp)*h_inv(1, 3) &
1345 + real(m, dp)*h_inv(2, 3) &
1346 + real(n, dp)*h_inv(3, 3)
1349 IF (l == 0 .AND. m == 0 .AND. n == 0)
THEN
1355 length_x = length_x*twopi
1356 length_y = length_y*twopi
1357 length_z = length_z*twopi
1359 length = length_x**2 + length_y**2 + length_z**2
1361 END SUBROUTINE pw_vec_length
1377 PURE FUNCTION mirror_outside_bounds(grid_span, m, n, bounds)
RESULT(outside)
1379 INTEGER,
INTENT(IN) :: grid_span, m, n
1380 INTEGER,
DIMENSION(2, 3),
INTENT(IN) :: bounds
1383 outside = grid_span == halfspace .AND. &
1384 ((m == bounds(1, 2) .AND. bounds(2, 2) < -bounds(1, 2)) .OR. &
1385 (n == bounds(1, 3) .AND. bounds(2, 3) < -bounds(1, 3)))
1387 END FUNCTION mirror_outside_bounds
1401 SUBROUTINE pw_grid_count(h_inv, pw_grid, mp_comm, cutoff, yz_mask)
1403 REAL(KIND=dp),
DIMENSION(3, 3) :: h_inv
1404 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
1406 CLASS(mp_comm_type),
INTENT(IN) :: mp_comm
1407 REAL(KIND=dp),
INTENT(IN) :: cutoff
1408 INTEGER,
DIMENSION(:, :),
INTENT(OUT) :: yz_mask
1410 INTEGER :: l, m, mm, n, n_upperlimit, nlim(2), nn
1411 INTEGER(KIND=int_8) :: gpt
1412 REAL(KIND=dp) :: length, length_x, length_y, length_z
1414 associate(bounds => pw_grid%bounds)
1416 IF (pw_grid%grid_span == halfspace)
THEN
1418 ELSE IF (pw_grid%grid_span == fullspace)
THEN
1419 n_upperlimit = bounds(2, 3)
1421 cpabort(
"No type set for the grid")
1426 IF (pw_grid%para%mode == pw_mode_local)
THEN
1427 nlim(1) = bounds(1, 3)
1428 nlim(2) = n_upperlimit
1429 ELSE IF (pw_grid%para%mode == pw_mode_distributed)
THEN
1430 n = n_upperlimit - bounds(1, 3) + 1
1431 nlim = get_limit(n, mp_comm%num_pe, mp_comm%mepos)
1432 nlim = nlim + bounds(1, 3) - 1
1434 cpabort(
"para % mode not specified")
1438 DO n = nlim(1), nlim(2)
1439 nn = n - bounds(1, 3) + 1
1440 DO m = bounds(1, 2), bounds(2, 2)
1441 mm = m - bounds(1, 2) + 1
1442 DO l = bounds(1, 1), bounds(2, 1)
1443 IF (pw_grid%grid_span == halfspace .AND. n == 0)
THEN
1444 IF ((m == 0 .AND. l > 0) .OR. (m > 0)) cycle
1449 IF (mirror_outside_bounds(pw_grid%grid_span, m, n, bounds)) cycle
1451 CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1453 IF (0.5_dp*length <= cutoff)
THEN
1455 yz_mask(mm, nn) = yz_mask(mm, nn) + 1
1464 IF (pw_grid%para%mode == pw_mode_distributed)
THEN
1465 CALL mp_comm%sum(gpt)
1466 CALL mp_comm%sum(yz_mask)
1468 pw_grid%ngpts_cut = gpt
1470 END SUBROUTINE pw_grid_count
1482 SUBROUTINE pw_grid_assign(h_inv, pw_grid, cutoff)
1484 REAL(KIND=dp),
DIMENSION(3, 3) :: h_inv
1485 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
1486 REAL(kind=dp),
INTENT(IN) :: cutoff
1488 CHARACTER(len=*),
PARAMETER :: routinen =
'pw_grid_assign'
1490 INTEGER :: gpt, handle, i, ip, l, lby, lbz, ll, m, &
1491 mm, n, n_upperlimit, nn
1492 INTEGER(KIND=int_8) :: gpt_global
1493 INTEGER,
DIMENSION(2, 3) :: bol, bounds
1494 REAL(kind=dp) :: length, length_x, length_y, length_z
1496 CALL timeset(routinen, handle)
1498 bounds = pw_grid%bounds
1499 lby = pw_grid%bounds(1, 2)
1500 lbz = pw_grid%bounds(1, 3)
1502 IF (pw_grid%grid_span == halfspace)
THEN
1504 ELSE IF (pw_grid%grid_span == fullspace)
THEN
1505 n_upperlimit = bounds(2, 3)
1507 cpabort(
"No type set for the grid")
1511 IF (pw_grid%para%mode == pw_mode_local)
THEN
1513 DO n = bounds(1, 3), n_upperlimit
1514 DO m = bounds(1, 2), bounds(2, 2)
1515 DO l = bounds(1, 1), bounds(2, 1)
1516 IF (pw_grid%grid_span == halfspace .AND. n == 0)
THEN
1517 IF ((m == 0 .AND. l > 0) .OR. (m > 0)) cycle
1520 IF (mirror_outside_bounds(pw_grid%grid_span, m, n, bounds)) cycle
1522 CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1524 IF (0.5_dp*length <= cutoff)
THEN
1526 pw_grid%g(1, gpt) = length_x
1527 pw_grid%g(2, gpt) = length_y
1528 pw_grid%g(3, gpt) = length_z
1529 pw_grid%gsq(gpt) = length
1530 pw_grid%g_hat(1, gpt) = l
1531 pw_grid%g_hat(2, gpt) = m
1532 pw_grid%g_hat(3, gpt) = n
1541 IF (pw_grid%para%ray_distribution)
THEN
1544 ip = pw_grid%para%group%mepos
1545 DO i = 1, pw_grid%para%nyzray(ip)
1546 n = pw_grid%para%yzp(2, i, ip) + lbz - 1
1547 m = pw_grid%para%yzp(1, i, ip) + lby - 1
1548 IF (n > n_upperlimit) cycle
1550 IF (mirror_outside_bounds(pw_grid%grid_span, m, n, bounds)) cycle
1551 DO l = bounds(1, 1), bounds(2, 1)
1552 IF (pw_grid%grid_span == halfspace .AND. n == 0)
THEN
1553 IF ((m == 0 .AND. l > 0) .OR. (m > 0)) cycle
1556 CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1558 IF (0.5_dp*length <= cutoff)
THEN
1560 pw_grid%g(1, gpt) = length_x
1561 pw_grid%g(2, gpt) = length_y
1562 pw_grid%g(3, gpt) = length_z
1563 pw_grid%gsq(gpt) = length
1564 pw_grid%g_hat(1, gpt) = l
1565 pw_grid%g_hat(2, gpt) = m
1566 pw_grid%g_hat(3, gpt) = n
1574 bol = pw_grid%para%bo(:, :, pw_grid%para%group%mepos, 3)
1576 DO n = bounds(1, 3), bounds(2, 3)
1578 nn = n + pw_grid%npts(3) + 1
1582 IF (nn < bol(1, 3) .OR. nn > bol(2, 3)) cycle
1583 DO m = bounds(1, 2), bounds(2, 2)
1585 mm = m + pw_grid%npts(2) + 1
1589 IF (mm < bol(1, 2) .OR. mm > bol(2, 2)) cycle
1590 DO l = bounds(1, 1), bounds(2, 1)
1592 ll = l + pw_grid%npts(1) + 1
1596 IF (ll < bol(1, 1) .OR. ll > bol(2, 1)) cycle
1598 CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1601 pw_grid%g(1, gpt) = length_x
1602 pw_grid%g(2, gpt) = length_y
1603 pw_grid%g(3, gpt) = length_z
1604 pw_grid%gsq(gpt) = length
1605 pw_grid%g_hat(1, gpt) = l
1606 pw_grid%g_hat(2, gpt) = m
1607 pw_grid%g_hat(3, gpt) = n
1618 cpassert(pw_grid%ngpts_cut_local == gpt)
1619 IF (pw_grid%para%mode == pw_mode_distributed)
THEN
1621 CALL pw_grid%para%group%sum(gpt_global)
1622 cpassert(pw_grid%ngpts_cut == gpt_global)
1625 pw_grid%have_g0 = .false.
1626 pw_grid%first_gne0 = 1
1627 DO gpt = 1, pw_grid%ngpts_cut_local
1628 IF (all(pw_grid%g_hat(:, gpt) == 0))
THEN
1629 pw_grid%have_g0 = .true.
1630 pw_grid%first_gne0 = 2
1635 CALL pw_grid_set_maps(pw_grid%grid_span, pw_grid%g_hat, &
1636 pw_grid%mapl, pw_grid%mapm, pw_grid%mapn, pw_grid%npts)
1638 CALL timestop(handle)
1640 END SUBROUTINE pw_grid_assign
1657 SUBROUTINE pw_grid_set_maps(grid_span, g_hat, mapl, mapm, mapn, npts)
1659 INTEGER,
INTENT(IN) :: grid_span
1660 INTEGER,
DIMENSION(:, :),
INTENT(IN) :: g_hat
1661 TYPE(map_pn),
INTENT(INOUT) :: mapl, mapm, mapn
1662 INTEGER,
DIMENSION(:),
INTENT(IN) :: npts
1664 INTEGER :: gpt, l, m, n, ng
1673 mapl%pos(l) = l + npts(1)
1678 mapm%pos(m) = m + npts(2)
1683 mapn%pos(n) = n + npts(3)
1690 IF (grid_span == halfspace)
THEN
1695 mapl%neg(l) = npts(1) - l
1700 mapm%neg(m) = npts(2) - m
1705 mapn%neg(n) = npts(3) - n
1712 END SUBROUTINE pw_grid_set_maps
1726 SUBROUTINE pw_grid_allocate(pw_grid, ng, bounds)
1729 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
1730 INTEGER,
INTENT(IN) :: ng
1731 INTEGER,
DIMENSION(:, :),
INTENT(IN) :: bounds
1733 CHARACTER(len=*),
PARAMETER :: routineN =
'pw_grid_allocate'
1736#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
1737 INTEGER(KIND=C_SIZE_T) :: length
1738 TYPE(c_ptr) :: cptr_g_hatmap
1744 CALL timeset(routinen, handle)
1746 ALLOCATE (pw_grid%g(3, ng))
1747 ALLOCATE (pw_grid%gsq(ng))
1748 ALLOCATE (pw_grid%g_hat(3, ng))
1751 IF (pw_grid%grid_span == halfspace) nmaps = 2
1752#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
1755 length = int(int_size*max(ng, 1)*max(nmaps, 1), kind=c_size_t)
1756 stat = offload_malloc_pinned_mem(cptr_g_hatmap, length)
1758 CALL c_f_pointer(cptr_g_hatmap, pw_grid%g_hatmap, [max(ng, 1), max(nmaps, 1)])
1760 ALLOCATE (pw_grid%g_hatmap(max(ng, 1), max(nmaps, 1)))
1763 IF (pw_grid%para%mode == pw_mode_distributed)
THEN
1764 ALLOCATE (pw_grid%grays(pw_grid%npts(1), &
1765 pw_grid%para%nyzray(pw_grid%para%group%mepos)))
1768 ALLOCATE (pw_grid%mapl%pos(bounds(1, 1):bounds(2, 1)))
1769 ALLOCATE (pw_grid%mapl%neg(bounds(1, 1):bounds(2, 1)))
1770 ALLOCATE (pw_grid%mapm%pos(bounds(1, 2):bounds(2, 2)))
1771 ALLOCATE (pw_grid%mapm%neg(bounds(1, 2):bounds(2, 2)))
1772 ALLOCATE (pw_grid%mapn%pos(bounds(1, 3):bounds(2, 3)))
1773 ALLOCATE (pw_grid%mapn%neg(bounds(1, 3):bounds(2, 3)))
1775 CALL timestop(handle)
1777 END SUBROUTINE pw_grid_allocate
1798 SUBROUTINE pw_grid_sort(pw_grid, ref_grid)
1801 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
1802 TYPE(pw_grid_type),
INTENT(IN),
OPTIONAL :: ref_grid
1804 CHARACTER(len=*),
PARAMETER :: routineN =
'pw_grid_sort'
1806 INTEGER :: handle, i, ig, ih, ip, is, it, ng, ngr
1807 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: idx
1808 INTEGER,
ALLOCATABLE,
DIMENSION(:, :) :: int_tmp
1810 REAL(KIND=dp) :: gig, gigr
1811 REAL(KIND=dp),
ALLOCATABLE,
DIMENSION(:, :) :: real_tmp
1813 CALL timeset(routinen, handle)
1815 ng =
SIZE(pw_grid%gsq)
1819 CALL sort(pw_grid%gsq, ng, idx)
1821 CALL sort_shells(pw_grid%gsq, pw_grid%g_hat, idx)
1823 ALLOCATE (real_tmp(3, ng))
1825 real_tmp(1, i) = pw_grid%g(1, idx(i))
1826 real_tmp(2, i) = pw_grid%g(2, idx(i))
1827 real_tmp(3, i) = pw_grid%g(3, idx(i))
1830 pw_grid%g(1, i) = real_tmp(1, i)
1831 pw_grid%g(2, i) = real_tmp(2, i)
1832 pw_grid%g(3, i) = real_tmp(3, i)
1834 DEALLOCATE (real_tmp)
1836 ALLOCATE (int_tmp(3, ng))
1838 int_tmp(1, i) = pw_grid%g_hat(1, idx(i))
1839 int_tmp(2, i) = pw_grid%g_hat(2, idx(i))
1840 int_tmp(3, i) = pw_grid%g_hat(3, idx(i))
1843 pw_grid%g_hat(1, i) = int_tmp(1, i)
1844 pw_grid%g_hat(2, i) = int_tmp(2, i)
1845 pw_grid%g_hat(3, i) = int_tmp(3, i)
1847 DEALLOCATE (int_tmp)
1852 IF (
PRESENT(ref_grid))
THEN
1853 ngr =
SIZE(ref_grid%gsq)
1855 IF (pw_grid%spherical)
THEN
1856 IF (.NOT. all(pw_grid%g_hat(1:3, 1:ngr) &
1857 == ref_grid%g_hat(1:3, 1:ngr)))
THEN
1858 cpabort(
"G space sorting not compatible")
1861 ALLOCATE (pw_grid%gidx(1:ngr))
1866 IF (.NOT. all(pw_grid%g_hat(1:3, ig) &
1867 == ref_grid%g_hat(1:3, ig)))
EXIT
1868 pw_grid%gidx(ig) = ig
1876 gig = pw_grid%gsq(ig)
1877 gigr = max(1._dp, gig)
1879 DO ih = is + 1,
SIZE(ref_grid%gsq)
1880 IF (abs(gig - ref_grid%gsq(ih))/gigr > 1.e-12_dp) cycle
1884 IF (.NOT. g_found)
THEN
1885 WRITE (*,
"(A,I10,F20.10)")
"G-vector", ig, pw_grid%gsq(ig)
1886 cpabort(
"G vector not found")
1889 DO ih = ip + 1,
SIZE(ref_grid%gsq)
1890 IF (abs(gig - ref_grid%gsq(ih))/gigr > 1.e-12_dp) cycle
1891 IF (pw_grid%g_hat(1, ig) /= ref_grid%g_hat(1, ih)) cycle
1892 IF (pw_grid%g_hat(2, ig) /= ref_grid%g_hat(2, ih)) cycle
1893 IF (pw_grid%g_hat(3, ig) /= ref_grid%g_hat(3, ih)) cycle
1894 pw_grid%gidx(ig) = ih
1897 IF (pw_grid%gidx(ig) == 0)
THEN
1898 WRITE (*,
"(A,2I10)")
" G-Shell ", is + 1, ip + 1
1899 WRITE (*,
"(A,I10,3I6,F20.10)") &
1900 " G-vector", ig, pw_grid%g_hat(1:3, ig), pw_grid%gsq(ig)
1901 DO ih = 1,
SIZE(ref_grid%gsq)
1902 IF (pw_grid%g_hat(1, ig) /= ref_grid%g_hat(1, ih)) cycle
1903 IF (pw_grid%g_hat(2, ig) /= ref_grid%g_hat(2, ih)) cycle
1904 IF (pw_grid%g_hat(3, ig) /= ref_grid%g_hat(3, ih)) cycle
1905 WRITE (*,
"(A,I10,3I6,F20.10)") &
1906 " G-vector", ih, ref_grid%g_hat(1:3, ih), ref_grid%gsq(ih)
1908 cpabort(
"G vector not found")
1916 gig = ref_grid%gsq(ig)
1917 gigr = max(1._dp, gig)
1920 IF (abs(pw_grid%gsq(ih) - gig)/gigr > 1.e-12_dp) cycle
1924 IF (.NOT. g_found)
THEN
1925 WRITE (*,
"(A,I10,F20.10)")
"G-vector", ig, ref_grid%gsq(ig)
1926 cpabort(
"G vector not found")
1930 IF (abs(pw_grid%gsq(ih) - gig)/gigr > 1.e-12_dp) cycle
1931 IF (pw_grid%g_hat(1, ih) /= ref_grid%g_hat(1, ig)) cycle
1932 IF (pw_grid%g_hat(2, ih) /= ref_grid%g_hat(2, ig)) cycle
1933 IF (pw_grid%g_hat(3, ih) /= ref_grid%g_hat(3, ig)) cycle
1934 pw_grid%gidx(ig) = ih
1937 IF (pw_grid%gidx(ig) == 0)
THEN
1938 WRITE (*,
"(A,2I10)")
" G-Shell ", is + 1, ip + 1
1939 WRITE (*,
"(A,I10,3I6,F20.10)") &
1940 " G-vector", ig, ref_grid%g_hat(1:3, ig), ref_grid%gsq(ig)
1942 IF (pw_grid%g_hat(1, ih) /= ref_grid%g_hat(1, ig)) cycle
1943 IF (pw_grid%g_hat(2, ih) /= ref_grid%g_hat(2, ig)) cycle
1944 IF (pw_grid%g_hat(3, ih) /= ref_grid%g_hat(3, ig)) cycle
1945 WRITE (*,
"(A,I10,3I6,F20.10)") &
1946 " G-vector", ih, pw_grid%g_hat(1:3, ih), pw_grid%gsq(ih)
1948 cpabort(
"G vector not found")
1954 IF (any(pw_grid%gidx == 0))
THEN
1955 cpabort(
"G space sorting not compatible")
1961 IF (pw_grid%have_g0)
THEN
1962 IF (pw_grid%gsq(1) /= 0.0_dp)
THEN
1963 cpabort(
"G = 0 not in first position")
1967 CALL timestop(handle)
1969 END SUBROUTINE pw_grid_sort
1977 SUBROUTINE sort_shells(gsq, g_hat, idx)
1980 REAL(KIND=dp),
DIMENSION(:),
INTENT(IN) :: gsq
1981 INTEGER,
DIMENSION(:, :),
INTENT(IN) :: g_hat
1982 INTEGER,
DIMENSION(:),
INTENT(INOUT) :: idx
1984 CHARACTER(len=*),
PARAMETER :: routineN =
'sort_shells'
1985 REAL(KIND=dp),
PARAMETER :: small = 5.e-16_dp
1987 INTEGER :: handle, ig, ng, s1, s2
1988 REAL(KIND=dp) :: s_begin
1990 CALL timeset(routinen, handle)
2001 IF (abs(gsq(ig) - s_begin) < small)
THEN
2004 CALL redist(g_hat, idx, s1, s2)
2010 CALL redist(g_hat, idx, s1, s2)
2012 CALL timestop(handle)
2014 END SUBROUTINE sort_shells
2023 SUBROUTINE redist(g_hat, idx, s1, s2)
2026 INTEGER,
DIMENSION(:, :),
INTENT(IN) :: g_hat
2027 INTEGER,
DIMENSION(:),
INTENT(INOUT) :: idx
2028 INTEGER,
INTENT(IN) :: s1, s2
2030 INTEGER :: i, ii, n1, n2, n3, ns
2031 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: indl
2032 REAL(KIND=dp),
ALLOCATABLE,
DIMENSION(:) :: slen
2034 IF (s2 <= s1)
RETURN
2044 slen(i - s1 + 1) = 1000.0_dp*real(n1, dp) + &
2045 REAL(n2, dp) + 0.001_dp*
REAL(n3, dp)
2047 CALL sort(slen, ns, indl)
2049 ii = indl(i) + s1 - 1
2052 idx(s1:s2) = indl(1:ns)
2057 END SUBROUTINE redist
2067 SUBROUTINE pw_grid_remap(pw_grid, yz)
2070 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
2071 INTEGER,
DIMENSION(:, :),
INTENT(OUT) :: yz
2073 CHARACTER(len=*),
PARAMETER :: routineN =
'pw_grid_remap'
2075 INTEGER :: gpt, handle, i, ip, is, j, m, n
2077 IF (pw_grid%para%mode == pw_mode_local)
RETURN
2079 CALL timeset(routinen, handle)
2081 associate(ny => pw_grid%npts(2), nz => pw_grid%npts(3), posm => pw_grid%mapm%pos, posn => pw_grid%mapn%pos, &
2082 negm => pw_grid%mapm%neg, negn => pw_grid%mapn%neg)
2085 pw_grid%para%yzp = 0
2086 pw_grid%para%yzq = 0
2088 DO gpt = 1,
SIZE(pw_grid%gsq)
2089 m = posm(pw_grid%g_hat(2, gpt)) + 1
2090 n = posn(pw_grid%g_hat(3, gpt)) + 1
2091 yz(m, n) = yz(m, n) + 1
2093 IF (pw_grid%grid_span == halfspace)
THEN
2094 DO gpt = 1,
SIZE(pw_grid%gsq)
2095 m = negm(pw_grid%g_hat(2, gpt)) + 1
2096 n = negn(pw_grid%g_hat(3, gpt)) + 1
2097 yz(m, n) = yz(m, n) + 1
2101 ip = pw_grid%para%group%mepos
2105 IF (yz(j, i) > 0)
THEN
2107 pw_grid%para%yzp(1, is, ip) = j
2108 pw_grid%para%yzp(2, is, ip) = i
2109 pw_grid%para%yzq(j, i) = is
2115 cpassert(is == pw_grid%para%nyzray(ip))
2116 CALL pw_grid%para%group%sum(pw_grid%para%yzp)
2118 CALL timestop(handle)
2120 END SUBROUTINE pw_grid_remap
2137 REAL(kind=dp),
DIMENSION(3, 3),
INTENT(IN) :: cell_hmat
2138 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
2141 REAL(kind=dp) :: cell_deth, l, m, n
2142 REAL(kind=dp),
DIMENSION(3, 3) :: cell_h_inv
2143 REAL(kind=dp),
DIMENSION(:, :),
POINTER :: g
2145 cell_deth = abs(det_3x3(cell_hmat))
2146 IF (cell_deth < 1.0e-10_dp)
THEN
2147 CALL cp_abort(__location__, &
2148 "An invalid set of cell vectors was specified. "// &
2149 "The determinant det(h) is too small")
2151 cell_h_inv = inv_3x3(cell_hmat)
2155 CALL cell2grid(cell_hmat, cell_h_inv, cell_deth, pw_grid)
2157 DO gpt = 1,
SIZE(g, 2)
2159 l = twopi*real(pw_grid%g_hat(1, gpt), kind=dp)
2160 m = twopi*real(pw_grid%g_hat(2, gpt), kind=dp)
2161 n = twopi*real(pw_grid%g_hat(3, gpt), kind=dp)
2163 g(1, gpt) = l*cell_h_inv(1, 1) + m*cell_h_inv(2, 1) + n*cell_h_inv(3, 1)
2164 g(2, gpt) = l*cell_h_inv(1, 2) + m*cell_h_inv(2, 2) + n*cell_h_inv(3, 2)
2165 g(3, gpt) = l*cell_h_inv(1, 3) + m*cell_h_inv(2, 3) + n*cell_h_inv(3, 3)
2167 pw_grid%gsq(gpt) = g(1, gpt)*g(1, gpt) &
2168 + g(2, gpt)*g(2, gpt) &
2169 + g(3, gpt)*g(3, gpt)
2185 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
2187 cpassert(pw_grid%ref_count > 0)
2188 pw_grid%ref_count = pw_grid%ref_count + 1
2202 TYPE(pw_grid_type),
POINTER :: pw_grid
2204#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
2205 INTEGER,
POINTER :: dummy_ptr
2209 IF (
ASSOCIATED(pw_grid))
THEN
2210 cpassert(pw_grid%ref_count > 0)
2211 pw_grid%ref_count = pw_grid%ref_count - 1
2212 IF (pw_grid%ref_count == 0)
THEN
2213 IF (
ASSOCIATED(pw_grid%gidx))
THEN
2214 DEALLOCATE (pw_grid%gidx)
2216 IF (
ASSOCIATED(pw_grid%g))
THEN
2217 DEALLOCATE (pw_grid%g)
2219 IF (
ASSOCIATED(pw_grid%gsq))
THEN
2220 DEALLOCATE (pw_grid%gsq)
2222 IF (
ALLOCATED(pw_grid%g_hat))
THEN
2223 DEALLOCATE (pw_grid%g_hat)
2225 IF (
ASSOCIATED(pw_grid%g_hatmap))
THEN
2226#if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
2227 dummy_ptr => pw_grid%g_hatmap(1, 1)
2228 stat = offload_free_pinned_mem(c_loc(dummy_ptr))
2231 DEALLOCATE (pw_grid%g_hatmap)
2234 IF (
ASSOCIATED(pw_grid%grays))
THEN
2235 DEALLOCATE (pw_grid%grays)
2237 IF (
ALLOCATED(pw_grid%mapl%pos))
THEN
2238 DEALLOCATE (pw_grid%mapl%pos)
2240 IF (
ALLOCATED(pw_grid%mapm%pos))
THEN
2241 DEALLOCATE (pw_grid%mapm%pos)
2243 IF (
ALLOCATED(pw_grid%mapn%pos))
THEN
2244 DEALLOCATE (pw_grid%mapn%pos)
2246 IF (
ALLOCATED(pw_grid%mapl%neg))
THEN
2247 DEALLOCATE (pw_grid%mapl%neg)
2249 IF (
ALLOCATED(pw_grid%mapm%neg))
THEN
2250 DEALLOCATE (pw_grid%mapm%neg)
2252 IF (
ALLOCATED(pw_grid%mapn%neg))
THEN
2253 DEALLOCATE (pw_grid%mapn%neg)
2255 IF (
ALLOCATED(pw_grid%para%bo))
THEN
2256 DEALLOCATE (pw_grid%para%bo)
2258 IF (pw_grid%para%mode == pw_mode_distributed)
THEN
2259 IF (
ALLOCATED(pw_grid%para%yzp))
THEN
2260 DEALLOCATE (pw_grid%para%yzp)
2262 IF (
ALLOCATED(pw_grid%para%yzq))
THEN
2263 DEALLOCATE (pw_grid%para%yzq)
2265 IF (
ALLOCATED(pw_grid%para%nyzray))
THEN
2266 DEALLOCATE (pw_grid%para%nyzray)
2270 CALL pw_grid%para%group%free()
2271 IF (
ALLOCATED(pw_grid%para%pos_of_x))
THEN
2272 DEALLOCATE (pw_grid%para%pos_of_x)
2275 IF (
ASSOCIATED(pw_grid))
THEN
2276 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().