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 : !> \note
10 : !> If parallel mode is distributed certain combination of
11 : !> "in_use" and "in_space" can not be used.
12 : !> For performance reasons it would be better to have the loops
13 : !> over g-vectors in the gather/scatter routines in new subprograms
14 : !> with the actual arrays (also the addressing) in the parameter list
15 : !> \par History
16 : !> JGH (29-Dec-2000) : Changes for parallel use
17 : !> JGH (13-Mar-2001) : added timing calls
18 : !> JGH (26-Feb-2003) : OpenMP enabled
19 : !> JGH (17-Nov-2007) : Removed mass arrays
20 : !> JGH (01-Dec-2007) : Removed and renamed routines
21 : !> JGH (04-Jul-2019) : added pw_multiply routine
22 : !> 03.2008 [tlaino] : Splitting pw_types into pw_types and pw_methods
23 : !> \author apsi
24 : ! **************************************************************************************************
25 : MODULE pw_methods
26 : #:include "pw_types.fypp"
27 : USE cp_log_handling, ONLY: cp_logger_get_default_io_unit, &
28 : cp_to_string
29 : USE fft_tools, ONLY: BWFFT, &
30 : FWFFT, &
31 : fft3d
32 : USE kahan_sum, ONLY: accurate_dot_product, &
33 : accurate_sum
34 : USE kinds, ONLY: dp
35 : USE machine, ONLY: m_memory
36 : USE mathconstants, ONLY: z_zero
37 : USE pw_copy_all, ONLY: pw_copy_match
38 : USE pw_fpga, ONLY: pw_fpga_c1dr3d_3d_dp, &
39 : pw_fpga_c1dr3d_3d_sp, &
40 : pw_fpga_init_bitstream, &
41 : pw_fpga_r3dc1d_3d_dp, &
42 : pw_fpga_r3dc1d_3d_sp
43 : USE pw_gpu, ONLY: pw_gpu_c1dr3d_3d, &
44 : pw_gpu_c1dr3d_3d_ps, &
45 : pw_gpu_r3dc1d_3d, &
46 : pw_gpu_r3dc1d_3d_ps
47 : USE pw_grid_types, ONLY: HALFSPACE, &
48 : PW_MODE_DISTRIBUTED, &
49 : PW_MODE_LOCAL, &
50 : pw_grid_type
51 : #:for space in pw_spaces
52 : #:for kind in pw_kinds
53 : USE pw_types, ONLY: pw_${kind}$_${space}$_type
54 : #:endfor
55 : #:endfor
56 : #include "../base/base_uses.f90"
57 :
58 : IMPLICIT NONE
59 :
60 : PRIVATE
61 :
62 : PUBLIC :: pw_zero, pw_structure_factor, pw_smoothing
63 : PUBLIC :: pw_copy, pw_axpy, pw_transfer, pw_scale
64 : PUBLIC :: pw_gauss_damp, pw_compl_gauss_damp, pw_derive, pw_laplace, pw_dr2, pw_write, pw_multiply
65 : PUBLIC :: pw_log_deriv_gauss, pw_log_deriv_compl_gauss, pw_log_deriv_mix_cl, pw_log_deriv_trunc
66 : PUBLIC :: pw_gauss_damp_mix, pw_multiply_with
67 : PUBLIC :: pw_integral_ab, pw_integral_a2b
68 : PUBLIC :: pw_dr2_gg, pw_integrate_function
69 : PUBLIC :: pw_set, pw_truncated
70 : PUBLIC :: pw_scatter, pw_gather
71 : PUBLIC :: pw_copy_to_array, pw_copy_from_array
72 :
73 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'pw_methods'
74 : LOGICAL, PARAMETER, PRIVATE :: debug_this_module = .FALSE.
75 : INTEGER, PARAMETER, PUBLIC :: do_accurate_sum = 0, &
76 : do_standard_sum = 1
77 :
78 : INTERFACE pw_zero
79 : #:for space in pw_spaces
80 : #:for kind in pw_kinds
81 : MODULE PROCEDURE pw_zero_${kind}$_${space}$
82 : #:endfor
83 : #:endfor
84 : END INTERFACE
85 :
86 : INTERFACE pw_scale
87 : #:for space in pw_spaces
88 : #:for kind in pw_kinds
89 : MODULE PROCEDURE pw_scale_${kind}$_${space}$
90 : #:endfor
91 : #:endfor
92 : END INTERFACE
93 :
94 : INTERFACE pw_write
95 : #:for space in pw_spaces
96 : #:for kind in pw_kinds
97 : MODULE PROCEDURE pw_write_${kind}$_${space}$
98 : #:endfor
99 : #:endfor
100 : END INTERFACE
101 :
102 : INTERFACE pw_integrate_function
103 : #:for space in pw_spaces
104 : #:for kind in pw_kinds
105 : MODULE PROCEDURE pw_integrate_function_${kind}$_${space}$
106 : #:endfor
107 : #:endfor
108 : END INTERFACE
109 :
110 : INTERFACE pw_set
111 : #:for space in pw_spaces
112 : #:for kind in pw_kinds
113 : MODULE PROCEDURE pw_set_value_${kind}$_${space}$
114 : MODULE PROCEDURE pw_zero_${kind}$_${space}$
115 : #:endfor
116 : #:endfor
117 : END INTERFACE
118 :
119 : INTERFACE pw_copy
120 : #:for space in pw_spaces
121 : #:for kind, kind2 in pw_kinds2_sameD
122 : MODULE PROCEDURE pw_copy_${kind}$_${kind2}$_${space}$
123 : #:endfor
124 : #:endfor
125 : END INTERFACE
126 :
127 : INTERFACE pw_axpy
128 : #:for space in pw_spaces
129 : #:for kind, kind2 in pw_kinds2_sameD
130 : MODULE PROCEDURE pw_axpy_${kind}$_${kind2}$_${space}$
131 : #:endfor
132 : #:endfor
133 : END INTERFACE
134 :
135 : INTERFACE pw_multiply
136 : #:for space in pw_spaces
137 : #:for kind, kind2 in pw_kinds2_sameD
138 : MODULE PROCEDURE pw_multiply_${kind}$_${kind2}$_${space}$
139 : #:endfor
140 : #:endfor
141 : END INTERFACE
142 :
143 : INTERFACE pw_multiply_with
144 : #:for space in pw_spaces
145 : #:for kind, kind2 in pw_kinds2_sameD
146 : MODULE PROCEDURE pw_multiply_with_${kind}$_${kind2}$_${space}$
147 : #:endfor
148 : #:endfor
149 : END INTERFACE
150 :
151 : INTERFACE pw_integral_ab
152 : #:for space in pw_spaces
153 : #:for kind, kind2 in pw_kinds2_sameD
154 : MODULE PROCEDURE pw_integral_ab_${kind}$_${kind2}$_${space}$
155 : #:endfor
156 : #:endfor
157 : END INTERFACE
158 :
159 : INTERFACE pw_integral_a2b
160 : #:for kind, kind2 in pw_kinds2_sameD
161 : #:if kind[1]=="1"
162 : MODULE PROCEDURE pw_integral_a2b_${kind}$_${kind2}$
163 : #:endif
164 : #:endfor
165 : END INTERFACE
166 :
167 : INTERFACE pw_gather
168 : #:for kind in pw_kinds
169 : #:if kind[1]=="1"
170 : MODULE PROCEDURE pw_gather_p_${kind}$
171 : #:endif
172 : #:endfor
173 : #:for kind, kind2 in pw_kinds2
174 : #:if kind[1]=="1" and kind2[1]=="3"
175 : MODULE PROCEDURE pw_gather_s_${kind}$_${kind2}$
176 : #:endif
177 : #:endfor
178 : END INTERFACE
179 :
180 : INTERFACE pw_scatter
181 : #:for kind in pw_kinds
182 : #:if kind[1]=="1"
183 : MODULE PROCEDURE pw_scatter_p_${kind}$
184 : #:endif
185 : #:endfor
186 : #:for kind, kind2 in pw_kinds2
187 : #:if kind[1]=="1" and kind2[1]=="3"
188 : MODULE PROCEDURE pw_scatter_s_${kind}$_${kind2}$
189 : #:endif
190 : #:endfor
191 : END INTERFACE
192 :
193 : INTERFACE pw_copy_to_array
194 : #:for space in pw_spaces
195 : #:for kind, kind2 in pw_kinds2_sameD
196 : MODULE PROCEDURE pw_copy_to_array_${kind}$_${kind2}$_${space}$
197 : #:endfor
198 : #:endfor
199 : END INTERFACE
200 :
201 : INTERFACE pw_copy_from_array
202 : #:for space in pw_spaces
203 : #:for kind, kind2 in pw_kinds2_sameD
204 : MODULE PROCEDURE pw_copy_from_array_${kind}$_${kind2}$_${space}$
205 : #:endfor
206 : #:endfor
207 : END INTERFACE
208 :
209 : INTERFACE pw_transfer
210 : #:for kind, kind2 in pw_kinds2
211 : #:if kind[1]=="1" and kind2[1]=="3"
212 : MODULE PROCEDURE pw_gather_s_${kind}$_${kind2}$_2
213 : MODULE PROCEDURE pw_scatter_s_${kind}$_${kind2}$_2
214 : #:endif
215 : #:for space in pw_spaces
216 : #:if kind[1]==kind2[1]
217 : MODULE PROCEDURE pw_copy_${kind}$_${kind2}$_${space}$
218 : #:endif
219 : #:endfor
220 : #:if kind2[0]=="c" and kind[1]=="3"
221 : MODULE PROCEDURE fft_wrap_pw1pw2_${kind}$_${kind2}$_rs_gs
222 : #:endif
223 : #:if kind[0]=="c" and kind2[1]=="3"
224 : MODULE PROCEDURE fft_wrap_pw1pw2_${kind}$_${kind2}$_gs_rs
225 : #:endif
226 : #:endfor
227 : END INTERFACE
228 :
229 : CONTAINS
230 : #:for kind, type in pw_list
231 : #:for space in pw_spaces
232 : ! **************************************************************************************************
233 : !> \brief Set values of a pw type to zero
234 : !> \param pw ...
235 : !> \par History
236 : !> none
237 : !> \author apsi
238 : ! **************************************************************************************************
239 1113410 : SUBROUTINE pw_zero_${kind}$_${space}$ (pw)
240 :
241 : TYPE(pw_${kind}$_${space}$_type), INTENT(INOUT) :: pw
242 :
243 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_zero'
244 :
245 : INTEGER :: handle
246 :
247 1113410 : CALL timeset(routineN, handle)
248 :
249 1113410 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw)
250 : pw%array = ${type2type("0.0_dp", "r3d", kind)}$
251 : !$OMP END PARALLEL WORKSHARE
252 :
253 1113410 : CALL timestop(handle)
254 :
255 1113410 : END SUBROUTINE pw_zero_${kind}$_${space}$
256 :
257 : ! **************************************************************************************************
258 : !> \brief multiplies pw coeffs with a number
259 : !> \param pw ...
260 : !> \param a ...
261 : !> \par History
262 : !> 11.2004 created [Joost VandeVondele]
263 : ! **************************************************************************************************
264 454492 : SUBROUTINE pw_scale_${kind}$_${space}$ (pw, a)
265 :
266 : TYPE(pw_${kind}$_${space}$_type), INTENT(INOUT) :: pw
267 : REAL(KIND=dp), INTENT(IN) :: a
268 :
269 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_scale'
270 :
271 : INTEGER :: handle
272 :
273 454492 : CALL timeset(routineN, handle)
274 :
275 454492 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(A, pw)
276 : pw%array = a*pw%array
277 : !$OMP END PARALLEL WORKSHARE
278 :
279 454492 : CALL timestop(handle)
280 :
281 454492 : END SUBROUTINE pw_scale_${kind}$_${space}$
282 :
283 : ! **************************************************************************************************
284 : !> \brief writes a small description of the actual grid
285 : !> (change to output the data as cube file, maybe with an
286 : !> optional long_description arg?)
287 : !> \param pw the pw data to output
288 : !> \param unit_nr the unit to output to
289 : !> \par History
290 : !> 08.2002 created [fawzi]
291 : !> \author Fawzi Mohamed
292 : ! **************************************************************************************************
293 0 : SUBROUTINE pw_write_${kind}$_${space}$ (pw, unit_nr)
294 :
295 : TYPE(pw_${kind}$_${space}$_type), INTENT(in) :: pw
296 : INTEGER, INTENT(in) :: unit_nr
297 :
298 : INTEGER :: iostatus
299 :
300 0 : WRITE (unit=unit_nr, fmt="('<pw>:{ ')", iostat=iostatus)
301 :
302 0 : WRITE (unit=unit_nr, fmt="(a)", iostat=iostatus) " in_use=${kind}$"
303 0 : IF (ASSOCIATED(pw%array)) THEN
304 : #:if kind[1]=='1'
305 : WRITE (unit=unit_nr, fmt="(' array=<${kind[0]}$(',i8,':',i8,')>')") &
306 0 : LBOUND(pw%array, 1), UBOUND(pw%array, 1)
307 : #:else
308 : WRITE (unit=unit_nr, fmt="(' array=<${kind[0]}$(',i8,':',i8,',',i8,':',i8,',',i8,':',i8,')>')") &
309 0 : LBOUND(pw%array, 1), UBOUND(pw%array, 1), LBOUND(pw%array, 2), UBOUND(pw%array, 2), &
310 0 : LBOUND(pw%array, 3), UBOUND(pw%array, 3)
311 : #:endif
312 : ELSE
313 0 : WRITE (unit=unit_nr, fmt="(' array=*null*')")
314 : END IF
315 :
316 0 : END SUBROUTINE pw_write_${kind}$_${space}$
317 :
318 : ! **************************************************************************************************
319 : !> \brief ...
320 : !> \param fun ...
321 : !> \param isign ...
322 : !> \param oprt ...
323 : !> \return ...
324 : ! **************************************************************************************************
325 422664 : FUNCTION pw_integrate_function_${kind}$_${space}$ (fun, isign, oprt) RESULT(total_fun)
326 :
327 : TYPE(pw_${kind}$_${space}$_type), INTENT(IN) :: fun
328 : INTEGER, INTENT(IN), OPTIONAL :: isign
329 : CHARACTER(len=*), INTENT(IN), OPTIONAL :: oprt
330 : REAL(KIND=dp) :: total_fun
331 :
332 : INTEGER :: iop
333 :
334 422664 : iop = 0
335 :
336 422664 : IF (PRESENT(oprt)) THEN
337 : SELECT CASE (oprt)
338 : CASE ("ABS", "abs")
339 0 : iop = 1
340 : CASE DEFAULT
341 2016 : CPABORT("Unknown operator")
342 : END SELECT
343 : END IF
344 :
345 101461 : total_fun = 0.0_dp
346 :
347 : #:if space == "rs"
348 : ! do reduction using maximum accuracy
349 : IF (iop == 1) THEN
350 106574285 : total_fun = fun%pw_grid%dvol*accurate_sum(ABS(fun%array))
351 : ELSE
352 319187 : total_fun = fun%pw_grid%dvol*accurate_sum(${type2type("fun%array", kind, "r1d")}$)
353 : END IF
354 : #:elif space == "gs"
355 : IF (iop == 1) &
356 0 : CPABORT("Operator ABS not implemented")
357 : #:if kind[1:]=="1d"
358 101461 : IF (fun%pw_grid%have_g0) total_fun = fun%pw_grid%vol*${type2type("fun%array(1)", kind, "r1d")}$
359 : #:else
360 0 : CPABORT("Reciprocal space integration for 3D grids not implemented!")
361 : #:endif
362 : #:else
363 : CPABORT("No space defined")
364 : #:endif
365 :
366 422664 : IF (fun%pw_grid%para%mode /= PW_MODE_LOCAL) THEN
367 417220 : CALL fun%pw_grid%para%group%sum(total_fun)
368 : END IF
369 :
370 422664 : IF (PRESENT(isign)) THEN
371 306436 : total_fun = total_fun*SIGN(1._dp, REAL(isign, dp))
372 : END IF
373 :
374 422664 : END FUNCTION pw_integrate_function_${kind}$_${space}$
375 :
376 : ! **************************************************************************************************
377 : !> \brief ...
378 : !> \param pw ...
379 : !> \param value ...
380 : ! **************************************************************************************************
381 118 : SUBROUTINE pw_set_value_${kind}$_${space}$ (pw, value)
382 : TYPE(pw_${kind}$_${space}$_type), INTENT(IN) :: pw
383 : REAL(KIND=dp), INTENT(IN) :: value
384 :
385 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_set_value'
386 :
387 : INTEGER :: handle
388 :
389 118 : CALL timeset(routineN, handle)
390 :
391 118 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw,value)
392 : pw%array = ${type2type("value", "r3d", kind)}$
393 : !$OMP END PARALLEL WORKSHARE
394 :
395 118 : CALL timestop(handle)
396 :
397 118 : END SUBROUTINE pw_set_value_${kind}$_${space}$
398 : #:endfor
399 :
400 : #:if kind[1]=="1"
401 : ! **************************************************************************************************
402 : !> \brief ...
403 : !> \param pw ...
404 : !> \param c ...
405 : !> \param scale ...
406 : ! **************************************************************************************************
407 1294126 : SUBROUTINE pw_gather_p_${kind}$ (pw, c, scale)
408 :
409 : TYPE(pw_${kind}$_gs_type), INTENT(INOUT) :: pw
410 : COMPLEX(KIND=dp), DIMENSION(:, :), CONTIGUOUS, INTENT(IN) :: c
411 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: scale
412 :
413 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_gather_p'
414 :
415 : INTEGER :: gpt, handle, l, m, mn, n
416 :
417 1294126 : CALL timeset(routineN, handle)
418 :
419 1294126 : IF (pw%pw_grid%para%mode /= PW_MODE_DISTRIBUTED) THEN
420 0 : CPABORT("This grid type is not distributed")
421 : END IF
422 :
423 : ASSOCIATE (mapl => pw%pw_grid%mapl%pos, mapm => pw%pw_grid%mapm%pos, mapn => pw%pw_grid%mapn%pos, &
424 : ngpts => SIZE(pw%pw_grid%gsq), ghat => pw%pw_grid%g_hat, yzq => pw%pw_grid%para%yzq)
425 :
426 1294126 : IF (PRESENT(scale)) THEN
427 : !$OMP PARALLEL DO DEFAULT(NONE), &
428 : !$OMP PRIVATE(l, m, mn, n), &
429 0 : !$OMP SHARED(c, pw, scale)
430 : DO gpt = 1, ngpts
431 : l = mapl(ghat(1, gpt)) + 1
432 : m = mapm(ghat(2, gpt)) + 1
433 : n = mapn(ghat(3, gpt)) + 1
434 : mn = yzq(m, n)
435 : pw%array(gpt) = scale*${type2type("c(l, mn)", "c3d", kind)}$
436 : END DO
437 : !$OMP END PARALLEL DO
438 : ELSE
439 : !$OMP PARALLEL DO DEFAULT(NONE), &
440 : !$OMP PRIVATE(l, m, mn, n), &
441 1294126 : !$OMP SHARED(c, pw)
442 : DO gpt = 1, ngpts
443 : l = mapl(ghat(1, gpt)) + 1
444 : m = mapm(ghat(2, gpt)) + 1
445 : n = mapn(ghat(3, gpt)) + 1
446 : mn = yzq(m, n)
447 : pw%array(gpt) = ${type2type("c(l, mn)", "c3d", kind)}$
448 : END DO
449 : !$OMP END PARALLEL DO
450 : END IF
451 :
452 : END ASSOCIATE
453 :
454 1294126 : CALL timestop(handle)
455 :
456 1294126 : END SUBROUTINE pw_gather_p_${kind}$
457 :
458 : ! **************************************************************************************************
459 : !> \brief ...
460 : !> \param pw ...
461 : !> \param c ...
462 : !> \param scale ...
463 : ! **************************************************************************************************
464 1327506 : SUBROUTINE pw_scatter_p_${kind}$ (pw, c, scale)
465 : TYPE(pw_${kind}$_gs_type), INTENT(IN) :: pw
466 : COMPLEX(KIND=dp), DIMENSION(:, :), CONTIGUOUS, INTENT(INOUT) :: c
467 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: scale
468 :
469 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_scatter_p'
470 :
471 : INTEGER :: gpt, handle, l, m, mn, n
472 :
473 1327506 : CALL timeset(routineN, handle)
474 :
475 1327506 : IF (pw%pw_grid%para%mode /= PW_MODE_DISTRIBUTED) THEN
476 0 : CPABORT("This grid type is not distributed")
477 : END IF
478 :
479 : ASSOCIATE (mapl => pw%pw_grid%mapl%pos, mapm => pw%pw_grid%mapm%pos, mapn => pw%pw_grid%mapn%pos, &
480 : ghat => pw%pw_grid%g_hat, yzq => pw%pw_grid%para%yzq, ngpts => SIZE(pw%pw_grid%gsq))
481 :
482 41396640840 : IF (.NOT. PRESENT(scale)) c = z_zero
483 :
484 1327506 : IF (PRESENT(scale)) THEN
485 : !$OMP PARALLEL DO DEFAULT(NONE), &
486 : !$OMP PRIVATE(l, m, mn, n), &
487 0 : !$OMP SHARED(c, pw, scale)
488 : DO gpt = 1, ngpts
489 : l = mapl(ghat(1, gpt)) + 1
490 : m = mapm(ghat(2, gpt)) + 1
491 : n = mapn(ghat(3, gpt)) + 1
492 : mn = yzq(m, n)
493 : c(l, mn) = ${type2type("scale*pw%array(gpt)", kind, "c3d")}$
494 : END DO
495 : !$OMP END PARALLEL DO
496 : ELSE
497 : !$OMP PARALLEL DO DEFAULT(NONE), &
498 : !$OMP PRIVATE(l, m, mn, n), &
499 1327506 : !$OMP SHARED(c, pw)
500 : DO gpt = 1, ngpts
501 : l = mapl(ghat(1, gpt)) + 1
502 : m = mapm(ghat(2, gpt)) + 1
503 : n = mapn(ghat(3, gpt)) + 1
504 : mn = yzq(m, n)
505 : c(l, mn) = ${type2type("pw%array(gpt)", kind, "c3d")}$
506 : END DO
507 : !$OMP END PARALLEL DO
508 : END IF
509 :
510 : END ASSOCIATE
511 :
512 1327506 : IF (pw%pw_grid%grid_span == HALFSPACE) THEN
513 :
514 : ASSOCIATE (mapm => pw%pw_grid%mapm%neg, mapn => pw%pw_grid%mapn%neg, mapl => pw%pw_grid%mapl%neg, &
515 : ghat => pw%pw_grid%g_hat, ngpts => SIZE(pw%pw_grid%gsq), yzq => pw%pw_grid%para%yzq)
516 :
517 112496 : IF (PRESENT(scale)) THEN
518 : !$OMP PARALLEL DO DEFAULT(NONE), &
519 : !$OMP PRIVATE(l, m, mn, n), &
520 0 : !$OMP SHARED(c, pw, scale)
521 : DO gpt = 1, ngpts
522 : l = mapl(ghat(1, gpt)) + 1
523 : m = mapm(ghat(2, gpt)) + 1
524 : n = mapn(ghat(3, gpt)) + 1
525 : mn = yzq(m, n)
526 : c(l, mn) = scale*#{if kind[0]=="c"}#CONJG#{endif}#(${type2type("pw%array(gpt)", kind, "c3d")}$)
527 : END DO
528 : !$OMP END PARALLEL DO
529 : ELSE
530 : !$OMP PARALLEL DO DEFAULT(NONE), &
531 : !$OMP PRIVATE(l, m, mn, n) &
532 112496 : !$OMP SHARED(c, pw)
533 : DO gpt = 1, ngpts
534 : l = mapl(ghat(1, gpt)) + 1
535 : m = mapm(ghat(2, gpt)) + 1
536 : n = mapn(ghat(3, gpt)) + 1
537 : mn = yzq(m, n)
538 : c(l, mn) = #{if kind[0]=="c"}#CONJG#{endif}#(${type2type("pw%array(gpt)", kind, "c3d")}$)
539 : END DO
540 : !$OMP END PARALLEL DO
541 : END IF
542 : END ASSOCIATE
543 : END IF
544 :
545 1327506 : CALL timestop(handle)
546 :
547 1327506 : END SUBROUTINE pw_scatter_p_${kind}$
548 : #:endif
549 : #:endfor
550 :
551 : #:for kind, type, kind2, type2 in pw_list2_sameD
552 : #:for space in pw_spaces
553 : ! **************************************************************************************************
554 : !> \brief copy a pw type variable
555 : !> \param pw1 ...
556 : !> \param pw2 ...
557 : !> \par History
558 : !> JGH (7-Mar-2001) : check for pw_grid %id_nr, allow copy if
559 : !> in_use == COMPLEXDATA1D and in_space == RECIPROCALSPACE
560 : !> JGH (21-Feb-2003) : Code for generalized reference grids
561 : !> \author apsi
562 : !> \note
563 : !> Currently only copying of respective types allowed,
564 : !> in order to avoid errors
565 : ! **************************************************************************************************
566 2964594 : SUBROUTINE pw_copy_${kind}$_${kind2}$_${space}$ (pw1, pw2)
567 :
568 : TYPE(pw_${kind}$_${space}$_type), INTENT(IN) :: pw1
569 : TYPE(pw_${kind2}$_${space}$_type), INTENT(INOUT) :: pw2
570 :
571 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_copy'
572 :
573 : INTEGER :: handle
574 : #:if kind[1:]=='1d'
575 : INTEGER :: i, j, ng, ng1, ng2, ns
576 : #:endif
577 :
578 2964594 : CALL timeset(routineN, handle)
579 :
580 2964594 : IF (pw1%pw_grid%spherical .neqv. pw2%pw_grid%spherical) &
581 0 : CPABORT("Both grids must be either spherical or non-spherical!")
582 : #:if space != "gs"
583 611717 : IF (pw1%pw_grid%spherical) &
584 0 : CPABORT("Spherical grids only exist in reciprocal space!")
585 : #:endif
586 :
587 : #:if kind[1]=='1'
588 2352877 : IF (.NOT. ASSOCIATED(pw1%pw_grid, pw2%pw_grid)) THEN
589 652326 : IF (pw1%pw_grid%spherical .AND. pw2%pw_grid%spherical) THEN
590 0 : IF (pw_compatible(pw1%pw_grid, pw2%pw_grid)) THEN
591 0 : ng1 = SIZE(pw1%array)
592 0 : ng2 = SIZE(pw2%array)
593 0 : ng = MIN(ng1, ng2)
594 0 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(ng, pw1, pw2)
595 : pw2%array(1:ng) = ${type2type("pw1%array(1:ng)", kind, kind2)}$
596 : !$OMP END PARALLEL WORKSHARE
597 0 : IF (ng2 > ng) THEN
598 0 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(ng, ng2, pw2)
599 : pw2%array(ng + 1:ng2) = ${type2type("0.0_dp", "r3d", kind2)}$
600 : !$OMP END PARALLEL WORKSHARE
601 : END IF
602 : ELSE
603 0 : CPABORT("Copies between spherical grids require compatible grids!")
604 : END IF
605 : ELSE
606 652326 : ng1 = SIZE(pw1%array)
607 652326 : ng2 = SIZE(pw2%array)
608 652326 : ns = 2*MAX(ng1, ng2)
609 :
610 652326 : IF ((pw1%pw_grid%id_nr == pw2%pw_grid%reference)) THEN
611 651958 : IF (ng1 >= ng2) THEN
612 651958 : !$OMP PARALLEL DO PRIVATE(i,j) DEFAULT(NONE) SHARED(ng2, pw1, pw2)
613 : DO i = 1, ng2
614 : j = pw2%pw_grid%gidx(i)
615 : pw2%array(i) = ${type2type("pw1%array(j)", kind, kind2)}$
616 : END DO
617 : !$OMP END PARALLEL DO
618 : ELSE
619 0 : CALL pw_zero(pw2)
620 0 : !$OMP PARALLEL DO PRIVATE(i,j) DEFAULT(NONE) SHARED(ng1, pw1, pw2)
621 : DO i = 1, ng1
622 : j = pw2%pw_grid%gidx(i)
623 : pw2%array(j) = ${type2type("pw1%array(i)", kind, kind2)}$
624 : END DO
625 : !$OMP END PARALLEL DO
626 : END IF
627 368 : ELSE IF ((pw2%pw_grid%id_nr == pw1%pw_grid%reference)) THEN
628 366 : IF (ng1 >= ng2) THEN
629 0 : !$OMP PARALLEL DO PRIVATE(i,j) DEFAULT(NONE) SHARED(ng2, pw1, pw2)
630 : DO i = 1, ng2
631 : j = pw1%pw_grid%gidx(i)
632 : pw2%array(i) = ${type2type("pw1%array(j)", kind, kind2)}$
633 : END DO
634 : !$OMP END PARALLEL DO
635 : ELSE
636 366 : CALL pw_zero(pw2)
637 366 : !$OMP PARALLEL DO PRIVATE(i,j) DEFAULT(NONE) SHARED(ng1, pw1, pw2)
638 : DO i = 1, ng1
639 : j = pw1%pw_grid%gidx(i)
640 : pw2%array(j) = ${type2type("pw1%array(i)", kind, kind2)}$
641 : END DO
642 : !$OMP END PARALLEL DO
643 : END IF
644 : ELSE
645 : #:if kind=='c1d' and kind2=='c1d' and space=="gs"
646 2 : CALL pw_copy_match(pw1, pw2)
647 : #:else
648 0 : CPABORT("Copy not implemented!")
649 : #:endif
650 : END IF
651 :
652 : END IF
653 :
654 : ELSE
655 1700551 : !$OMP PARALLEL WORKSHARE PRIVATE(i) DEFAULT(NONE) SHARED(pw1, pw2)
656 : pw2%array = ${type2type("pw1%array", kind, kind2)}$
657 : !$OMP END PARALLEL WORKSHARE
658 : END IF
659 : #:else
660 2446868 : IF (ANY(SHAPE(pw2%array) /= SHAPE(pw1%array))) &
661 0 : CPABORT("3D grids must be compatible!")
662 611717 : IF (pw1%pw_grid%spherical) &
663 0 : CPABORT("3D grids must not be spherical!")
664 611717 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw1,pw2)
665 : pw2%array(:, :, :) = ${type2type("pw1%array(:, :, :)", kind, kind2)}$
666 : !$OMP END PARALLEL WORKSHARE
667 : #:endif
668 :
669 2964594 : CALL timestop(handle)
670 :
671 2964594 : END SUBROUTINE pw_copy_${kind}$_${kind2}$_${space}$
672 :
673 : ! **************************************************************************************************
674 : !> \brief ...
675 : !> \param pw ...
676 : !> \param array ...
677 : ! **************************************************************************************************
678 1577233 : SUBROUTINE pw_copy_to_array_${kind}$_${kind2}$_${space}$ (pw, array)
679 : TYPE(pw_${kind}$_${space}$_type), INTENT(IN) :: pw
680 : ${type2}$, INTENT(INOUT) :: array
681 :
682 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_copy_to_array'
683 :
684 : INTEGER :: handle
685 :
686 1577233 : CALL timeset(routineN, handle)
687 :
688 : #:if kind[1]=="1"
689 0 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw, array)
690 : array(:) = ${type2type("pw%array(:)", kind, kind2)}$
691 : !$OMP END PARALLEL WORKSHARE
692 : #:else
693 1577233 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw, array)
694 : array(:, :, :) = ${type2type("pw%array(:, :, :)", kind, kind2)}$
695 : !$OMP END PARALLEL WORKSHARE
696 : #:endif
697 :
698 1577233 : CALL timestop(handle)
699 1577233 : END SUBROUTINE pw_copy_to_array_${kind}$_${kind2}$_${space}$
700 :
701 : ! **************************************************************************************************
702 : !> \brief ...
703 : !> \param pw ...
704 : !> \param array ...
705 : ! **************************************************************************************************
706 1626556 : SUBROUTINE pw_copy_from_array_${kind}$_${kind2}$_${space}$ (pw, array)
707 : TYPE(pw_${kind}$_${space}$_type), INTENT(IN) :: pw
708 : ${type2}$, INTENT(IN) :: array
709 :
710 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_copy_from_array'
711 :
712 : INTEGER :: handle
713 :
714 1626556 : CALL timeset(routineN, handle)
715 :
716 1626556 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw, array)
717 : pw%array = ${type2type("array", kind2, kind)}$
718 : !$OMP END PARALLEL WORKSHARE
719 :
720 1626556 : CALL timestop(handle)
721 1626556 : END SUBROUTINE pw_copy_from_array_${kind}$_${kind2}$_${space}$
722 :
723 : ! **************************************************************************************************
724 : !> \brief pw2 = alpha*pw1 + beta*pw2
725 : !> alpha defaults to 1, beta defaults to 1
726 : !> \param pw1 ...
727 : !> \param pw2 ...
728 : !> \param alpha ...
729 : !> \param beta ...
730 : !> \param allow_noncompatible_grids ...
731 : !> \par History
732 : !> JGH (21-Feb-2003) : added reference grid functionality
733 : !> JGH (01-Dec-2007) : rename and remove complex alpha
734 : !> \author apsi
735 : !> \note
736 : !> Currently only summing up of respective types allowed,
737 : !> in order to avoid errors
738 : ! **************************************************************************************************
739 1861964 : SUBROUTINE pw_axpy_${kind}$_${kind2}$_${space}$ (pw1, pw2, alpha, beta, allow_noncompatible_grids)
740 :
741 : TYPE(pw_${kind}$_${space}$_type), INTENT(IN) :: pw1
742 : TYPE(pw_${kind2}$_${space}$_type), INTENT(INOUT) :: pw2
743 : REAL(KIND=dp), INTENT(in), OPTIONAL :: alpha, beta
744 : LOGICAL, INTENT(IN), OPTIONAL :: allow_noncompatible_grids
745 :
746 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_axpy'
747 :
748 : INTEGER :: handle
749 : LOGICAL :: my_allow_noncompatible_grids
750 : REAL(KIND=dp) :: my_alpha, my_beta
751 : #:if kind[1]=='1'
752 : INTEGER :: i, j, ng, ng1, ng2
753 : #:endif
754 :
755 1861964 : CALL timeset(routineN, handle)
756 :
757 1861964 : my_alpha = 1.0_dp
758 1861964 : IF (PRESENT(alpha)) my_alpha = alpha
759 :
760 1861964 : my_beta = 1.0_dp
761 1861964 : IF (PRESENT(beta)) my_beta = beta
762 :
763 1861964 : my_allow_noncompatible_grids = .FALSE.
764 1861964 : IF (PRESENT(allow_noncompatible_grids)) my_allow_noncompatible_grids = allow_noncompatible_grids
765 :
766 1861964 : IF (my_beta /= 1.0_dp) THEN
767 95005 : IF (my_beta == 0.0_dp) THEN
768 1524 : CALL pw_zero(pw2)
769 : ELSE
770 93481 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw2,my_beta)
771 : pw2%array = pw2%array*my_beta
772 : !$OMP END PARALLEL WORKSHARE
773 : END IF
774 : END IF
775 :
776 : #:if kind[1]=='1'
777 1359336 : IF (ASSOCIATED(pw1%pw_grid, pw2%pw_grid)) THEN
778 :
779 640796 : IF (my_alpha == 1.0_dp) THEN
780 622700 : !$OMP PARALLEL WORKSHARE PRIVATE(i) DEFAULT(NONE) SHARED(pw1, pw2)
781 : pw2%array = pw2%array + ${type2type("pw1%array", kind, kind2)}$
782 : !$OMP END PARALLEL WORKSHARE
783 18096 : ELSE IF (my_alpha /= 0.0_dp) THEN
784 18096 : !$OMP PARALLEL WORKSHARE PRIVATE(i) DEFAULT(NONE) SHARED(pw2,pw1,my_alpha)
785 : pw2%array = pw2%array + my_alpha*${type2type("pw1%array", kind, kind2)}$
786 : !$OMP END PARALLEL WORKSHARE
787 : END IF
788 :
789 718540 : ELSE IF (pw_compatible(pw1%pw_grid, pw2%pw_grid) .OR. my_allow_noncompatible_grids) THEN
790 :
791 718540 : ng1 = SIZE(pw1%array)
792 718540 : ng2 = SIZE(pw2%array)
793 718540 : ng = MIN(ng1, ng2)
794 :
795 718540 : IF (pw1%pw_grid%spherical) THEN
796 0 : IF (my_alpha == 1.0_dp) THEN
797 0 : !$OMP PARALLEL DO PRIVATE(i) DEFAULT(NONE) SHARED(ng, pw1, pw2)
798 : DO i = 1, ng
799 : pw2%array(i) = pw2%array(i) + ${type2type("pw1%array(i)", kind, kind2)}$
800 : END DO
801 : !$OMP END PARALLEL DO
802 0 : ELSE IF (my_alpha /= 0.0_dp) THEN
803 0 : !$OMP PARALLEL DO PRIVATE(i) DEFAULT(NONE) SHARED(pw2,pw1,my_alpha,ng)
804 : DO i = 1, ng
805 : pw2%array(i) = pw2%array(i) + my_alpha*${type2type("pw1%array(i)", kind, kind2)}$
806 : END DO
807 : !$OMP END PARALLEL DO
808 : END IF
809 718540 : ELSE IF ((pw1%pw_grid%id_nr == pw2%pw_grid%reference)) THEN
810 1098 : IF (ng1 >= ng2) THEN
811 1098 : IF (my_alpha == 1.0_dp) THEN
812 1098 : !$OMP PARALLEL DO PRIVATE(i,j) DEFAULT(NONE) SHARED(ng, pw1, pw2)
813 : DO i = 1, ng
814 : j = pw2%pw_grid%gidx(i)
815 : pw2%array(i) = pw2%array(i) + ${type2type("pw1%array(j)", kind, kind2)}$
816 : END DO
817 : !$OMP END PARALLEL DO
818 0 : ELSE IF (my_alpha /= 0.0_dp) THEN
819 0 : !$OMP PARALLEL DO PRIVATE(i,j) DEFAULT(NONE) SHARED(my_alpha, ng, pw1, pw2)
820 : DO i = 1, ng
821 : j = pw2%pw_grid%gidx(i)
822 : pw2%array(i) = pw2%array(i) + my_alpha*${type2type("pw1%array(j)", kind, kind2)}$
823 : END DO
824 : !$OMP END PARALLEL DO
825 : END IF
826 : ELSE
827 0 : IF (my_alpha == 1.0_dp) THEN
828 0 : !$OMP PARALLEL DO PRIVATE(i,j) DEFAULT(NONE) SHARED(ng, pw1, pw2)
829 : DO i = 1, ng
830 : j = pw2%pw_grid%gidx(i)
831 : pw2%array(j) = pw2%array(j) + ${type2type("pw1%array(i)", kind, kind2)}$
832 : END DO
833 : !$OMP END PARALLEL DO
834 0 : ELSE IF (my_alpha /= 0.0_dp) THEN
835 0 : !$OMP PARALLEL DO PRIVATE(i,j) DEFAULT(NONE) SHARED(my_alpha, ng, pw1, pw2)
836 : DO i = 1, ng
837 : j = pw2%pw_grid%gidx(i)
838 : pw2%array(j) = pw2%array(j) + my_alpha*${type2type("pw1%array(i)", kind, kind2)}$
839 : END DO
840 : !$OMP END PARALLEL DO
841 : END IF
842 : END IF
843 717442 : ELSE IF ((pw2%pw_grid%id_nr == pw1%pw_grid%reference)) THEN
844 717442 : IF (ng1 >= ng2) THEN
845 0 : IF (my_alpha == 1.0_dp) THEN
846 0 : !$OMP PARALLEL DO PRIVATE(i,j) DEFAULT(NONE) SHARED(ng, pw1, pw2)
847 : DO i = 1, ng
848 : j = pw1%pw_grid%gidx(i)
849 : pw2%array(i) = pw2%array(i) + ${type2type("pw1%array(j)", kind, kind2)}$
850 : END DO
851 : !$OMP END PARALLEL DO
852 0 : ELSE IF (my_alpha /= 0.0_dp) THEN
853 0 : !$OMP PARALLEL DO PRIVATE(i,j) DEFAULT(NONE) SHARED(my_alpha, ng, pw1, pw2)
854 : DO i = 1, ng
855 : j = pw1%pw_grid%gidx(i)
856 : pw2%array(i) = pw2%array(i) + my_alpha*${type2type("pw1%array(j)", kind, kind2)}$
857 : END DO
858 : !$OMP END PARALLEL DO
859 : END IF
860 : ELSE
861 717442 : IF (my_alpha == 1.0_dp) THEN
862 717442 : !$OMP PARALLEL DO PRIVATE(i,j) DEFAULT(NONE) SHARED(ng, pw1, pw2)
863 : DO i = 1, ng
864 : j = pw1%pw_grid%gidx(i)
865 : pw2%array(j) = pw2%array(j) + ${type2type("pw1%array(i)", kind, kind2)}$
866 : END DO
867 : !$OMP END PARALLEL DO
868 0 : ELSE IF (my_alpha /= 0.0_dp) THEN
869 0 : !$OMP PARALLEL DO PRIVATE(i,j) DEFAULT(NONE) SHARED(my_alpha, ng, pw1, pw2)
870 : DO i = 1, ng
871 : j = pw1%pw_grid%gidx(i)
872 : pw2%array(j) = pw2%array(j) + my_alpha*${type2type("pw1%array(i)", kind, kind2)}$
873 : END DO
874 : !$OMP END PARALLEL DO
875 : END IF
876 : END IF
877 : ELSE
878 0 : CPABORT("Grids not compatible")
879 : END IF
880 : #:else
881 502628 : IF (ASSOCIATED(pw1%pw_grid, pw2%pw_grid)) THEN
882 502098 : IF (my_alpha == 1.0_dp) THEN
883 289616 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw1, pw2)
884 : pw2%array = pw2%array + ${type2type("pw1%array", kind, kind2)}$
885 : !$OMP END PARALLEL WORKSHARE
886 212482 : ELSE IF (my_alpha /= 0.0_dp) THEN
887 211048 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw1, pw2, my_alpha)
888 : pw2%array = pw2%array + my_alpha*${type2type("pw1%array", kind, kind2)}$
889 : !$OMP END PARALLEL WORKSHARE
890 : END IF
891 :
892 530 : ELSE IF (pw_compatible(pw1%pw_grid, pw2%pw_grid) .OR. my_allow_noncompatible_grids) THEN
893 :
894 2120 : IF (ANY(SHAPE(pw1%array) /= SHAPE(pw2%array))) &
895 0 : CPABORT("Noncommensurate grids not implemented for 3D grids!")
896 :
897 530 : IF (my_alpha == 1.0_dp) THEN
898 444 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw1,pw2)
899 : pw2%array = pw2%array + ${type2type("pw1%array", kind, kind2)}$
900 : !$OMP END PARALLEL WORKSHARE
901 : ELSE
902 86 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw1,pw2,my_alpha)
903 : pw2%array = pw2%array + my_alpha*${type2type("pw1%array", kind, kind2)}$
904 : !$OMP END PARALLEL WORKSHARE
905 : END IF
906 : #:endif
907 :
908 : ELSE
909 :
910 0 : CPABORT("Grids not compatible")
911 :
912 : END IF
913 :
914 1861964 : CALL timestop(handle)
915 :
916 1861964 : END SUBROUTINE pw_axpy_${kind}$_${kind2}$_${space}$
917 :
918 : ! **************************************************************************************************
919 : !> \brief pw_out = pw_out + alpha * pw1 * pw2
920 : !> alpha defaults to 1
921 : !> \param pw_out ...
922 : !> \param pw1 ...
923 : !> \param pw2 ...
924 : !> \param alpha ...
925 : !> \author JGH
926 : ! **************************************************************************************************
927 3961 : SUBROUTINE pw_multiply_${kind}$_${kind2}$_${space}$ (pw_out, pw1, pw2, alpha)
928 :
929 : TYPE(pw_${kind}$_${space}$_type), INTENT(INOUT) :: pw_out
930 : TYPE(pw_${kind}$_${space}$_type), INTENT(IN) :: pw1
931 : TYPE(pw_${kind2}$_${space}$_type), INTENT(IN) :: pw2
932 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: alpha
933 :
934 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_multiply'
935 :
936 : INTEGER :: handle
937 : REAL(KIND=dp) :: my_alpha
938 :
939 3961 : CALL timeset(routineN, handle)
940 :
941 3961 : my_alpha = 1.0_dp
942 3961 : IF (PRESENT(alpha)) my_alpha = alpha
943 :
944 7922 : IF (.NOT. ASSOCIATED(pw_out%pw_grid, pw1%pw_grid) .OR. .NOT. ASSOCIATED(pw_out%pw_grid, pw2%pw_grid)) &
945 0 : CPABORT("pw_multiply not implemented for non-identical grids!")
946 :
947 3961 : IF (my_alpha == 1.0_dp) THEN
948 3897 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw_out, pw1, pw2)
949 : pw_out%array = pw_out%array + pw1%array*${type2type("pw2%array", kind2, kind)}$
950 : !$OMP END PARALLEL WORKSHARE
951 : ELSE
952 64 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(my_alpha, pw_out, pw1, pw2)
953 : pw_out%array = pw_out%array + my_alpha*pw1%array*${type2type("pw2%array", kind2, kind)}$
954 : !$OMP END PARALLEL WORKSHARE
955 : END IF
956 :
957 3961 : CALL timestop(handle)
958 :
959 3961 : END SUBROUTINE pw_multiply_${kind}$_${kind2}$_${space}$
960 :
961 : ! **************************************************************************************************
962 : !> \brief ...
963 : !> \param pw1 ...
964 : !> \param pw2 ...
965 : ! **************************************************************************************************
966 385242 : SUBROUTINE pw_multiply_with_${kind}$_${kind2}$_${space}$ (pw1, pw2)
967 : TYPE(pw_${kind}$_${space}$_type), INTENT(INOUT) :: pw1
968 : TYPE(pw_${kind2}$_${space}$_type), INTENT(IN) :: pw2
969 :
970 : CHARACTER(LEN=*), PARAMETER :: routineN = 'pw_multiply_with'
971 :
972 : INTEGER :: handle
973 :
974 385242 : CALL timeset(routineN, handle)
975 :
976 385242 : IF (.NOT. ASSOCIATED(pw1%pw_grid, pw2%pw_grid)) &
977 0 : CPABORT("Incompatible grids!")
978 :
979 385242 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw1,pw2)
980 : pw1%array = pw1%array*${type2type("pw2%array", kind2, kind)}$
981 : !$OMP END PARALLEL WORKSHARE
982 :
983 385242 : CALL timestop(handle)
984 :
985 385242 : END SUBROUTINE pw_multiply_with_${kind}$_${kind2}$_${space}$
986 :
987 : ! **************************************************************************************************
988 : !> \brief Calculate integral over unit cell for functions in plane wave basis
989 : !> only returns the real part of it ......
990 : !> \param pw1 ...
991 : !> \param pw2 ...
992 : !> \param sumtype ...
993 : !> \param just_sum ...
994 : !> \param local_only ...
995 : !> \return ...
996 : !> \par History
997 : !> JGH (14-Mar-2001) : Parallel sum and some tests, HALFSPACE case
998 : !> \author apsi
999 : ! **************************************************************************************************
1000 699219 : FUNCTION pw_integral_ab_${kind}$_${kind2}$_${space}$ (pw1, pw2, sumtype, just_sum, local_only) RESULT(integral_value)
1001 :
1002 : TYPE(pw_${kind}$_${space}$_type), INTENT(IN) :: pw1
1003 : TYPE(pw_${kind2}$_${space}$_type), INTENT(IN) :: pw2
1004 : INTEGER, INTENT(IN), OPTIONAL :: sumtype
1005 : LOGICAL, INTENT(IN), OPTIONAL :: just_sum, local_only
1006 : REAL(KIND=dp) :: integral_value
1007 :
1008 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_integral_ab'
1009 :
1010 : INTEGER :: handle, loc_sumtype
1011 : LOGICAL :: my_just_sum, my_local_only
1012 :
1013 699219 : CALL timeset(routineN, handle)
1014 :
1015 699219 : loc_sumtype = do_accurate_sum
1016 699219 : IF (PRESENT(sumtype)) loc_sumtype = sumtype
1017 :
1018 699219 : my_local_only = .FALSE.
1019 699219 : IF (PRESENT(local_only)) my_local_only = local_only
1020 :
1021 699219 : IF (.NOT. ASSOCIATED(pw1%pw_grid, pw2%pw_grid)) THEN
1022 0 : CPABORT("Grids incompatible")
1023 : END IF
1024 :
1025 699219 : my_just_sum = .FALSE.
1026 699219 : IF (PRESENT(just_sum)) my_just_sum = just_sum
1027 :
1028 : ! do standard sum
1029 699219 : IF (loc_sumtype == do_standard_sum) THEN
1030 :
1031 : ! Do standard sum
1032 :
1033 : #:if kind=="r1d" and kind2=="r1d"
1034 0 : integral_value = DOT_PRODUCT(pw1%array, pw2%array)
1035 : #:elif kind=="r3d" and kind2=="r3d"
1036 1060137716 : integral_value = SUM(pw1%array*pw2%array)
1037 : #:elif kind[0]=="r"
1038 0 : integral_value = SUM(pw1%array*REAL(pw2%array, KIND=dp)) !? complex bit
1039 : #:elif kind2[0]=="r"
1040 0 : integral_value = SUM(REAL(pw1%array, KIND=dp)*pw2%array) !? complex bit
1041 : #:else
1042 : integral_value = SUM(REAL(CONJG(pw1%array) &
1043 0 : *pw2%array, KIND=dp)) !? complex bit
1044 : #:endif
1045 :
1046 : ELSE
1047 :
1048 : ! Do accurate sum
1049 : #:if kind[0]=="r" and kind2[0]=="r"
1050 54738 : integral_value = accurate_dot_product(pw1%array, pw2%array)
1051 : #:elif kind[0]=="r"
1052 0 : integral_value = accurate_sum(pw1%array*REAL(pw2%array, KIND=dp)) !? complex bit
1053 : #:elif kind2[0]=="r"
1054 0 : integral_value = accurate_sum(REAL(pw1%array, KIND=dp)*pw2%array) !? complex bit
1055 : #:else
1056 : integral_value = accurate_sum(REAL(CONJG(pw1%array) &
1057 8772065534 : *pw2%array, KIND=dp)) !? complex bit
1058 : #:endif
1059 :
1060 : END IF
1061 :
1062 699219 : IF (.NOT. my_just_sum) THEN
1063 : #:if space == "rs"
1064 306194 : integral_value = integral_value*pw1%pw_grid%dvol
1065 : #:elif space == "gs"
1066 392927 : integral_value = integral_value*pw1%pw_grid%vol
1067 : #:else
1068 : #:stop "Unknown space: "+space
1069 : #:endif
1070 : END IF
1071 :
1072 : #:if kind[1]=="1"
1073 392927 : IF (pw1%pw_grid%grid_span == HALFSPACE) THEN
1074 236744 : integral_value = 2.0_dp*integral_value
1075 236744 : IF (pw1%pw_grid%have_g0) integral_value = integral_value - &
1076 : #:if kind[0]=="c"
1077 128781 : REAL(CONJG(pw1%array(1))*pw2%array(1), KIND=dp)
1078 : #:elif kind2[0]=="r"
1079 0 : pw1%array(1)*pw2%array(1)
1080 : #:else
1081 0 : pw1%array(1)*REAL(pw2%array(1), KIND=dp)
1082 : #:endif
1083 : END IF
1084 : #:endif
1085 :
1086 699219 : IF (.NOT. my_local_only .AND. pw1%pw_grid%para%mode == PW_MODE_DISTRIBUTED) &
1087 382326 : CALL pw1%pw_grid%para%group%sum(integral_value)
1088 :
1089 699219 : CALL timestop(handle)
1090 :
1091 699219 : END FUNCTION pw_integral_ab_${kind}$_${kind2}$_${space}$
1092 : #:endfor
1093 :
1094 : #:if kind[1]=="1"
1095 : ! **************************************************************************************************
1096 : !> \brief ...
1097 : !> \param pw1 ...
1098 : !> \param pw2 ...
1099 : !> \return ...
1100 : ! **************************************************************************************************
1101 82848 : FUNCTION pw_integral_a2b_${kind}$_${kind2}$ (pw1, pw2) RESULT(integral_value)
1102 :
1103 : TYPE(pw_${kind}$_gs_type), INTENT(IN) :: pw1
1104 : TYPE(pw_${kind2}$_gs_type), INTENT(IN) :: pw2
1105 : REAL(KIND=dp) :: integral_value
1106 :
1107 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_integral_a2b'
1108 :
1109 : INTEGER :: handle
1110 :
1111 82848 : CALL timeset(routineN, handle)
1112 :
1113 82848 : IF (.NOT. ASSOCIATED(pw1%pw_grid, pw2%pw_grid)) THEN
1114 0 : CPABORT("Grids incompatible")
1115 : END IF
1116 :
1117 : #:if kind[0]=="c"
1118 : #:if kind2[0]=="c"
1119 241222920 : integral_value = accurate_sum(REAL(CONJG(pw1%array)*pw2%array, KIND=dp)*pw1%pw_grid%gsq)
1120 : #:else
1121 0 : integral_value = accurate_sum(REAL(CONJG(pw1%array), KIND=dp)*pw2%array*pw1%pw_grid%gsq)
1122 : #:endif
1123 : #:elif kind2[0]=="c"
1124 0 : integral_value = accurate_sum(pw1%array*REAL(pw2%array, KIND=dp)*pw1%pw_grid%gsq)
1125 : #:else
1126 0 : integral_value = accurate_sum(pw1%array*pw2%array*pw1%pw_grid%gsq)
1127 : #:endif
1128 82848 : IF (pw1%pw_grid%grid_span == HALFSPACE) THEN
1129 82848 : integral_value = 2.0_dp*integral_value
1130 : END IF
1131 :
1132 82848 : integral_value = integral_value*pw1%pw_grid%vol
1133 :
1134 82848 : IF (pw1%pw_grid%para%mode == PW_MODE_DISTRIBUTED) &
1135 78120 : CALL pw1%pw_grid%para%group%sum(integral_value)
1136 82848 : CALL timestop(handle)
1137 :
1138 82848 : END FUNCTION pw_integral_a2b_${kind}$_${kind2}$
1139 : #:endif
1140 : #:endfor
1141 :
1142 : #:for kind, type, kind2, type2 in pw_list2
1143 : #:for space in pw_spaces
1144 : #:for space2 in pw_spaces
1145 :
1146 : #:if space != space2 and ((space=="rs" and kind[1]=="3" and kind2[0]=="c") or (space=="gs" and kind2[1]=="3" and kind[0]=="c"))
1147 : ! **************************************************************************************************
1148 : !> \brief Generic function for 3d FFT of a coefficient_type or pw_r3d_rs_type
1149 : !> \param pw1 ...
1150 : !> \param pw2 ...
1151 : !> \param debug ...
1152 : !> \par History
1153 : !> JGH (30-12-2000): New setup of functions and adaptation to parallelism
1154 : !> JGH (04-01-2001): Moved routine from pws to this module, only covers
1155 : !> pw_types, no more coefficient types
1156 : !> \author apsi
1157 : !> \note
1158 : !> fft_wrap_pw1pw2
1159 : ! **************************************************************************************************
1160 3204861 : SUBROUTINE fft_wrap_pw1pw2_${kind}$_${kind2}$_${space}$_${space2}$ (pw1, pw2, debug)
1161 :
1162 : TYPE(pw_${kind}$_${space}$_type), INTENT(IN) :: pw1
1163 : TYPE(pw_${kind2}$_${space2}$_type), INTENT(INOUT) :: pw2
1164 : LOGICAL, INTENT(IN), OPTIONAL :: debug
1165 :
1166 : CHARACTER(len=*), PARAMETER :: routineN = 'fft_wrap_pw1pw2'
1167 :
1168 3204861 : COMPLEX(KIND=dp), DIMENSION(:, :), CONTIGUOUS, POINTER :: grays
1169 3204861 : COMPLEX(KIND=dp), DIMENSION(:, :, :), CONTIGUOUS, POINTER :: c_in, c_out
1170 : INTEGER :: handle, handle2, my_pos, nrays, &
1171 : out_unit
1172 : #:if (space=="rs" and kind=="r3d" and kind2=="c1d") or (space=="gs" and kind=="c1d" and kind2=="r3d")
1173 : INTEGER, DIMENSION(3) :: nloc
1174 : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
1175 : LOGICAL :: use_pw_gpu
1176 : #endif
1177 : #:endif
1178 3204861 : INTEGER, DIMENSION(:), POINTER :: n
1179 : LOGICAL :: test
1180 :
1181 3204861 : CALL timeset(routineN, handle2)
1182 3204861 : out_unit = cp_logger_get_default_io_unit()
1183 : CALL timeset(routineN//"_"//TRIM(ADJUSTL(cp_to_string( &
1184 3204861 : CEILING(pw1%pw_grid%cutoff/10)*10))), handle)
1185 :
1186 3204861 : NULLIFY (c_in)
1187 3204861 : NULLIFY (c_out)
1188 :
1189 3204861 : IF (PRESENT(debug)) THEN
1190 1072 : test = debug
1191 : ELSE
1192 3203789 : test = .FALSE.
1193 : END IF
1194 :
1195 : !..check if grids are compatible
1196 3204861 : IF (.NOT. ASSOCIATED(pw1%pw_grid, pw2%pw_grid)) THEN
1197 0 : IF (pw1%pw_grid%dvol /= pw2%pw_grid%dvol) THEN
1198 0 : CPABORT("PW grids not compatible")
1199 : END IF
1200 0 : IF (pw1%pw_grid%para%group /= pw2%pw_grid%para%group) THEN
1201 0 : CPABORT("PW grids have not compatible MPI groups")
1202 : END IF
1203 : END IF
1204 :
1205 3204861 : n => pw1%pw_grid%npts
1206 :
1207 3204861 : IF (pw1%pw_grid%para%mode == PW_MODE_LOCAL) THEN
1208 :
1209 : !
1210 : !..replicated data, use local FFT
1211 : !
1212 :
1213 583229 : IF (test .AND. out_unit > 0) THEN
1214 0 : WRITE (out_unit, '(A)') " FFT Protocol "
1215 : #:if space=="rs"
1216 0 : WRITE (out_unit, '(A,T76,A)') " Transform direction ", "FWFFT"
1217 0 : WRITE (out_unit, '(A,T72,A)') " in space ", "REALSPACE"
1218 0 : WRITE (out_unit, '(A,T72,A)') " out space ", "REALSPACE"
1219 : #:else
1220 0 : WRITE (out_unit, '(A,T76,A)') " Transform direction ", "BWFFT"
1221 0 : WRITE (out_unit, '(A,T66,A)') " in space ", "RECIPROCALSPACE"
1222 0 : WRITE (out_unit, '(A,T66,A)') " out space ", "RECIPROCALSPACE"
1223 : #:endif
1224 : END IF
1225 :
1226 : #:if space=="rs"
1227 : #:if kind==kind2=="c3d"
1228 0 : c_in => pw1%array
1229 0 : c_out => pw2%array
1230 0 : CALL fft3d(FWFFT, n, c_in, c_out, debug=test)
1231 : #:elif kind=="r3d" and kind2=="c3d"
1232 0 : pw2%array = CMPLX(pw1%array, 0.0_dp, KIND=dp)
1233 0 : c_out => pw2%array
1234 0 : CALL fft3d(FWFFT, n, c_out, debug=test)
1235 : #:elif kind=="c3d" and kind2=="c1d"
1236 0 : c_in => pw1%array
1237 0 : ALLOCATE (c_out(n(1), n(2), n(3)))
1238 : ! transform
1239 0 : CALL fft3d(FWFFT, n, c_in, c_out, debug=test)
1240 : ! gather results
1241 0 : IF (test .AND. out_unit > 0) WRITE (out_unit, '(A)') " PW_GATHER : 3d -> 1d "
1242 0 : CALL pw_gather_s_${kind2}$_c3d(pw2, c_out)
1243 0 : DEALLOCATE (c_out)
1244 : #:elif kind=="r3d" and kind2=="c1d"
1245 : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
1246 : CALL pw_gpu_r3dc1d_3d(pw1, pw2)
1247 : #elif defined (__PW_FPGA)
1248 : ALLOCATE (c_out(n(1), n(2), n(3)))
1249 : ! check if bitstream for the fft size is present
1250 : ! if not, perform fft3d in CPU
1251 : IF (pw_fpga_init_bitstream(n) == 1) THEN
1252 : CALL pw_copy_to_array(pw1, c_out)
1253 : #if (__PW_FPGA_SP && __PW_FPGA)
1254 : CALL pw_fpga_r3dc1d_3d_sp(n, c_out)
1255 : #else
1256 : CALL pw_fpga_r3dc1d_3d_dp(n, c_out)
1257 : #endif
1258 : CALL zdscal(n(1)*n(2)*n(3), 1.0_dp/pw1%pw_grid%ngpts, c_out, 1)
1259 : CALL pw_gather_s_${kind2}$_c3d(pw2, c_out)
1260 : ELSE
1261 : CALL pw_copy_to_array(pw1, c_out)
1262 : CALL fft3d(FWFFT, n, c_out, debug=test)
1263 : CALL pw_gather_s_${kind2}$_c3d(pw2, c_out)
1264 : END IF
1265 : DEALLOCATE (c_out)
1266 : #else
1267 1418215 : ALLOCATE (c_out(n(1), n(2), n(3)))
1268 2622598750 : c_out = 0.0_dp
1269 283643 : CALL pw_copy_to_array(pw1, c_out)
1270 283643 : CALL fft3d(FWFFT, n, c_out, debug=test)
1271 283643 : CALL pw_gather_s_${kind2}$_c3d(pw2, c_out)
1272 283643 : DEALLOCATE (c_out)
1273 : #endif
1274 : #:endif
1275 : #:else
1276 : #:if kind=="c3d" and kind2=="c3d"
1277 0 : c_in => pw1%array
1278 0 : c_out => pw2%array
1279 0 : CALL fft3d(BWFFT, n, c_in, c_out, debug=test)
1280 : #:elif kind=="c3d" and kind2=="r3d"
1281 0 : c_in => pw1%array
1282 0 : ALLOCATE (c_out(n(1), n(2), n(3)))
1283 0 : CALL fft3d(BWFFT, n, c_in, c_out, debug=test)
1284 : ! use real part only
1285 0 : IF (test .AND. out_unit > 0) WRITE (out_unit, '(A)') " REAL part "
1286 0 : pw2%array = REAL(c_out, KIND=dp)
1287 0 : DEALLOCATE (c_out)
1288 : #:elif kind=="c1d" and kind2=="c3d"
1289 0 : c_out => pw2%array
1290 0 : IF (test .AND. out_unit > 0) WRITE (out_unit, '(A)') " PW_SCATTER : 3d -> 1d "
1291 0 : CALL pw_scatter_s_${kind}$_c3d(pw1, c_out)
1292 0 : CALL fft3d(BWFFT, n, c_out, debug=test)
1293 : #:elif kind=="c1d" and kind2=="r3d"
1294 : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
1295 : CALL pw_gpu_c1dr3d_3d(pw1, pw2)
1296 : #elif defined (__PW_FPGA)
1297 : ALLOCATE (c_out(n(1), n(2), n(3)))
1298 : ! check if bitstream for the fft size is present
1299 : ! if not, perform fft3d in CPU
1300 : IF (pw_fpga_init_bitstream(n) == 1) THEN
1301 : CALL pw_scatter_s_${kind}$_c3d(pw1, c_out)
1302 : ! transform using FPGA
1303 : #if (__PW_FPGA_SP && __PW_FPGA)
1304 : CALL pw_fpga_c1dr3d_3d_sp(n, c_out)
1305 : #else
1306 : CALL pw_fpga_c1dr3d_3d_dp(n, c_out)
1307 : #endif
1308 : CALL zdscal(n(1)*n(2)*n(3), 1.0_dp, c_out, 1)
1309 : ! use real part only
1310 : CALL pw_copy_from_array(pw2, c_out)
1311 : ELSE
1312 : IF (test .AND. out_unit > 0) WRITE (out_unit, '(A)') " PW_SCATTER : 3d -> 1d "
1313 : CALL pw_scatter_s_${kind}$_c3d(pw1, c_out)
1314 : ! transform
1315 : CALL fft3d(BWFFT, n, c_out, debug=test)
1316 : ! use real part only
1317 : IF (test .AND. out_unit > 0) WRITE (out_unit, '(A)') " REAL part "
1318 : CALL pw_copy_from_array(pw2, c_out)
1319 : END IF
1320 : DEALLOCATE (c_out)
1321 : #else
1322 1497930 : ALLOCATE (c_out(n(1), n(2), n(3)))
1323 299586 : IF (test .AND. out_unit > 0) WRITE (out_unit, '(A)') " PW_SCATTER : 3d -> 1d "
1324 299586 : CALL pw_scatter_s_${kind}$_c3d(pw1, c_out)
1325 : ! transform
1326 299586 : CALL fft3d(BWFFT, n, c_out, debug=test)
1327 : ! use real part only
1328 299586 : IF (test .AND. out_unit > 0) WRITE (out_unit, '(A)') " REAL part "
1329 299586 : CALL pw_copy_from_array(pw2, c_out)
1330 299586 : DEALLOCATE (c_out)
1331 : #endif
1332 : #:endif
1333 : #:endif
1334 :
1335 583229 : IF (test .AND. out_unit > 0) WRITE (out_unit, '(A)') " End of FFT Protocol "
1336 :
1337 : ELSE
1338 :
1339 : !
1340 : !..parallel FFT
1341 : !
1342 :
1343 2621632 : IF (test .AND. out_unit > 0) THEN
1344 8 : WRITE (out_unit, '(A)') " FFT Protocol "
1345 : #:if space=="rs"
1346 4 : WRITE (out_unit, '(A,T76,A)') " Transform direction ", "FWFFT"
1347 4 : WRITE (out_unit, '(A,T72,A)') " in space ", "REALSPACE"
1348 4 : WRITE (out_unit, '(A,T72,A)') " out space ", "REALSPACE"
1349 : #:else
1350 4 : WRITE (out_unit, '(A,T76,A)') " Transform direction ", "BWFFT"
1351 4 : WRITE (out_unit, '(A,T66,A)') " in space ", "RECIPROCALSPACE"
1352 4 : WRITE (out_unit, '(A,T66,A)') " out space ", "RECIPROCALSPACE"
1353 : #:endif
1354 : END IF
1355 :
1356 2621632 : my_pos = pw1%pw_grid%para%group%mepos
1357 2621632 : nrays = pw1%pw_grid%para%nyzray(my_pos)
1358 2621632 : grays => pw1%pw_grid%grays
1359 :
1360 : #:if space=="rs"
1361 : #:if kind=="c3d" and kind2=="c1d"
1362 : !..prepare input
1363 536 : c_in => pw1%array
1364 1918288 : grays = z_zero
1365 : !..transform
1366 536 : IF (pw1%pw_grid%para%ray_distribution) THEN
1367 : CALL fft3d(FWFFT, n, c_in, grays, pw1%pw_grid%para%group, &
1368 : pw1%pw_grid%para%yzp, pw1%pw_grid%para%nyzray, &
1369 432 : pw1%pw_grid%para%bo, debug=test)
1370 : ELSE
1371 : CALL fft3d(FWFFT, n, c_in, grays, pw1%pw_grid%para%group, &
1372 104 : pw1%pw_grid%para%bo, debug=test)
1373 : END IF
1374 : !..prepare output
1375 536 : IF (test .AND. out_unit > 0) &
1376 4 : WRITE (out_unit, '(A)') " PW_GATHER : 2d -> 1d "
1377 536 : CALL pw_gather_p_${kind2}$ (pw2, grays)
1378 : #:elif kind=="r3d" and kind2=="c1d"
1379 : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
1380 : ! (no ray dist. is not efficient in CUDA)
1381 : use_pw_gpu = pw1%pw_grid%para%ray_distribution
1382 : IF (use_pw_gpu) THEN
1383 : CALL pw_gpu_r3dc1d_3d_ps(pw1, pw2)
1384 : ELSE
1385 : #endif
1386 : !.. prepare input
1387 5174360 : nloc = pw1%pw_grid%npts_local
1388 6467950 : ALLOCATE (c_in(nloc(1), nloc(2), nloc(3)))
1389 1293590 : CALL pw_copy_to_array(pw1, c_in)
1390 37308218805 : grays = z_zero
1391 : !..transform
1392 1293590 : IF (pw1%pw_grid%para%ray_distribution) THEN
1393 : CALL fft3d(FWFFT, n, c_in, grays, pw1%pw_grid%para%group, &
1394 : pw1%pw_grid%para%yzp, pw1%pw_grid%para%nyzray, &
1395 1293590 : pw1%pw_grid%para%bo, debug=test)
1396 : ELSE
1397 : CALL fft3d(FWFFT, n, c_in, grays, pw1%pw_grid%para%group, &
1398 0 : pw1%pw_grid%para%bo, debug=test)
1399 : END IF
1400 : !..prepare output
1401 1293590 : IF (test .AND. out_unit > 0) &
1402 0 : WRITE (out_unit, '(A)') " PW_GATHER : 2d -> 1d "
1403 1293590 : CALL pw_gather_p_${kind2}$ (pw2, grays)
1404 1293590 : DEALLOCATE (c_in)
1405 :
1406 : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
1407 : END IF
1408 : #endif
1409 : #:endif
1410 : #:else
1411 : #:if kind=="c1d" and kind2=="c3d"
1412 : !..prepare input
1413 536 : IF (test .AND. out_unit > 0) &
1414 4 : WRITE (out_unit, '(A)') " PW_SCATTER : 2d -> 1d "
1415 1918288 : grays = z_zero
1416 536 : CALL pw_scatter_p_${kind}$ (pw1, grays)
1417 536 : c_in => pw2%array
1418 : !..transform
1419 536 : IF (pw1%pw_grid%para%ray_distribution) THEN
1420 : CALL fft3d(BWFFT, n, c_in, grays, pw1%pw_grid%para%group, &
1421 : pw1%pw_grid%para%yzp, pw1%pw_grid%para%nyzray, &
1422 432 : pw1%pw_grid%para%bo, debug=test)
1423 : ELSE
1424 : CALL fft3d(BWFFT, n, c_in, grays, pw1%pw_grid%para%group, &
1425 104 : pw1%pw_grid%para%bo, debug=test)
1426 : END IF
1427 : !..prepare output (nothing to do)
1428 : #:elif kind=="c1d" and kind2=="r3d"
1429 : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
1430 : ! (no ray dist. is not efficient in CUDA)
1431 : use_pw_gpu = pw1%pw_grid%para%ray_distribution
1432 : IF (use_pw_gpu) THEN
1433 : CALL pw_gpu_c1dr3d_3d_ps(pw1, pw2)
1434 : ELSE
1435 : #endif
1436 : !.. prepare input
1437 1326970 : IF (test .AND. out_unit > 0) &
1438 0 : WRITE (out_unit, '(A)') " PW_SCATTER : 2d -> 1d "
1439 41394722552 : grays = z_zero
1440 1326970 : CALL pw_scatter_p_${kind}$ (pw1, grays)
1441 5307880 : nloc = pw2%pw_grid%npts_local
1442 6634850 : ALLOCATE (c_in(nloc(1), nloc(2), nloc(3)))
1443 : !..transform
1444 1326970 : IF (pw1%pw_grid%para%ray_distribution) THEN
1445 : CALL fft3d(BWFFT, n, c_in, grays, pw1%pw_grid%para%group, &
1446 : pw1%pw_grid%para%yzp, pw1%pw_grid%para%nyzray, &
1447 1326970 : pw1%pw_grid%para%bo, debug=test)
1448 : ELSE
1449 : CALL fft3d(BWFFT, n, c_in, grays, pw1%pw_grid%para%group, &
1450 0 : pw1%pw_grid%para%bo, debug=test)
1451 : END IF
1452 : !..prepare output
1453 1326970 : IF (test .AND. out_unit > 0) &
1454 0 : WRITE (out_unit, '(A)') " Real part "
1455 1326970 : CALL pw_copy_from_array(pw2, c_in)
1456 1326970 : DEALLOCATE (c_in)
1457 : #if defined(__OFFLOAD) && !defined(__NO_OFFLOAD_PW)
1458 : END IF
1459 : #endif
1460 : #:endif
1461 : #:endif
1462 : END IF
1463 :
1464 3204861 : IF (test .AND. out_unit > 0) THEN
1465 8 : WRITE (out_unit, '(A)') " End of FFT Protocol "
1466 : END IF
1467 :
1468 3204861 : CALL timestop(handle)
1469 3204861 : CALL timestop(handle2)
1470 :
1471 3204861 : END SUBROUTINE fft_wrap_pw1pw2_${kind}$_${kind2}$_${space}$_${space2}$
1472 : #:endif
1473 : #:endfor
1474 : #:endfor
1475 :
1476 : #:if kind[1]=='1' and kind2[1]=='3'
1477 :
1478 : ! **************************************************************************************************
1479 : !> \brief Gathers the pw vector from a 3d data field
1480 : !> \param pw ...
1481 : !> \param c ...
1482 : !> \param scale ...
1483 : !> \par History
1484 : !> none
1485 : !> \author JGH
1486 : ! **************************************************************************************************
1487 0 : SUBROUTINE pw_gather_s_${kind}$_${kind2}$_2(pw1, pw2, scale)
1488 :
1489 : TYPE(pw_${kind2}$_gs_type), INTENT(IN) :: pw1
1490 : TYPE(pw_${kind}$_gs_type), INTENT(INOUT) :: pw2
1491 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: scale
1492 :
1493 0 : CALL pw_gather_s_${kind}$_${kind2}$ (pw2, pw1%array, scale)
1494 :
1495 0 : END SUBROUTINE pw_gather_s_${kind}$_${kind2}$_2
1496 :
1497 : ! **************************************************************************************************
1498 : !> \brief Gathers the pw vector from a 3d data field
1499 : !> \param pw ...
1500 : !> \param c ...
1501 : !> \param scale ...
1502 : !> \par History
1503 : !> none
1504 : !> \author JGH
1505 : ! **************************************************************************************************
1506 283643 : SUBROUTINE pw_gather_s_${kind}$_${kind2}$ (pw, c, scale)
1507 :
1508 : TYPE(pw_${kind}$_gs_type), INTENT(INOUT) :: pw
1509 : ${type2}$, CONTIGUOUS, INTENT(IN) :: c
1510 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: scale
1511 :
1512 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_gather_s'
1513 :
1514 : INTEGER :: gpt, handle, l, m, n
1515 :
1516 283643 : CALL timeset(routineN, handle)
1517 :
1518 : ASSOCIATE (mapl => pw%pw_grid%mapl%pos, mapm => pw%pw_grid%mapm%pos, mapn => pw%pw_grid%mapn%pos, &
1519 : ngpts => SIZE(pw%pw_grid%gsq), ghat => pw%pw_grid%g_hat)
1520 :
1521 283643 : IF (PRESENT(scale)) THEN
1522 0 : !$OMP PARALLEL DO PRIVATE(gpt, l, m, n) DEFAULT(NONE) SHARED(c, pw, scale)
1523 : DO gpt = 1, ngpts
1524 : l = mapl(ghat(1, gpt)) + 1
1525 : m = mapm(ghat(2, gpt)) + 1
1526 : n = mapn(ghat(3, gpt)) + 1
1527 : pw%array(gpt) = scale*${type2type("c(l, m, n)", kind2, kind)}$
1528 : END DO
1529 : !$OMP END PARALLEL DO
1530 : ELSE
1531 283643 : !$OMP PARALLEL DO PRIVATE(gpt, l, m, n) DEFAULT(NONE) SHARED(c, pw)
1532 : DO gpt = 1, ngpts
1533 : l = mapl(ghat(1, gpt)) + 1
1534 : m = mapm(ghat(2, gpt)) + 1
1535 : n = mapn(ghat(3, gpt)) + 1
1536 : pw%array(gpt) = ${type2type("c(l, m, n)", kind2, kind)}$
1537 : END DO
1538 : !$OMP END PARALLEL DO
1539 : END IF
1540 :
1541 : END ASSOCIATE
1542 :
1543 283643 : CALL timestop(handle)
1544 :
1545 283643 : END SUBROUTINE pw_gather_s_${kind}$_${kind2}$
1546 :
1547 : ! **************************************************************************************************
1548 : !> \brief Scatters a pw vector to a 3d data field
1549 : !> \param pw ...
1550 : !> \param c ...
1551 : !> \param scale ...
1552 : !> \par History
1553 : !> none
1554 : !> \author JGH
1555 : ! **************************************************************************************************
1556 0 : SUBROUTINE pw_scatter_s_${kind}$_${kind2}$_2(pw1, pw2, scale)
1557 :
1558 : TYPE(pw_${kind}$_gs_type), INTENT(IN) :: pw1
1559 : TYPE(pw_${kind2}$_gs_type), INTENT(INOUT) :: pw2
1560 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: scale
1561 :
1562 0 : CALL pw_scatter_s_${kind}$_${kind2}$ (pw1, pw2%array, scale)
1563 :
1564 0 : END SUBROUTINE pw_scatter_s_${kind}$_${kind2}$_2
1565 :
1566 : ! **************************************************************************************************
1567 : !> \brief Scatters a pw vector to a 3d data field
1568 : !> \param pw ...
1569 : !> \param c ...
1570 : !> \param scale ...
1571 : !> \par History
1572 : !> none
1573 : !> \author JGH
1574 : ! **************************************************************************************************
1575 299586 : SUBROUTINE pw_scatter_s_${kind}$_${kind2}$ (pw, c, scale)
1576 :
1577 : TYPE(pw_${kind}$_gs_type), INTENT(IN) :: pw
1578 : ${type2}$, CONTIGUOUS, INTENT(INOUT) :: c
1579 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: scale
1580 :
1581 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_scatter_s'
1582 :
1583 : INTEGER :: gpt, handle, l, m, n
1584 :
1585 299586 : CALL timeset(routineN, handle)
1586 :
1587 : ASSOCIATE (mapl => pw%pw_grid%mapl%pos, mapm => pw%pw_grid%mapm%pos, mapn => pw%pw_grid%mapn%pos, &
1588 : ghat => pw%pw_grid%g_hat, ngpts => SIZE(pw%pw_grid%gsq))
1589 :
1590 : ! should only zero the unused bits (but the zero is needed)
1591 2533418275 : IF (.NOT. PRESENT(scale)) c = 0.0_dp
1592 :
1593 299586 : IF (PRESENT(scale)) THEN
1594 0 : !$OMP PARALLEL DO PRIVATE(gpt, l, m, n) DEFAULT(NONE) SHARED(c, pw, scale)
1595 : DO gpt = 1, ngpts
1596 : l = mapl(ghat(1, gpt)) + 1
1597 : m = mapm(ghat(2, gpt)) + 1
1598 : n = mapn(ghat(3, gpt)) + 1
1599 : c(l, m, n) = scale*${type2type("pw%array(gpt)", kind, kind2)}$
1600 : END DO
1601 : !$OMP END PARALLEL DO
1602 : ELSE
1603 299586 : !$OMP PARALLEL DO PRIVATE(gpt, l, m, n) DEFAULT(NONE) SHARED(c, pw)
1604 : DO gpt = 1, ngpts
1605 : l = mapl(ghat(1, gpt)) + 1
1606 : m = mapm(ghat(2, gpt)) + 1
1607 : n = mapn(ghat(3, gpt)) + 1
1608 : c(l, m, n) = ${type2type("pw%array(gpt)", kind, kind2)}$
1609 : END DO
1610 : !$OMP END PARALLEL DO
1611 : END IF
1612 :
1613 : END ASSOCIATE
1614 :
1615 299586 : IF (pw%pw_grid%grid_span == HALFSPACE) THEN
1616 :
1617 : ASSOCIATE (mapl => pw%pw_grid%mapl%neg, mapm => pw%pw_grid%mapm%neg, mapn => pw%pw_grid%mapn%neg, &
1618 : ghat => pw%pw_grid%g_hat, ngpts => SIZE(pw%pw_grid%gsq))
1619 :
1620 8922 : IF (PRESENT(scale)) THEN
1621 0 : !$OMP PARALLEL DO PRIVATE(gpt, l, m, n) DEFAULT(NONE) SHARED(c, pw, scale)
1622 : DO gpt = 1, ngpts
1623 : l = mapl(ghat(1, gpt)) + 1
1624 : m = mapm(ghat(2, gpt)) + 1
1625 : n = mapn(ghat(3, gpt)) + 1
1626 : c(l, m, n) = scale*#{if kind[0]=="c" and kind2[0]=="c"}#CONJG#{endif}#(${type2type("pw%array(gpt)", kind, kind2)}$)
1627 : END DO
1628 : !$OMP END PARALLEL DO
1629 : ELSE
1630 8922 : !$OMP PARALLEL DO PRIVATE(gpt, l, m, n) DEFAULT(NONE) SHARED(c, pw)
1631 : DO gpt = 1, ngpts
1632 : l = mapl(ghat(1, gpt)) + 1
1633 : m = mapm(ghat(2, gpt)) + 1
1634 : n = mapn(ghat(3, gpt)) + 1
1635 : c(l, m, n) = #{if kind[0]=="c" and kind2[0]=="c"}#CONJG#{endif}#(${type2type("pw%array(gpt)", kind, kind2)}$)
1636 : END DO
1637 : !$OMP END PARALLEL DO
1638 : END IF
1639 :
1640 : END ASSOCIATE
1641 :
1642 : END IF
1643 :
1644 299586 : CALL timestop(handle)
1645 :
1646 299586 : END SUBROUTINE pw_scatter_s_${kind}$_${kind2}$
1647 : #:endif
1648 : #:endfor
1649 :
1650 : ! **************************************************************************************************
1651 : !> \brief Multiply all data points with a Gaussian damping factor
1652 : !> Needed for longrange Coulomb potential
1653 : !> V(\vec r)=erf(omega*r)/r
1654 : !> V(\vec g)=\frac{4*\pi}{g**2}*exp(-g**2/omega**2)
1655 : !> \param pw ...
1656 : !> \param omega ...
1657 : !> \par History
1658 : !> Frederick Stein (12-04-2019) created
1659 : !> \author Frederick Stein (12-Apr-2019)
1660 : !> \note
1661 : !> Performs a Gaussian damping
1662 : ! **************************************************************************************************
1663 3841 : SUBROUTINE pw_gauss_damp(pw, omega)
1664 :
1665 : TYPE(pw_c1d_gs_type), INTENT(INOUT) :: pw
1666 : REAL(KIND=dp), INTENT(IN) :: omega
1667 :
1668 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_gauss_damp'
1669 :
1670 : INTEGER :: handle
1671 : REAL(KIND=dp) :: omega_2
1672 :
1673 3841 : CALL timeset(routineN, handle)
1674 3841 : CPASSERT(omega >= 0)
1675 :
1676 3841 : omega_2 = omega*omega
1677 3841 : omega_2 = 0.25_dp/omega_2
1678 :
1679 3841 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw,omega_2)
1680 : pw%array = pw%array*EXP(-pw%pw_grid%gsq*omega_2)
1681 : !$OMP END PARALLEL WORKSHARE
1682 :
1683 3841 : CALL timestop(handle)
1684 :
1685 3841 : END SUBROUTINE pw_gauss_damp
1686 :
1687 : ! **************************************************************************************************
1688 : !> \brief Multiply all data points with the logarithmic derivative of a Gaussian
1689 : !> \param pw ...
1690 : !> \param omega ...
1691 : !> \note
1692 : !> Performs a Gaussian damping
1693 : ! **************************************************************************************************
1694 1329 : SUBROUTINE pw_log_deriv_gauss(pw, omega)
1695 :
1696 : TYPE(pw_c1d_gs_type), INTENT(IN) :: pw
1697 : REAL(KIND=dp), INTENT(IN) :: omega
1698 :
1699 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_log_deriv_gauss'
1700 :
1701 : INTEGER :: handle
1702 : REAL(KIND=dp) :: omega_2
1703 :
1704 1329 : CALL timeset(routineN, handle)
1705 1329 : CPASSERT(omega >= 0)
1706 :
1707 1329 : omega_2 = omega*omega
1708 1329 : omega_2 = 0.25_dp/omega_2
1709 :
1710 1329 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw,omega_2)
1711 : pw%array = pw%array*(1.0_dp + omega_2*pw%pw_grid%gsq)
1712 : !$OMP END PARALLEL WORKSHARE
1713 :
1714 1329 : CALL timestop(handle)
1715 1329 : END SUBROUTINE pw_log_deriv_gauss
1716 :
1717 : ! **************************************************************************************************
1718 : !> \brief Multiply all data points with a Gaussian damping factor
1719 : !> Needed for longrange Coulomb potential
1720 : !> V(\vec r)=erf(omega*r)/r
1721 : !> V(\vec g)=\frac{4*\pi}{g**2}*exp(-g**2/omega**2)
1722 : !> \param pw ...
1723 : !> \param omega ...
1724 : !> \par History
1725 : !> Frederick Stein (12-04-2019) created
1726 : !> \author Frederick Stein (12-Apr-2019)
1727 : !> \note
1728 : !> Performs a Gaussian damping
1729 : ! **************************************************************************************************
1730 0 : SUBROUTINE pw_compl_gauss_damp(pw, omega)
1731 :
1732 : TYPE(pw_c1d_gs_type), INTENT(INOUT) :: pw
1733 : REAL(KIND=dp), INTENT(IN) :: omega
1734 :
1735 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_compl_gauss_damp'
1736 :
1737 : INTEGER :: cnt, handle, i
1738 : REAL(KIND=dp) :: omega_2, tmp
1739 :
1740 0 : CALL timeset(routineN, handle)
1741 :
1742 0 : omega_2 = omega*omega
1743 0 : omega_2 = 0.25_dp/omega_2
1744 :
1745 0 : cnt = SIZE(pw%array)
1746 :
1747 0 : !$OMP PARALLEL DO PRIVATE(i, tmp) DEFAULT(NONE) SHARED(cnt, pw,omega_2)
1748 : DO i = 1, cnt
1749 : tmp = -omega_2*pw%pw_grid%gsq(i)
1750 : IF (ABS(tmp) > 1.0E-5_dp) THEN
1751 : pw%array(i) = pw%array(i)*(1.0_dp - EXP(tmp))
1752 : ELSE
1753 : pw%array(i) = pw%array(i)*(tmp + 0.5_dp*tmp*(tmp + (1.0_dp/3.0_dp)*tmp**2))
1754 : END IF
1755 : END DO
1756 : !$OMP END PARALLEL DO
1757 :
1758 0 : CALL timestop(handle)
1759 :
1760 0 : END SUBROUTINE pw_compl_gauss_damp
1761 :
1762 : ! **************************************************************************************************
1763 : !> \brief Multiply all data points with the logarithmic derivative of the complementary Gaussian damping factor
1764 : !> \param pw ...
1765 : !> \param omega ...
1766 : !> \note
1767 : ! **************************************************************************************************
1768 0 : SUBROUTINE pw_log_deriv_compl_gauss(pw, omega)
1769 :
1770 : TYPE(pw_c1d_gs_type), INTENT(IN) :: pw
1771 : REAL(KIND=dp), INTENT(IN) :: omega
1772 :
1773 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_log_deriv_compl_gauss'
1774 :
1775 : INTEGER :: handle, i
1776 : REAL(KIND=dp) :: omega_2, tmp
1777 :
1778 0 : CALL timeset(routineN, handle)
1779 :
1780 0 : omega_2 = omega*omega
1781 0 : omega_2 = 0.25_dp/omega_2
1782 :
1783 : !$OMP PARALLEL DO DEFAULT(NONE) PRIVATE(i,tmp) &
1784 0 : !$OMP SHARED(pw,omega_2)
1785 : DO i = 1, SIZE(pw%array)
1786 : tmp = omega_2*pw%pw_grid%gsq(i)
1787 : ! For too small arguments, use the Taylor polynomial to prevent division by zero
1788 : IF (ABS(tmp) >= 0.003_dp) THEN
1789 : pw%array(i) = pw%array(i)*(1.0_dp - tmp*EXP(-tmp)/(1.0_dp - EXP(-tmp)))
1790 : ELSE
1791 : pw%array(i) = pw%array(i)*(0.5_dp*tmp - tmp**2/12.0_dp)
1792 : END IF
1793 : END DO
1794 : !$OMP END PARALLEL DO
1795 :
1796 0 : CALL timestop(handle)
1797 :
1798 0 : END SUBROUTINE pw_log_deriv_compl_gauss
1799 :
1800 : ! **************************************************************************************************
1801 : !> \brief Multiply all data points with a Gaussian damping factor and mixes it with the original function
1802 : !> Needed for mixed longrange/Coulomb potential
1803 : !> V(\vec r)=(a+b*erf(omega*r))/r
1804 : !> V(\vec g)=\frac{4*\pi}{g**2}*(a+b*exp(-g**2/omega**2))
1805 : !> \param pw ...
1806 : !> \param omega ...
1807 : !> \param scale_coul ...
1808 : !> \param scale_long ...
1809 : !> \par History
1810 : !> Frederick Stein (16-Dec-2021) created
1811 : !> \author Frederick Stein (16-Dec-2021)
1812 : !> \note
1813 : !> Performs a Gaussian damping
1814 : ! **************************************************************************************************
1815 332 : SUBROUTINE pw_gauss_damp_mix(pw, omega, scale_coul, scale_long)
1816 :
1817 : TYPE(pw_c1d_gs_type), INTENT(INOUT) :: pw
1818 : REAL(KIND=dp), INTENT(IN) :: omega, scale_coul, scale_long
1819 :
1820 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_gauss_damp_mix'
1821 :
1822 : INTEGER :: handle
1823 : REAL(KIND=dp) :: omega_2
1824 :
1825 332 : CALL timeset(routineN, handle)
1826 :
1827 332 : omega_2 = omega*omega
1828 332 : omega_2 = 0.25_dp/omega_2
1829 :
1830 332 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw, omega_2, scale_coul, scale_long)
1831 : pw%array = pw%array*(scale_coul + scale_long*EXP(-pw%pw_grid%gsq*omega_2))
1832 : !$OMP END PARALLEL WORKSHARE
1833 :
1834 332 : CALL timestop(handle)
1835 :
1836 332 : END SUBROUTINE pw_gauss_damp_mix
1837 :
1838 : ! **************************************************************************************************
1839 : !> \brief Multiply all data points with the logarithmic derivative of the mixed longrange/Coulomb potential
1840 : !> Needed for mixed longrange/Coulomb potential
1841 : !> \param pw ...
1842 : !> \param omega ...
1843 : !> \param scale_coul ...
1844 : !> \param scale_long ...
1845 : !> \note
1846 : ! **************************************************************************************************
1847 249 : SUBROUTINE pw_log_deriv_mix_cl(pw, omega, scale_coul, scale_long)
1848 :
1849 : TYPE(pw_c1d_gs_type), INTENT(IN) :: pw
1850 : REAL(KIND=dp), INTENT(IN) :: omega, scale_coul, scale_long
1851 :
1852 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_log_deriv_mix_cl'
1853 :
1854 : INTEGER :: handle, i
1855 : REAL(KIND=dp) :: omega_2, tmp
1856 :
1857 249 : CALL timeset(routineN, handle)
1858 :
1859 249 : omega_2 = omega*omega
1860 249 : omega_2 = 0.25_dp/omega_2
1861 :
1862 : !$OMP PARALLEL DO DEFAULT(NONE) PRIVATE(i,tmp) &
1863 249 : !$OMP SHARED(pw,omega_2,scale_long,scale_coul)
1864 : DO i = 1, SIZE(pw%array)
1865 : tmp = omega_2*pw%pw_grid%gsq(i)
1866 : pw%array(i) = pw%array(i)*(1.0_dp + scale_long*tmp*EXP(-tmp)/(scale_coul + scale_long*EXP(-tmp)))
1867 : END DO
1868 : !$OMP END PARALLEL DO
1869 :
1870 249 : CALL timestop(handle)
1871 :
1872 249 : END SUBROUTINE pw_log_deriv_mix_cl
1873 :
1874 : ! **************************************************************************************************
1875 : !> \brief Multiply all data points with a complementary cosine
1876 : !> Needed for truncated Coulomb potential
1877 : !> V(\vec r)=1/r if r<rc, 0 else
1878 : !> V(\vec g)=\frac{4*\pi}{g**2}*(1-cos(g*rc))
1879 : !> \param pw ...
1880 : !> \param rcutoff ...
1881 : !> \par History
1882 : !> Frederick Stein (07-06-2021) created
1883 : !> \author Frederick Stein (07-Jun-2021)
1884 : !> \note
1885 : !> Multiplies by complementary cosine
1886 : ! **************************************************************************************************
1887 0 : SUBROUTINE pw_truncated(pw, rcutoff)
1888 :
1889 : TYPE(pw_c1d_gs_type), INTENT(INOUT) :: pw
1890 : REAL(KIND=dp), INTENT(IN) :: rcutoff
1891 :
1892 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_truncated'
1893 :
1894 : INTEGER :: handle, i
1895 : REAL(KIND=dp) :: tmp
1896 :
1897 0 : CALL timeset(routineN, handle)
1898 0 : CPASSERT(rcutoff >= 0)
1899 :
1900 0 : !$OMP PARALLEL DO PRIVATE(i,tmp) DEFAULT(NONE) SHARED(pw, rcutoff)
1901 : DO i = 1, SIZE(pw%array)
1902 : tmp = SQRT(pw%pw_grid%gsq(i))*rcutoff
1903 : IF (tmp >= 0.005_dp) THEN
1904 : pw%array(i) = pw%array(i)*(1.0_dp - COS(tmp))
1905 : ELSE
1906 : pw%array(i) = pw%array(i)*tmp**2/2.0_dp*(1.0 - tmp**2/12.0_dp)
1907 : END IF
1908 : END DO
1909 : !$OMP END PARALLEL DO
1910 :
1911 0 : CALL timestop(handle)
1912 :
1913 0 : END SUBROUTINE pw_truncated
1914 :
1915 : ! **************************************************************************************************
1916 : !> \brief Multiply all data points with the logarithmic derivative of the complementary cosine
1917 : !> This function is needed for virials using truncated Coulomb potentials
1918 : !> \param pw ...
1919 : !> \param rcutoff ...
1920 : !> \note
1921 : ! **************************************************************************************************
1922 0 : SUBROUTINE pw_log_deriv_trunc(pw, rcutoff)
1923 :
1924 : TYPE(pw_c1d_gs_type), INTENT(IN) :: pw
1925 : REAL(KIND=dp), INTENT(IN) :: rcutoff
1926 :
1927 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_log_deriv_trunc'
1928 :
1929 : INTEGER :: handle, i
1930 : REAL(KIND=dp) :: rchalf, tmp
1931 :
1932 0 : CALL timeset(routineN, handle)
1933 0 : CPASSERT(rcutoff >= 0)
1934 :
1935 0 : rchalf = 0.5_dp*rcutoff
1936 : !$OMP PARALLEL DO DEFAULT(NONE) PRIVATE(i,tmp) &
1937 0 : !$OMP SHARED(pw,rchalf)
1938 : DO i = 1, SIZE(pw%array)
1939 : tmp = rchalf*SQRT(pw%pw_grid%gsq(i))
1940 : ! For too small arguments, use the Taylor polynomial to prevent division by zero
1941 : IF (ABS(tmp) >= 0.0001_dp) THEN
1942 : pw%array(i) = pw%array(i)*(1.0_dp - tmp/TAN(tmp))
1943 : ELSE
1944 : pw%array(i) = pw%array(i)*tmp**2*(1.0_dp + tmp**2/15.0_dp)/3.0_dp
1945 : END IF
1946 : END DO
1947 : !$OMP END PARALLEL DO
1948 :
1949 0 : CALL timestop(handle)
1950 :
1951 0 : END SUBROUTINE pw_log_deriv_trunc
1952 :
1953 : ! **************************************************************************************************
1954 : !> \brief Calculate the derivative of a plane wave vector
1955 : !> \param pw ...
1956 : !> \param n ...
1957 : !> \par History
1958 : !> JGH (06-10-2002) allow only for inplace derivatives
1959 : !> \author JGH (25-Feb-2001)
1960 : !> \note
1961 : !> Calculate the derivative dx^n(1) dy^n(2) dz^n(3) PW
1962 : ! **************************************************************************************************
1963 1228941 : SUBROUTINE pw_derive(pw, n)
1964 :
1965 : TYPE(pw_c1d_gs_type), INTENT(INOUT) :: pw
1966 : INTEGER, DIMENSION(3), INTENT(IN) :: n
1967 :
1968 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_derive'
1969 :
1970 : COMPLEX(KIND=dp) :: im
1971 : INTEGER :: handle, m
1972 :
1973 1228941 : CALL timeset(routineN, handle)
1974 :
1975 4915764 : IF (ANY(n < 0)) &
1976 0 : CPABORT("Nonnegative exponents are not supported!")
1977 :
1978 4915764 : m = SUM(n)
1979 1228941 : im = CMPLX(0.0_dp, 1.0_dp, KIND=dp)**m
1980 :
1981 1228941 : IF (n(1) == 1) THEN
1982 410103 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw)
1983 : pw%array(:) = pw%array(:)*pw%pw_grid%g(1, :)
1984 : !$OMP END PARALLEL WORKSHARE
1985 818838 : ELSE IF (n(1) > 1) THEN
1986 132 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(n, pw)
1987 : pw%array(:) = pw%array(:)*(pw%pw_grid%g(1, :)**n(1))
1988 : !$OMP END PARALLEL WORKSHARE
1989 : END IF
1990 :
1991 1228941 : IF (n(2) == 1) THEN
1992 409647 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw)
1993 : pw%array(:) = pw%array(:)*pw%pw_grid%g(2, :)
1994 : !$OMP END PARALLEL WORKSHARE
1995 819294 : ELSE IF (n(2) > 1) THEN
1996 132 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(n, pw)
1997 : pw%array(:) = pw%array(:)*(pw%pw_grid%g(2, :)**n(2))
1998 : !$OMP END PARALLEL WORKSHARE
1999 : END IF
2000 :
2001 1228941 : IF (n(3) == 1) THEN
2002 409191 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw)
2003 : pw%array(:) = pw%array(:)*pw%pw_grid%g(3, :)
2004 : !$OMP END PARALLEL WORKSHARE
2005 819750 : ELSE IF (n(3) > 1) THEN
2006 132 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(n, pw)
2007 : pw%array(:) = pw%array(:)*(pw%pw_grid%g(3, :)**n(3))
2008 : !$OMP END PARALLEL WORKSHARE
2009 : END IF
2010 :
2011 : ! im can take the values 1, -1, i, -i
2012 : ! skip this if im == 1
2013 1228941 : IF (ABS(REAL(im, KIND=dp) - 1.0_dp) > 1.0E-10_dp) THEN
2014 1228941 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(im, pw)
2015 : pw%array(:) = im*pw%array(:)
2016 : !$OMP END PARALLEL WORKSHARE
2017 : END IF
2018 :
2019 1228941 : CALL timestop(handle)
2020 :
2021 1228941 : END SUBROUTINE pw_derive
2022 :
2023 : ! **************************************************************************************************
2024 : !> \brief Calculate the Laplacian of a plane wave vector
2025 : !> \param pw ...
2026 : !> \par History
2027 : !> Frederick Stein (01-02-2022) created
2028 : !> \author JGH (25-Feb-2001)
2029 : !> \note
2030 : !> Calculate the derivative DELTA PW
2031 : ! **************************************************************************************************
2032 2406 : SUBROUTINE pw_laplace(pw)
2033 :
2034 : TYPE(pw_c1d_gs_type), INTENT(INOUT) :: pw
2035 :
2036 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_laplace'
2037 :
2038 : INTEGER :: handle
2039 :
2040 2406 : CALL timeset(routineN, handle)
2041 :
2042 2406 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(pw)
2043 : pw%array(:) = -pw%array(:)*pw%pw_grid%gsq(:)
2044 : !$OMP END PARALLEL WORKSHARE
2045 :
2046 2406 : CALL timestop(handle)
2047 :
2048 2406 : END SUBROUTINE pw_laplace
2049 :
2050 : ! **************************************************************************************************
2051 : !> \brief Calculate the tensorial 2nd derivative of a plane wave vector
2052 : !> \param pw ...
2053 : !> \param pwdr2 ...
2054 : !> \param i ...
2055 : !> \param j ...
2056 : !> \par History
2057 : !> none
2058 : !> \author JGH (05-May-2006)
2059 : !> \note
2060 : ! **************************************************************************************************
2061 198 : SUBROUTINE pw_dr2(pw, pwdr2, i, j)
2062 :
2063 : TYPE(pw_c1d_gs_type), INTENT(INOUT) :: pw, pwdr2
2064 : INTEGER, INTENT(IN) :: i, j
2065 :
2066 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_dr2'
2067 :
2068 : INTEGER :: cnt, handle, ig
2069 : REAL(KIND=dp) :: gg, o3
2070 :
2071 198 : CALL timeset(routineN, handle)
2072 :
2073 198 : o3 = 1.0_dp/3.0_dp
2074 :
2075 198 : cnt = SIZE(pw%array)
2076 :
2077 198 : IF (i == j) THEN
2078 108 : !$OMP PARALLEL DO DEFAULT(NONE) PRIVATE(ig,gg) SHARED(cnt, i, o3, pw, pwdr2)
2079 : DO ig = 1, cnt
2080 : gg = pw%pw_grid%g(i, ig)**2 - o3*pw%pw_grid%gsq(ig)
2081 : pwdr2%array(ig) = gg*pw%array(ig)
2082 : END DO
2083 : !$OMP END PARALLEL DO
2084 : ELSE
2085 90 : !$OMP PARALLEL DO PRIVATE (ig) DEFAULT(NONE) SHARED(cnt, i, j, pw, pwdr2)
2086 : DO ig = 1, cnt
2087 : pwdr2%array(ig) = pw%array(ig)*(pw%pw_grid%g(i, ig)*pw%pw_grid%g(j, ig))
2088 : END DO
2089 : !$OMP END PARALLEL DO
2090 : END IF
2091 :
2092 198 : CALL timestop(handle)
2093 :
2094 198 : END SUBROUTINE pw_dr2
2095 :
2096 : ! **************************************************************************************************
2097 : !> \brief Calculate the tensorial 2nd derivative of a plane wave vector
2098 : !> and divides by |G|^2. pwdr2_gg(G=0) is put to zero.
2099 : !> \param pw ...
2100 : !> \param pwdr2_gg ...
2101 : !> \param i ...
2102 : !> \param j ...
2103 : !> \par History
2104 : !> none
2105 : !> \author RD (20-Nov-2006)
2106 : !> \note
2107 : !> Adapted from pw_dr2
2108 : ! **************************************************************************************************
2109 12 : SUBROUTINE pw_dr2_gg(pw, pwdr2_gg, i, j)
2110 :
2111 : TYPE(pw_c1d_gs_type), INTENT(INOUT) :: pw, pwdr2_gg
2112 : INTEGER, INTENT(IN) :: i, j
2113 :
2114 : INTEGER :: cnt, handle, ig
2115 : REAL(KIND=dp) :: gg, o3
2116 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_dr2_gg'
2117 :
2118 12 : CALL timeset(routineN, handle)
2119 :
2120 12 : o3 = 1.0_dp/3.0_dp
2121 :
2122 12 : cnt = SIZE(pw%array)
2123 :
2124 12 : IF (i == j) THEN
2125 6 : !$OMP PARALLEL DO PRIVATE (ig) DEFAULT(NONE) PRIVATE(gg) SHARED(cnt, i, o3, pw, pwdr2_gg)
2126 : DO ig = pw%pw_grid%first_gne0, cnt
2127 : gg = pw%pw_grid%g(i, ig)**2 - o3*pw%pw_grid%gsq(ig)
2128 : pwdr2_gg%array(ig) = gg*pw%array(ig)/pw%pw_grid%gsq(ig)
2129 : END DO
2130 : !$OMP END PARALLEL DO
2131 : ELSE
2132 6 : !$OMP PARALLEL DO PRIVATE (ig) DEFAULT(NONE) SHARED(cnt, i, j, pw, pwdr2_gg)
2133 : DO ig = pw%pw_grid%first_gne0, cnt
2134 : pwdr2_gg%array(ig) = pw%array(ig)*(pw%pw_grid%g(i, ig)*pw%pw_grid%g(j, ig)) &
2135 : /pw%pw_grid%gsq(ig)
2136 : END DO
2137 : !$OMP END PARALLEL DO
2138 : END IF
2139 :
2140 12 : IF (pw%pw_grid%have_g0) pwdr2_gg%array(1) = 0.0_dp
2141 :
2142 12 : CALL timestop(handle)
2143 :
2144 12 : END SUBROUTINE pw_dr2_gg
2145 :
2146 : ! **************************************************************************************************
2147 : !> \brief Multiplies a G-space function with a smoothing factor of the form
2148 : !> f(|G|) = exp((ecut - G^2)/sigma)/(1+exp((ecut - G^2)/sigma))
2149 : !> \param pw ...
2150 : !> \param ecut ...
2151 : !> \param sigma ...
2152 : !> \par History
2153 : !> none
2154 : !> \author JGH (09-June-2006)
2155 : !> \note
2156 : ! **************************************************************************************************
2157 30 : SUBROUTINE pw_smoothing(pw, ecut, sigma)
2158 :
2159 : TYPE(pw_c1d_gs_type), INTENT(INOUT) :: pw
2160 : REAL(KIND=dp), INTENT(IN) :: ecut, sigma
2161 :
2162 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_smoothing'
2163 :
2164 : INTEGER :: cnt, handle, ig
2165 : REAL(KIND=dp) :: arg, f
2166 :
2167 30 : CALL timeset(routineN, handle)
2168 :
2169 30 : cnt = SIZE(pw%array)
2170 :
2171 30 : !$OMP PARALLEL DO DEFAULT(NONE) PRIVATE(ig, arg, f) SHARED(cnt, ecut, pw, sigma)
2172 : DO ig = 1, cnt
2173 : arg = (ecut - pw%pw_grid%gsq(ig))/sigma
2174 : f = EXP(arg)/(1 + EXP(arg))
2175 : pw%array(ig) = f*pw%array(ig)
2176 : END DO
2177 : !$OMP END PARALLEL DO
2178 :
2179 30 : CALL timestop(handle)
2180 :
2181 30 : END SUBROUTINE pw_smoothing
2182 :
2183 : ! **************************************************************************************************
2184 : !> \brief ...
2185 : !> \param grida ...
2186 : !> \param gridb ...
2187 : !> \return ...
2188 : ! **************************************************************************************************
2189 719070 : ELEMENTAL FUNCTION pw_compatible(grida, gridb) RESULT(compat)
2190 :
2191 : TYPE(pw_grid_type), INTENT(IN) :: grida, gridb
2192 : LOGICAL :: compat
2193 :
2194 719070 : compat = .FALSE.
2195 :
2196 719070 : IF (grida%id_nr == gridb%id_nr) THEN
2197 : compat = .TRUE.
2198 719070 : ELSE IF (grida%reference == gridb%id_nr) THEN
2199 : compat = .TRUE.
2200 1628 : ELSE IF (gridb%reference == grida%id_nr) THEN
2201 1098 : compat = .TRUE.
2202 : END IF
2203 :
2204 719070 : END FUNCTION pw_compatible
2205 :
2206 : ! **************************************************************************************************
2207 : !> \brief Calculate the structure factor for point r
2208 : !> \param sf ...
2209 : !> \param r ...
2210 : !> \par History
2211 : !> none
2212 : !> \author JGH (05-May-2006)
2213 : !> \note
2214 : ! **************************************************************************************************
2215 76 : SUBROUTINE pw_structure_factor(sf, r)
2216 :
2217 : TYPE(pw_c1d_gs_type), INTENT(INOUT) :: sf
2218 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: r
2219 :
2220 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_structure_factor'
2221 :
2222 : INTEGER :: cnt, handle, ig
2223 : REAL(KIND=dp) :: arg
2224 :
2225 76 : CALL timeset(routineN, handle)
2226 :
2227 76 : cnt = SIZE(sf%array)
2228 :
2229 76 : !$OMP PARALLEL DO PRIVATE (ig, arg) DEFAULT(NONE) SHARED(cnt, r, sf)
2230 : DO ig = 1, cnt
2231 : arg = DOT_PRODUCT(sf%pw_grid%g(:, ig), r)
2232 : sf%array(ig) = CMPLX(COS(arg), -SIN(arg), KIND=dp)
2233 : END DO
2234 : !$OMP END PARALLEL DO
2235 :
2236 76 : CALL timestop(handle)
2237 :
2238 76 : END SUBROUTINE pw_structure_factor
2239 :
2240 : END MODULE pw_methods
|