37 USE iso_c_binding,
ONLY: c_f_pointer,&
64 #include "../base/base_uses.f90"
74 INTEGER :: grid_tag = 0
75 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'pw_grids'
94 TYPE(pw_grid_type),
POINTER :: pw_grid
96 CLASS(mp_comm_type),
INTENT(in) :: pe_group
97 LOGICAL,
INTENT(IN),
OPTIONAL :: local
102 IF (
PRESENT(local)) my_local = local
103 cpassert(.NOT.
ASSOCIATED(pw_grid))
106 pw_grid%cutoff = 0.0_dp
109 pw_grid%para%rs_dims = 0
110 pw_grid%reference = 0
111 pw_grid%ref_count = 1
113 NULLIFY (pw_grid%gsq)
114 NULLIFY (pw_grid%g_hatmap)
115 NULLIFY (pw_grid%gidx)
116 NULLIFY (pw_grid%grays)
119 grid_tag = grid_tag + 1
120 pw_grid%id_nr = grid_tag
123 CALL pw_grid%para%group%from_dup(pe_group)
124 pw_grid%para%group_size = pw_grid%para%group%num_pe
125 pw_grid%para%my_pos = pw_grid%para%group%mepos
126 pw_grid%para%group_head_id = 0
127 pw_grid%para%group_head = &
128 (pw_grid%para%group_head_id == pw_grid%para%my_pos)
129 IF (pw_grid%para%group_size > 1 .AND. (.NOT. my_local))
THEN
148 TYPE(pw_grid_type),
INTENT(IN) :: grida, gridb
153 IF (grida%id_nr == gridb%id_nr)
THEN
183 ngpts_cut, dr, cutoff, orthorhombic, gvectors, gsquare)
185 TYPE(pw_grid_type),
INTENT(IN) :: pw_grid
186 INTEGER,
INTENT(OUT),
OPTIONAL :: id_nr, mode
187 REAL(
dp),
INTENT(OUT),
OPTIONAL :: vol, dvol
188 INTEGER,
DIMENSION(3),
INTENT(OUT),
OPTIONAL :: npts
189 INTEGER(int_8),
INTENT(OUT),
OPTIONAL :: ngpts, ngpts_cut
190 REAL(
dp),
DIMENSION(3),
INTENT(OUT),
OPTIONAL :: dr
191 REAL(
dp),
INTENT(OUT),
OPTIONAL :: cutoff
192 LOGICAL,
INTENT(OUT),
OPTIONAL :: orthorhombic
193 REAL(
dp),
DIMENSION(:, :),
OPTIONAL,
POINTER :: gvectors
194 REAL(
dp),
DIMENSION(:),
OPTIONAL,
POINTER :: gsquare
196 cpassert(pw_grid%ref_count > 0)
198 IF (
PRESENT(id_nr)) id_nr = pw_grid%id_nr
199 IF (
PRESENT(mode)) mode = pw_grid%para%mode
200 IF (
PRESENT(vol)) vol = pw_grid%vol
201 IF (
PRESENT(dvol)) dvol = pw_grid%dvol
202 IF (
PRESENT(npts)) npts(1:3) = pw_grid%npts(1:3)
203 IF (
PRESENT(ngpts)) ngpts = pw_grid%ngpts
204 IF (
PRESENT(ngpts_cut)) ngpts_cut = pw_grid%ngpts_cut
205 IF (
PRESENT(dr)) dr = pw_grid%dr
206 IF (
PRESENT(cutoff)) cutoff = pw_grid%cutoff
207 IF (
PRESENT(orthorhombic)) orthorhombic = pw_grid%orthorhombic
208 IF (
PRESENT(gvectors)) gvectors => pw_grid%g
209 IF (
PRESENT(gsquare)) gsquare => pw_grid%gsq
225 SUBROUTINE set_pw_grid_info(pw_grid, grid_span, npts, bounds, cutoff, spherical)
227 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
228 INTEGER,
INTENT(in),
OPTIONAL :: grid_span
229 INTEGER,
DIMENSION(3),
INTENT(IN),
OPTIONAL :: npts
230 INTEGER,
DIMENSION(2, 3),
INTENT(IN),
OPTIONAL :: bounds
231 REAL(kind=
dp),
INTENT(IN),
OPTIONAL :: cutoff
232 LOGICAL,
INTENT(IN),
OPTIONAL :: spherical
234 cpassert(pw_grid%ref_count > 0)
236 IF (
PRESENT(grid_span))
THEN
237 pw_grid%grid_span = grid_span
239 IF (
PRESENT(bounds) .AND.
PRESENT(npts))
THEN
240 pw_grid%bounds = bounds
242 cpassert(all(npts == bounds(2, :) - bounds(1, :) + 1))
243 ELSE IF (
PRESENT(bounds))
THEN
244 pw_grid%bounds = bounds
245 pw_grid%npts = bounds(2, :) - bounds(1, :) + 1
246 ELSE IF (
PRESENT(npts))
THEN
250 IF (
PRESENT(cutoff))
THEN
251 pw_grid%cutoff = cutoff
252 IF (
PRESENT(spherical))
THEN
253 pw_grid%spherical = spherical
255 pw_grid%spherical = .false.
259 END SUBROUTINE set_pw_grid_info
283 SUBROUTINE pw_grid_setup(cell_hmat, pw_grid, grid_span, cutoff, bounds, bounds_local, npts, &
284 spherical, odd, fft_usage, ncommensurate, icommensurate, blocked, ref_grid, &
287 REAL(kind=
dp),
DIMENSION(3, 3),
INTENT(IN) :: cell_hmat
288 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
289 INTEGER,
INTENT(in),
OPTIONAL :: grid_span
290 REAL(kind=
dp),
INTENT(IN),
OPTIONAL :: cutoff
291 INTEGER,
DIMENSION(2, 3),
INTENT(IN),
OPTIONAL :: bounds, bounds_local
292 INTEGER,
DIMENSION(3),
INTENT(IN),
OPTIONAL :: npts
293 LOGICAL,
INTENT(in),
OPTIONAL :: spherical, odd, fft_usage
294 INTEGER,
INTENT(in),
OPTIONAL :: ncommensurate, icommensurate, blocked
295 TYPE(pw_grid_type),
INTENT(IN),
OPTIONAL :: ref_grid
296 INTEGER,
DIMENSION(2),
INTENT(in),
OPTIONAL :: rs_dims
297 INTEGER,
INTENT(in),
OPTIONAL :: iounit
299 CHARACTER(len=*),
PARAMETER :: routinen =
'pw_grid_setup'
301 INTEGER :: handle, my_icommensurate, &
303 INTEGER,
DIMENSION(3) :: n
304 LOGICAL :: my_fft_usage, my_odd, my_spherical
305 REAL(kind=
dp) :: cell_deth, my_cutoff
306 REAL(kind=
dp),
DIMENSION(3, 3) :: cell_h_inv
308 CALL timeset(routinen, handle)
310 cell_deth = abs(
det_3x3(cell_hmat))
311 IF (cell_deth < 1.0e-10_dp)
THEN
312 CALL cp_abort(__location__, &
313 "An invalid set of cell vectors was specified. "// &
314 "The determinant det(h) is too small")
316 cell_h_inv =
inv_3x3(cell_hmat)
318 IF (
PRESENT(grid_span))
THEN
319 CALL set_pw_grid_info(pw_grid, grid_span=grid_span)
322 IF (
PRESENT(spherical))
THEN
323 my_spherical = spherical
325 my_spherical = .false.
328 IF (
PRESENT(odd))
THEN
334 IF (
PRESENT(fft_usage))
THEN
335 my_fft_usage = fft_usage
337 my_fft_usage = .false.
340 IF (
PRESENT(ncommensurate))
THEN
341 my_ncommensurate = ncommensurate
342 IF (
PRESENT(icommensurate))
THEN
343 my_icommensurate = icommensurate
345 my_icommensurate = min(1, ncommensurate)
352 IF (
PRESENT(bounds))
THEN
353 IF (
PRESENT(cutoff))
THEN
354 CALL set_pw_grid_info(pw_grid, bounds=bounds, cutoff=cutoff, &
355 spherical=my_spherical)
357 n = bounds(2, :) - bounds(1, :) + 1
359 my_cutoff = 0.5_dp*my_cutoff*my_cutoff
360 CALL set_pw_grid_info(pw_grid, bounds=bounds, cutoff=my_cutoff, &
361 spherical=my_spherical)
363 ELSE IF (
PRESENT(npts))
THEN
365 IF (
PRESENT(cutoff))
THEN
369 my_cutoff = 0.5_dp*my_cutoff*my_cutoff
371 IF (my_fft_usage)
THEN
373 spherical=my_spherical, odd=my_odd, fft_usage=my_fft_usage, &
374 ncommensurate=my_ncommensurate, icommensurate=my_icommensurate, &
375 ref_grid=ref_grid, n_orig=n)
377 CALL set_pw_grid_info(pw_grid, npts=n, cutoff=my_cutoff, &
378 spherical=my_spherical)
379 ELSE IF (
PRESENT(cutoff))
THEN
381 spherical=my_spherical, odd=my_odd, fft_usage=my_fft_usage, &
382 ncommensurate=my_ncommensurate, icommensurate=my_icommensurate, &
384 CALL set_pw_grid_info(pw_grid, npts=n, cutoff=cutoff, &
385 spherical=my_spherical)
387 cpabort(
"BOUNDS, NPTS or CUTOFF have to be specified")
390 CALL pw_grid_setup_internal(cell_hmat, cell_h_inv, cell_deth, pw_grid, bounds_local=bounds_local, &
391 blocked=blocked, ref_grid=ref_grid, rs_dims=rs_dims, iounit=iounit)
393 #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
394 CALL pw_grid_create_ghatmap(pw_grid)
397 CALL timestop(handle)
401 #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
407 SUBROUTINE pw_grid_create_ghatmap(pw_grid)
409 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
411 CHARACTER(len=*),
PARAMETER :: routinen =
'pw_grid_create_ghatmap'
413 INTEGER :: gpt, handle, l, m, mn, n
415 CALL timeset(routinen, handle)
418 cpassert(pw_grid%ref_count > 0)
422 associate(g_hat => pw_grid%g_hat, g_hatmap => pw_grid%g_hatmap, pmapl => pw_grid%mapl%pos, &
423 pmapm => pw_grid%mapm%pos, pmapn => pw_grid%mapn%pos, nmapl => pw_grid%mapl%neg, &
424 nmapm => pw_grid%mapm%neg, nmapn => pw_grid%mapn%neg, ngpts =>
SIZE(pw_grid%gsq), &
425 npts => pw_grid%npts, yzq => pw_grid%para%yzq)
431 l = pmapl(g_hat(1, gpt))
432 m = pmapm(g_hat(2, gpt))
433 n = pmapn(g_hat(3, gpt))
436 g_hatmap(gpt, 1) = l + npts(1)*(m + npts(2)*n)
440 l = nmapl(g_hat(1, gpt))
441 m = nmapm(g_hat(2, gpt))
442 n = nmapn(g_hat(3, gpt))
445 g_hatmap(gpt, 2) = l + npts(1)*(m + npts(2)*n)
450 l = pmapl(g_hat(1, gpt))
451 m = pmapm(g_hat(2, gpt)) + 1
452 n = pmapn(g_hat(3, gpt)) + 1
456 g_hatmap(gpt, 1) = l + npts(1)*mn
460 l = nmapl(g_hat(1, gpt))
461 m = nmapm(g_hat(2, gpt)) + 1
462 n = nmapn(g_hat(3, gpt)) + 1
466 g_hatmap(gpt, 2) = l + npts(1)*mn
472 CALL timestop(handle)
474 END SUBROUTINE pw_grid_create_ghatmap
503 SUBROUTINE pw_grid_setup_internal(cell_hmat, cell_h_inv, cell_deth, pw_grid, bounds_local, &
504 blocked, ref_grid, rs_dims, iounit)
505 REAL(kind=dp),
DIMENSION(3, 3),
INTENT(IN) :: cell_hmat, cell_h_inv
506 REAL(kind=dp),
INTENT(IN) :: cell_deth
507 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
508 INTEGER,
DIMENSION(2, 3),
INTENT(IN),
OPTIONAL :: bounds_local
509 INTEGER,
INTENT(in),
OPTIONAL :: blocked
510 TYPE(pw_grid_type),
INTENT(in),
OPTIONAL :: ref_grid
511 INTEGER,
DIMENSION(2),
INTENT(in),
OPTIONAL :: rs_dims
512 INTEGER,
INTENT(in),
OPTIONAL :: iounit
514 CHARACTER(len=*),
PARAMETER :: routinen =
'pw_grid_setup_internal'
516 INTEGER :: handle, n(3)
517 INTEGER,
ALLOCATABLE,
DIMENSION(:, :) :: yz_mask
518 REAL(kind=dp) :: ecut
522 CALL timeset(routinen, handle)
524 cpassert(pw_grid%ref_count > 0)
527 IF (
PRESENT(ref_grid))
THEN
528 pw_grid%reference = ref_grid%id_nr
531 IF (pw_grid%spherical)
THEN
532 ecut = pw_grid%cutoff
537 n(:) = pw_grid%npts(:)
543 ALLOCATE (yz_mask(n(2), n(3)))
544 CALL pw_grid_count(cell_h_inv, pw_grid, ecut, yz_mask)
547 IF (
PRESENT(ref_grid))
THEN
548 cpassert(pw_grid%para%mode == ref_grid%para%mode)
549 cpassert(pw_grid%grid_span == ref_grid%grid_span)
550 cpassert(pw_grid%spherical .EQV. ref_grid%spherical)
554 CALL pw_grid_distribute(pw_grid, yz_mask, bounds_local=bounds_local, ref_grid=ref_grid, blocked=blocked, &
558 CALL pw_grid_allocate(pw_grid, pw_grid%ngpts_cut_local, &
562 CALL pw_grid_assign(cell_h_inv, pw_grid, ecut)
565 CALL pw_grid_sort(pw_grid, ref_grid)
567 CALL pw_grid_remap(pw_grid, yz_mask)
571 CALL cell2grid(cell_hmat, cell_h_inv, cell_deth, pw_grid)
576 IF (
PRESENT(iounit))
THEN
577 CALL pw_grid_print(pw_grid, iounit)
580 CALL timestop(handle)
582 END SUBROUTINE pw_grid_setup_internal
593 SUBROUTINE cell2grid(cell_hmat, cell_h_inv, cell_deth, pw_grid)
594 REAL(kind=dp),
DIMENSION(3, 3),
INTENT(IN) :: cell_hmat, cell_h_inv
595 REAL(kind=dp),
INTENT(IN) :: cell_deth
596 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
598 pw_grid%vol = abs(cell_deth)
599 pw_grid%dvol = pw_grid%vol/real(pw_grid%ngpts, kind=dp)
600 pw_grid%dr(1) = sqrt(sum(cell_hmat(:, 1)**2)) &
601 /real(pw_grid%npts(1), kind=dp)
602 pw_grid%dr(2) = sqrt(sum(cell_hmat(:, 2)**2)) &
603 /real(pw_grid%npts(2), kind=dp)
604 pw_grid%dr(3) = sqrt(sum(cell_hmat(:, 3)**2)) &
605 /real(pw_grid%npts(3), kind=dp)
606 pw_grid%dh(:, 1) = cell_hmat(:, 1)/real(pw_grid%npts(1), kind=dp)
607 pw_grid%dh(:, 2) = cell_hmat(:, 2)/real(pw_grid%npts(2), kind=dp)
608 pw_grid%dh(:, 3) = cell_hmat(:, 3)/real(pw_grid%npts(3), kind=dp)
609 pw_grid%dh_inv(1, :) = cell_h_inv(1, :)*real(pw_grid%npts(1), kind=dp)
610 pw_grid%dh_inv(2, :) = cell_h_inv(2, :)*real(pw_grid%npts(2), kind=dp)
611 pw_grid%dh_inv(3, :) = cell_h_inv(3, :)*real(pw_grid%npts(3), kind=dp)
613 IF ((cell_hmat(1, 2) == 0.0_dp) .AND. (cell_hmat(1, 3) == 0.0_dp) .AND. &
614 (cell_hmat(2, 1) == 0.0_dp) .AND. (cell_hmat(2, 3) == 0.0_dp) .AND. &
615 (cell_hmat(3, 1) == 0.0_dp) .AND. (cell_hmat(3, 2) == 0.0_dp))
THEN
616 pw_grid%orthorhombic = .true.
618 pw_grid%orthorhombic = .false.
620 END SUBROUTINE cell2grid
628 SUBROUTINE pw_grid_print(pw_grid, info)
630 TYPE(pw_grid_type),
INTENT(IN) :: pw_grid
631 INTEGER,
INTENT(IN) :: info
634 INTEGER(KIND=int_8) :: n(3)
635 REAL(kind=dp) :: rv(3, 3)
642 IF (pw_grid%para%mode == pw_mode_local)
THEN
644 WRITE (info,
'(/,A,T71,I10)') &
645 " PW_GRID| Information for grid number ", pw_grid%id_nr
646 IF (pw_grid%reference > 0)
THEN
647 WRITE (info,
'(A,T71,I10)') &
648 " PW_GRID| Number of the reference grid ", pw_grid%reference
650 WRITE (info,
'(" PW_GRID| Cutoff [a.u.]",T71,f10.1)') pw_grid%cutoff
651 IF (pw_grid%spherical)
THEN
652 WRITE (info,
'(A,T78,A)')
" PW_GRID| spherical cutoff: ",
"YES"
653 WRITE (info,
'(A,T71,I10)')
" PW_GRID| Grid points within cutoff", &
656 WRITE (info,
'(A,T78,A)')
" PW_GRID| spherical cutoff: ",
" NO"
659 WRITE (info,
'(A,I3,T30,2I8,T62,A,T71,I10)')
" PW_GRID| Bounds ", &
660 i, pw_grid%bounds(1, i), pw_grid%bounds(2, i), &
661 "Points:", pw_grid%npts(i)
663 WRITE (info,
'(A,G12.4,T50,A,T67,F14.4)') &
664 " PW_GRID| Volume element (a.u.^3)", &
665 pw_grid%dvol,
" Volume (a.u.^3) :", pw_grid%vol
666 IF (pw_grid%grid_span == halfspace)
THEN
667 WRITE (info,
'(A,T72,A)')
" PW_GRID| Grid span",
"HALFSPACE"
669 WRITE (info,
'(A,T72,A)')
" PW_GRID| Grid span",
"FULLSPACE"
674 n(1) = pw_grid%ngpts_cut_local
675 n(2) = pw_grid%ngpts_local
676 CALL pw_grid%para%group%sum(n(1:2))
677 n(3) = sum(pw_grid%para%nyzray)
678 rv(:, 1) = real(n, kind=dp)/real(pw_grid%para%group_size, kind=dp)
679 n(1) = pw_grid%ngpts_cut_local
680 n(2) = pw_grid%ngpts_local
681 CALL pw_grid%para%group%max(n(1:2))
682 n(3) = maxval(pw_grid%para%nyzray)
683 rv(:, 2) = real(n, kind=dp)
684 n(1) = pw_grid%ngpts_cut_local
685 n(2) = pw_grid%ngpts_local
686 CALL pw_grid%para%group%min(n(1:2))
687 n(3) = minval(pw_grid%para%nyzray)
688 rv(:, 3) = real(n, kind=dp)
690 IF (pw_grid%para%group_head .AND. info > 0)
THEN
691 WRITE (info,
'(/,A,T71,I10)') &
692 " PW_GRID| Information for grid number ", pw_grid%id_nr
693 IF (pw_grid%reference > 0)
THEN
694 WRITE (info,
'(A,T71,I10)') &
695 " PW_GRID| Number of the reference grid ", pw_grid%reference
697 WRITE (info,
'(A,T60,I10,A)') &
698 " PW_GRID| Grid distributed over ", pw_grid%para%group_size, &
700 WRITE (info,
'(A,T71,2I5)') &
701 " PW_GRID| Real space group dimensions ", pw_grid%para%rs_dims
702 IF (pw_grid%para%blocked)
THEN
703 WRITE (info,
'(A,T78,A)')
" PW_GRID| the grid is blocked: ",
"YES"
705 WRITE (info,
'(A,T78,A)')
" PW_GRID| the grid is blocked: ",
" NO"
707 WRITE (info,
'(" PW_GRID| Cutoff [a.u.]",T71,f10.1)') pw_grid%cutoff
708 IF (pw_grid%spherical)
THEN
709 WRITE (info,
'(A,T78,A)')
" PW_GRID| spherical cutoff: ",
"YES"
710 WRITE (info,
'(A,T71,I10)')
" PW_GRID| Grid points within cutoff", &
713 WRITE (info,
'(A,T78,A)')
" PW_GRID| spherical cutoff: ",
" NO"
716 WRITE (info,
'(A,I3,T30,2I8,T62,A,T71,I10)')
" PW_GRID| Bounds ", &
717 i, pw_grid%bounds(1, i), pw_grid%bounds(2, i), &
718 "Points:", pw_grid%npts(i)
720 WRITE (info,
'(A,G12.4,T50,A,T67,F14.4)') &
721 " PW_GRID| Volume element (a.u.^3)", &
722 pw_grid%dvol,
" Volume (a.u.^3) :", pw_grid%vol
723 IF (pw_grid%grid_span == halfspace)
THEN
724 WRITE (info,
'(A,T72,A)')
" PW_GRID| Grid span",
"HALFSPACE"
726 WRITE (info,
'(A,T72,A)')
" PW_GRID| Grid span",
"FULLSPACE"
728 WRITE (info,
'(A,T48,A)')
" PW_GRID| Distribution", &
730 WRITE (info,
'(A,T45,F12.1,2I12)')
" PW_GRID| G-Vectors", &
731 rv(1, 1), nint(rv(1, 2)), nint(rv(1, 3))
732 WRITE (info,
'(A,T45,F12.1,2I12)')
" PW_GRID| G-Rays ", &
733 rv(3, 1), nint(rv(3, 2)), nint(rv(3, 3))
734 WRITE (info,
'(A,T45,F12.1,2I12)')
" PW_GRID| Real Space Points", &
735 rv(2, 1), nint(rv(2, 2)), nint(rv(2, 3))
739 END SUBROUTINE pw_grid_print
755 SUBROUTINE pw_grid_distribute(pw_grid, yz_mask, bounds_local, ref_grid, blocked, rs_dims)
757 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
758 INTEGER,
DIMENSION(:, :),
INTENT(INOUT) :: yz_mask
759 INTEGER,
DIMENSION(2, 3),
INTENT(IN),
OPTIONAL :: bounds_local
760 TYPE(pw_grid_type),
INTENT(IN),
OPTIONAL :: ref_grid
761 INTEGER,
INTENT(IN),
OPTIONAL :: blocked
762 INTEGER,
DIMENSION(2),
INTENT(in),
OPTIONAL :: rs_dims
764 CHARACTER(len=*),
PARAMETER :: routinen =
'pw_grid_distribute'
766 INTEGER :: blocked_local, coor(2), gmax, handle, i, &
767 i1, i2, ip, ipl, ipp, itmp, j, l, lby, &
768 lbz, lo(2), m, n, np, ns, nx, ny, nz, &
770 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: pemap
771 INTEGER,
ALLOCATABLE,
DIMENSION(:, :) :: yz_index
772 INTEGER,
ALLOCATABLE,
DIMENSION(:, :, :) :: axis_dist_all
773 INTEGER,
DIMENSION(2, 3) :: axis_dist
775 TYPE(mp_comm_type) :: mp_comm_old
779 CALL timeset(routinen, handle)
781 lby = pw_grid%bounds(1, 2)
782 lbz = pw_grid%bounds(1, 3)
784 pw_grid%ngpts = product(int(pw_grid%npts, kind=int_8))
785 cpassert(all(pw_grid%para%rs_dims == 0))
786 IF (
PRESENT(rs_dims))
THEN
787 pw_grid%para%rs_dims = rs_dims
790 IF (
PRESENT(blocked))
THEN
791 blocked_local = blocked
796 pw_grid%para%blocked = .false.
798 IF (pw_grid%para%mode == pw_mode_local)
THEN
800 pw_grid%para%ray_distribution = .false.
802 pw_grid%bounds_local = pw_grid%bounds
803 pw_grid%npts_local = pw_grid%npts
804 cpassert(pw_grid%ngpts_cut < huge(pw_grid%ngpts_cut_local))
805 pw_grid%ngpts_cut_local = int(pw_grid%ngpts_cut)
806 cpassert(pw_grid%ngpts < huge(pw_grid%ngpts_local))
807 pw_grid%ngpts_local = int(pw_grid%ngpts)
808 pw_grid%para%rs_dims = 1
809 mp_comm_old = mp_comm_self
810 CALL pw_grid%para%rs_group%create(mp_comm_old, 2, &
811 pw_grid%para%rs_dims)
812 pw_grid%para%rs_dims = pw_grid%para%rs_group%num_pe_cart
813 pw_grid%para%rs_pos = pw_grid%para%rs_group%mepos_cart
814 CALL pw_grid%para%rs_group%rank_cart(pw_grid%para%rs_pos, pw_grid%para%rs_mpo)
815 pw_grid%para%group_size = 1
816 ALLOCATE (pw_grid%para%bo(2, 3, 0:0, 3))
818 pw_grid%para%bo(1, 1:3, 0, i) = 1
819 pw_grid%para%bo(2, 1:3, 0, i) = pw_grid%npts(1:3)
828 np = pw_grid%para%group_size
839 IF (any(pw_grid%para%rs_dims <= 0))
THEN
840 IF (all(pw_grid%para%rs_dims <= 0))
THEN
841 pw_grid%para%rs_dims = (/0, 0/)
843 IF (pw_grid%para%rs_dims(1) > 0)
THEN
844 pw_grid%para%rs_dims(2) = np/pw_grid%para%rs_dims(1)
846 pw_grid%para%rs_dims(1) = np/pw_grid%para%rs_dims(2)
851 IF (product(pw_grid%para%rs_dims) .NE. np) pw_grid%para%rs_dims = (/0, 0/)
853 IF (all(pw_grid%para%rs_dims == (/1, np/))) pw_grid%para%rs_dims = (/0, 0/)
856 IF (all(pw_grid%para%rs_dims == (/0, 0/)))
THEN
860 CALL mp_dims_create(np, pw_grid%para%rs_dims)
862 IF (pw_grid%para%rs_dims(1) > pw_grid%para%rs_dims(2))
THEN
863 itmp = pw_grid%para%rs_dims(1)
864 pw_grid%para%rs_dims(1) = pw_grid%para%rs_dims(2)
865 pw_grid%para%rs_dims(2) = itmp
868 IF (pw_grid%para%rs_dims(1) == 1)
THEN
869 itmp = pw_grid%para%rs_dims(1)
870 pw_grid%para%rs_dims(1) = pw_grid%para%rs_dims(2)
871 pw_grid%para%rs_dims(2) = itmp
874 pw_grid%para%rs_dims = (/np, 1/)
879 SELECT CASE (blocked_local)
885 IF (all(pw_grid%para%rs_dims == (/np, 1/)))
THEN
895 CALL pw_grid%para%rs_group%create(pw_grid%para%group, 2, &
896 pw_grid%para%rs_dims)
897 pw_grid%para%rs_dims = pw_grid%para%rs_group%num_pe_cart
898 pw_grid%para%rs_pos = pw_grid%para%rs_group%mepos_cart
899 CALL pw_grid%para%rs_group%rank_cart(pw_grid%para%rs_pos, pw_grid%para%rs_mpo)
901 IF (
PRESENT(bounds_local))
THEN
902 pw_grid%bounds_local = bounds_local
904 lo = get_limit(nx, pw_grid%para%rs_dims(1), &
905 pw_grid%para%rs_pos(1))
906 pw_grid%bounds_local(:, 1) = lo + pw_grid%bounds(1, 1) - 1
907 lo = get_limit(ny, pw_grid%para%rs_dims(2), &
908 pw_grid%para%rs_pos(2))
909 pw_grid%bounds_local(:, 2) = lo + pw_grid%bounds(1, 2) - 1
910 pw_grid%bounds_local(:, 3) = pw_grid%bounds(:, 3)
913 pw_grid%npts_local(:) = pw_grid%bounds_local(2, :) &
914 - pw_grid%bounds_local(1, :) + 1
917 ALLOCATE (pw_grid%para%bo(2, 3, 0:np - 1, 3))
918 rsd = pw_grid%para%rs_dims
920 IF (
PRESENT(bounds_local))
THEN
923 axis_dist(:, i) = bounds_local(:, i) - pw_grid%bounds(1, i) + 1
925 ALLOCATE (axis_dist_all(2, 3, np))
926 CALL pw_grid%para%rs_group%allgather(axis_dist, axis_dist_all)
928 CALL pw_grid%para%rs_group%coords(ip, coor)
930 pw_grid%para%bo(1:2, 1, ip, 1) = axis_dist_all(1:2, 1, ip + 1)
931 pw_grid%para%bo(1:2, 2, ip, 1) = axis_dist_all(1:2, 2, ip + 1)
932 pw_grid%para%bo(1, 3, ip, 1) = 1
933 pw_grid%para%bo(2, 3, ip, 1) = nz
935 pw_grid%para%bo(1:2, 1, ip, 2) = axis_dist_all(1:2, 1, ip + 1)
936 pw_grid%para%bo(1, 2, ip, 2) = 1
937 pw_grid%para%bo(2, 2, ip, 2) = ny
938 pw_grid%para%bo(1:2, 3, ip, 2) = get_limit(nz, rsd(2), coor(2))
940 pw_grid%para%bo(1, 1, ip, 3) = 1
941 pw_grid%para%bo(2, 1, ip, 3) = nx
942 pw_grid%para%bo(1:2, 2, ip, 3) = get_limit(ny, rsd(1), coor(1))
943 pw_grid%para%bo(1:2, 3, ip, 3) = get_limit(nz, rsd(2), coor(2))
945 DEALLOCATE (axis_dist_all)
948 CALL pw_grid%para%rs_group%coords(ip, coor)
950 pw_grid%para%bo(1:2, 1, ip, 1) = get_limit(nx, rsd(1), coor(1))
951 pw_grid%para%bo(1:2, 2, ip, 1) = get_limit(ny, rsd(2), coor(2))
952 pw_grid%para%bo(1, 3, ip, 1) = 1
953 pw_grid%para%bo(2, 3, ip, 1) = nz
955 pw_grid%para%bo(1:2, 1, ip, 2) = get_limit(nx, rsd(1), coor(1))
956 pw_grid%para%bo(1, 2, ip, 2) = 1
957 pw_grid%para%bo(2, 2, ip, 2) = ny
958 pw_grid%para%bo(1:2, 3, ip, 2) = get_limit(nz, rsd(2), coor(2))
960 pw_grid%para%bo(1, 1, ip, 3) = 1
961 pw_grid%para%bo(2, 1, ip, 3) = nx
962 pw_grid%para%bo(1:2, 2, ip, 3) = get_limit(ny, rsd(1), coor(1))
963 pw_grid%para%bo(1:2, 3, ip, 3) = get_limit(nz, rsd(2), coor(2))
967 pw_grid%ngpts_cut_local = 0
969 ALLOCATE (pw_grid%para%nyzray(0:np - 1))
971 ALLOCATE (pw_grid%para%yzq(ny, nz))
973 IF (pw_grid%spherical .OR. pw_grid%grid_span == halfspace &
974 .OR. .NOT. blocking)
THEN
976 pw_grid%para%ray_distribution = .true.
978 pw_grid%para%yzq = -1
979 IF (
PRESENT(ref_grid))
THEN
981 CALL pre_tag(pw_grid, yz_mask, ref_grid)
988 i1 =
SIZE(yz_mask, 1)
989 i2 =
SIZE(yz_mask, 2)
990 ALLOCATE (yz_index(2, i1*i2))
991 CALL order_mask(yz_mask, yz_index)
993 lo(1) = yz_index(1, i)
994 lo(2) = yz_index(2, i)
995 IF (lo(1)*lo(2) == 0) cycle
996 gmax = yz_mask(lo(1), lo(2))
998 yz_mask(lo(1), lo(2)) = 0
999 ip = mod(i - 1, 2*np)
1000 IF (ip > np - 1) ip = 2*np - ip - 1
1001 IF (ip == pw_grid%para%my_pos)
THEN
1002 pw_grid%ngpts_cut_local = pw_grid%ngpts_cut_local + gmax
1004 pw_grid%para%yzq(lo(1), lo(2)) = ip
1005 IF (pw_grid%grid_span == halfspace)
THEN
1006 m = -lo(1) - 2*lby + 2
1007 n = -lo(2) - 2*lbz + 2
1008 pw_grid%para%yzq(m, n) = ip
1013 DEALLOCATE (yz_index)
1016 pw_grid%para%nyzray = 0
1019 ip = pw_grid%para%yzq(j, i)
1020 IF (ip >= 0) pw_grid%para%nyzray(ip) = &
1021 pw_grid%para%nyzray(ip) + 1
1026 ns = maxval(pw_grid%para%nyzray(0:np - 1))
1027 ALLOCATE (pw_grid%para%yzp(2, ns, 0:np - 1))
1030 pw_grid%para%nyzray = 0
1033 ip = pw_grid%para%yzq(j, i)
1035 pw_grid%para%nyzray(ip) = &
1036 pw_grid%para%nyzray(ip) + 1
1037 ns = pw_grid%para%nyzray(ip)
1038 pw_grid%para%yzp(1, ns, ip) = j
1039 pw_grid%para%yzp(2, ns, ip) = i
1040 IF (ip == pw_grid%para%my_pos)
THEN
1041 pw_grid%para%yzq(j, i) = ns
1043 pw_grid%para%yzq(j, i) = -1
1046 pw_grid%para%yzq(j, i) = -2
1051 pw_grid%ngpts_local = product(pw_grid%npts_local)
1058 pw_grid%para%blocked = .true.
1059 pw_grid%para%ray_distribution = .false.
1062 m = pw_grid%para%bo(2, 2, ip, 3) - &
1063 pw_grid%para%bo(1, 2, ip, 3) + 1
1064 n = pw_grid%para%bo(2, 3, ip, 3) - &
1065 pw_grid%para%bo(1, 3, ip, 3) + 1
1066 pw_grid%para%nyzray(ip) = n*m
1069 ipl = pw_grid%para%rs_mpo
1070 l = pw_grid%para%bo(2, 1, ipl, 3) - &
1071 pw_grid%para%bo(1, 1, ipl, 3) + 1
1072 m = pw_grid%para%bo(2, 2, ipl, 3) - &
1073 pw_grid%para%bo(1, 2, ipl, 3) + 1
1074 n = pw_grid%para%bo(2, 3, ipl, 3) - &
1075 pw_grid%para%bo(1, 3, ipl, 3) + 1
1076 pw_grid%ngpts_cut_local = l*m*n
1077 pw_grid%ngpts_local = pw_grid%ngpts_cut_local
1079 pw_grid%para%yzq = 0
1080 ny = pw_grid%para%bo(2, 2, ipl, 3) - &
1081 pw_grid%para%bo(1, 2, ipl, 3) + 1
1082 DO n = pw_grid%para%bo(1, 3, ipl, 3), &
1083 pw_grid%para%bo(2, 3, ipl, 3)
1084 i = n - pw_grid%para%bo(1, 3, ipl, 3)
1085 DO m = pw_grid%para%bo(1, 2, ipl, 3), &
1086 pw_grid%para%bo(2, 2, ipl, 3)
1087 j = m - pw_grid%para%bo(1, 2, ipl, 3) + 1
1088 pw_grid%para%yzq(m, n) = j + i*ny
1093 ns = maxval(pw_grid%para%nyzray(0:np - 1))
1094 ALLOCATE (pw_grid%para%yzp(2, ns, 0:np - 1))
1095 pw_grid%para%yzp = 0
1097 ALLOCATE (pemap(0:np - 1))
1099 pemap(pw_grid%para%my_pos) = pw_grid%para%rs_mpo
1100 CALL pw_grid%para%group%sum(pemap)
1105 DO n = pw_grid%para%bo(1, 3, ipp, 3), &
1106 pw_grid%para%bo(2, 3, ipp, 3)
1107 i = n - pw_grid%bounds(1, 3) + 1
1108 DO m = pw_grid%para%bo(1, 2, ipp, 3), &
1109 pw_grid%para%bo(2, 2, ipp, 3)
1110 j = m - pw_grid%bounds(1, 2) + 1
1112 pw_grid%para%yzp(1, ns, ip) = j
1113 pw_grid%para%yzp(2, ns, ip) = i
1116 cpassert(ns == pw_grid%para%nyzray(ip))
1127 IF (pw_grid%para%mode .EQ. pw_mode_distributed)
THEN
1128 ALLOCATE (pw_grid%para%pos_of_x(pw_grid%bounds(1, 1):pw_grid%bounds(2, 1)))
1129 pw_grid%para%pos_of_x = 0
1130 pw_grid%para%pos_of_x(pw_grid%bounds_local(1, 1):pw_grid%bounds_local(2, 1)) = pw_grid%para%my_pos
1131 CALL pw_grid%para%group%sum(pw_grid%para%pos_of_x)
1134 ALLOCATE (pw_grid%para%pos_of_x(pw_grid%bounds(1, 1):pw_grid%bounds(2, 1)))
1135 pw_grid%para%pos_of_x = 0
1138 CALL timestop(handle)
1140 END SUBROUTINE pw_grid_distribute
1150 SUBROUTINE pre_tag(pw_grid, yz_mask, ref_grid)
1152 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
1153 INTEGER,
DIMENSION(:, :),
INTENT(INOUT) :: yz_mask
1154 TYPE(pw_grid_type),
INTENT(IN) :: ref_grid
1156 INTEGER :: gmax, ig, ip, lby, lbz, my, mz, ny, nz, &
1157 uby, ubz, y, yp, z, zp
1159 ny = ref_grid%npts(2)
1160 nz = ref_grid%npts(3)
1161 lby = pw_grid%bounds(1, 2)
1162 lbz = pw_grid%bounds(1, 3)
1163 uby = pw_grid%bounds(2, 2)
1164 ubz = pw_grid%bounds(2, 3)
1165 my =
SIZE(yz_mask, 1)
1166 mz =
SIZE(yz_mask, 2)
1169 DO ip = 0, ref_grid%para%group_size - 1
1170 DO ig = 1, ref_grid%para%nyzray(ip)
1173 y = ref_grid%para%yzp(1, ig, ip) - 1
1174 IF (y >= ny/2) y = y - ny
1175 z = ref_grid%para%yzp(2, ig, ip) - 1
1176 IF (z >= nz/2) z = z - nz
1178 IF (y < lby .OR. y > uby .OR. z < lbz .OR. z > ubz) cycle
1183 IF (pw_grid%grid_span == halfspace)
THEN
1188 IF (yp < 1 .OR. yp > my .OR. zp < 1 .OR. zp > mz) cycle
1189 gmax = max(yz_mask(y, z), yz_mask(yp, zp))
1190 IF (gmax == 0) cycle
1193 pw_grid%para%yzq(y, z) = ip
1194 pw_grid%para%yzq(yp, zp) = ip
1196 gmax = yz_mask(y, z)
1197 IF (gmax == 0) cycle
1199 pw_grid%para%yzq(y, z) = ip
1201 IF (ip == pw_grid%para%my_pos)
THEN
1202 pw_grid%ngpts_cut_local = pw_grid%ngpts_cut_local + gmax
1207 END SUBROUTINE pre_tag
1214 PURE SUBROUTINE order_mask(yz_mask, yz_index)
1216 INTEGER,
DIMENSION(:, :),
INTENT(IN) :: yz_mask
1217 INTEGER,
DIMENSION(:, :),
INTENT(OUT) :: yz_index
1219 INTEGER :: i1, i2, ic, icount, ii, im, jc, jj
1227 i1 =
SIZE(yz_mask, 1)
1228 i2 =
SIZE(yz_mask, 2)
1236 IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2)
THEN
1237 IF (yz_mask(ii, jj) /= 0)
THEN
1238 yz_index(1, icount) = ii
1239 yz_index(2, icount) = jj
1243 DO im = 1, max(ic + 1, jc + 1)
1245 DO jj = jc - im, jc + im
1246 IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2)
THEN
1247 IF (yz_mask(ii, jj) /= 0)
THEN
1248 yz_index(1, icount) = ii
1249 yz_index(2, icount) = jj
1255 DO jj = jc - im, jc + im
1256 IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2)
THEN
1257 IF (yz_mask(ii, jj) /= 0)
THEN
1258 yz_index(1, icount) = ii
1259 yz_index(2, icount) = jj
1265 DO ii = ic - im + 1, ic + im - 1
1266 IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2)
THEN
1267 IF (yz_mask(ii, jj) /= 0)
THEN
1268 yz_index(1, icount) = ii
1269 yz_index(2, icount) = jj
1275 DO ii = ic - im + 1, ic + im - 1
1276 IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2)
THEN
1277 IF (yz_mask(ii, jj) /= 0)
THEN
1278 yz_index(1, icount) = ii
1279 yz_index(2, icount) = jj
1286 END SUBROUTINE order_mask
1298 PURE SUBROUTINE pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1300 REAL(kind=dp),
DIMENSION(3, 3),
INTENT(IN) :: h_inv
1301 REAL(kind=dp),
INTENT(OUT) :: length_x, length_y, length_z, length
1302 INTEGER,
INTENT(IN) :: l, m, n
1305 = real(l, dp)*h_inv(1, 1) &
1306 + real(m, dp)*h_inv(2, 1) &
1307 + real(n, dp)*h_inv(3, 1)
1309 = real(l, dp)*h_inv(1, 2) &
1310 + real(m, dp)*h_inv(2, 2) &
1311 + real(n, dp)*h_inv(3, 2)
1313 = real(l, dp)*h_inv(1, 3) &
1314 + real(m, dp)*h_inv(2, 3) &
1315 + real(n, dp)*h_inv(3, 3)
1318 IF (l == 0 .AND. m == 0 .AND. n == 0)
THEN
1324 length_x = length_x*twopi
1325 length_y = length_y*twopi
1326 length_z = length_z*twopi
1328 length = length_x**2 + length_y**2 + length_z**2
1343 SUBROUTINE pw_grid_count(h_inv, pw_grid, cutoff, yz_mask)
1345 REAL(kind=dp),
DIMENSION(3, 3) :: h_inv
1346 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
1347 REAL(kind=dp),
INTENT(IN) :: cutoff
1348 INTEGER,
DIMENSION(:, :),
INTENT(OUT) :: yz_mask
1350 INTEGER :: l, m, mm, n, n_upperlimit, nlim(2), nn
1351 INTEGER(KIND=int_8) :: gpt
1352 REAL(kind=dp) :: length, length_x, length_y, length_z
1354 associate(bounds => pw_grid%bounds)
1356 IF (pw_grid%grid_span == halfspace)
THEN
1358 ELSE IF (pw_grid%grid_span == fullspace)
THEN
1359 n_upperlimit = bounds(2, 3)
1361 cpabort(
"No type set for the grid")
1366 IF (pw_grid%para%mode == pw_mode_local)
THEN
1367 nlim(1) = bounds(1, 3)
1368 nlim(2) = n_upperlimit
1369 ELSE IF (pw_grid%para%mode == pw_mode_distributed)
THEN
1370 n = n_upperlimit - bounds(1, 3) + 1
1371 nlim = get_limit(n, pw_grid%para%group_size, pw_grid%para%my_pos)
1372 nlim = nlim + bounds(1, 3) - 1
1374 cpabort(
"para % mode not specified")
1378 DO n = nlim(1), nlim(2)
1379 nn = n - bounds(1, 3) + 1
1380 DO m = bounds(1, 2), bounds(2, 2)
1381 mm = m - bounds(1, 2) + 1
1382 DO l = bounds(1, 1), bounds(2, 1)
1383 IF (pw_grid%grid_span == halfspace .AND. n == 0)
THEN
1384 IF ((m == 0 .AND. l > 0) .OR. (m > 0)) cycle
1387 CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1389 IF (0.5_dp*length <= cutoff)
THEN
1391 yz_mask(mm, nn) = yz_mask(mm, nn) + 1
1400 IF (pw_grid%para%mode == pw_mode_distributed)
THEN
1401 CALL pw_grid%para%group%sum(gpt)
1402 CALL pw_grid%para%group%sum(yz_mask)
1404 pw_grid%ngpts_cut = gpt
1406 END SUBROUTINE pw_grid_count
1418 SUBROUTINE pw_grid_assign(h_inv, pw_grid, cutoff)
1420 REAL(kind=dp),
DIMENSION(3, 3) :: h_inv
1421 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
1422 REAL(kind=dp),
INTENT(IN) :: cutoff
1424 CHARACTER(len=*),
PARAMETER :: routinen =
'pw_grid_assign'
1426 INTEGER :: gpt, handle, i, ip, l, lby, lbz, ll, m, &
1427 mm, n, n_upperlimit, nn
1428 INTEGER(KIND=int_8) :: gpt_global
1429 INTEGER,
DIMENSION(2, 3) :: bol, bounds
1430 REAL(kind=dp) :: length, length_x, length_y, length_z
1432 CALL timeset(routinen, handle)
1434 bounds = pw_grid%bounds
1435 lby = pw_grid%bounds(1, 2)
1436 lbz = pw_grid%bounds(1, 3)
1438 IF (pw_grid%grid_span == halfspace)
THEN
1440 ELSE IF (pw_grid%grid_span == fullspace)
THEN
1441 n_upperlimit = bounds(2, 3)
1443 cpabort(
"No type set for the grid")
1447 IF (pw_grid%para%mode == pw_mode_local)
THEN
1449 DO n = bounds(1, 3), n_upperlimit
1450 DO m = bounds(1, 2), bounds(2, 2)
1451 DO l = bounds(1, 1), bounds(2, 1)
1452 IF (pw_grid%grid_span == halfspace .AND. n == 0)
THEN
1453 IF ((m == 0 .AND. l > 0) .OR. (m > 0)) cycle
1456 CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1458 IF (0.5_dp*length <= cutoff)
THEN
1460 pw_grid%g(1, gpt) = length_x
1461 pw_grid%g(2, gpt) = length_y
1462 pw_grid%g(3, gpt) = length_z
1463 pw_grid%gsq(gpt) = length
1464 pw_grid%g_hat(1, gpt) = l
1465 pw_grid%g_hat(2, gpt) = m
1466 pw_grid%g_hat(3, gpt) = n
1475 IF (pw_grid%para%ray_distribution)
THEN
1478 ip = pw_grid%para%my_pos
1479 DO i = 1, pw_grid%para%nyzray(ip)
1480 n = pw_grid%para%yzp(2, i, ip) + lbz - 1
1481 m = pw_grid%para%yzp(1, i, ip) + lby - 1
1482 IF (n > n_upperlimit) cycle
1483 DO l = bounds(1, 1), bounds(2, 1)
1484 IF (pw_grid%grid_span == halfspace .AND. n == 0)
THEN
1485 IF ((m == 0 .AND. l > 0) .OR. (m > 0)) cycle
1488 CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1490 IF (0.5_dp*length <= cutoff)
THEN
1492 pw_grid%g(1, gpt) = length_x
1493 pw_grid%g(2, gpt) = length_y
1494 pw_grid%g(3, gpt) = length_z
1495 pw_grid%gsq(gpt) = length
1496 pw_grid%g_hat(1, gpt) = l
1497 pw_grid%g_hat(2, gpt) = m
1498 pw_grid%g_hat(3, gpt) = n
1506 bol = pw_grid%para%bo(:, :, pw_grid%para%rs_mpo, 3)
1508 DO n = bounds(1, 3), bounds(2, 3)
1510 nn = n + pw_grid%npts(3) + 1
1514 IF (nn < bol(1, 3) .OR. nn > bol(2, 3)) cycle
1515 DO m = bounds(1, 2), bounds(2, 2)
1517 mm = m + pw_grid%npts(2) + 1
1521 IF (mm < bol(1, 2) .OR. mm > bol(2, 2)) cycle
1522 DO l = bounds(1, 1), bounds(2, 1)
1524 ll = l + pw_grid%npts(1) + 1
1528 IF (ll < bol(1, 1) .OR. ll > bol(2, 1)) cycle
1530 CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1533 pw_grid%g(1, gpt) = length_x
1534 pw_grid%g(2, gpt) = length_y
1535 pw_grid%g(3, gpt) = length_z
1536 pw_grid%gsq(gpt) = length
1537 pw_grid%g_hat(1, gpt) = l
1538 pw_grid%g_hat(2, gpt) = m
1539 pw_grid%g_hat(3, gpt) = n
1550 cpassert(pw_grid%ngpts_cut_local == gpt)
1551 IF (pw_grid%para%mode == pw_mode_distributed)
THEN
1553 CALL pw_grid%para%group%sum(gpt_global)
1554 cpassert(pw_grid%ngpts_cut == gpt_global)
1557 pw_grid%have_g0 = .false.
1558 pw_grid%first_gne0 = 1
1559 DO gpt = 1, pw_grid%ngpts_cut_local
1560 IF (all(pw_grid%g_hat(:, gpt) == 0))
THEN
1561 pw_grid%have_g0 = .true.
1562 pw_grid%first_gne0 = 2
1567 CALL pw_grid_set_maps(pw_grid%grid_span, pw_grid%g_hat, &
1568 pw_grid%mapl, pw_grid%mapm, pw_grid%mapn, pw_grid%npts)
1570 CALL timestop(handle)
1572 END SUBROUTINE pw_grid_assign
1589 SUBROUTINE pw_grid_set_maps(grid_span, g_hat, mapl, mapm, mapn, npts)
1591 INTEGER,
INTENT(IN) :: grid_span
1592 INTEGER,
DIMENSION(:, :),
INTENT(IN) :: g_hat
1593 TYPE(map_pn),
INTENT(INOUT) :: mapl, mapm, mapn
1594 INTEGER,
DIMENSION(:),
INTENT(IN) :: npts
1596 INTEGER :: gpt, l, m, n, ng
1605 mapl%pos(l) = l + npts(1)
1610 mapm%pos(m) = m + npts(2)
1615 mapn%pos(n) = n + npts(3)
1622 IF (grid_span == halfspace)
THEN
1627 mapl%neg(l) = npts(1) - l
1632 mapm%neg(m) = npts(2) - m
1637 mapn%neg(n) = npts(3) - n
1644 END SUBROUTINE pw_grid_set_maps
1658 SUBROUTINE pw_grid_allocate(pw_grid, ng, bounds)
1661 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
1662 INTEGER,
INTENT(IN) :: ng
1663 INTEGER,
DIMENSION(:, :),
INTENT(IN) :: bounds
1665 CHARACTER(len=*),
PARAMETER :: routinen =
'pw_grid_allocate'
1668 #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
1669 INTEGER(KIND=C_SIZE_T) :: length
1670 TYPE(c_ptr) :: cptr_g_hatmap
1676 CALL timeset(routinen, handle)
1678 ALLOCATE (pw_grid%g(3, ng))
1679 ALLOCATE (pw_grid%gsq(ng))
1680 ALLOCATE (pw_grid%g_hat(3, ng))
1683 IF (pw_grid%grid_span == halfspace) nmaps = 2
1684 #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
1687 length = int(int_size*max(ng, 1)*max(nmaps, 1), kind=c_size_t)
1688 stat = offload_malloc_pinned_mem(cptr_g_hatmap, length)
1690 CALL c_f_pointer(cptr_g_hatmap, pw_grid%g_hatmap, (/max(ng, 1), max(nmaps, 1)/))
1692 ALLOCATE (pw_grid%g_hatmap(1, 1))
1695 IF (pw_grid%para%mode == pw_mode_distributed)
THEN
1696 ALLOCATE (pw_grid%grays(pw_grid%npts(1), &
1697 pw_grid%para%nyzray(pw_grid%para%my_pos)))
1700 ALLOCATE (pw_grid%mapl%pos(bounds(1, 1):bounds(2, 1)))
1701 ALLOCATE (pw_grid%mapl%neg(bounds(1, 1):bounds(2, 1)))
1702 ALLOCATE (pw_grid%mapm%pos(bounds(1, 2):bounds(2, 2)))
1703 ALLOCATE (pw_grid%mapm%neg(bounds(1, 2):bounds(2, 2)))
1704 ALLOCATE (pw_grid%mapn%pos(bounds(1, 3):bounds(2, 3)))
1705 ALLOCATE (pw_grid%mapn%neg(bounds(1, 3):bounds(2, 3)))
1707 CALL timestop(handle)
1709 END SUBROUTINE pw_grid_allocate
1730 SUBROUTINE pw_grid_sort(pw_grid, ref_grid)
1733 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
1734 TYPE(pw_grid_type),
INTENT(IN),
OPTIONAL :: ref_grid
1736 CHARACTER(len=*),
PARAMETER :: routinen =
'pw_grid_sort'
1738 INTEGER :: handle, i, ig, ih, ip, is, it, ng, ngr
1739 INTEGER,
ALLOCATABLE,
DIMENSION(:) ::
idx
1740 INTEGER,
ALLOCATABLE,
DIMENSION(:, :) :: int_tmp
1742 REAL(kind=dp) :: gig, gigr
1743 REAL(kind=dp),
ALLOCATABLE,
DIMENSION(:, :) :: real_tmp
1745 CALL timeset(routinen, handle)
1747 ng =
SIZE(pw_grid%gsq)
1751 CALL sort(pw_grid%gsq, ng,
idx)
1753 CALL sort_shells(pw_grid%gsq, pw_grid%g_hat,
idx)
1755 ALLOCATE (real_tmp(3, ng))
1757 real_tmp(1, i) = pw_grid%g(1,
idx(i))
1758 real_tmp(2, i) = pw_grid%g(2,
idx(i))
1759 real_tmp(3, i) = pw_grid%g(3,
idx(i))
1762 pw_grid%g(1, i) = real_tmp(1, i)
1763 pw_grid%g(2, i) = real_tmp(2, i)
1764 pw_grid%g(3, i) = real_tmp(3, i)
1766 DEALLOCATE (real_tmp)
1768 ALLOCATE (int_tmp(3, ng))
1770 int_tmp(1, i) = pw_grid%g_hat(1,
idx(i))
1771 int_tmp(2, i) = pw_grid%g_hat(2,
idx(i))
1772 int_tmp(3, i) = pw_grid%g_hat(3,
idx(i))
1775 pw_grid%g_hat(1, i) = int_tmp(1, i)
1776 pw_grid%g_hat(2, i) = int_tmp(2, i)
1777 pw_grid%g_hat(3, i) = int_tmp(3, i)
1779 DEALLOCATE (int_tmp)
1784 IF (
PRESENT(ref_grid))
THEN
1785 ngr =
SIZE(ref_grid%gsq)
1787 IF (pw_grid%spherical)
THEN
1788 IF (.NOT. all(pw_grid%g_hat(1:3, 1:ngr) &
1789 == ref_grid%g_hat(1:3, 1:ngr)))
THEN
1790 cpabort(
"G space sorting not compatible")
1793 ALLOCATE (pw_grid%gidx(1:ngr))
1798 IF (.NOT. all(pw_grid%g_hat(1:3, ig) &
1799 == ref_grid%g_hat(1:3, ig)))
EXIT
1800 pw_grid%gidx(ig) = ig
1808 gig = pw_grid%gsq(ig)
1809 gigr = max(1._dp, gig)
1811 DO ih = is + 1,
SIZE(ref_grid%gsq)
1812 IF (abs(gig - ref_grid%gsq(ih))/gigr > 1.e-12_dp) cycle
1816 IF (.NOT. g_found)
THEN
1817 WRITE (*,
"(A,I10,F20.10)")
"G-vector", ig, pw_grid%gsq(ig)
1818 cpabort(
"G vector not found")
1821 DO ih = ip + 1,
SIZE(ref_grid%gsq)
1822 IF (abs(gig - ref_grid%gsq(ih))/gigr > 1.e-12_dp) cycle
1823 IF (pw_grid%g_hat(1, ig) /= ref_grid%g_hat(1, ih)) cycle
1824 IF (pw_grid%g_hat(2, ig) /= ref_grid%g_hat(2, ih)) cycle
1825 IF (pw_grid%g_hat(3, ig) /= ref_grid%g_hat(3, ih)) cycle
1826 pw_grid%gidx(ig) = ih
1829 IF (pw_grid%gidx(ig) == 0)
THEN
1830 WRITE (*,
"(A,2I10)")
" G-Shell ", is + 1, ip + 1
1831 WRITE (*,
"(A,I10,3I6,F20.10)") &
1832 " G-vector", ig, pw_grid%g_hat(1:3, ig), pw_grid%gsq(ig)
1833 DO ih = 1,
SIZE(ref_grid%gsq)
1834 IF (pw_grid%g_hat(1, ig) /= ref_grid%g_hat(1, ih)) cycle
1835 IF (pw_grid%g_hat(2, ig) /= ref_grid%g_hat(2, ih)) cycle
1836 IF (pw_grid%g_hat(3, ig) /= ref_grid%g_hat(3, ih)) cycle
1837 WRITE (*,
"(A,I10,3I6,F20.10)") &
1838 " G-vector", ih, ref_grid%g_hat(1:3, ih), ref_grid%gsq(ih)
1840 cpabort(
"G vector not found")
1848 gig = ref_grid%gsq(ig)
1849 gigr = max(1._dp, gig)
1852 IF (abs(pw_grid%gsq(ih) - gig)/gigr > 1.e-12_dp) cycle
1856 IF (.NOT. g_found)
THEN
1857 WRITE (*,
"(A,I10,F20.10)")
"G-vector", ig, ref_grid%gsq(ig)
1858 cpabort(
"G vector not found")
1862 IF (abs(pw_grid%gsq(ih) - gig)/gigr > 1.e-12_dp) cycle
1863 IF (pw_grid%g_hat(1, ih) /= ref_grid%g_hat(1, ig)) cycle
1864 IF (pw_grid%g_hat(2, ih) /= ref_grid%g_hat(2, ig)) cycle
1865 IF (pw_grid%g_hat(3, ih) /= ref_grid%g_hat(3, ig)) cycle
1866 pw_grid%gidx(ig) = ih
1869 IF (pw_grid%gidx(ig) == 0)
THEN
1870 WRITE (*,
"(A,2I10)")
" G-Shell ", is + 1, ip + 1
1871 WRITE (*,
"(A,I10,3I6,F20.10)") &
1872 " G-vector", ig, ref_grid%g_hat(1:3, ig), ref_grid%gsq(ig)
1874 IF (pw_grid%g_hat(1, ih) /= ref_grid%g_hat(1, ig)) cycle
1875 IF (pw_grid%g_hat(2, ih) /= ref_grid%g_hat(2, ig)) cycle
1876 IF (pw_grid%g_hat(3, ih) /= ref_grid%g_hat(3, ig)) cycle
1877 WRITE (*,
"(A,I10,3I6,F20.10)") &
1878 " G-vector", ih, pw_grid%g_hat(1:3, ih), pw_grid%gsq(ih)
1880 cpabort(
"G vector not found")
1886 IF (any(pw_grid%gidx == 0))
THEN
1887 cpabort(
"G space sorting not compatible")
1893 IF (pw_grid%have_g0)
THEN
1894 IF (pw_grid%gsq(1) /= 0.0_dp)
THEN
1895 cpabort(
"G = 0 not in first position")
1899 CALL timestop(handle)
1901 END SUBROUTINE pw_grid_sort
1909 SUBROUTINE sort_shells(gsq, g_hat, idx)
1912 REAL(kind=dp),
DIMENSION(:),
INTENT(IN) :: gsq
1913 INTEGER,
DIMENSION(:, :),
INTENT(IN) :: g_hat
1914 INTEGER,
DIMENSION(:),
INTENT(INOUT) ::
idx
1916 CHARACTER(len=*),
PARAMETER :: routinen =
'sort_shells'
1917 REAL(kind=dp),
PARAMETER :: small = 5.e-16_dp
1919 INTEGER :: handle, ig, ng, s1, s2
1920 REAL(kind=dp) :: s_begin
1922 CALL timeset(routinen, handle)
1933 IF (abs(gsq(ig) - s_begin) < small)
THEN
1936 CALL redist(g_hat,
idx, s1, s2)
1942 CALL redist(g_hat,
idx, s1, s2)
1944 CALL timestop(handle)
1946 END SUBROUTINE sort_shells
1955 SUBROUTINE redist(g_hat, idx, s1, s2)
1958 INTEGER,
DIMENSION(:, :),
INTENT(IN) :: g_hat
1959 INTEGER,
DIMENSION(:),
INTENT(INOUT) ::
idx
1960 INTEGER,
INTENT(IN) :: s1, s2
1962 INTEGER :: i, ii, n1, n2, n3, ns
1963 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: indl
1964 REAL(kind=dp),
ALLOCATABLE,
DIMENSION(:) :: slen
1966 IF (s2 <= s1)
RETURN
1976 slen(i - s1 + 1) = 1000.0_dp*real(n1, dp) + &
1977 REAL(n2, dp) + 0.001_dp*
REAL(n3, dp)
1979 CALL sort(slen, ns, indl)
1981 ii = indl(i) + s1 - 1
1984 idx(s1:s2) = indl(1:ns)
1989 END SUBROUTINE redist
1999 SUBROUTINE pw_grid_remap(pw_grid, yz)
2002 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
2003 INTEGER,
DIMENSION(:, :),
INTENT(OUT) :: yz
2005 CHARACTER(len=*),
PARAMETER :: routinen =
'pw_grid_remap'
2007 INTEGER :: gpt, handle, i, ip, is, j, m, n
2009 IF (pw_grid%para%mode == pw_mode_local)
RETURN
2011 CALL timeset(routinen, handle)
2013 associate(ny => pw_grid%npts(2), nz => pw_grid%npts(3), posm => pw_grid%mapm%pos, posn => pw_grid%mapn%pos, &
2014 negm => pw_grid%mapm%neg, negn => pw_grid%mapn%neg)
2017 pw_grid%para%yzp = 0
2018 pw_grid%para%yzq = 0
2020 DO gpt = 1,
SIZE(pw_grid%gsq)
2021 m = posm(pw_grid%g_hat(2, gpt)) + 1
2022 n = posn(pw_grid%g_hat(3, gpt)) + 1
2023 yz(m, n) = yz(m, n) + 1
2025 IF (pw_grid%grid_span == halfspace)
THEN
2026 DO gpt = 1,
SIZE(pw_grid%gsq)
2027 m = negm(pw_grid%g_hat(2, gpt)) + 1
2028 n = negn(pw_grid%g_hat(3, gpt)) + 1
2029 yz(m, n) = yz(m, n) + 1
2033 ip = pw_grid%para%my_pos
2037 IF (yz(j, i) > 0)
THEN
2039 pw_grid%para%yzp(1, is, ip) = j
2040 pw_grid%para%yzp(2, is, ip) = i
2041 pw_grid%para%yzq(j, i) = is
2047 cpassert(is == pw_grid%para%nyzray(ip))
2048 CALL pw_grid%para%group%sum(pw_grid%para%yzp)
2050 CALL timestop(handle)
2052 END SUBROUTINE pw_grid_remap
2069 REAL(kind=dp),
DIMENSION(3, 3),
INTENT(IN) :: cell_hmat
2070 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
2073 REAL(kind=dp) :: cell_deth, l, m, n
2074 REAL(kind=dp),
DIMENSION(3, 3) :: cell_h_inv
2075 REAL(kind=dp),
DIMENSION(:, :),
POINTER :: g
2077 cell_deth = abs(
det_3x3(cell_hmat))
2078 IF (cell_deth < 1.0e-10_dp)
THEN
2079 CALL cp_abort(__location__, &
2080 "An invalid set of cell vectors was specified. "// &
2081 "The determinant det(h) is too small")
2083 cell_h_inv = inv_3x3(cell_hmat)
2087 CALL cell2grid(cell_hmat, cell_h_inv, cell_deth, pw_grid)
2089 DO gpt = 1,
SIZE(g, 2)
2091 l = twopi*real(pw_grid%g_hat(1, gpt), kind=dp)
2092 m = twopi*real(pw_grid%g_hat(2, gpt), kind=dp)
2093 n = twopi*real(pw_grid%g_hat(3, gpt), kind=dp)
2095 g(1, gpt) = l*cell_h_inv(1, 1) + m*cell_h_inv(2, 1) + n*cell_h_inv(3, 1)
2096 g(2, gpt) = l*cell_h_inv(1, 2) + m*cell_h_inv(2, 2) + n*cell_h_inv(3, 2)
2097 g(3, gpt) = l*cell_h_inv(1, 3) + m*cell_h_inv(2, 3) + n*cell_h_inv(3, 3)
2099 pw_grid%gsq(gpt) = g(1, gpt)*g(1, gpt) &
2100 + g(2, gpt)*g(2, gpt) &
2101 + g(3, gpt)*g(3, gpt)
2117 TYPE(pw_grid_type),
INTENT(INOUT) :: pw_grid
2119 cpassert(pw_grid%ref_count > 0)
2120 pw_grid%ref_count = pw_grid%ref_count + 1
2134 TYPE(pw_grid_type),
POINTER :: pw_grid
2136 #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
2137 INTEGER,
POINTER :: dummy_ptr
2141 IF (
ASSOCIATED(pw_grid))
THEN
2142 cpassert(pw_grid%ref_count > 0)
2143 pw_grid%ref_count = pw_grid%ref_count - 1
2144 IF (pw_grid%ref_count == 0)
THEN
2145 IF (
ASSOCIATED(pw_grid%gidx))
THEN
2146 DEALLOCATE (pw_grid%gidx)
2148 IF (
ASSOCIATED(pw_grid%g))
THEN
2149 DEALLOCATE (pw_grid%g)
2151 IF (
ASSOCIATED(pw_grid%gsq))
THEN
2152 DEALLOCATE (pw_grid%gsq)
2154 IF (
ALLOCATED(pw_grid%g_hat))
THEN
2155 DEALLOCATE (pw_grid%g_hat)
2157 IF (
ASSOCIATED(pw_grid%g_hatmap))
THEN
2158 #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
2159 dummy_ptr => pw_grid%g_hatmap(1, 1)
2160 stat = offload_free_pinned_mem(c_loc(dummy_ptr))
2163 DEALLOCATE (pw_grid%g_hatmap)
2166 IF (
ASSOCIATED(pw_grid%grays))
THEN
2167 DEALLOCATE (pw_grid%grays)
2169 IF (
ALLOCATED(pw_grid%mapl%pos))
THEN
2170 DEALLOCATE (pw_grid%mapl%pos)
2172 IF (
ALLOCATED(pw_grid%mapm%pos))
THEN
2173 DEALLOCATE (pw_grid%mapm%pos)
2175 IF (
ALLOCATED(pw_grid%mapn%pos))
THEN
2176 DEALLOCATE (pw_grid%mapn%pos)
2178 IF (
ALLOCATED(pw_grid%mapl%neg))
THEN
2179 DEALLOCATE (pw_grid%mapl%neg)
2181 IF (
ALLOCATED(pw_grid%mapm%neg))
THEN
2182 DEALLOCATE (pw_grid%mapm%neg)
2184 IF (
ALLOCATED(pw_grid%mapn%neg))
THEN
2185 DEALLOCATE (pw_grid%mapn%neg)
2187 IF (
ALLOCATED(pw_grid%para%bo))
THEN
2188 DEALLOCATE (pw_grid%para%bo)
2190 IF (pw_grid%para%mode == pw_mode_distributed)
THEN
2191 IF (
ALLOCATED(pw_grid%para%yzp))
THEN
2192 DEALLOCATE (pw_grid%para%yzp)
2194 IF (
ALLOCATED(pw_grid%para%yzq))
THEN
2195 DEALLOCATE (pw_grid%para%yzq)
2197 IF (
ALLOCATED(pw_grid%para%nyzray))
THEN
2198 DEALLOCATE (pw_grid%para%nyzray)
2202 CALL pw_grid%para%group%free()
2203 IF (product(pw_grid%para%rs_dims) /= 0) &
2204 CALL pw_grid%para%rs_group%free()
2205 IF (
ALLOCATED(pw_grid%para%pos_of_x))
THEN
2206 DEALLOCATE (pw_grid%para%pos_of_x)
2209 IF (
ASSOCIATED(pw_grid))
THEN
2210 DEALLOCATE (pw_grid)
real(kind=dp) function det_3x3(a)
...
static GRID_HOST_DEVICE int idx(const orbital a)
Return coset index of given orbital angular momentum.
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 pw_grid_setup(cell_hmat, pw_grid, grid_span, cutoff, bounds, bounds_local, npts, spherical, odd, fft_usage, ncommensurate, icommensurate, blocked, ref_grid, rs_dims, iounit)
sets up a pw_grid
subroutine, public pw_grid_create(pw_grid, pe_group, local)
Initialize a PW grid with all defaults.
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()