Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief This module defines the grid data type and some basic operations on it
10 : !> \note
11 : !> pw_grid_create : set the defaults
12 : !> pw_grid_release : release all memory connected to type
13 : !> pw_grid_setup : main routine to set up a grid
14 : !> input: cell (the box for the grid)
15 : !> pw_grid (the grid; pw_grid%grid_span has to be set)
16 : !> cutoff (optional, if not given pw_grid%bounds has to be set)
17 : !> pe_group (optional, if not given we have a local grid)
18 : !>
19 : !> if no cutoff or a negative cutoff is given, all g-vectors
20 : !> in the box are included (no spherical cutoff)
21 : !>
22 : !> for a distributed setup the array in para rs_dims has to
23 : !> be initialized
24 : !> output: pw_grid
25 : !>
26 : !> pw_grid_change : updates g-vectors after a change of the box
27 : !> \par History
28 : !> JGH (20-12-2000) : Adapted for parallel use
29 : !> JGH (07-02-2001) : Added constructor and destructor routines
30 : !> JGH (21-02-2003) : Generalized reference grid concept
31 : !> JGH (19-11-2007) : Refactoring and modularization
32 : !> JGH (21-12-2007) : pw_grid_setup refactoring
33 : !> \author apsi
34 : !> CJM
35 : ! **************************************************************************************************
36 : MODULE pw_grids
37 : USE ISO_C_BINDING, ONLY: C_F_POINTER,&
38 : C_LOC,&
39 : C_PTR,&
40 : C_SIZE_T
41 : USE kinds, ONLY: dp,&
42 : int_8,&
43 : int_size
44 : USE mathconstants, ONLY: twopi
45 : USE mathlib, ONLY: det_3x3,&
46 : inv_3x3
47 : USE message_passing, ONLY: mp_comm_self,&
48 : mp_comm_type,&
49 : mp_dims_create
50 : USE offload_api, ONLY: offload_activate_chosen_device,&
51 : offload_free_pinned_mem,&
52 : offload_malloc_pinned_mem
53 : USE pw_grid_info, ONLY: pw_find_cutoff,&
54 : pw_grid_bounds_from_n,&
55 : pw_grid_init_setup
56 : USE pw_grid_types, ONLY: FULLSPACE,&
57 : HALFSPACE,&
58 : PW_MODE_DISTRIBUTED,&
59 : PW_MODE_LOCAL,&
60 : map_pn,&
61 : pw_grid_type
62 : USE util, ONLY: get_limit,&
63 : sort
64 : #include "../base/base_uses.f90"
65 :
66 : IMPLICIT NONE
67 :
68 : PRIVATE
69 : PUBLIC :: pw_grid_create, pw_grid_retain, pw_grid_release
70 : PUBLIC :: get_pw_grid_info, pw_grid_compare
71 : PUBLIC :: pw_grid_change
72 :
73 : INTEGER :: grid_tag = 0
74 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'pw_grids'
75 :
76 : ! Distribution in g-space can be
77 : INTEGER, PARAMETER, PUBLIC :: do_pw_grid_blocked_false = 0, &
78 : do_pw_grid_blocked_true = 1, &
79 : do_pw_grid_blocked_free = 2
80 :
81 : INTERFACE pw_grid_create
82 : MODULE PROCEDURE pw_grid_create_local
83 : MODULE PROCEDURE pw_grid_create_extended
84 : END INTERFACE
85 :
86 : CONTAINS
87 :
88 : ! **************************************************************************************************
89 : !> \brief Initialize a PW grid with bounds only (used by some routines)
90 : !> \param pw_grid ...
91 : !> \param bounds ...
92 : !> \par History
93 : !> JGH (21-Feb-2003) : initialize pw_grid%reference
94 : !> \author JGH (7-Feb-2001) & fawzi
95 : ! **************************************************************************************************
96 59066 : SUBROUTINE pw_grid_create_local(pw_grid, bounds)
97 :
98 : TYPE(pw_grid_type), POINTER :: pw_grid
99 : INTEGER, DIMENSION(2, 3), INTENT(IN) :: bounds
100 :
101 : INTEGER, DIMENSION(2) :: rs_dims
102 :
103 59066 : CPASSERT(.NOT. ASSOCIATED(pw_grid))
104 3484894 : ALLOCATE (pw_grid)
105 590660 : pw_grid%bounds = bounds
106 590660 : pw_grid%bounds_local = bounds
107 236264 : pw_grid%npts = bounds(2, :) - bounds(1, :) + 1
108 236264 : pw_grid%npts_local = pw_grid%npts
109 236264 : pw_grid%ngpts = PRODUCT(INT(pw_grid%npts, KIND=int_8))
110 59066 : pw_grid%ngpts_cut = pw_grid%ngpts
111 236264 : pw_grid%ngpts_local = PRODUCT(pw_grid%npts)
112 59066 : pw_grid%ngpts_cut_local = pw_grid%ngpts_local
113 59066 : pw_grid%grid_span = FULLSPACE
114 59066 : pw_grid%para%mode = PW_MODE_LOCAL
115 59066 : pw_grid%reference = 0
116 59066 : pw_grid%ref_count = 1
117 59066 : NULLIFY (pw_grid%g)
118 59066 : NULLIFY (pw_grid%gsq)
119 59066 : NULLIFY (pw_grid%g_hatmap)
120 59066 : NULLIFY (pw_grid%gidx)
121 59066 : NULLIFY (pw_grid%grays)
122 :
123 : ! assign a unique tag to this grid
124 59066 : grid_tag = grid_tag + 1
125 59066 : pw_grid%id_nr = grid_tag
126 :
127 : ! parallel info
128 177198 : rs_dims = 1
129 59066 : CALL pw_grid%para%group%create(mp_comm_self, 2, rs_dims)
130 59066 : IF (pw_grid%para%group%num_pe > 1) THEN
131 0 : pw_grid%para%mode = PW_MODE_DISTRIBUTED
132 : ELSE
133 59066 : pw_grid%para%mode = PW_MODE_LOCAL
134 : END IF
135 :
136 59066 : END SUBROUTINE pw_grid_create_local
137 :
138 : ! **************************************************************************************************
139 : !> \brief Check if two pw_grids are equal
140 : !> \param grida ...
141 : !> \param gridb ...
142 : !> \return ...
143 : !> \par History
144 : !> none
145 : !> \author JGH (14-Feb-2001)
146 : ! **************************************************************************************************
147 7174059 : FUNCTION pw_grid_compare(grida, gridb) RESULT(equal)
148 :
149 : TYPE(pw_grid_type), INTENT(IN) :: grida, gridb
150 : LOGICAL :: equal
151 :
152 : !------------------------------------------------------------------------------
153 :
154 7174059 : IF (grida%id_nr == gridb%id_nr) THEN
155 : equal = .TRUE.
156 : ELSE
157 : ! for the moment all grids with different identifiers are considered as not equal
158 : ! later we can get this more relaxed
159 18 : equal = .FALSE.
160 : END IF
161 :
162 7174059 : END FUNCTION pw_grid_compare
163 :
164 : ! **************************************************************************************************
165 : !> \brief Access to information stored in the pw_grid_type
166 : !> \param pw_grid ...
167 : !> \param id_nr ...
168 : !> \param mode ...
169 : !> \param vol ...
170 : !> \param dvol ...
171 : !> \param npts ...
172 : !> \param ngpts ...
173 : !> \param ngpts_cut ...
174 : !> \param dr ...
175 : !> \param cutoff ...
176 : !> \param orthorhombic ...
177 : !> \param gvectors ...
178 : !> \param gsquare ...
179 : !> \par History
180 : !> none
181 : !> \author JGH (17-Nov-2007)
182 : ! **************************************************************************************************
183 60482 : SUBROUTINE get_pw_grid_info(pw_grid, id_nr, mode, vol, dvol, npts, ngpts, &
184 : ngpts_cut, dr, cutoff, orthorhombic, gvectors, gsquare)
185 :
186 : TYPE(pw_grid_type), INTENT(IN) :: pw_grid
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
196 :
197 60482 : CPASSERT(pw_grid%ref_count > 0)
198 :
199 60482 : IF (PRESENT(id_nr)) id_nr = pw_grid%id_nr
200 60482 : IF (PRESENT(mode)) mode = pw_grid%para%mode
201 60482 : IF (PRESENT(vol)) vol = pw_grid%vol
202 60482 : IF (PRESENT(dvol)) dvol = pw_grid%dvol
203 302234 : IF (PRESENT(npts)) npts(1:3) = pw_grid%npts(1:3)
204 60482 : IF (PRESENT(ngpts)) ngpts = pw_grid%ngpts
205 60482 : IF (PRESENT(ngpts_cut)) ngpts_cut = pw_grid%ngpts_cut
206 60618 : IF (PRESENT(dr)) dr = pw_grid%dr
207 60482 : IF (PRESENT(cutoff)) cutoff = pw_grid%cutoff
208 60482 : IF (PRESENT(orthorhombic)) orthorhombic = pw_grid%orthorhombic
209 60482 : IF (PRESENT(gvectors)) gvectors => pw_grid%g
210 60482 : IF (PRESENT(gsquare)) gsquare => pw_grid%gsq
211 :
212 60482 : END SUBROUTINE get_pw_grid_info
213 :
214 : ! **************************************************************************************************
215 : !> \brief Set some information stored in the pw_grid_type
216 : !> \param pw_grid ...
217 : !> \param grid_span ...
218 : !> \param npts ...
219 : !> \param bounds ...
220 : !> \param cutoff ...
221 : !> \param spherical ...
222 : !> \par History
223 : !> none
224 : !> \author JGH (19-Nov-2007)
225 : ! **************************************************************************************************
226 65160 : SUBROUTINE set_pw_grid_info(pw_grid, grid_span, npts, bounds, cutoff, spherical)
227 :
228 : TYPE(pw_grid_type), INTENT(INOUT) :: pw_grid
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
234 :
235 65160 : CPASSERT(pw_grid%ref_count > 0)
236 :
237 65160 : IF (PRESENT(grid_span)) THEN
238 32013 : pw_grid%grid_span = grid_span
239 : END IF
240 65160 : IF (PRESENT(bounds) .AND. PRESENT(npts)) THEN
241 0 : pw_grid%bounds = bounds
242 0 : pw_grid%npts = npts
243 0 : CPASSERT(ALL(npts == bounds(2, :) - bounds(1, :) + 1))
244 65160 : ELSE IF (PRESENT(bounds)) THEN
245 11170 : pw_grid%bounds = bounds
246 4468 : pw_grid%npts = bounds(2, :) - bounds(1, :) + 1
247 64043 : ELSE IF (PRESENT(npts)) THEN
248 128120 : pw_grid%npts = npts
249 320300 : pw_grid%bounds = pw_grid_bounds_from_n(npts)
250 : END IF
251 65160 : IF (PRESENT(cutoff)) THEN
252 33147 : pw_grid%cutoff = cutoff
253 33147 : IF (PRESENT(spherical)) THEN
254 33147 : pw_grid%spherical = spherical
255 : ELSE
256 0 : pw_grid%spherical = .FALSE.
257 : END IF
258 : END IF
259 :
260 65160 : END SUBROUTINE set_pw_grid_info
261 :
262 : ! **************************************************************************************************
263 : !> \brief sets up a pw_grid
264 : !> \param pw_grid ...
265 : !> \param mp_comm ...
266 : !> \param cell_hmat ...
267 : !> \param grid_span ...
268 : !> \param cutoff ...
269 : !> \param bounds ...
270 : !> \param bounds_local ...
271 : !> \param npts ...
272 : !> \param spherical ...
273 : !> \param odd ...
274 : !> \param fft_usage ...
275 : !> \param ncommensurate ...
276 : !> \param icommensurate ...
277 : !> \param blocked ...
278 : !> \param ref_grid ...
279 : !> \param rs_dims ...
280 : !> \param iounit ...
281 : !> \author JGH (21-Dec-2007)
282 : !> \note
283 : !> this is the function that should be used in the future
284 : ! **************************************************************************************************
285 33147 : 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, &
287 : rs_dims, iounit)
288 :
289 : TYPE(pw_grid_type), POINTER :: pw_grid
290 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN) :: cell_hmat
291 :
292 : CLASS(mp_comm_type), INTENT(IN) :: mp_comm
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
299 : TYPE(pw_grid_type), INTENT(IN), OPTIONAL :: ref_grid
300 : INTEGER, DIMENSION(2), INTENT(in), OPTIONAL :: rs_dims
301 : INTEGER, INTENT(in), OPTIONAL :: iounit
302 :
303 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_grid_setup'
304 :
305 : INTEGER :: handle, my_icommensurate, &
306 : my_ncommensurate
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
311 :
312 33147 : CALL timeset(routineN, handle)
313 :
314 33147 : CPASSERT(.NOT. ASSOCIATED(pw_grid))
315 1723644 : ALLOCATE (pw_grid)
316 331470 : pw_grid%bounds = 0
317 33147 : pw_grid%cutoff = 0.0_dp
318 33147 : pw_grid%grid_span = FULLSPACE
319 : pw_grid%para%mode = PW_MODE_LOCAL
320 : pw_grid%reference = 0
321 33147 : pw_grid%ref_count = 1
322 33147 : NULLIFY (pw_grid%g)
323 33147 : NULLIFY (pw_grid%gsq)
324 33147 : NULLIFY (pw_grid%g_hatmap)
325 33147 : NULLIFY (pw_grid%gidx)
326 33147 : NULLIFY (pw_grid%grays)
327 :
328 : ! assign a unique tag to this grid
329 33147 : grid_tag = grid_tag + 1
330 33147 : pw_grid%id_nr = grid_tag
331 :
332 : ! parallel info
333 33147 : IF (mp_comm%num_pe > 1) THEN
334 28044 : pw_grid%para%mode = PW_MODE_DISTRIBUTED
335 : ELSE
336 : pw_grid%para%mode = PW_MODE_LOCAL
337 : END IF
338 :
339 33147 : cell_deth = ABS(det_3x3(cell_hmat))
340 33147 : IF (cell_deth < 1.0E-10_dp) THEN
341 : CALL cp_abort(__LOCATION__, &
342 : "An invalid set of cell vectors was specified. "// &
343 0 : "The determinant det(h) is too small")
344 : END IF
345 33147 : cell_h_inv = inv_3x3(cell_hmat)
346 :
347 33147 : IF (PRESENT(grid_span)) THEN
348 32013 : CALL set_pw_grid_info(pw_grid, grid_span=grid_span)
349 : END IF
350 :
351 33147 : IF (PRESENT(spherical)) THEN
352 32935 : my_spherical = spherical
353 : ELSE
354 212 : my_spherical = .FALSE.
355 : END IF
356 :
357 33147 : IF (PRESENT(odd)) THEN
358 28632 : my_odd = odd
359 : ELSE
360 4515 : my_odd = .FALSE.
361 : END IF
362 :
363 33147 : IF (PRESENT(fft_usage)) THEN
364 33023 : my_fft_usage = fft_usage
365 : ELSE
366 124 : my_fft_usage = .FALSE.
367 : END IF
368 :
369 33147 : IF (PRESENT(ncommensurate)) THEN
370 28572 : my_ncommensurate = ncommensurate
371 28572 : IF (PRESENT(icommensurate)) THEN
372 28572 : my_icommensurate = icommensurate
373 : ELSE
374 0 : my_icommensurate = MIN(1, ncommensurate)
375 : END IF
376 : ELSE
377 4575 : my_ncommensurate = 0
378 4575 : my_icommensurate = 1
379 : END IF
380 :
381 33147 : IF (PRESENT(bounds)) THEN
382 1117 : IF (PRESENT(cutoff)) THEN
383 : CALL set_pw_grid_info(pw_grid, bounds=bounds, cutoff=cutoff, &
384 172 : spherical=my_spherical)
385 : ELSE
386 3780 : n = bounds(2, :) - bounds(1, :) + 1
387 945 : my_cutoff = pw_find_cutoff(n, cell_h_inv)
388 945 : my_cutoff = 0.5_dp*my_cutoff*my_cutoff
389 : CALL set_pw_grid_info(pw_grid, bounds=bounds, cutoff=my_cutoff, &
390 945 : spherical=my_spherical)
391 : END IF
392 32030 : ELSE IF (PRESENT(npts)) THEN
393 2368 : n = npts
394 2368 : IF (PRESENT(cutoff)) THEN
395 22 : my_cutoff = cutoff
396 : ELSE
397 2346 : my_cutoff = pw_find_cutoff(npts, cell_h_inv)
398 2346 : my_cutoff = 0.5_dp*my_cutoff*my_cutoff
399 : END IF
400 2368 : IF (my_fft_usage) THEN
401 : n = pw_grid_init_setup(cell_hmat, cutoff=my_cutoff, &
402 : spherical=my_spherical, odd=my_odd, fft_usage=my_fft_usage, &
403 : ncommensurate=my_ncommensurate, icommensurate=my_icommensurate, &
404 9472 : ref_grid=ref_grid, n_orig=n)
405 : END IF
406 : CALL set_pw_grid_info(pw_grid, npts=n, cutoff=my_cutoff, &
407 2368 : spherical=my_spherical)
408 29662 : ELSE IF (PRESENT(cutoff)) THEN
409 : n = pw_grid_init_setup(cell_hmat, cutoff=cutoff, &
410 : spherical=my_spherical, odd=my_odd, fft_usage=my_fft_usage, &
411 : ncommensurate=my_ncommensurate, icommensurate=my_icommensurate, &
412 29662 : ref_grid=ref_grid)
413 : CALL set_pw_grid_info(pw_grid, npts=n, cutoff=cutoff, &
414 29662 : spherical=my_spherical)
415 : ELSE
416 0 : CPABORT("BOUNDS, NPTS or CUTOFF have to be specified")
417 : END IF
418 :
419 : CALL pw_grid_setup_internal(cell_hmat, cell_h_inv, cell_deth, pw_grid, mp_comm, bounds_local=bounds_local, &
420 33147 : blocked=blocked, ref_grid=ref_grid, rs_dims=rs_dims, iounit=iounit)
421 :
422 : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
423 : CALL pw_grid_create_ghatmap(pw_grid)
424 : #endif
425 :
426 33147 : CALL timestop(handle)
427 :
428 33147 : END SUBROUTINE pw_grid_create_extended
429 :
430 : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
431 : ! **************************************************************************************************
432 : !> \brief sets up a combined index for CUDA gather and scatter
433 : !> \param pw_grid ...
434 : !> \author Gloess Andreas (xx-Dec-2012)
435 : ! **************************************************************************************************
436 : SUBROUTINE pw_grid_create_ghatmap(pw_grid)
437 :
438 : TYPE(pw_grid_type), INTENT(INOUT) :: pw_grid
439 :
440 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_grid_create_ghatmap'
441 :
442 : INTEGER :: gpt, handle, l, m, mn, n
443 :
444 : CALL timeset(routineN, handle)
445 :
446 : ! some checks
447 : CPASSERT(pw_grid%ref_count > 0)
448 :
449 : ! mapping of map_x( g_hat(i,j)) to g_hatmap
450 : ! the second index is for switching from gather(1) to scatter(2)
451 : ASSOCIATE (g_hat => pw_grid%g_hat, g_hatmap => pw_grid%g_hatmap, pmapl => pw_grid%mapl%pos, &
452 : pmapm => pw_grid%mapm%pos, pmapn => pw_grid%mapn%pos, nmapl => pw_grid%mapl%neg, &
453 : nmapm => pw_grid%mapm%neg, nmapn => pw_grid%mapn%neg, ngpts => SIZE(pw_grid%gsq), &
454 : npts => pw_grid%npts, yzq => pw_grid%para%yzq)
455 : ! initialize map array to minus one, to guarantee memory
456 : ! range checking errors in CUDA part (just to be sure)
457 : g_hatmap(:, :) = -1
458 : IF (pw_grid%para%mode /= PW_MODE_DISTRIBUTED) THEN
459 : DO gpt = 1, ngpts
460 : l = pmapl(g_hat(1, gpt))
461 : m = pmapm(g_hat(2, gpt))
462 : n = pmapn(g_hat(3, gpt))
463 : !ATTENTION: C-mapping [start-index=0] !!!!
464 : !ATTENTION: potential integer overflow !!!!
465 : g_hatmap(gpt, 1) = l + npts(1)*(m + npts(2)*n)
466 : END DO
467 : IF (pw_grid%grid_span == HALFSPACE) THEN
468 : DO gpt = 1, ngpts
469 : l = nmapl(g_hat(1, gpt))
470 : m = nmapm(g_hat(2, gpt))
471 : n = nmapn(g_hat(3, gpt))
472 : !ATTENTION: C-mapping [start-index=0] !!!!
473 : !ATTENTION: potential integer overflow !!!!
474 : g_hatmap(gpt, 2) = l + npts(1)*(m + npts(2)*n)
475 : END DO
476 : END IF
477 : ELSE
478 : DO gpt = 1, ngpts
479 : l = pmapl(g_hat(1, gpt))
480 : m = pmapm(g_hat(2, gpt)) + 1
481 : n = pmapn(g_hat(3, gpt)) + 1
482 : !ATTENTION: C-mapping [start-index=0] !!!!
483 : !ATTENTION: potential integer overflow !!!!
484 : mn = yzq(m, n) - 1
485 : g_hatmap(gpt, 1) = l + npts(1)*mn
486 : END DO
487 : IF (pw_grid%grid_span == HALFSPACE) THEN
488 : DO gpt = 1, ngpts
489 : l = nmapl(g_hat(1, gpt))
490 : m = nmapm(g_hat(2, gpt)) + 1
491 : n = nmapn(g_hat(3, gpt)) + 1
492 : !ATTENTION: C-mapping [start-index=0] !!!!
493 : !ATTENTION: potential integer overflow !!!!
494 : mn = yzq(m, n) - 1
495 : g_hatmap(gpt, 2) = l + npts(1)*mn
496 : END DO
497 : END IF
498 : END IF
499 : END ASSOCIATE
500 :
501 : CALL timestop(handle)
502 :
503 : END SUBROUTINE pw_grid_create_ghatmap
504 : #endif
505 :
506 : ! **************************************************************************************************
507 : !> \brief sets up a pw_grid, needs valid bounds as input, it is up to you to
508 : !> make sure of it using pw_grid_bounds_from_n
509 : !> \param cell_hmat ...
510 : !> \param cell_h_inv ...
511 : !> \param cell_deth ...
512 : !> \param pw_grid ...
513 : !> \param mp_comm ...
514 : !> \param bounds_local ...
515 : !> \param blocked ...
516 : !> \param ref_grid ...
517 : !> \param rs_dims ...
518 : !> \param iounit ...
519 : !> \par History
520 : !> JGH (20-Dec-2000) : Adapted for parallel use
521 : !> JGH (28-Feb-2001) : New optional argument fft_usage
522 : !> JGH (21-Mar-2001) : Reference grid code
523 : !> JGH (21-Mar-2001) : New optional argument symm_usage
524 : !> JGH (22-Mar-2001) : Simplify group assignment (mp_comm_dup)
525 : !> JGH (21-May-2002) : Remove orthorhombic keyword (code is fast enough)
526 : !> JGH (19-Feb-2003) : Negative cutoff can be used for non-spheric grids
527 : !> Joost VandeVondele (Feb-2004) : optionally generate pw grids that are commensurate in rs
528 : !> JGH (18-Dec-2007) : Refactoring
529 : !> \author fawzi
530 : !> \note
531 : !> this is the function that should be used in the future
532 : ! **************************************************************************************************
533 33147 : SUBROUTINE pw_grid_setup_internal(cell_hmat, cell_h_inv, cell_deth, pw_grid, mp_comm, bounds_local, &
534 : blocked, ref_grid, rs_dims, iounit)
535 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN) :: cell_hmat, cell_h_inv
536 : REAL(KIND=dp), INTENT(IN) :: cell_deth
537 : TYPE(pw_grid_type), INTENT(INOUT) :: pw_grid
538 :
539 : CLASS(mp_comm_type), INTENT(IN) :: mp_comm
540 : INTEGER, DIMENSION(2, 3), INTENT(IN), OPTIONAL :: bounds_local
541 : INTEGER, INTENT(in), OPTIONAL :: blocked
542 : TYPE(pw_grid_type), INTENT(in), OPTIONAL :: ref_grid
543 : INTEGER, DIMENSION(2), INTENT(in), OPTIONAL :: rs_dims
544 : INTEGER, INTENT(in), OPTIONAL :: iounit
545 :
546 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_grid_setup_internal'
547 :
548 : INTEGER :: handle, n(3)
549 33147 : INTEGER, ALLOCATABLE, DIMENSION(:, :) :: yz_mask
550 : REAL(KIND=dp) :: ecut
551 :
552 : !------------------------------------------------------------------------------
553 :
554 33147 : CALL timeset(routineN, handle)
555 :
556 33147 : CPASSERT(pw_grid%ref_count > 0)
557 :
558 : ! set pointer to possible reference grid
559 33147 : IF (PRESENT(ref_grid)) THEN
560 20912 : pw_grid%reference = ref_grid%id_nr
561 : END IF
562 :
563 33147 : IF (pw_grid%spherical) THEN
564 3207 : ecut = pw_grid%cutoff
565 : ELSE
566 29940 : ecut = 1.e10_dp
567 : END IF
568 :
569 132588 : n(:) = pw_grid%npts(:)
570 :
571 : ! Find the number of grid points
572 : ! yz_mask counts the number of g-vectors orthogonal to the yz plane
573 : ! the indices in yz_mask are from -n/2 .. n/2 shifted by n/2 + 1
574 : ! these are not mapped indices !
575 132588 : ALLOCATE (yz_mask(n(2), n(3)))
576 33147 : CALL pw_grid_count(cell_h_inv, pw_grid, mp_comm, ecut, yz_mask)
577 :
578 : ! Check if reference grid is compatible
579 33147 : IF (PRESENT(ref_grid)) THEN
580 20912 : CPASSERT(pw_grid%para%mode == ref_grid%para%mode)
581 20912 : CPASSERT(pw_grid%grid_span == ref_grid%grid_span)
582 20912 : CPASSERT(pw_grid%spherical .EQV. ref_grid%spherical)
583 : END IF
584 :
585 : ! Distribute grid
586 : CALL pw_grid_distribute(pw_grid, mp_comm, yz_mask, bounds_local=bounds_local, ref_grid=ref_grid, blocked=blocked, &
587 33147 : rs_dims=rs_dims)
588 :
589 : ! Allocate the grid fields
590 : CALL pw_grid_allocate(pw_grid, pw_grid%ngpts_cut_local, &
591 33147 : pw_grid%bounds)
592 :
593 : ! Fill in the grid structure
594 33147 : CALL pw_grid_assign(cell_h_inv, pw_grid, ecut)
595 :
596 : ! Sort g vector wrt length (only local for each processor)
597 33147 : CALL pw_grid_sort(pw_grid, ref_grid)
598 :
599 33147 : CALL pw_grid_remap(pw_grid, yz_mask)
600 :
601 33147 : DEALLOCATE (yz_mask)
602 :
603 33147 : CALL cell2grid(cell_hmat, cell_h_inv, cell_deth, pw_grid)
604 : !
605 : ! Output: All the information of this grid type
606 : !
607 :
608 33147 : IF (PRESENT(iounit)) THEN
609 33125 : CALL pw_grid_print(pw_grid, iounit)
610 : END IF
611 :
612 33147 : CALL timestop(handle)
613 :
614 33147 : END SUBROUTINE pw_grid_setup_internal
615 :
616 : ! **************************************************************************************************
617 : !> \brief Helper routine used by pw_grid_setup_internal and pw_grid_change
618 : !> \param cell_hmat ...
619 : !> \param cell_h_inv ...
620 : !> \param cell_deth ...
621 : !> \param pw_grid ...
622 : !> \par History moved common code into new subroutine
623 : !> \author Ole Schuett
624 : ! **************************************************************************************************
625 44261 : SUBROUTINE cell2grid(cell_hmat, cell_h_inv, cell_deth, pw_grid)
626 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN) :: cell_hmat, cell_h_inv
627 : REAL(KIND=dp), INTENT(IN) :: cell_deth
628 : TYPE(pw_grid_type), INTENT(INOUT) :: pw_grid
629 :
630 44261 : pw_grid%vol = ABS(cell_deth)
631 44261 : pw_grid%dvol = pw_grid%vol/REAL(pw_grid%ngpts, KIND=dp)
632 : pw_grid%dr(1) = SQRT(SUM(cell_hmat(:, 1)**2)) &
633 177044 : /REAL(pw_grid%npts(1), KIND=dp)
634 : pw_grid%dr(2) = SQRT(SUM(cell_hmat(:, 2)**2)) &
635 177044 : /REAL(pw_grid%npts(2), KIND=dp)
636 : pw_grid%dr(3) = SQRT(SUM(cell_hmat(:, 3)**2)) &
637 177044 : /REAL(pw_grid%npts(3), KIND=dp)
638 177044 : pw_grid%dh(:, 1) = cell_hmat(:, 1)/REAL(pw_grid%npts(1), KIND=dp)
639 177044 : pw_grid%dh(:, 2) = cell_hmat(:, 2)/REAL(pw_grid%npts(2), KIND=dp)
640 177044 : pw_grid%dh(:, 3) = cell_hmat(:, 3)/REAL(pw_grid%npts(3), KIND=dp)
641 177044 : pw_grid%dh_inv(1, :) = cell_h_inv(1, :)*REAL(pw_grid%npts(1), KIND=dp)
642 177044 : pw_grid%dh_inv(2, :) = cell_h_inv(2, :)*REAL(pw_grid%npts(2), KIND=dp)
643 177044 : pw_grid%dh_inv(3, :) = cell_h_inv(3, :)*REAL(pw_grid%npts(3), KIND=dp)
644 :
645 : IF ((cell_hmat(1, 2) == 0.0_dp) .AND. (cell_hmat(1, 3) == 0.0_dp) .AND. &
646 : (cell_hmat(2, 1) == 0.0_dp) .AND. (cell_hmat(2, 3) == 0.0_dp) .AND. &
647 44261 : (cell_hmat(3, 1) == 0.0_dp) .AND. (cell_hmat(3, 2) == 0.0_dp)) THEN
648 36555 : pw_grid%orthorhombic = .TRUE.
649 : ELSE
650 7706 : pw_grid%orthorhombic = .FALSE.
651 : END IF
652 44261 : END SUBROUTINE cell2grid
653 :
654 : ! **************************************************************************************************
655 : !> \brief Output of information on pw_grid
656 : !> \param pw_grid ...
657 : !> \param info ...
658 : !> \author JGH[18-05-2007] from earlier versions
659 : ! **************************************************************************************************
660 33125 : SUBROUTINE pw_grid_print(pw_grid, info)
661 :
662 : TYPE(pw_grid_type), INTENT(IN) :: pw_grid
663 : INTEGER, INTENT(IN) :: info
664 :
665 : INTEGER :: i
666 : INTEGER(KIND=int_8) :: n(3)
667 : REAL(KIND=dp) :: rv(3, 3)
668 :
669 : !------------------------------------------------------------------------------
670 : !
671 : ! Output: All the information of this grid type
672 : !
673 :
674 33125 : IF (pw_grid%para%mode == PW_MODE_LOCAL) THEN
675 5103 : IF (info > 0) THEN
676 : WRITE (info, '(/,A,T71,I10)') &
677 429 : " PW_GRID| Information for grid number ", pw_grid%id_nr
678 429 : IF (pw_grid%reference > 0) THEN
679 : WRITE (info, '(A,T71,I10)') &
680 108 : " PW_GRID| Number of the reference grid ", pw_grid%reference
681 : END IF
682 429 : WRITE (info, '(" PW_GRID| Cutoff [a.u.]",T71,f10.1)') pw_grid%cutoff
683 429 : IF (pw_grid%spherical) THEN
684 200 : WRITE (info, '(A,T78,A)') " PW_GRID| spherical cutoff: ", "YES"
685 200 : WRITE (info, '(A,T71,I10)') " PW_GRID| Grid points within cutoff", &
686 400 : pw_grid%ngpts_cut
687 : ELSE
688 229 : WRITE (info, '(A,T78,A)') " PW_GRID| spherical cutoff: ", " NO"
689 : END IF
690 1716 : DO i = 1, 3
691 1287 : WRITE (info, '(A,I3,T30,2I8,T62,A,T71,I10)') " PW_GRID| Bounds ", &
692 1287 : i, pw_grid%bounds(1, I), pw_grid%bounds(2, I), &
693 3003 : "Points:", pw_grid%npts(I)
694 : END DO
695 : WRITE (info, '(A,G12.4,T50,A,T67,F14.4)') &
696 429 : " PW_GRID| Volume element (a.u.^3)", &
697 858 : pw_grid%dvol, " Volume (a.u.^3) :", pw_grid%vol
698 429 : IF (pw_grid%grid_span == HALFSPACE) THEN
699 289 : WRITE (info, '(A,T72,A)') " PW_GRID| Grid span", "HALFSPACE"
700 : ELSE
701 140 : WRITE (info, '(A,T72,A)') " PW_GRID| Grid span", "FULLSPACE"
702 : END IF
703 : END IF
704 : ELSE
705 :
706 28022 : n(1) = pw_grid%ngpts_cut_local
707 28022 : n(2) = pw_grid%ngpts_local
708 28022 : CALL pw_grid%para%group%sum(n(1:2))
709 84066 : n(3) = SUM(pw_grid%para%nyzray)
710 112088 : rv(:, 1) = REAL(n, KIND=dp)/REAL(pw_grid%para%group%num_pe, KIND=dp)
711 28022 : n(1) = pw_grid%ngpts_cut_local
712 28022 : n(2) = pw_grid%ngpts_local
713 28022 : CALL pw_grid%para%group%max(n(1:2))
714 84066 : n(3) = MAXVAL(pw_grid%para%nyzray)
715 112088 : rv(:, 2) = REAL(n, KIND=dp)
716 28022 : n(1) = pw_grid%ngpts_cut_local
717 28022 : n(2) = pw_grid%ngpts_local
718 28022 : CALL pw_grid%para%group%min(n(1:2))
719 84066 : n(3) = MINVAL(pw_grid%para%nyzray)
720 112088 : rv(:, 3) = REAL(n, KIND=dp)
721 :
722 28022 : IF (info > 0) THEN
723 : WRITE (info, '(/,A,T71,I10)') &
724 6289 : " PW_GRID| Information for grid number ", pw_grid%id_nr
725 6289 : IF (pw_grid%reference > 0) THEN
726 : WRITE (info, '(A,T71,I10)') &
727 4062 : " PW_GRID| Number of the reference grid ", pw_grid%reference
728 : END IF
729 : WRITE (info, '(A,T60,I10,A)') &
730 6289 : " PW_GRID| Grid distributed over ", pw_grid%para%group%num_pe, &
731 12578 : " processors"
732 : WRITE (info, '(A,T71,2I5)') &
733 6289 : " PW_GRID| Real space group dimensions ", pw_grid%para%group%num_pe_cart
734 6289 : IF (pw_grid%para%blocked) THEN
735 6 : WRITE (info, '(A,T78,A)') " PW_GRID| the grid is blocked: ", "YES"
736 : ELSE
737 6283 : WRITE (info, '(A,T78,A)') " PW_GRID| the grid is blocked: ", " NO"
738 : END IF
739 6289 : WRITE (info, '(" PW_GRID| Cutoff [a.u.]",T71,f10.1)') pw_grid%cutoff
740 6289 : IF (pw_grid%spherical) THEN
741 392 : WRITE (info, '(A,T78,A)') " PW_GRID| spherical cutoff: ", "YES"
742 392 : WRITE (info, '(A,T71,I10)') " PW_GRID| Grid points within cutoff", &
743 784 : pw_grid%ngpts_cut
744 : ELSE
745 5897 : WRITE (info, '(A,T78,A)') " PW_GRID| spherical cutoff: ", " NO"
746 : END IF
747 25156 : DO i = 1, 3
748 18867 : WRITE (info, '(A,I3,T30,2I8,T62,A,T71,I10)') " PW_GRID| Bounds ", &
749 18867 : i, pw_grid%bounds(1, I), pw_grid%bounds(2, I), &
750 44023 : "Points:", pw_grid%npts(I)
751 : END DO
752 : WRITE (info, '(A,G12.4,T50,A,T67,F14.4)') &
753 6289 : " PW_GRID| Volume element (a.u.^3)", &
754 12578 : pw_grid%dvol, " Volume (a.u.^3) :", pw_grid%vol
755 6289 : IF (pw_grid%grid_span == HALFSPACE) THEN
756 400 : WRITE (info, '(A,T72,A)') " PW_GRID| Grid span", "HALFSPACE"
757 : ELSE
758 5889 : WRITE (info, '(A,T72,A)') " PW_GRID| Grid span", "FULLSPACE"
759 : END IF
760 6289 : WRITE (info, '(A,T48,A)') " PW_GRID| Distribution", &
761 12578 : " Average Max Min"
762 6289 : WRITE (info, '(A,T45,F12.1,2I12)') " PW_GRID| G-Vectors", &
763 12578 : rv(1, 1), NINT(rv(1, 2)), NINT(rv(1, 3))
764 6289 : WRITE (info, '(A,T45,F12.1,2I12)') " PW_GRID| G-Rays ", &
765 12578 : rv(3, 1), NINT(rv(3, 2)), NINT(rv(3, 3))
766 6289 : WRITE (info, '(A,T45,F12.1,2I12)') " PW_GRID| Real Space Points", &
767 12578 : rv(2, 1), NINT(rv(2, 2)), NINT(rv(2, 3))
768 : END IF ! group head
769 : END IF ! local
770 :
771 33125 : END SUBROUTINE pw_grid_print
772 :
773 : ! **************************************************************************************************
774 : !> \brief Distribute grids in real and Fourier Space to the processors in group
775 : !> \param pw_grid ...
776 : !> \param mp_comm ...
777 : !> \param yz_mask ...
778 : !> \param bounds_local ...
779 : !> \param ref_grid ...
780 : !> \param blocked ...
781 : !> \param rs_dims ...
782 : !> \par History
783 : !> JGH (01-Mar-2001) optional reference grid
784 : !> JGH (22-May-2002) bug fix for pre_tag and HALFSPACE grids
785 : !> JGH (09-Sep-2003) reduce scaling for distribution
786 : !> \author JGH (22-12-2000)
787 : ! **************************************************************************************************
788 33147 : SUBROUTINE pw_grid_distribute(pw_grid, mp_comm, yz_mask, bounds_local, ref_grid, blocked, rs_dims)
789 :
790 : TYPE(pw_grid_type), INTENT(INOUT) :: pw_grid
791 :
792 : CLASS(mp_comm_type), INTENT(IN) :: mp_comm
793 : INTEGER, DIMENSION(:, :), INTENT(INOUT) :: yz_mask
794 : INTEGER, DIMENSION(2, 3), INTENT(IN), OPTIONAL :: bounds_local
795 : TYPE(pw_grid_type), INTENT(IN), OPTIONAL :: ref_grid
796 : INTEGER, INTENT(IN), OPTIONAL :: blocked
797 : INTEGER, DIMENSION(2), INTENT(in), OPTIONAL :: rs_dims
798 :
799 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_grid_distribute'
800 :
801 : INTEGER :: blocked_local, coor(2), gmax, handle, i, &
802 : i1, i2, ip, ipl, ipp, itmp, j, l, lby, &
803 : lbz, lo(2), m, n, np, ns, nx, ny, nz, &
804 : rsd(2)
805 33147 : INTEGER, ALLOCATABLE, DIMENSION(:) :: pemap
806 33147 : INTEGER, ALLOCATABLE, DIMENSION(:, :) :: yz_index
807 33147 : INTEGER, ALLOCATABLE, DIMENSION(:, :, :) :: axis_dist_all
808 : INTEGER, DIMENSION(2) :: my_rs_dims
809 : INTEGER, DIMENSION(2, 3) :: axis_dist
810 : LOGICAL :: blocking
811 :
812 : !------------------------------------------------------------------------------
813 :
814 33147 : CALL timeset(routineN, handle)
815 :
816 33147 : lby = pw_grid%bounds(1, 2)
817 33147 : lbz = pw_grid%bounds(1, 3)
818 :
819 132588 : pw_grid%ngpts = PRODUCT(INT(pw_grid%npts, KIND=int_8))
820 :
821 33147 : my_rs_dims = 0
822 33147 : IF (PRESENT(rs_dims)) THEN
823 32136 : my_rs_dims = rs_dims
824 : END IF
825 :
826 33147 : IF (PRESENT(blocked)) THEN
827 29766 : blocked_local = blocked
828 : ELSE
829 : blocked_local = do_pw_grid_blocked_free
830 : END IF
831 :
832 33147 : pw_grid%para%blocked = .FALSE.
833 :
834 33147 : IF (pw_grid%para%mode == PW_MODE_LOCAL) THEN
835 :
836 5103 : pw_grid%para%ray_distribution = .FALSE.
837 :
838 51030 : pw_grid%bounds_local = pw_grid%bounds
839 20412 : pw_grid%npts_local = pw_grid%npts
840 5103 : CPASSERT(pw_grid%ngpts_cut < HUGE(pw_grid%ngpts_cut_local))
841 5103 : pw_grid%ngpts_cut_local = INT(pw_grid%ngpts_cut)
842 5103 : CPASSERT(pw_grid%ngpts < HUGE(pw_grid%ngpts_local))
843 5103 : pw_grid%ngpts_local = INT(pw_grid%ngpts)
844 15309 : my_rs_dims = 1
845 5103 : CALL pw_grid%para%group%create(mp_comm, 2, my_rs_dims)
846 :
847 5103 : ALLOCATE (pw_grid%para%bo(2, 3, 0:0, 3))
848 20412 : DO i = 1, 3
849 61236 : pw_grid%para%bo(1, 1:3, 0, i) = 1
850 66339 : pw_grid%para%bo(2, 1:3, 0, i) = pw_grid%npts(1:3)
851 : END DO
852 :
853 : ELSE
854 :
855 : !..find the real space distribution
856 28044 : nx = pw_grid%npts(1)
857 28044 : ny = pw_grid%npts(2)
858 28044 : nz = pw_grid%npts(3)
859 28044 : np = mp_comm%num_pe
860 :
861 : ! The user can specify 2 strictly positive indices => specific layout
862 : ! 1 strictly positive index => the other is fixed by the number of CPUs
863 : ! 0 strictly positive indices => fully free distribution
864 : ! if fully free or the user request can not be fulfilled, we optimize heuristically ourselves by:
865 : ! 1) nx>np -> taking a plane distribution (/np,1/)
866 : ! 2) nx<np -> taking the most square distribution
867 : ! if blocking is free:
868 : ! 1) blocked=.FALSE. for plane distributions
869 : ! 2) blocked=.TRUE. for non-plane distributions
870 39856 : IF (ANY(my_rs_dims <= 0)) THEN
871 66390 : IF (ALL(my_rs_dims <= 0)) THEN
872 22114 : my_rs_dims = [0, 0]
873 : ELSE
874 24 : IF (my_rs_dims(1) > 0) THEN
875 0 : my_rs_dims(2) = np/my_rs_dims(1)
876 : ELSE
877 24 : my_rs_dims(1) = np/my_rs_dims(2)
878 : END IF
879 : END IF
880 : END IF
881 : ! reset if the distribution can not be fulfilled
882 84132 : IF (PRODUCT(my_rs_dims) .NE. np) my_rs_dims = [0, 0]
883 : ! reset if the distribution can not be dealt with [1,np]
884 28092 : IF (ALL(my_rs_dims == [1, np])) my_rs_dims = [0, 0]
885 :
886 : ! if [0,0] now, we can optimize it ourselves
887 72328 : IF (ALL(my_rs_dims == [0, 0])) THEN
888 : ! only small grids have a chance to be 2d distributed
889 22142 : IF (nx < np) THEN
890 : ! gives the most square looking distribution
891 0 : CALL mp_dims_create(np, my_rs_dims)
892 : ! we tend to like the first index being smaller than the second
893 0 : IF (my_rs_dims(1) > my_rs_dims(2)) THEN
894 0 : itmp = my_rs_dims(1)
895 0 : my_rs_dims(1) = my_rs_dims(2)
896 0 : my_rs_dims(2) = itmp
897 : END IF
898 : ! but should avoid having the first index 1 in all cases
899 0 : IF (my_rs_dims(1) == 1) THEN
900 0 : itmp = my_rs_dims(1)
901 0 : my_rs_dims(1) = my_rs_dims(2)
902 0 : my_rs_dims(2) = itmp
903 : END IF
904 : ELSE
905 66426 : my_rs_dims = [np, 1]
906 : END IF
907 : END IF
908 :
909 : ! now fix the blocking if we have a choice
910 : SELECT CASE (blocked_local)
911 : CASE (do_pw_grid_blocked_false)
912 28 : blocking = .FALSE.
913 : CASE (do_pw_grid_blocked_true)
914 28 : blocking = .TRUE.
915 : CASE (do_pw_grid_blocked_free)
916 26526 : IF (ALL(my_rs_dims == [np, 1])) THEN
917 : blocking = .FALSE.
918 : ELSE
919 0 : blocking = .TRUE.
920 : END IF
921 : CASE DEFAULT
922 28044 : CPABORT("")
923 : END SELECT
924 :
925 : !..create group for real space distribution
926 28044 : CALL pw_grid%para%group%create(mp_comm, 2, my_rs_dims)
927 :
928 28044 : IF (PRESENT(bounds_local)) THEN
929 220 : pw_grid%bounds_local = bounds_local
930 : ELSE
931 : lo = get_limit(nx, pw_grid%para%group%num_pe_cart(1), &
932 28022 : pw_grid%para%group%mepos_cart(1))
933 84066 : pw_grid%bounds_local(:, 1) = lo + pw_grid%bounds(1, 1) - 1
934 : lo = get_limit(ny, pw_grid%para%group%num_pe_cart(2), &
935 28022 : pw_grid%para%group%mepos_cart(2))
936 84066 : pw_grid%bounds_local(:, 2) = lo + pw_grid%bounds(1, 2) - 1
937 84066 : pw_grid%bounds_local(:, 3) = pw_grid%bounds(:, 3)
938 : END IF
939 :
940 : pw_grid%npts_local(:) = pw_grid%bounds_local(2, :) &
941 112176 : - pw_grid%bounds_local(1, :) + 1
942 :
943 : !..the third distribution is needed for the second step in the FFT
944 112176 : ALLOCATE (pw_grid%para%bo(2, 3, 0:np - 1, 3))
945 84132 : rsd = pw_grid%para%group%num_pe_cart
946 :
947 28044 : IF (PRESENT(bounds_local)) THEN
948 : ! axis_dist tells what portion of 1 .. nx , 1 .. ny , 1 .. nz are in the current process
949 88 : DO i = 1, 3
950 220 : axis_dist(:, i) = bounds_local(:, i) - pw_grid%bounds(1, i) + 1
951 : END DO
952 66 : ALLOCATE (axis_dist_all(2, 3, np))
953 22 : CALL pw_grid%para%group%allgather(axis_dist, axis_dist_all)
954 66 : DO ip = 0, np - 1
955 44 : CALL pw_grid%para%group%coords(ip, coor)
956 : ! distribution xyZ
957 132 : pw_grid%para%bo(1:2, 1, ip, 1) = axis_dist_all(1:2, 1, ip + 1)
958 132 : pw_grid%para%bo(1:2, 2, ip, 1) = axis_dist_all(1:2, 2, ip + 1)
959 44 : pw_grid%para%bo(1, 3, ip, 1) = 1
960 44 : pw_grid%para%bo(2, 3, ip, 1) = nz
961 : ! distribution xYz
962 132 : pw_grid%para%bo(1:2, 1, ip, 2) = axis_dist_all(1:2, 1, ip + 1)
963 44 : pw_grid%para%bo(1, 2, ip, 2) = 1
964 44 : pw_grid%para%bo(2, 2, ip, 2) = ny
965 132 : pw_grid%para%bo(1:2, 3, ip, 2) = get_limit(nz, rsd(2), coor(2))
966 : ! distribution Xyz
967 44 : pw_grid%para%bo(1, 1, ip, 3) = 1
968 44 : pw_grid%para%bo(2, 1, ip, 3) = nx
969 132 : pw_grid%para%bo(1:2, 2, ip, 3) = get_limit(ny, rsd(1), coor(1))
970 154 : pw_grid%para%bo(1:2, 3, ip, 3) = get_limit(nz, rsd(2), coor(2))
971 : END DO
972 22 : DEALLOCATE (axis_dist_all)
973 : ELSE
974 84066 : DO ip = 0, np - 1
975 56044 : CALL pw_grid%para%group%coords(ip, coor)
976 : ! distribution xyZ
977 168132 : pw_grid%para%bo(1:2, 1, ip, 1) = get_limit(nx, rsd(1), coor(1))
978 168132 : pw_grid%para%bo(1:2, 2, ip, 1) = get_limit(ny, rsd(2), coor(2))
979 56044 : pw_grid%para%bo(1, 3, ip, 1) = 1
980 56044 : pw_grid%para%bo(2, 3, ip, 1) = nz
981 : ! distribution xYz
982 168132 : pw_grid%para%bo(1:2, 1, ip, 2) = get_limit(nx, rsd(1), coor(1))
983 56044 : pw_grid%para%bo(1, 2, ip, 2) = 1
984 56044 : pw_grid%para%bo(2, 2, ip, 2) = ny
985 168132 : pw_grid%para%bo(1:2, 3, ip, 2) = get_limit(nz, rsd(2), coor(2))
986 : ! distribution Xyz
987 56044 : pw_grid%para%bo(1, 1, ip, 3) = 1
988 56044 : pw_grid%para%bo(2, 1, ip, 3) = nx
989 168132 : pw_grid%para%bo(1:2, 2, ip, 3) = get_limit(ny, rsd(1), coor(1))
990 196154 : pw_grid%para%bo(1:2, 3, ip, 3) = get_limit(nz, rsd(2), coor(2))
991 : END DO
992 : END IF
993 : !..find the g space distribution
994 28044 : pw_grid%ngpts_cut_local = 0
995 :
996 84132 : ALLOCATE (pw_grid%para%nyzray(0:np - 1))
997 :
998 112176 : ALLOCATE (pw_grid%para%yzq(ny, nz))
999 :
1000 : IF (pw_grid%spherical .OR. pw_grid%grid_span == HALFSPACE &
1001 28044 : .OR. .NOT. blocking) THEN
1002 :
1003 28032 : pw_grid%para%ray_distribution = .TRUE.
1004 :
1005 31147498 : pw_grid%para%yzq = -1
1006 28032 : IF (PRESENT(ref_grid)) THEN
1007 : ! tag all vectors from the reference grid
1008 17948 : CALL pre_tag(pw_grid, yz_mask, ref_grid)
1009 : END IF
1010 :
1011 : ! Round Robin distribution
1012 : ! Processors 0 .. NP-1, NP-1 .. 0 get the largest remaining batch
1013 : ! of g vectors in turn
1014 :
1015 28032 : i1 = SIZE(yz_mask, 1)
1016 28032 : i2 = SIZE(yz_mask, 2)
1017 84096 : ALLOCATE (yz_index(2, i1*i2))
1018 28032 : CALL order_mask(yz_mask, yz_index)
1019 30398592 : DO i = 1, i1*i2
1020 30370560 : lo(1) = yz_index(1, i)
1021 30370560 : lo(2) = yz_index(2, i)
1022 30370560 : IF (lo(1)*lo(2) == 0) CYCLE
1023 18682542 : gmax = yz_mask(lo(1), lo(2))
1024 18682542 : IF (gmax == 0) CYCLE
1025 18682542 : yz_mask(lo(1), lo(2)) = 0
1026 18682542 : ip = MOD(i - 1, 2*np)
1027 18682542 : IF (ip > np - 1) ip = 2*np - ip - 1
1028 18682542 : IF (ip == pw_grid%para%group%mepos) THEN
1029 9341271 : pw_grid%ngpts_cut_local = pw_grid%ngpts_cut_local + gmax
1030 : END IF
1031 18682542 : pw_grid%para%yzq(lo(1), lo(2)) = ip
1032 18710574 : IF (pw_grid%grid_span == HALFSPACE) THEN
1033 1227096 : m = -lo(1) - 2*lby + 2
1034 1227096 : n = -lo(2) - 2*lbz + 2
1035 1227096 : pw_grid%para%yzq(m, n) = ip
1036 1227096 : yz_mask(m, n) = 0
1037 : END IF
1038 : END DO
1039 :
1040 28032 : DEALLOCATE (yz_index)
1041 :
1042 : ! Count the total number of rays on each processor
1043 84096 : pw_grid%para%nyzray = 0
1044 776938 : DO i = 1, nz
1045 31147498 : DO j = 1, ny
1046 30370560 : ip = pw_grid%para%yzq(j, i)
1047 30370560 : IF (ip >= 0) pw_grid%para%nyzray(ip) = &
1048 29917018 : pw_grid%para%nyzray(ip) + 1
1049 : END DO
1050 : END DO
1051 :
1052 : ! Allocate mapping array (y:z, nray, nproc)
1053 84096 : ns = MAXVAL(pw_grid%para%nyzray(0:np - 1))
1054 112128 : ALLOCATE (pw_grid%para%yzp(2, ns, 0:np - 1))
1055 :
1056 : ! Fill mapping array, recalculate nyzray for convenience
1057 84096 : pw_grid%para%nyzray = 0
1058 776938 : DO i = 1, nz
1059 31147498 : DO j = 1, ny
1060 30370560 : ip = pw_grid%para%yzq(j, i)
1061 31119466 : IF (ip >= 0) THEN
1062 : pw_grid%para%nyzray(ip) = &
1063 29168112 : pw_grid%para%nyzray(ip) + 1
1064 29168112 : ns = pw_grid%para%nyzray(ip)
1065 29168112 : pw_grid%para%yzp(1, ns, ip) = j
1066 29168112 : pw_grid%para%yzp(2, ns, ip) = i
1067 29168112 : IF (ip == pw_grid%para%group%mepos) THEN
1068 14584056 : pw_grid%para%yzq(j, i) = ns
1069 : ELSE
1070 14584056 : pw_grid%para%yzq(j, i) = -1
1071 : END IF
1072 : ELSE
1073 1202448 : pw_grid%para%yzq(j, i) = -2
1074 : END IF
1075 : END DO
1076 : END DO
1077 :
1078 112128 : pw_grid%ngpts_local = PRODUCT(pw_grid%npts_local)
1079 :
1080 : ELSE
1081 : !
1082 : ! block distribution of g vectors, we do not have a spherical cutoff
1083 : !
1084 :
1085 12 : pw_grid%para%blocked = .TRUE.
1086 12 : pw_grid%para%ray_distribution = .FALSE.
1087 :
1088 36 : DO ip = 0, np - 1
1089 : m = pw_grid%para%bo(2, 2, ip, 3) - &
1090 24 : pw_grid%para%bo(1, 2, ip, 3) + 1
1091 : n = pw_grid%para%bo(2, 3, ip, 3) - &
1092 24 : pw_grid%para%bo(1, 3, ip, 3) + 1
1093 36 : pw_grid%para%nyzray(ip) = n*m
1094 : END DO
1095 :
1096 12 : ipl = pw_grid%para%group%mepos
1097 : l = pw_grid%para%bo(2, 1, ipl, 3) - &
1098 12 : pw_grid%para%bo(1, 1, ipl, 3) + 1
1099 : m = pw_grid%para%bo(2, 2, ipl, 3) - &
1100 12 : pw_grid%para%bo(1, 2, ipl, 3) + 1
1101 : n = pw_grid%para%bo(2, 3, ipl, 3) - &
1102 12 : pw_grid%para%bo(1, 3, ipl, 3) + 1
1103 12 : pw_grid%ngpts_cut_local = l*m*n
1104 12 : pw_grid%ngpts_local = pw_grid%ngpts_cut_local
1105 :
1106 4816 : pw_grid%para%yzq = 0
1107 : ny = pw_grid%para%bo(2, 2, ipl, 3) - &
1108 12 : pw_grid%para%bo(1, 2, ipl, 3) + 1
1109 254 : DO n = pw_grid%para%bo(1, 3, ipl, 3), &
1110 12 : pw_grid%para%bo(2, 3, ipl, 3)
1111 242 : i = n - pw_grid%para%bo(1, 3, ipl, 3)
1112 2523 : DO m = pw_grid%para%bo(1, 2, ipl, 3), &
1113 254 : pw_grid%para%bo(2, 2, ipl, 3)
1114 2281 : j = m - pw_grid%para%bo(1, 2, ipl, 3) + 1
1115 2523 : pw_grid%para%yzq(m, n) = j + i*ny
1116 : END DO
1117 : END DO
1118 :
1119 : ! Allocate mapping array (y:z, nray, nproc)
1120 36 : ns = MAXVAL(pw_grid%para%nyzray(0:np - 1))
1121 48 : ALLOCATE (pw_grid%para%yzp(2, ns, 0:np - 1))
1122 14112 : pw_grid%para%yzp = 0
1123 :
1124 36 : ALLOCATE (pemap(0:np - 1))
1125 36 : pemap = 0
1126 12 : pemap(pw_grid%para%group%mepos) = pw_grid%para%group%mepos
1127 12 : CALL pw_grid%para%group%sum(pemap)
1128 :
1129 36 : DO ip = 0, np - 1
1130 24 : ipp = pemap(ip)
1131 24 : ns = 0
1132 508 : DO n = pw_grid%para%bo(1, 3, ipp, 3), &
1133 24 : pw_grid%para%bo(2, 3, ipp, 3)
1134 484 : i = n - pw_grid%bounds(1, 3) + 1
1135 5046 : DO m = pw_grid%para%bo(1, 2, ipp, 3), &
1136 508 : pw_grid%para%bo(2, 2, ipp, 3)
1137 4562 : j = m - pw_grid%bounds(1, 2) + 1
1138 4562 : ns = ns + 1
1139 4562 : pw_grid%para%yzp(1, ns, ip) = j
1140 5046 : pw_grid%para%yzp(2, ns, ip) = i
1141 : END DO
1142 : END DO
1143 36 : CPASSERT(ns == pw_grid%para%nyzray(ip))
1144 : END DO
1145 :
1146 12 : DEALLOCATE (pemap)
1147 :
1148 : END IF
1149 :
1150 : END IF
1151 :
1152 : ! pos_of_x(i) tells on which cpu pw%array(i,:,:) is located
1153 : ! should be computable in principle, without the need for communication
1154 33147 : IF (pw_grid%para%mode .EQ. PW_MODE_DISTRIBUTED) THEN
1155 84132 : ALLOCATE (pw_grid%para%pos_of_x(pw_grid%bounds(1, 1):pw_grid%bounds(2, 1)))
1156 768604 : pw_grid%para%pos_of_x = 0
1157 398324 : pw_grid%para%pos_of_x(pw_grid%bounds_local(1, 1):pw_grid%bounds_local(2, 1)) = pw_grid%para%group%mepos
1158 28044 : CALL pw_grid%para%group%sum(pw_grid%para%pos_of_x)
1159 : ELSE
1160 : ! this should not be needed
1161 15309 : ALLOCATE (pw_grid%para%pos_of_x(pw_grid%bounds(1, 1):pw_grid%bounds(2, 1)))
1162 86334 : pw_grid%para%pos_of_x = 0
1163 : END IF
1164 :
1165 33147 : CALL timestop(handle)
1166 :
1167 33147 : END SUBROUTINE pw_grid_distribute
1168 :
1169 : ! **************************************************************************************************
1170 : !> \brief ...
1171 : !> \param pw_grid ...
1172 : !> \param yz_mask ...
1173 : !> \param ref_grid ...
1174 : !> \par History
1175 : !> - Fix mapping bug for pw_grid eqv to ref_grid (21.11.2019, MK)
1176 : ! **************************************************************************************************
1177 17948 : SUBROUTINE pre_tag(pw_grid, yz_mask, ref_grid)
1178 :
1179 : TYPE(pw_grid_type), INTENT(INOUT) :: pw_grid
1180 : INTEGER, DIMENSION(:, :), INTENT(INOUT) :: yz_mask
1181 : TYPE(pw_grid_type), INTENT(IN) :: ref_grid
1182 :
1183 : INTEGER :: gmax, ig, ip, lby, lbz, my, mz, ny, nz, &
1184 : uby, ubz, y, yp, z, zp
1185 :
1186 17948 : ny = ref_grid%npts(2)
1187 17948 : nz = ref_grid%npts(3)
1188 17948 : lby = pw_grid%bounds(1, 2)
1189 17948 : lbz = pw_grid%bounds(1, 3)
1190 17948 : uby = pw_grid%bounds(2, 2)
1191 17948 : ubz = pw_grid%bounds(2, 3)
1192 17948 : my = SIZE(yz_mask, 1)
1193 17948 : mz = SIZE(yz_mask, 2)
1194 :
1195 : ! loop over all processors and all g vectors yz lines on this processor
1196 53844 : DO ip = 0, ref_grid%para%group%num_pe - 1
1197 47476162 : DO ig = 1, ref_grid%para%nyzray(ip)
1198 : ! go from mapped coordinates to original coordinates
1199 : ! 1, 2, ..., n-1, n -> 0, 1, ..., (n/2)-1, -(n/2), -(n/2)+1, ..., -2, -1
1200 47422318 : y = ref_grid%para%yzp(1, ig, ip) - 1
1201 47422318 : IF (y >= ny/2) y = y - ny
1202 47422318 : z = ref_grid%para%yzp(2, ig, ip) - 1
1203 47422318 : IF (z >= nz/2) z = z - nz
1204 : ! check if this is inside the realm of the new grid
1205 47422318 : IF (y < lby .OR. y > uby .OR. z < lbz .OR. z > ubz) CYCLE
1206 : ! go to shifted coordinates
1207 9260734 : y = y - lby + 1
1208 9260734 : z = z - lbz + 1
1209 : ! this tag is outside the cutoff range of the new grid
1210 9260734 : IF (pw_grid%grid_span == HALFSPACE) THEN
1211 0 : yp = -y - 2*lby + 2
1212 0 : zp = -z - 2*lbz + 2
1213 : ! if the reference grid is larger than the mirror point may be
1214 : ! outside the new grid even if the original point is inside
1215 0 : IF (yp < 1 .OR. yp > my .OR. zp < 1 .OR. zp > mz) CYCLE
1216 0 : gmax = MAX(yz_mask(y, z), yz_mask(yp, zp))
1217 0 : IF (gmax == 0) CYCLE
1218 0 : yz_mask(y, z) = 0
1219 0 : yz_mask(yp, zp) = 0
1220 0 : pw_grid%para%yzq(y, z) = ip
1221 0 : pw_grid%para%yzq(yp, zp) = ip
1222 : ELSE
1223 9260734 : gmax = yz_mask(y, z)
1224 9260734 : IF (gmax == 0) CYCLE
1225 9260734 : yz_mask(y, z) = 0
1226 9260734 : pw_grid%para%yzq(y, z) = ip
1227 : END IF
1228 9296630 : IF (ip == pw_grid%para%group%mepos) THEN
1229 4630367 : pw_grid%ngpts_cut_local = pw_grid%ngpts_cut_local + gmax
1230 : END IF
1231 : END DO
1232 : END DO
1233 :
1234 17948 : END SUBROUTINE pre_tag
1235 :
1236 : ! **************************************************************************************************
1237 : !> \brief ...
1238 : !> \param yz_mask ...
1239 : !> \param yz_index ...
1240 : ! **************************************************************************************************
1241 28032 : PURE SUBROUTINE order_mask(yz_mask, yz_index)
1242 :
1243 : INTEGER, DIMENSION(:, :), INTENT(IN) :: yz_mask
1244 : INTEGER, DIMENSION(:, :), INTENT(OUT) :: yz_index
1245 :
1246 : INTEGER :: i1, i2, ic, icount, ii, im, jc, jj
1247 :
1248 : !NB load balance
1249 : !------------------------------------------------------------------------------
1250 : !NB spiral out from origin, so that even if overall grid is full and
1251 : !NB block distributed, spherical cutoff still leads to good load
1252 : !NB balance in cp_ddapc_apply_CD
1253 :
1254 28032 : i1 = SIZE(yz_mask, 1)
1255 28032 : i2 = SIZE(yz_mask, 2)
1256 91139712 : yz_index = 0
1257 :
1258 28032 : icount = 1
1259 28032 : ic = i1/2
1260 28032 : jc = i2/2
1261 28032 : ii = ic
1262 28032 : jj = jc
1263 28032 : IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2) THEN
1264 28032 : IF (yz_mask(ii, jj) /= 0) THEN
1265 10084 : yz_index(1, icount) = ii
1266 10084 : yz_index(2, icount) = jj
1267 10084 : icount = icount + 1
1268 : END IF
1269 : END IF
1270 428462 : DO im = 1, MAX(ic + 1, jc + 1)
1271 400430 : ii = ic - im
1272 10362956 : DO jj = jc - im, jc + im
1273 10362956 : IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2) THEN
1274 7297796 : IF (yz_mask(ii, jj) /= 0) THEN
1275 4549730 : yz_index(1, icount) = ii
1276 4549730 : yz_index(2, icount) = jj
1277 4549730 : icount = icount + 1
1278 : END IF
1279 : END IF
1280 : END DO
1281 400430 : ii = ic + im
1282 10362956 : DO jj = jc - im, jc + im
1283 10362956 : IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2) THEN
1284 8231796 : IF (yz_mask(ii, jj) /= 0) THEN
1285 4946532 : yz_index(1, icount) = ii
1286 4946532 : yz_index(2, icount) = jj
1287 4946532 : icount = icount + 1
1288 : END IF
1289 : END IF
1290 : END DO
1291 400430 : jj = jc - im
1292 9562096 : DO ii = ic - im + 1, ic + im - 1
1293 9562096 : IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2) THEN
1294 6958780 : IF (yz_mask(ii, jj) /= 0) THEN
1295 4675098 : yz_index(1, icount) = ii
1296 4675098 : yz_index(2, icount) = jj
1297 4675098 : icount = icount + 1
1298 : END IF
1299 : END IF
1300 : END DO
1301 9562096 : jj = jc + im
1302 9590128 : DO ii = ic - im + 1, ic + im - 1
1303 9562096 : IF (ii > 0 .AND. ii <= i1 .AND. jj > 0 .AND. jj <= i2) THEN
1304 7854156 : IF (yz_mask(ii, jj) /= 0) THEN
1305 4501098 : yz_index(1, icount) = ii
1306 4501098 : yz_index(2, icount) = jj
1307 4501098 : icount = icount + 1
1308 : END IF
1309 : END IF
1310 : END DO
1311 : END DO
1312 :
1313 28032 : END SUBROUTINE order_mask
1314 : ! **************************************************************************************************
1315 : !> \brief compute the length of g vectors
1316 : !> \param h_inv ...
1317 : !> \param length_x ...
1318 : !> \param length_y ...
1319 : !> \param length_z ...
1320 : !> \param length ...
1321 : !> \param l ...
1322 : !> \param m ...
1323 : !> \param n ...
1324 : ! **************************************************************************************************
1325 1688121342 : PURE SUBROUTINE pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1326 :
1327 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN) :: h_inv
1328 : REAL(KIND=dp), INTENT(OUT) :: length_x, length_y, length_z, length
1329 : INTEGER, INTENT(IN) :: l, m, n
1330 :
1331 : length_x &
1332 : = REAL(l, dp)*h_inv(1, 1) &
1333 : + REAL(m, dp)*h_inv(2, 1) &
1334 1688121342 : + REAL(n, dp)*h_inv(3, 1)
1335 : length_y &
1336 : = REAL(l, dp)*h_inv(1, 2) &
1337 : + REAL(m, dp)*h_inv(2, 2) &
1338 1688121342 : + REAL(n, dp)*h_inv(3, 2)
1339 : length_z &
1340 : = REAL(l, dp)*h_inv(1, 3) &
1341 : + REAL(m, dp)*h_inv(2, 3) &
1342 1688121342 : + REAL(n, dp)*h_inv(3, 3)
1343 :
1344 : ! enforce strict zero-ness in this case (compiler optimization)
1345 1688121342 : IF (l == 0 .AND. m == 0 .AND. n == 0) THEN
1346 38250 : length_x = 0
1347 38250 : length_y = 0
1348 38250 : length_z = 0
1349 : END IF
1350 :
1351 1688121342 : length_x = length_x*twopi
1352 1688121342 : length_y = length_y*twopi
1353 1688121342 : length_z = length_z*twopi
1354 :
1355 1688121342 : length = length_x**2 + length_y**2 + length_z**2
1356 :
1357 1688121342 : END SUBROUTINE
1358 :
1359 : ! **************************************************************************************************
1360 : !> \brief Count total number of g vectors
1361 : !> \param h_inv ...
1362 : !> \param pw_grid ...
1363 : !> \param mp_comm ...
1364 : !> \param cutoff ...
1365 : !> \param yz_mask ...
1366 : !> \par History
1367 : !> JGH (22-12-2000) : Adapted for parallel use
1368 : !> \author apsi
1369 : !> Christopher Mundy
1370 : ! **************************************************************************************************
1371 33147 : SUBROUTINE pw_grid_count(h_inv, pw_grid, mp_comm, cutoff, yz_mask)
1372 :
1373 : REAL(KIND=dp), DIMENSION(3, 3) :: h_inv
1374 : TYPE(pw_grid_type), INTENT(INOUT) :: pw_grid
1375 :
1376 : CLASS(mp_comm_type), INTENT(IN) :: mp_comm
1377 : REAL(KIND=dp), INTENT(IN) :: cutoff
1378 : INTEGER, DIMENSION(:, :), INTENT(OUT) :: yz_mask
1379 :
1380 : INTEGER :: l, m, mm, n, n_upperlimit, nlim(2), nn
1381 : INTEGER(KIND=int_8) :: gpt
1382 : REAL(KIND=dp) :: length, length_x, length_y, length_z
1383 :
1384 : ASSOCIATE (bounds => pw_grid%bounds)
1385 :
1386 33147 : IF (pw_grid%grid_span == HALFSPACE) THEN
1387 : n_upperlimit = 0
1388 29736 : ELSE IF (pw_grid%grid_span == FULLSPACE) THEN
1389 29736 : n_upperlimit = bounds(2, 3)
1390 : ELSE
1391 0 : CPABORT("No type set for the grid")
1392 : END IF
1393 :
1394 : ! finds valid g-points within grid
1395 33147 : gpt = 0
1396 33147 : IF (pw_grid%para%mode == PW_MODE_LOCAL) THEN
1397 5103 : nlim(1) = bounds(1, 3)
1398 5103 : nlim(2) = n_upperlimit
1399 28044 : ELSE IF (pw_grid%para%mode == PW_MODE_DISTRIBUTED) THEN
1400 28044 : n = n_upperlimit - bounds(1, 3) + 1
1401 28044 : nlim = get_limit(n, mp_comm%num_pe, mp_comm%mepos)
1402 84132 : nlim = nlim + bounds(1, 3) - 1
1403 : ELSE
1404 0 : CPABORT("para % mode not specified")
1405 : END IF
1406 :
1407 33435067 : yz_mask = 0
1408 486051 : DO n = nlim(1), nlim(2)
1409 419757 : nn = n - bounds(1, 3) + 1
1410 16267353 : DO m = bounds(1, 2), bounds(2, 2)
1411 15814449 : mm = m - bounds(1, 2) + 1
1412 869476559 : DO l = bounds(1, 1), bounds(2, 1)
1413 853242353 : IF (pw_grid%grid_span == HALFSPACE .AND. n == 0) THEN
1414 2965529 : IF ((m == 0 .AND. l > 0) .OR. (m > 0)) CYCLE
1415 : END IF
1416 :
1417 851649296 : CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1418 :
1419 867463745 : IF (0.5_dp*length <= cutoff) THEN
1420 811001030 : gpt = gpt + 1
1421 811001030 : yz_mask(mm, nn) = yz_mask(mm, nn) + 1
1422 : END IF
1423 :
1424 : END DO
1425 : END DO
1426 : END DO
1427 : END ASSOCIATE
1428 :
1429 : ! number of g-vectors for grid
1430 33147 : IF (pw_grid%para%mode == PW_MODE_DISTRIBUTED) THEN
1431 28044 : CALL mp_comm%sum(gpt)
1432 62276584 : CALL mp_comm%sum(yz_mask)
1433 : END IF
1434 33147 : pw_grid%ngpts_cut = gpt
1435 :
1436 33147 : END SUBROUTINE pw_grid_count
1437 :
1438 : ! **************************************************************************************************
1439 : !> \brief Setup maps from 1d to 3d space
1440 : !> \param h_inv ...
1441 : !> \param pw_grid ...
1442 : !> \param cutoff ...
1443 : !> \par History
1444 : !> JGH (29-12-2000) : Adapted for parallel use
1445 : !> \author apsi
1446 : !> Christopher Mundy
1447 : ! **************************************************************************************************
1448 33147 : SUBROUTINE pw_grid_assign(h_inv, pw_grid, cutoff)
1449 :
1450 : REAL(KIND=dp), DIMENSION(3, 3) :: h_inv
1451 : TYPE(pw_grid_type), INTENT(INOUT) :: pw_grid
1452 : REAL(KIND=dp), INTENT(IN) :: cutoff
1453 :
1454 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_grid_assign'
1455 :
1456 : INTEGER :: gpt, handle, i, ip, l, lby, lbz, ll, m, &
1457 : mm, n, n_upperlimit, nn
1458 : INTEGER(KIND=int_8) :: gpt_global
1459 : INTEGER, DIMENSION(2, 3) :: bol, bounds
1460 : REAL(KIND=dp) :: length, length_x, length_y, length_z
1461 :
1462 33147 : CALL timeset(routineN, handle)
1463 :
1464 331470 : bounds = pw_grid%bounds
1465 33147 : lby = pw_grid%bounds(1, 2)
1466 33147 : lbz = pw_grid%bounds(1, 3)
1467 :
1468 33147 : IF (pw_grid%grid_span == HALFSPACE) THEN
1469 : n_upperlimit = 0
1470 29736 : ELSE IF (pw_grid%grid_span == FULLSPACE) THEN
1471 29736 : n_upperlimit = bounds(2, 3)
1472 : ELSE
1473 0 : CPABORT("No type set for the grid")
1474 : END IF
1475 :
1476 : ! finds valid g-points within grid
1477 33147 : IF (pw_grid%para%mode == PW_MODE_LOCAL) THEN
1478 5103 : gpt = 0
1479 70085 : DO n = bounds(1, 3), n_upperlimit
1480 1579939 : DO m = bounds(1, 2), bounds(2, 2)
1481 59220684 : DO l = bounds(1, 1), bounds(2, 1)
1482 57645848 : IF (pw_grid%grid_span == HALFSPACE .AND. n == 0) THEN
1483 1157021 : IF ((m == 0 .AND. l > 0) .OR. (m > 0)) CYCLE
1484 : END IF
1485 :
1486 56946134 : CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1487 :
1488 58455988 : IF (0.5_dp*length <= cutoff) THEN
1489 43347699 : gpt = gpt + 1
1490 43347699 : pw_grid%g(1, gpt) = length_x
1491 43347699 : pw_grid%g(2, gpt) = length_y
1492 43347699 : pw_grid%g(3, gpt) = length_z
1493 43347699 : pw_grid%gsq(gpt) = length
1494 43347699 : pw_grid%g_hat(1, gpt) = l
1495 43347699 : pw_grid%g_hat(2, gpt) = m
1496 43347699 : pw_grid%g_hat(3, gpt) = n
1497 : END IF
1498 :
1499 : END DO
1500 : END DO
1501 : END DO
1502 :
1503 : ELSE
1504 :
1505 28044 : IF (pw_grid%para%ray_distribution) THEN
1506 :
1507 28032 : gpt = 0
1508 28032 : ip = pw_grid%para%group%mepos
1509 14612088 : DO i = 1, pw_grid%para%nyzray(ip)
1510 14584056 : n = pw_grid%para%yzp(2, i, ip) + lbz - 1
1511 14584056 : m = pw_grid%para%yzp(1, i, ip) + lby - 1
1512 14584056 : IF (n > n_upperlimit) CYCLE
1513 794314035 : DO l = bounds(1, 1), bounds(2, 1)
1514 780296779 : IF (pw_grid%grid_span == HALFSPACE .AND. n == 0) THEN
1515 1629336 : IF ((m == 0 .AND. l > 0) .OR. (m > 0)) CYCLE
1516 : END IF
1517 :
1518 779482991 : CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1519 :
1520 794067047 : IF (0.5_dp*length <= cutoff) THEN
1521 767610410 : gpt = gpt + 1
1522 767610410 : pw_grid%g(1, gpt) = length_x
1523 767610410 : pw_grid%g(2, gpt) = length_y
1524 767610410 : pw_grid%g(3, gpt) = length_z
1525 767610410 : pw_grid%gsq(gpt) = length
1526 767610410 : pw_grid%g_hat(1, gpt) = l
1527 767610410 : pw_grid%g_hat(2, gpt) = m
1528 767610410 : pw_grid%g_hat(3, gpt) = n
1529 : END IF
1530 :
1531 : END DO
1532 : END DO
1533 :
1534 : ELSE
1535 :
1536 120 : bol = pw_grid%para%bo(:, :, pw_grid%para%group%mepos, 3)
1537 12 : gpt = 0
1538 254 : DO n = bounds(1, 3), bounds(2, 3)
1539 242 : IF (n < 0) THEN
1540 120 : nn = n + pw_grid%npts(3) + 1
1541 : ELSE
1542 122 : nn = n + 1
1543 : END IF
1544 242 : IF (nn < bol(1, 3) .OR. nn > bol(2, 3)) CYCLE
1545 4816 : DO m = bounds(1, 2), bounds(2, 2)
1546 4562 : IF (m < 0) THEN
1547 2216 : mm = m + pw_grid%npts(2) + 1
1548 : ELSE
1549 2346 : mm = m + 1
1550 : END IF
1551 4562 : IF (mm < bol(1, 2) .OR. mm > bol(2, 2)) CYCLE
1552 45444 : DO l = bounds(1, 1), bounds(2, 1)
1553 42921 : IF (l < 0) THEN
1554 21148 : ll = l + pw_grid%npts(1) + 1
1555 : ELSE
1556 21773 : ll = l + 1
1557 : END IF
1558 42921 : IF (ll < bol(1, 1) .OR. ll > bol(2, 1)) CYCLE
1559 :
1560 42921 : CALL pw_vec_length(h_inv, length_x, length_y, length_z, length, l, m, n)
1561 :
1562 42921 : gpt = gpt + 1
1563 42921 : pw_grid%g(1, gpt) = length_x
1564 42921 : pw_grid%g(2, gpt) = length_y
1565 42921 : pw_grid%g(3, gpt) = length_z
1566 42921 : pw_grid%gsq(gpt) = length
1567 42921 : pw_grid%g_hat(1, gpt) = l
1568 42921 : pw_grid%g_hat(2, gpt) = m
1569 47483 : pw_grid%g_hat(3, gpt) = n
1570 :
1571 : END DO
1572 : END DO
1573 : END DO
1574 :
1575 : END IF
1576 :
1577 : END IF
1578 :
1579 : ! Check the number of g-vectors for grid
1580 33147 : CPASSERT(pw_grid%ngpts_cut_local == gpt)
1581 33147 : IF (pw_grid%para%mode == PW_MODE_DISTRIBUTED) THEN
1582 28044 : gpt_global = gpt
1583 28044 : CALL pw_grid%para%group%sum(gpt_global)
1584 28044 : CPASSERT(pw_grid%ngpts_cut == gpt_global)
1585 : END IF
1586 :
1587 33147 : pw_grid%have_g0 = .FALSE.
1588 33147 : pw_grid%first_gne0 = 1
1589 611524609 : DO gpt = 1, pw_grid%ngpts_cut_local
1590 623427317 : IF (ALL(pw_grid%g_hat(:, gpt) == 0)) THEN
1591 19125 : pw_grid%have_g0 = .TRUE.
1592 19125 : pw_grid%first_gne0 = 2
1593 19125 : EXIT
1594 : END IF
1595 : END DO
1596 :
1597 : CALL pw_grid_set_maps(pw_grid%grid_span, pw_grid%g_hat, &
1598 33147 : pw_grid%mapl, pw_grid%mapm, pw_grid%mapn, pw_grid%npts)
1599 :
1600 33147 : CALL timestop(handle)
1601 :
1602 33147 : END SUBROUTINE pw_grid_assign
1603 :
1604 : ! **************************************************************************************************
1605 : !> \brief Setup maps from 1d to 3d space
1606 : !> \param grid_span ...
1607 : !> \param g_hat ...
1608 : !> \param mapl ...
1609 : !> \param mapm ...
1610 : !> \param mapn ...
1611 : !> \param npts ...
1612 : !> \par History
1613 : !> JGH (21-12-2000) : Size of g_hat locally determined
1614 : !> \author apsi
1615 : !> Christopher Mundy
1616 : !> \note
1617 : !> Maps are to full 3D space (not distributed)
1618 : ! **************************************************************************************************
1619 33147 : SUBROUTINE pw_grid_set_maps(grid_span, g_hat, mapl, mapm, mapn, npts)
1620 :
1621 : INTEGER, INTENT(IN) :: grid_span
1622 : INTEGER, DIMENSION(:, :), INTENT(IN) :: g_hat
1623 : TYPE(map_pn), INTENT(INOUT) :: mapl, mapm, mapn
1624 : INTEGER, DIMENSION(:), INTENT(IN) :: npts
1625 :
1626 : INTEGER :: gpt, l, m, n, ng
1627 :
1628 33147 : ng = SIZE(g_hat, 2)
1629 :
1630 811034177 : DO gpt = 1, ng
1631 811001030 : l = g_hat(1, gpt)
1632 811001030 : m = g_hat(2, gpt)
1633 811001030 : n = g_hat(3, gpt)
1634 811001030 : IF (l < 0) THEN
1635 403206492 : mapl%pos(l) = l + npts(1)
1636 : ELSE
1637 407794538 : mapl%pos(l) = l
1638 : END IF
1639 811001030 : IF (m < 0) THEN
1640 403628183 : mapm%pos(m) = m + npts(2)
1641 : ELSE
1642 407372847 : mapm%pos(m) = m
1643 : END IF
1644 811001030 : IF (n < 0) THEN
1645 419365092 : mapn%pos(n) = n + npts(3)
1646 : ELSE
1647 391635938 : mapn%pos(n) = n
1648 : END IF
1649 :
1650 : ! Generating the maps to the full 3-d space
1651 :
1652 811034177 : IF (grid_span == HALFSPACE) THEN
1653 :
1654 33226993 : IF (l <= 0) THEN
1655 17102585 : mapl%neg(l) = -l
1656 : ELSE
1657 16124408 : mapl%neg(l) = npts(1) - l
1658 : END IF
1659 33226993 : IF (m <= 0) THEN
1660 17538924 : mapm%neg(m) = -m
1661 : ELSE
1662 15688069 : mapm%neg(m) = npts(2) - m
1663 : END IF
1664 33226993 : IF (n <= 0) THEN
1665 33226993 : mapn%neg(n) = -n
1666 : ELSE
1667 0 : mapn%neg(n) = npts(3) - n
1668 : END IF
1669 :
1670 : END IF
1671 :
1672 : END DO
1673 :
1674 33147 : END SUBROUTINE pw_grid_set_maps
1675 :
1676 : ! **************************************************************************************************
1677 : !> \brief Allocate all (Pointer) Arrays in pw_grid
1678 : !> \param pw_grid ...
1679 : !> \param ng ...
1680 : !> \param bounds ...
1681 : !> \par History
1682 : !> JGH (20-12-2000) : Added status variable
1683 : !> Bounds of arrays now from calling routine, this
1684 : !> makes it independent from parallel setup
1685 : !> \author apsi
1686 : !> Christopher Mundy
1687 : ! **************************************************************************************************
1688 33147 : SUBROUTINE pw_grid_allocate(pw_grid, ng, bounds)
1689 :
1690 : ! Argument
1691 : TYPE(pw_grid_type), INTENT(INOUT) :: pw_grid
1692 : INTEGER, INTENT(IN) :: ng
1693 : INTEGER, DIMENSION(:, :), INTENT(IN) :: bounds
1694 :
1695 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_grid_allocate'
1696 :
1697 : INTEGER :: nmaps
1698 : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
1699 : INTEGER(KIND=C_SIZE_T) :: length
1700 : TYPE(C_PTR) :: cptr_g_hatmap
1701 : INTEGER :: stat
1702 : #endif
1703 :
1704 : INTEGER :: handle
1705 :
1706 33147 : CALL timeset(routineN, handle)
1707 :
1708 99441 : ALLOCATE (pw_grid%g(3, ng))
1709 99441 : ALLOCATE (pw_grid%gsq(ng))
1710 99441 : ALLOCATE (pw_grid%g_hat(3, ng))
1711 :
1712 : nmaps = 1
1713 33147 : IF (pw_grid%grid_span == HALFSPACE) nmaps = 2
1714 : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
1715 : CALL offload_activate_chosen_device()
1716 :
1717 : length = INT(int_size*MAX(ng, 1)*MAX(nmaps, 1), KIND=C_SIZE_T)
1718 : stat = offload_malloc_pinned_mem(cptr_g_hatmap, length)
1719 : CPASSERT(stat == 0)
1720 : CALL c_f_pointer(cptr_g_hatmap, pw_grid%g_hatmap, (/MAX(ng, 1), MAX(nmaps, 1)/))
1721 : #else
1722 33147 : ALLOCATE (pw_grid%g_hatmap(1, 1))
1723 : #endif
1724 :
1725 33147 : IF (pw_grid%para%mode == PW_MODE_DISTRIBUTED) THEN
1726 : ALLOCATE (pw_grid%grays(pw_grid%npts(1), &
1727 112176 : pw_grid%para%nyzray(pw_grid%para%group%mepos)))
1728 : END IF
1729 :
1730 99441 : ALLOCATE (pw_grid%mapl%pos(bounds(1, 1):bounds(2, 1)))
1731 99441 : ALLOCATE (pw_grid%mapl%neg(bounds(1, 1):bounds(2, 1)))
1732 99441 : ALLOCATE (pw_grid%mapm%pos(bounds(1, 2):bounds(2, 2)))
1733 99441 : ALLOCATE (pw_grid%mapm%neg(bounds(1, 2):bounds(2, 2)))
1734 99441 : ALLOCATE (pw_grid%mapn%pos(bounds(1, 3):bounds(2, 3)))
1735 99441 : ALLOCATE (pw_grid%mapn%neg(bounds(1, 3):bounds(2, 3)))
1736 :
1737 33147 : CALL timestop(handle)
1738 :
1739 33147 : END SUBROUTINE pw_grid_allocate
1740 :
1741 : ! **************************************************************************************************
1742 : !> \brief Sort g-vectors according to length
1743 : !> \param pw_grid ...
1744 : !> \param ref_grid ...
1745 : !> \par History
1746 : !> JGH (20-12-2000) : allocate idx, ng = SIZE ( pw_grid % gsq ) the
1747 : !> sorting is local and independent from parallelisation
1748 : !> WARNING: Global ordering depends now on the number
1749 : !> of cpus.
1750 : !> JGH (28-02-2001) : check for ordering against reference grid
1751 : !> JGH (01-05-2001) : sort spherical cutoff grids also within shells
1752 : !> reference grids for non-spherical cutoffs
1753 : !> JGH (20-06-2001) : do not sort non-spherical grids
1754 : !> JGH (19-02-2003) : Order all grids, this makes subgrids also for
1755 : !> non-spherical cutoffs possible
1756 : !> JGH (21-02-2003) : Introduce gather array for general reference grids
1757 : !> \author apsi
1758 : !> Christopher Mundy
1759 : ! **************************************************************************************************
1760 33147 : SUBROUTINE pw_grid_sort(pw_grid, ref_grid)
1761 :
1762 : ! Argument
1763 : TYPE(pw_grid_type), INTENT(INOUT) :: pw_grid
1764 : TYPE(pw_grid_type), INTENT(IN), OPTIONAL :: ref_grid
1765 :
1766 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_grid_sort'
1767 :
1768 : INTEGER :: handle, i, ig, ih, ip, is, it, ng, ngr
1769 : INTEGER, ALLOCATABLE, DIMENSION(:) :: idx
1770 33147 : INTEGER, ALLOCATABLE, DIMENSION(:, :) :: int_tmp
1771 : LOGICAL :: g_found
1772 : REAL(KIND=dp) :: gig, gigr
1773 33147 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: real_tmp
1774 :
1775 33147 : CALL timeset(routineN, handle)
1776 :
1777 33147 : ng = SIZE(pw_grid%gsq)
1778 99441 : ALLOCATE (idx(ng))
1779 :
1780 : ! grids are (locally) ordered by length of G-vectors
1781 33147 : CALL sort(pw_grid%gsq, ng, idx)
1782 : ! within shells order wrt x,y,z
1783 33147 : CALL sort_shells(pw_grid%gsq, pw_grid%g_hat, idx)
1784 :
1785 99441 : ALLOCATE (real_tmp(3, ng))
1786 811034177 : DO i = 1, ng
1787 811001030 : real_tmp(1, i) = pw_grid%g(1, idx(i))
1788 811001030 : real_tmp(2, i) = pw_grid%g(2, idx(i))
1789 811034177 : real_tmp(3, i) = pw_grid%g(3, idx(i))
1790 : END DO
1791 811034177 : DO i = 1, ng
1792 811001030 : pw_grid%g(1, i) = real_tmp(1, i)
1793 811001030 : pw_grid%g(2, i) = real_tmp(2, i)
1794 811034177 : pw_grid%g(3, i) = real_tmp(3, i)
1795 : END DO
1796 33147 : DEALLOCATE (real_tmp)
1797 :
1798 99441 : ALLOCATE (int_tmp(3, ng))
1799 811034177 : DO i = 1, ng
1800 811001030 : int_tmp(1, i) = pw_grid%g_hat(1, idx(i))
1801 811001030 : int_tmp(2, i) = pw_grid%g_hat(2, idx(i))
1802 811034177 : int_tmp(3, i) = pw_grid%g_hat(3, idx(i))
1803 : END DO
1804 811034177 : DO i = 1, ng
1805 811001030 : pw_grid%g_hat(1, i) = int_tmp(1, i)
1806 811001030 : pw_grid%g_hat(2, i) = int_tmp(2, i)
1807 811034177 : pw_grid%g_hat(3, i) = int_tmp(3, i)
1808 : END DO
1809 33147 : DEALLOCATE (int_tmp)
1810 :
1811 33147 : DEALLOCATE (idx)
1812 :
1813 : ! check if ordering is compatible to reference grid
1814 33147 : IF (PRESENT(ref_grid)) THEN
1815 20912 : ngr = SIZE(ref_grid%gsq)
1816 20912 : ngr = MIN(ng, ngr)
1817 20912 : IF (pw_grid%spherical) THEN
1818 0 : IF (.NOT. ALL(pw_grid%g_hat(1:3, 1:ngr) &
1819 : == ref_grid%g_hat(1:3, 1:ngr))) THEN
1820 0 : CPABORT("G space sorting not compatible")
1821 : END IF
1822 : ELSE
1823 62736 : ALLOCATE (pw_grid%gidx(1:ngr))
1824 176899881 : pw_grid%gidx = 0
1825 : ! first try as many trivial associations as possible
1826 20912 : it = 0
1827 94002427 : DO ig = 1, ngr
1828 375949780 : IF (.NOT. ALL(pw_grid%g_hat(1:3, ig) &
1829 : == ref_grid%g_hat(1:3, ig))) EXIT
1830 93981515 : pw_grid%gidx(ig) = ig
1831 94002427 : it = ig
1832 : END DO
1833 : ! now for the ones that could not be done
1834 20912 : IF (ng == ngr) THEN
1835 : ! for the case pw_grid <= ref_grid
1836 20912 : is = it
1837 82918366 : DO ig = it + 1, ngr
1838 82897454 : gig = pw_grid%gsq(ig)
1839 82897454 : gigr = MAX(1._dp, gig)
1840 82897454 : g_found = .FALSE.
1841 416340475 : DO ih = is + 1, SIZE(ref_grid%gsq)
1842 416340475 : IF (ABS(gig - ref_grid%gsq(ih))/gigr > 1.e-12_dp) CYCLE
1843 : g_found = .TRUE.
1844 333443021 : EXIT
1845 : END DO
1846 82897454 : IF (.NOT. g_found) THEN
1847 0 : WRITE (*, "(A,I10,F20.10)") "G-vector", ig, pw_grid%gsq(ig)
1848 0 : CPABORT("G vector not found")
1849 : END IF
1850 82897454 : ip = ih - 1
1851 5698733083 : DO ih = ip + 1, SIZE(ref_grid%gsq)
1852 5698733083 : IF (ABS(gig - ref_grid%gsq(ih))/gigr > 1.e-12_dp) CYCLE
1853 5698733083 : IF (pw_grid%g_hat(1, ig) /= ref_grid%g_hat(1, ih)) CYCLE
1854 316146545 : IF (pw_grid%g_hat(2, ig) /= ref_grid%g_hat(2, ih)) CYCLE
1855 102588510 : IF (pw_grid%g_hat(3, ig) /= ref_grid%g_hat(3, ih)) CYCLE
1856 82897454 : pw_grid%gidx(ig) = ih
1857 5698733083 : EXIT
1858 : END DO
1859 82897454 : IF (pw_grid%gidx(ig) == 0) THEN
1860 0 : WRITE (*, "(A,2I10)") " G-Shell ", is + 1, ip + 1
1861 : WRITE (*, "(A,I10,3I6,F20.10)") &
1862 0 : " G-vector", ig, pw_grid%g_hat(1:3, ig), pw_grid%gsq(ig)
1863 0 : DO ih = 1, SIZE(ref_grid%gsq)
1864 0 : IF (pw_grid%g_hat(1, ig) /= ref_grid%g_hat(1, ih)) CYCLE
1865 0 : IF (pw_grid%g_hat(2, ig) /= ref_grid%g_hat(2, ih)) CYCLE
1866 0 : IF (pw_grid%g_hat(3, ig) /= ref_grid%g_hat(3, ih)) CYCLE
1867 : WRITE (*, "(A,I10,3I6,F20.10)") &
1868 0 : " G-vector", ih, ref_grid%g_hat(1:3, ih), ref_grid%gsq(ih)
1869 : END DO
1870 0 : CPABORT("G vector not found")
1871 : END IF
1872 82918366 : is = ip
1873 : END DO
1874 : ELSE
1875 : ! for the case pw_grid > ref_grid
1876 0 : is = it
1877 0 : DO ig = it + 1, ngr
1878 0 : gig = ref_grid%gsq(ig)
1879 0 : gigr = MAX(1._dp, gig)
1880 0 : g_found = .FALSE.
1881 0 : DO ih = is + 1, ng
1882 0 : IF (ABS(pw_grid%gsq(ih) - gig)/gigr > 1.e-12_dp) CYCLE
1883 : g_found = .TRUE.
1884 0 : EXIT
1885 : END DO
1886 0 : IF (.NOT. g_found) THEN
1887 0 : WRITE (*, "(A,I10,F20.10)") "G-vector", ig, ref_grid%gsq(ig)
1888 0 : CPABORT("G vector not found")
1889 : END IF
1890 0 : ip = ih - 1
1891 0 : DO ih = ip + 1, ng
1892 0 : IF (ABS(pw_grid%gsq(ih) - gig)/gigr > 1.e-12_dp) CYCLE
1893 0 : IF (pw_grid%g_hat(1, ih) /= ref_grid%g_hat(1, ig)) CYCLE
1894 0 : IF (pw_grid%g_hat(2, ih) /= ref_grid%g_hat(2, ig)) CYCLE
1895 0 : IF (pw_grid%g_hat(3, ih) /= ref_grid%g_hat(3, ig)) CYCLE
1896 0 : pw_grid%gidx(ig) = ih
1897 0 : EXIT
1898 : END DO
1899 0 : IF (pw_grid%gidx(ig) == 0) THEN
1900 0 : WRITE (*, "(A,2I10)") " G-Shell ", is + 1, ip + 1
1901 : WRITE (*, "(A,I10,3I6,F20.10)") &
1902 0 : " G-vector", ig, ref_grid%g_hat(1:3, ig), ref_grid%gsq(ig)
1903 0 : DO ih = 1, ng
1904 0 : IF (pw_grid%g_hat(1, ih) /= ref_grid%g_hat(1, ig)) CYCLE
1905 0 : IF (pw_grid%g_hat(2, ih) /= ref_grid%g_hat(2, ig)) CYCLE
1906 0 : IF (pw_grid%g_hat(3, ih) /= ref_grid%g_hat(3, ig)) CYCLE
1907 : WRITE (*, "(A,I10,3I6,F20.10)") &
1908 0 : " G-vector", ih, pw_grid%g_hat(1:3, ih), pw_grid%gsq(ih)
1909 : END DO
1910 0 : CPABORT("G vector not found")
1911 : END IF
1912 0 : is = ip
1913 : END DO
1914 : END IF
1915 : ! test if all g-vectors are associated
1916 176899881 : IF (ANY(pw_grid%gidx == 0)) THEN
1917 0 : CPABORT("G space sorting not compatible")
1918 : END IF
1919 : END IF
1920 : END IF
1921 :
1922 : !check if G=0 is at first position
1923 33147 : IF (pw_grid%have_g0) THEN
1924 19125 : IF (pw_grid%gsq(1) /= 0.0_dp) THEN
1925 0 : CPABORT("G = 0 not in first position")
1926 : END IF
1927 : END IF
1928 :
1929 33147 : CALL timestop(handle)
1930 :
1931 33147 : END SUBROUTINE pw_grid_sort
1932 :
1933 : ! **************************************************************************************************
1934 : !> \brief ...
1935 : !> \param gsq ...
1936 : !> \param g_hat ...
1937 : !> \param idx ...
1938 : ! **************************************************************************************************
1939 33147 : SUBROUTINE sort_shells(gsq, g_hat, idx)
1940 :
1941 : ! Argument
1942 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: gsq
1943 : INTEGER, DIMENSION(:, :), INTENT(IN) :: g_hat
1944 : INTEGER, DIMENSION(:), INTENT(INOUT) :: idx
1945 :
1946 : CHARACTER(len=*), PARAMETER :: routineN = 'sort_shells'
1947 : REAL(KIND=dp), PARAMETER :: small = 5.e-16_dp
1948 :
1949 : INTEGER :: handle, ig, ng, s1, s2
1950 : REAL(KIND=dp) :: s_begin
1951 :
1952 33147 : CALL timeset(routineN, handle)
1953 :
1954 : ! Juergs temporary hack to get the grids sorted for large (4000Ry) cutoffs.
1955 : ! might need to call lapack for machine precision.
1956 :
1957 33147 : ng = SIZE(gsq)
1958 33147 : s_begin = -1.0_dp
1959 33147 : s1 = 0
1960 33147 : s2 = 0
1961 : ig = 1
1962 811034177 : DO ig = 1, ng
1963 811034177 : IF (ABS(gsq(ig) - s_begin) < small) THEN
1964 770549400 : s2 = ig
1965 : ELSE
1966 40451630 : CALL redist(g_hat, idx, s1, s2)
1967 40451630 : s_begin = gsq(ig)
1968 40451630 : s1 = ig
1969 40451630 : s2 = ig
1970 : END IF
1971 : END DO
1972 33147 : CALL redist(g_hat, idx, s1, s2)
1973 :
1974 33147 : CALL timestop(handle)
1975 :
1976 33147 : END SUBROUTINE sort_shells
1977 :
1978 : ! **************************************************************************************************
1979 : !> \brief ...
1980 : !> \param g_hat ...
1981 : !> \param idx ...
1982 : !> \param s1 ...
1983 : !> \param s2 ...
1984 : ! **************************************************************************************************
1985 40484777 : SUBROUTINE redist(g_hat, idx, s1, s2)
1986 :
1987 : ! Argument
1988 : INTEGER, DIMENSION(:, :), INTENT(IN) :: g_hat
1989 : INTEGER, DIMENSION(:), INTENT(INOUT) :: idx
1990 : INTEGER, INTENT(IN) :: s1, s2
1991 :
1992 : INTEGER :: i, ii, n1, n2, n3, ns
1993 40484777 : INTEGER, ALLOCATABLE, DIMENSION(:) :: indl
1994 40484777 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: slen
1995 :
1996 40484777 : IF (s2 <= s1) RETURN
1997 38704670 : ns = s2 - s1 + 1
1998 116114010 : ALLOCATE (indl(ns))
1999 116114010 : ALLOCATE (slen(ns))
2000 :
2001 847958740 : DO i = s1, s2
2002 809254070 : ii = idx(i)
2003 809254070 : n1 = g_hat(1, ii)
2004 809254070 : n2 = g_hat(2, ii)
2005 809254070 : n3 = g_hat(3, ii)
2006 : slen(i - s1 + 1) = 1000.0_dp*REAL(n1, dp) + &
2007 847958740 : REAL(n2, dp) + 0.001_dp*REAL(n3, dp)
2008 : END DO
2009 38704670 : CALL sort(slen, ns, indl)
2010 847958740 : DO i = 1, ns
2011 809254070 : ii = indl(i) + s1 - 1
2012 847958740 : indl(i) = idx(ii)
2013 : END DO
2014 847958740 : idx(s1:s2) = indl(1:ns)
2015 :
2016 38704670 : DEALLOCATE (indl)
2017 38704670 : DEALLOCATE (slen)
2018 :
2019 : END SUBROUTINE redist
2020 :
2021 : ! **************************************************************************************************
2022 : !> \brief Reorder yzq and yzp arrays for parallel FFT according to FFT mapping
2023 : !> \param pw_grid ...
2024 : !> \param yz ...
2025 : !> \par History
2026 : !> none
2027 : !> \author JGH (17-Jan-2001)
2028 : ! **************************************************************************************************
2029 33147 : SUBROUTINE pw_grid_remap(pw_grid, yz)
2030 :
2031 : ! Argument
2032 : TYPE(pw_grid_type), INTENT(INOUT) :: pw_grid
2033 : INTEGER, DIMENSION(:, :), INTENT(OUT) :: yz
2034 :
2035 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_grid_remap'
2036 :
2037 : INTEGER :: gpt, handle, i, ip, is, j, m, n
2038 :
2039 33147 : IF (pw_grid%para%mode == PW_MODE_LOCAL) RETURN
2040 :
2041 28044 : CALL timeset(routineN, handle)
2042 :
2043 : ASSOCIATE (ny => pw_grid%npts(2), nz => pw_grid%npts(3), posm => pw_grid%mapm%pos, posn => pw_grid%mapn%pos, &
2044 : negm => pw_grid%mapm%neg, negn => pw_grid%mapn%neg)
2045 :
2046 31152314 : yz = 0
2047 87696588 : pw_grid%para%yzp = 0
2048 31152314 : pw_grid%para%yzq = 0
2049 :
2050 767681375 : DO gpt = 1, SIZE(pw_grid%gsq)
2051 767653331 : m = posm(pw_grid%g_hat(2, gpt)) + 1
2052 767653331 : n = posn(pw_grid%g_hat(3, gpt)) + 1
2053 767681375 : yz(m, n) = yz(m, n) + 1
2054 : END DO
2055 28044 : IF (pw_grid%grid_span == HALFSPACE) THEN
2056 20665962 : DO gpt = 1, SIZE(pw_grid%gsq)
2057 20663702 : m = negm(pw_grid%g_hat(2, gpt)) + 1
2058 20663702 : n = negn(pw_grid%g_hat(3, gpt)) + 1
2059 20665962 : yz(m, n) = yz(m, n) + 1
2060 : END DO
2061 : END IF
2062 :
2063 28044 : ip = pw_grid%para%group%mepos
2064 28044 : is = 0
2065 805236 : DO i = 1, nz
2066 31152314 : DO j = 1, ny
2067 31124270 : IF (yz(j, i) > 0) THEN
2068 14586337 : is = is + 1
2069 14586337 : pw_grid%para%yzp(1, is, ip) = j
2070 14586337 : pw_grid%para%yzp(2, is, ip) = i
2071 14586337 : pw_grid%para%yzq(j, i) = is
2072 : END IF
2073 : END DO
2074 : END DO
2075 : END ASSOCIATE
2076 :
2077 28044 : CPASSERT(is == pw_grid%para%nyzray(ip))
2078 28044 : CALL pw_grid%para%group%sum(pw_grid%para%yzp)
2079 :
2080 28044 : CALL timestop(handle)
2081 :
2082 28044 : END SUBROUTINE pw_grid_remap
2083 :
2084 : ! **************************************************************************************************
2085 : !> \brief Recalculate the g-vectors after a change of the box
2086 : !> \param cell_hmat ...
2087 : !> \param pw_grid ...
2088 : !> \par History
2089 : !> JGH (20-12-2000) : get local grid size from definition of g.
2090 : !> Assume that gsq is allocated.
2091 : !> Local routine, no information on distribution of
2092 : !> PW required.
2093 : !> JGH (8-Mar-2001) : also update information on volume and grid spaceing
2094 : !> \author apsi
2095 : !> Christopher Mundy
2096 : ! **************************************************************************************************
2097 11114 : SUBROUTINE pw_grid_change(cell_hmat, pw_grid)
2098 : ! Argument
2099 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN) :: cell_hmat
2100 : TYPE(pw_grid_type), INTENT(INOUT) :: pw_grid
2101 :
2102 : INTEGER :: gpt
2103 : REAL(KIND=dp) :: cell_deth, l, m, n
2104 : REAL(KIND=dp), DIMENSION(3, 3) :: cell_h_inv
2105 11114 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: g
2106 :
2107 11114 : cell_deth = ABS(det_3x3(cell_hmat))
2108 11114 : IF (cell_deth < 1.0E-10_dp) THEN
2109 : CALL cp_abort(__LOCATION__, &
2110 : "An invalid set of cell vectors was specified. "// &
2111 0 : "The determinant det(h) is too small")
2112 : END IF
2113 11114 : cell_h_inv = inv_3x3(cell_hmat)
2114 :
2115 11114 : g => pw_grid%g
2116 :
2117 11114 : CALL cell2grid(cell_hmat, cell_h_inv, cell_deth, pw_grid)
2118 :
2119 105197171 : DO gpt = 1, SIZE(g, 2)
2120 :
2121 105186057 : l = twopi*REAL(pw_grid%g_hat(1, gpt), KIND=dp)
2122 105186057 : m = twopi*REAL(pw_grid%g_hat(2, gpt), KIND=dp)
2123 105186057 : n = twopi*REAL(pw_grid%g_hat(3, gpt), KIND=dp)
2124 :
2125 105186057 : g(1, gpt) = l*cell_h_inv(1, 1) + m*cell_h_inv(2, 1) + n*cell_h_inv(3, 1)
2126 105186057 : g(2, gpt) = l*cell_h_inv(1, 2) + m*cell_h_inv(2, 2) + n*cell_h_inv(3, 2)
2127 105186057 : g(3, gpt) = l*cell_h_inv(1, 3) + m*cell_h_inv(2, 3) + n*cell_h_inv(3, 3)
2128 :
2129 : pw_grid%gsq(gpt) = g(1, gpt)*g(1, gpt) &
2130 : + g(2, gpt)*g(2, gpt) &
2131 105197171 : + g(3, gpt)*g(3, gpt)
2132 :
2133 : END DO
2134 :
2135 11114 : END SUBROUTINE pw_grid_change
2136 :
2137 : ! **************************************************************************************************
2138 : !> \brief retains the given pw grid
2139 : !> \param pw_grid the pw grid to retain
2140 : !> \par History
2141 : !> 04.2003 created [fawzi]
2142 : !> \author fawzi
2143 : !> \note
2144 : !> see doc/ReferenceCounting.html
2145 : ! **************************************************************************************************
2146 7222410 : SUBROUTINE pw_grid_retain(pw_grid)
2147 : TYPE(pw_grid_type), INTENT(INOUT) :: pw_grid
2148 :
2149 7222410 : CPASSERT(pw_grid%ref_count > 0)
2150 7222410 : pw_grid%ref_count = pw_grid%ref_count + 1
2151 7222410 : END SUBROUTINE pw_grid_retain
2152 :
2153 : ! **************************************************************************************************
2154 : !> \brief releases the given pw grid
2155 : !> \param pw_grid the pw grid to release
2156 : !> \par History
2157 : !> 04.2003 created [fawzi]
2158 : !> \author fawzi
2159 : !> \note
2160 : !> see doc/ReferenceCounting.html
2161 : ! **************************************************************************************************
2162 14864920 : SUBROUTINE pw_grid_release(pw_grid)
2163 :
2164 : TYPE(pw_grid_type), POINTER :: pw_grid
2165 :
2166 : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
2167 : INTEGER, POINTER :: dummy_ptr
2168 : INTEGER :: stat
2169 : #endif
2170 :
2171 14864920 : IF (ASSOCIATED(pw_grid)) THEN
2172 7315631 : CPASSERT(pw_grid%ref_count > 0)
2173 7315631 : pw_grid%ref_count = pw_grid%ref_count - 1
2174 7315631 : IF (pw_grid%ref_count == 0) THEN
2175 93221 : IF (ASSOCIATED(pw_grid%gidx)) THEN
2176 20912 : DEALLOCATE (pw_grid%gidx)
2177 : END IF
2178 93221 : IF (ASSOCIATED(pw_grid%g)) THEN
2179 33147 : DEALLOCATE (pw_grid%g)
2180 : END IF
2181 93221 : IF (ASSOCIATED(pw_grid%gsq)) THEN
2182 33147 : DEALLOCATE (pw_grid%gsq)
2183 : END IF
2184 93221 : IF (ALLOCATED(pw_grid%g_hat)) THEN
2185 33147 : DEALLOCATE (pw_grid%g_hat)
2186 : END IF
2187 93221 : IF (ASSOCIATED(pw_grid%g_hatmap)) THEN
2188 : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
2189 : dummy_ptr => pw_grid%g_hatmap(1, 1)
2190 : stat = offload_free_pinned_mem(c_loc(dummy_ptr))
2191 : CPASSERT(stat == 0)
2192 : #else
2193 33147 : DEALLOCATE (pw_grid%g_hatmap)
2194 : #endif
2195 : END IF
2196 93221 : IF (ASSOCIATED(pw_grid%grays)) THEN
2197 28044 : DEALLOCATE (pw_grid%grays)
2198 : END IF
2199 93221 : IF (ALLOCATED(pw_grid%mapl%pos)) THEN
2200 33147 : DEALLOCATE (pw_grid%mapl%pos)
2201 : END IF
2202 93221 : IF (ALLOCATED(pw_grid%mapm%pos)) THEN
2203 33147 : DEALLOCATE (pw_grid%mapm%pos)
2204 : END IF
2205 93221 : IF (ALLOCATED(pw_grid%mapn%pos)) THEN
2206 33147 : DEALLOCATE (pw_grid%mapn%pos)
2207 : END IF
2208 93221 : IF (ALLOCATED(pw_grid%mapl%neg)) THEN
2209 33147 : DEALLOCATE (pw_grid%mapl%neg)
2210 : END IF
2211 93221 : IF (ALLOCATED(pw_grid%mapm%neg)) THEN
2212 33147 : DEALLOCATE (pw_grid%mapm%neg)
2213 : END IF
2214 93221 : IF (ALLOCATED(pw_grid%mapn%neg)) THEN
2215 33147 : DEALLOCATE (pw_grid%mapn%neg)
2216 : END IF
2217 93221 : IF (ALLOCATED(pw_grid%para%bo)) THEN
2218 33147 : DEALLOCATE (pw_grid%para%bo)
2219 : END IF
2220 93221 : IF (pw_grid%para%mode == PW_MODE_DISTRIBUTED) THEN
2221 28052 : IF (ALLOCATED(pw_grid%para%yzp)) THEN
2222 28044 : DEALLOCATE (pw_grid%para%yzp)
2223 : END IF
2224 28052 : IF (ALLOCATED(pw_grid%para%yzq)) THEN
2225 28044 : DEALLOCATE (pw_grid%para%yzq)
2226 : END IF
2227 28052 : IF (ALLOCATED(pw_grid%para%nyzray)) THEN
2228 28044 : DEALLOCATE (pw_grid%para%nyzray)
2229 : END IF
2230 : END IF
2231 : ! also release groups
2232 93221 : CALL pw_grid%para%group%free()
2233 93221 : IF (ALLOCATED(pw_grid%para%pos_of_x)) THEN
2234 34155 : DEALLOCATE (pw_grid%para%pos_of_x)
2235 : END IF
2236 :
2237 93221 : IF (ASSOCIATED(pw_grid)) THEN
2238 93221 : DEALLOCATE (pw_grid)
2239 : END IF
2240 : END IF
2241 : END IF
2242 14864920 : NULLIFY (pw_grid)
2243 14864920 : END SUBROUTINE pw_grid_release
2244 :
2245 : END MODULE pw_grids
|