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