Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief Creates the wavelet kernel for the wavelet based poisson solver.
10 : !> \author Florian Schiffmann (09.2007,fschiff)
11 : ! **************************************************************************************************
12 : MODULE ps_wavelet_base
13 : USE fft_lib, ONLY: fft_1d,&
14 : fft_create_plan_1d,&
15 : fft_destroy_plan
16 : USE fft_plan, ONLY: fft_plan_type
17 : USE fft_tools, ONLY: BWFFT,&
18 : FWFFT,&
19 : fft_alloc,&
20 : fft_dealloc
21 : USE kinds, ONLY: dp
22 : USE mathconstants, ONLY: pi
23 : USE message_passing, ONLY: mp_comm_type
24 : #include "../base/base_uses.f90"
25 :
26 : IMPLICIT NONE
27 :
28 : PRIVATE
29 :
30 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'ps_wavelet_base'
31 :
32 : PUBLIC :: scramble_unpack, p_poissonsolver, s_poissonsolver, f_poissonsolver
33 :
34 : CONTAINS
35 :
36 : ! **************************************************************************************************
37 : !> \brief ...
38 : !> \param n1 ...
39 : !> \param n2 ...
40 : !> \param n3 ...
41 : !> \param nd1 ...
42 : !> \param nd2 ...
43 : !> \param nd3 ...
44 : !> \param md1 ...
45 : !> \param md2 ...
46 : !> \param md3 ...
47 : !> \param nproc ...
48 : !> \param iproc ...
49 : !> \param zf ...
50 : !> \param scal ...
51 : !> \param hx ...
52 : !> \param hy ...
53 : !> \param hz ...
54 : !> \param mpi_group ...
55 : ! **************************************************************************************************
56 17323 : SUBROUTINE P_PoissonSolver(n1, n2, n3, nd1, nd2, nd3, md1, md2, md3, nproc, iproc, zf &
57 : , scal, hx, hy, hz, mpi_group)
58 : INTEGER, INTENT(in) :: n1, n2, n3, nd1, nd2, nd3, md1, md2, &
59 : md3, nproc, iproc
60 : REAL(KIND=dp), DIMENSION(md1, md3, md2/nproc), &
61 : INTENT(inout) :: zf
62 : REAL(KIND=dp), INTENT(in) :: scal, hx, hy, hz
63 :
64 : CLASS(mp_comm_type), INTENT(in) :: mpi_group
65 :
66 : INTEGER, PARAMETER :: ncache_optimal = 8*1024
67 :
68 : INTEGER :: i1, i3, j, j2, &
69 : J2stb, J2stf, j3, Jp2stb, Jp2stf, lot1, lot2, lot3, &
70 : lzt, ma, mb, ncache, nfft, stat, &
71 : final_chunk_size3, final_chunk_size1, final_chunk_size2
72 17323 : COMPLEX(KIND=dp), POINTER, CONTIGUOUS, DIMENSION(:, :) :: zt
73 17323 : COMPLEX(KIND=dp), POINTER, CONTIGUOUS, DIMENSION(:) :: zw1, zw2
74 : COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: zmpi2
75 : COMPLEX(KIND=dp), ALLOCATABLE, &
76 17323 : DIMENSION(:, :, :, :) :: zmpi1
77 : TYPE(fft_plan_type) :: fft_plan_bw3, fft_plan_bw3_last, fft_plan_fw3, fft_plan_fw3_last, &
78 : fft_plan_bw1, fft_plan_bw1_last, fft_plan_fw1, fft_plan_fw1_last, &
79 : fft_plan_bw2, fft_plan_bw2_last, fft_plan_fw2, fft_plan_fw2_last
80 :
81 0 : IF (nd1 < n1/2 + 1) CPABORT("Parallel convolution:ERROR:nd1")
82 17323 : IF (nd2 < n2/2 + 1) CPABORT("Parallel convolution:ERROR:nd2")
83 17323 : IF (nd3 < n3/2 + 1) CPABORT("Parallel convolution:ERROR:nd3")
84 17323 : IF (md1 < n1) CPABORT("Parallel convolution:ERROR:md1")
85 17323 : IF (md2 < n2) CPABORT("Parallel convolution:ERROR:md2")
86 17323 : IF (md3 < n3) CPABORT("Parallel convolution:ERROR:md3")
87 17323 : IF (MOD(nd3, nproc) /= 0) CPABORT("Parallel convolution:ERROR:nd3")
88 17323 : IF (MOD(md2, nproc) /= 0) CPABORT("Parallel convolution:ERROR:md2")
89 :
90 : !defining work arrays dimensions
91 17323 : ncache = ncache_optimal
92 17323 : IF (ncache <= MAX(n1, n2, n3)*4) ncache = MAX(n1, n2, n3)*4
93 :
94 17323 : lzt = n2
95 17323 : IF (MOD(n2, 2) == 0) lzt = lzt + 1
96 :
97 : !Allocations
98 34646 : CALL fft_alloc(zw1, [ncache/4])
99 17323 : zw1 = CMPLX(0.0_dp, 0.0_dp, KIND=dp)
100 34646 : CALL fft_alloc(zw2, [ncache/4])
101 17323 : zw2 = CMPLX(0.0_dp, 0.0_dp, KIND=dp)
102 51969 : CALL fft_alloc(zt, [lzt, n1])
103 17323 : zt = CMPLX(0.0_dp, 0.0_dp, KIND=dp)
104 86615 : ALLOCATE (zmpi2(n1, md2/nproc, nd3), SOURCE=CMPLX(0.0_dp, 0.0_dp, KIND=dp))
105 41353 : IF (nproc > 1) ALLOCATE (zmpi1(n1, md2/nproc, nd3/nproc, nproc), SOURCE=CMPLX(0.0_dp, 0.0_dp, KIND=dp))
106 :
107 : ! transform along z axis
108 : ! Leading dimensions in all three directions
109 17323 : lot1 = ncache/(4*n1)
110 17323 : lot2 = ncache/(4*n2)
111 17323 : lot3 = ncache/(4*n3)
112 :
113 : ! The size of the last chunk
114 17323 : final_chunk_size1 = MOD(n2, lot1)
115 17323 : final_chunk_size2 = MOD(n1, lot2)
116 17323 : final_chunk_size3 = MOD(n1, lot3)
117 :
118 : ! Prevent OOB-access if n2 < lot1
119 17323 : IF (n2 >= lot1) THEN
120 251 : CALL fft_create_plan_1d(fft_plan_bw1, BWFFT, .TRUE., .TRUE., lot1, lzt, n1, lot1, zw1, zt)
121 251 : CALL fft_create_plan_1d(fft_plan_fw1, FWFFT, .TRUE., .TRUE., lzt, lot1, n1, lot1, zt, zw1)
122 : END IF
123 17323 : IF (final_chunk_size1 > 0) THEN
124 : CALL fft_create_plan_1d(fft_plan_bw1_last, BWFFT, .TRUE., .TRUE., lot1, lzt, n1, &
125 17323 : final_chunk_size1, zw1, zt)
126 : CALL fft_create_plan_1d(fft_plan_fw1_last, FWFFT, .TRUE., .TRUE., lzt, lot1, n1, &
127 17323 : final_chunk_size1, zt, zw1)
128 : END IF
129 :
130 : ! Prevent OOB-access if n2 < lot1
131 17323 : IF (n1 >= lot2) THEN
132 251 : CALL fft_create_plan_1d(fft_plan_bw2, BWFFT, .TRUE., .TRUE., lot2, lot2, n2, lot2, zw1, zw2)
133 251 : CALL fft_create_plan_1d(fft_plan_fw2, FWFFT, .TRUE., .TRUE., lot2, lot2, n2, lot2, zw2, zw1)
134 : END IF
135 17323 : IF (final_chunk_size2 > 0) THEN
136 : CALL fft_create_plan_1d(fft_plan_bw2_last, BWFFT, .TRUE., .TRUE., lot2, lot2, n2, &
137 17323 : final_chunk_size2, zw1, zw2)
138 : CALL fft_create_plan_1d(fft_plan_fw2_last, FWFFT, .TRUE., .TRUE., lot2, lot2, n2, &
139 17323 : final_chunk_size2, zw2, zw1)
140 : END IF
141 :
142 : ! Prevent OOB-access if n1 < lot3
143 17323 : IF (n1 >= lot3) THEN
144 251 : CALL fft_create_plan_1d(fft_plan_fw3, FWFFT, .TRUE., .TRUE., lot3, lot3, n3, lot3, zw1, zw2)
145 251 : CALL fft_create_plan_1d(fft_plan_bw3, BWFFT, .TRUE., .TRUE., lot3, lot3, n3, lot3, zw1, zw2)
146 : END IF
147 17323 : IF (final_chunk_size3 > 0) THEN
148 : CALL fft_create_plan_1d(fft_plan_fw3_last, FWFFT, .TRUE., .TRUE., &
149 17323 : lot3, lot3, n3, final_chunk_size3, zw1, zw2)
150 : CALL fft_create_plan_1d(fft_plan_bw3_last, BWFFT, .TRUE., .TRUE., &
151 17323 : lot3, lot3, n3, final_chunk_size3, zw1, zw2)
152 : END IF
153 :
154 320326 : DO j2 = 1, md2/nproc
155 : !this condition ensures that we manage only the interesting part for the FFT
156 320326 : IF (iproc*(md2/nproc) + j2 <= n2) THEN
157 613678 : DO i1 = 1, n1, lot3
158 311348 : ma = i1
159 311348 : mb = MIN(i1 + (lot3 - 1), n1)
160 311348 : nfft = mb - ma + 1
161 : !inserting real data into complex array of half length
162 311348 : CALL P_fill_upcorn(md1, md3, lot3, nfft, n3, zf(i1, 1, j2), zw1)
163 :
164 : !performing FFT
165 : !input: I1,I3,J2,(Jp2)
166 : ! This is equivalent to
167 311348 : IF (nfft == lot3) THEN
168 9018 : CALL fft_1d(fft_plan_bw3, zw1, zw2, 1.0_dp, stat)
169 : ELSE
170 302330 : CALL fft_1d(fft_plan_bw3_last, zw1, zw2, 1.0_dp, stat)
171 : END IF
172 :
173 : !output: I1,i3,J2,(Jp2)
174 : !exchanging components
175 : !input: I1,i3,J2,(Jp2)
176 613678 : CALL scramble_P(i1, j2, lot3, nfft, n1, n3, md2, nproc, nd3, zw2, zmpi2)
177 : !output: I1,J2,i3,(Jp2)
178 : END DO
179 : END IF
180 : END DO
181 :
182 : !Interprocessor data transposition
183 : !input: I1,J2,j3,jp3,(Jp2)
184 17323 : IF (nproc > 1) THEN
185 : !communication scheduling
186 4806 : CALL mpi_group%alltoall(zmpi2, zmpi1, n1*(md2/nproc)*(nd3/nproc))
187 : END IF
188 : !output: I1,J2,j3,Jp2,(jp3)
189 :
190 : !now each process perform complete convolution of its planes
191 182731 : DO j3 = 1, nd3/nproc
192 : !this condition ensures that we manage only the interesting part for the FFT
193 182731 : IF (iproc*(nd3/nproc) + j3 <= n3/2 + 1) THEN
194 164470 : Jp2stb = 1
195 164470 : J2stb = 1
196 164470 : Jp2stf = 1
197 164470 : J2stf = 1
198 :
199 : ! transform along x axis
200 :
201 333616 : DO j = 1, n2, lot1
202 169146 : ma = j
203 169146 : mb = MIN(j + (lot1 - 1), n2)
204 169146 : nfft = mb - ma + 1
205 :
206 : !reverse index ordering, leaving the planes to be transformed at the end
207 : !input: I1,J2,j3,Jp2,(jp3)
208 169146 : IF (nproc == 1) THEN
209 136958 : CALL P_mpiswitch_upcorn(j3, nfft, Jp2stb, J2stb, lot1, n1, md2, nd3, nproc, zmpi2, zw1)
210 : ELSE
211 32188 : CALL P_mpiswitch_upcorn(j3, nfft, Jp2stb, J2stb, lot1, n1, md2, nd3, nproc, zmpi1, zw1)
212 : END IF
213 : !output: J2,Jp2,I1,j3,(jp3)
214 :
215 : !performing FFT
216 : !input: I2,I1,j3,(jp3)
217 : ! This is equivalent to
218 333616 : IF (nfft == lot1) THEN
219 4676 : CALL fft_1d(fft_plan_bw1, zw1, zt(j:, 1), 1.0_dp, stat)
220 : ELSE
221 164470 : CALL fft_1d(fft_plan_bw1_last, zw1, zt(j:, 1), 1.0_dp, stat)
222 : END IF
223 : !output: I2,i1,j3,(jp3)
224 : END DO
225 :
226 : !transform along y axis
227 :
228 333616 : DO j = 1, n1, lot2
229 169146 : ma = j
230 169146 : mb = MIN(j + (lot2 - 1), n1)
231 169146 : nfft = mb - ma + 1
232 :
233 : !reverse ordering
234 : !input: I2,i1,j3,(jp3)
235 169146 : CALL P_switch_upcorn(nfft, n2, lot2, n1, lzt, zt(:, j), zw1)
236 : !output: i1,I2,j3,(jp3)
237 :
238 : !performing FFT
239 : !input: i1,I2,j3,(jp3)
240 : ! This is equivalent to
241 169146 : IF (nfft == lot2) THEN
242 4676 : CALL fft_1d(fft_plan_bw2, zw1, zw2, 1.0_dp, stat)
243 : ELSE
244 164470 : CALL fft_1d(fft_plan_bw2_last, zw1, zw2, 1.0_dp, stat)
245 : END IF
246 : !output: i1,i2,j3,(jp3)
247 :
248 : !Multiply with kernel in fourier space
249 169146 : i3 = iproc*(nd3/nproc) + j3
250 169146 : CALL P_multkernel(n1, n2, n3, lot2, nfft, j, i3, zw2, hx, hy, hz)
251 :
252 : !TRANSFORM BACK IN REAL SPACE
253 :
254 : !transform along y axis
255 : !input: i1,i2,j3,(jp3)
256 : ! This is equivalent to
257 169146 : IF (nfft == lot2) THEN
258 4676 : CALL fft_1d(fft_plan_fw2, zw2, zw1, 1.0_dp, stat)
259 : ELSE
260 164470 : CALL fft_1d(fft_plan_fw2_last, zw2, zw1, 1.0_dp, stat)
261 : END IF
262 :
263 : !reverse ordering
264 : !input: i1,I2,j3,(jp3)
265 333616 : CALL P_unswitch_downcorn(nfft, n2, lot2, n1, lzt, zw1, zt(:, j))
266 : !output: I2,i1,j3,(jp3)
267 : END DO
268 :
269 : !transform along x axis
270 : !input: I2,i1,j3,(jp3)
271 333616 : DO j = 1, n2, lot1
272 169146 : ma = j
273 169146 : mb = MIN(j + (lot1 - 1), n2)
274 169146 : nfft = mb - ma + 1
275 :
276 : !performing FFT
277 : ! This is equivalent to
278 169146 : IF (nfft == lot1) THEN
279 4676 : CALL fft_1d(fft_plan_fw1, zt(j:, 1), zw2, 1.0_dp, stat)
280 : ELSE
281 164470 : CALL fft_1d(fft_plan_fw1_last, zt(j:, 1), zw2, 1.0_dp, stat)
282 : END IF
283 : !output: I2,I1,j3,(jp3)
284 :
285 : !reverse ordering
286 : !input: J2,Jp2,I1,j3,(jp3)
287 333616 : IF (nproc == 1) THEN
288 136958 : CALL P_unmpiswitch_downcorn(j3, nfft, Jp2stf, J2stf, lot1, n1, md2, nd3, nproc, zw2, zmpi2)
289 : ELSE
290 32188 : CALL P_unmpiswitch_downcorn(j3, nfft, Jp2stf, J2stf, lot1, n1, md2, nd3, nproc, zw2, zmpi1)
291 : END IF
292 : ! output: I1,J2,j3,Jp2,(jp3)
293 : END DO
294 : END IF
295 : END DO
296 :
297 : !Interprocessor data transposition
298 : !input: I1,J2,j3,Jp2,(jp3)
299 17323 : IF (nproc > 1) THEN
300 : !communication scheduling
301 4806 : CALL mpi_group%alltoall(zmpi1, zmpi2, n1*(md2/nproc)*(nd3/nproc))
302 : END IF
303 : !output: I1,J2,j3,jp3,(Jp2)
304 : !transform along z axis
305 : !input: I1,J2,i3,(Jp2)
306 320326 : DO j2 = 1, md2/nproc
307 : !this condition ensures that we manage only the interesting part for the FFT
308 320326 : IF (iproc*(md2/nproc) + j2 <= n2) THEN
309 613678 : DO i1 = 1, n1, lot3
310 311348 : ma = i1
311 311348 : mb = MIN(i1 + (lot3 - 1), n1)
312 311348 : nfft = mb - ma + 1
313 :
314 : !reverse ordering
315 : !input: I1,J2,i3,(Jp2)
316 311348 : CALL unscramble_P(i1, j2, lot3, nfft, n1, n3, md2, nproc, nd3, zmpi2, zw1)
317 : !output: I1,i3,J2,(Jp2)
318 :
319 : !performing FFT
320 : !input: I1,i3,J2,(Jp2)
321 : ! This is equivalent to
322 311348 : IF (nfft == lot3) THEN
323 9018 : CALL fft_1d(fft_plan_fw3, zw1, zw2, 1.0_dp, stat)
324 : ELSE
325 302330 : CALL fft_1d(fft_plan_fw3_last, zw1, zw2, 1.0_dp, stat)
326 : END IF
327 : !output: I1,I3,J2,(Jp2)
328 :
329 : !rebuild the output array
330 613678 : CALL P_unfill_downcorn(md1, md3, lot3, nfft, n3, zw2, zf(i1, 1, j2), scal)
331 :
332 : END DO
333 : END IF
334 : END DO
335 :
336 17323 : IF (n2 >= lot1) CALL fft_destroy_plan(fft_plan_bw1)
337 17323 : IF (final_chunk_size1 > 0) CALL fft_destroy_plan(fft_plan_bw1_last)
338 17323 : IF (n2 >= lot1) CALL fft_destroy_plan(fft_plan_fw1)
339 17323 : IF (final_chunk_size1 > 0) CALL fft_destroy_plan(fft_plan_fw1_last)
340 :
341 17323 : IF (n1 >= lot2) CALL fft_destroy_plan(fft_plan_bw2)
342 17323 : IF (final_chunk_size2 > 0) CALL fft_destroy_plan(fft_plan_bw2_last)
343 17323 : IF (n1 >= lot2) CALL fft_destroy_plan(fft_plan_fw2)
344 17323 : IF (final_chunk_size2 > 0) CALL fft_destroy_plan(fft_plan_fw2_last)
345 :
346 17323 : IF (n1 >= lot3) CALL fft_destroy_plan(fft_plan_fw3)
347 17323 : IF (final_chunk_size3 > 0) CALL fft_destroy_plan(fft_plan_fw3_last)
348 17323 : IF (n1 >= lot3) CALL fft_destroy_plan(fft_plan_bw3)
349 17323 : IF (final_chunk_size3 > 0) CALL fft_destroy_plan(fft_plan_bw3_last)
350 :
351 : !De-allocations
352 17323 : DEALLOCATE (zmpi2)
353 17323 : CALL fft_dealloc(zw1)
354 17323 : CALL fft_dealloc(zw2)
355 17323 : CALL fft_dealloc(zt)
356 17323 : IF (nproc > 1) DEALLOCATE (zmpi1)
357 658274 : END SUBROUTINE P_PoissonSolver
358 :
359 : ! **************************************************************************************************
360 : !> \brief ...
361 : !> \param j3 ...
362 : !> \param nfft ...
363 : !> \param Jp2stb ...
364 : !> \param J2stb ...
365 : !> \param lot ...
366 : !> \param n1 ...
367 : !> \param md2 ...
368 : !> \param nd3 ...
369 : !> \param nproc ...
370 : !> \param zmpi1 ...
371 : !> \param zw ...
372 : ! **************************************************************************************************
373 169146 : SUBROUTINE P_mpiswitch_upcorn(j3, nfft, Jp2stb, J2stb, lot, n1, md2, nd3, nproc, zmpi1, zw)
374 : INTEGER, INTENT(in) :: j3, nfft
375 : INTEGER, INTENT(inout) :: Jp2stb, J2stb
376 : INTEGER, INTENT(in) :: lot, n1, md2, nd3, nproc
377 : COMPLEX(KIND=dp), &
378 : DIMENSION(n1, md2/nproc, nd3/nproc, nproc), &
379 : INTENT(in) :: zmpi1
380 : COMPLEX(KIND=dp), DIMENSION(lot, n1), &
381 : INTENT(inout) :: zw
382 :
383 : INTEGER :: I1, J2, Jp2, mfft
384 :
385 169146 : mfft = 0
386 354650 : DO Jp2 = Jp2stb, nproc
387 3840810 : DO J2 = J2stb, md2/nproc
388 3655306 : mfft = mfft + 1
389 3655306 : IF (mfft > nfft) THEN
390 13478 : Jp2stb = Jp2
391 13478 : J2stb = J2
392 13478 : RETURN
393 : END IF
394 95925808 : DO I1 = 1, n1
395 95740304 : zw(mfft, I1) = zmpi1(I1, J2, j3, Jp2)
396 : END DO
397 : END DO
398 341172 : J2stb = 1
399 : END DO
400 : END SUBROUTINE P_mpiswitch_upcorn
401 :
402 : ! **************************************************************************************************
403 : !> \brief ...
404 : !> \param nfft ...
405 : !> \param n2 ...
406 : !> \param lot ...
407 : !> \param n1 ...
408 : !> \param lzt ...
409 : !> \param zt ...
410 : !> \param zw ...
411 : ! **************************************************************************************************
412 169146 : SUBROUTINE P_switch_upcorn(nfft, n2, lot, n1, lzt, zt, zw)
413 : INTEGER, INTENT(in) :: nfft, n2, lot, n1, lzt
414 : COMPLEX(KIND=dp), DIMENSION(lzt, n1), INTENT(in) :: zt
415 : COMPLEX(KIND=dp), DIMENSION(lot, n2), &
416 : INTENT(inout) :: zw
417 :
418 : INTEGER :: i, j
419 :
420 3810974 : DO j = 1, nfft
421 95909450 : DO i = 1, n2
422 95740304 : zw(j, i) = zt(i, j)
423 : END DO
424 : END DO
425 :
426 169146 : END SUBROUTINE P_switch_upcorn
427 :
428 : ! **************************************************************************************************
429 : !> \brief ...
430 : !> \param nfft ...
431 : !> \param n2 ...
432 : !> \param lot ...
433 : !> \param n1 ...
434 : !> \param lzt ...
435 : !> \param zw ...
436 : !> \param zt ...
437 : ! **************************************************************************************************
438 169146 : SUBROUTINE P_unswitch_downcorn(nfft, n2, lot, n1, lzt, zw, zt)
439 : INTEGER, INTENT(in) :: nfft, n2, lot, n1, lzt
440 : COMPLEX(KIND=dp), DIMENSION(lot, n2), INTENT(in) :: zw
441 : COMPLEX(KIND=dp), DIMENSION(lzt, n1), &
442 : INTENT(inout) :: zt
443 :
444 : INTEGER :: i, j
445 :
446 3810974 : DO j = 1, nfft
447 95909450 : DO i = 1, n2
448 95740304 : zt(i, j) = zw(j, i)
449 : END DO
450 : END DO
451 :
452 169146 : END SUBROUTINE P_unswitch_downcorn
453 :
454 : ! **************************************************************************************************
455 : !> \brief ...
456 : !> \param j3 ...
457 : !> \param nfft ...
458 : !> \param Jp2stf ...
459 : !> \param J2stf ...
460 : !> \param lot ...
461 : !> \param n1 ...
462 : !> \param md2 ...
463 : !> \param nd3 ...
464 : !> \param nproc ...
465 : !> \param zw ...
466 : !> \param zmpi1 ...
467 : ! **************************************************************************************************
468 169146 : SUBROUTINE P_unmpiswitch_downcorn(j3, nfft, Jp2stf, J2stf, lot, n1, md2, nd3, nproc, zw, zmpi1)
469 : INTEGER, INTENT(in) :: j3, nfft
470 : INTEGER, INTENT(inout) :: Jp2stf, J2stf
471 : INTEGER, INTENT(in) :: lot, n1, md2, nd3, nproc
472 : COMPLEX(KIND=dp), DIMENSION(lot, n1), INTENT(in) :: zw
473 : COMPLEX(KIND=dp), &
474 : DIMENSION(n1, md2/nproc, nd3/nproc, nproc), &
475 : INTENT(inout) :: zmpi1
476 :
477 : INTEGER :: I1, J2, Jp2, mfft
478 :
479 169146 : mfft = 0
480 354650 : DO Jp2 = Jp2stf, nproc
481 3840810 : DO J2 = J2stf, md2/nproc
482 3655306 : mfft = mfft + 1
483 3655306 : IF (mfft > nfft) THEN
484 13478 : Jp2stf = Jp2
485 13478 : J2stf = J2
486 13478 : RETURN
487 : END IF
488 95925808 : DO I1 = 1, n1
489 95740304 : zmpi1(I1, J2, j3, Jp2) = zw(mfft, I1)
490 : END DO
491 : END DO
492 341172 : J2stf = 1
493 : END DO
494 : END SUBROUTINE P_unmpiswitch_downcorn
495 :
496 : ! **************************************************************************************************
497 : !> \brief (Based on suitable modifications of S.Goedecker routines)
498 : !> Restore data into output array
499 : !> \param md1 Dimensions of the undistributed part of the real grid
500 : !> \param md3 Dimensions of the undistributed part of the real grid
501 : !> \param lot ...
502 : !> \param nfft number of planes
503 : !> \param n3 (twice the) dimension of the last FFTtransform
504 : !> \param zw FFT work array
505 : !> \param zf Original distributed density as well as
506 : !> Distributed solution of the poisson equation (inout)
507 : !> \param scal Needed to achieve unitarity and correct dimensions
508 : !> \date February 2006
509 : !> \author S. Goedecker, L. Genovese
510 : !> \note Assuming that high frequencies are in the corners
511 : !> and that n3 is multiple of 4
512 : !>
513 : !> RESTRICTIONS on USAGE
514 : !> Copyright (C) Stefan Goedecker, Cornell University, Ithaca, USA, 1994
515 : !> Copyright (C) Stefan Goedecker, MPI Stuttgart, Germany, 1999
516 : !> Copyright (C) 2002 Stefan Goedecker, CEA Grenoble
517 : !> This file is distributed under the terms of the
518 : !> GNU General Public License, see http://www.gnu.org/copyleft/gpl.txt .
519 : ! **************************************************************************************************
520 311348 : SUBROUTINE P_unfill_downcorn(md1, md3, lot, nfft, n3, zw, zf, scal)
521 : INTEGER, INTENT(in) :: md1, md3, lot, nfft, n3
522 : COMPLEX(KIND=dp), DIMENSION(lot, n3), INTENT(in) :: zw
523 : REAL(KIND=dp), DIMENSION(md1, md3), INTENT(inout) :: zf
524 : REAL(KIND=dp), INTENT(in) :: scal
525 :
526 : INTEGER :: i1, i3
527 : REAL(KIND=dp) :: pot1
528 :
529 7534542 : DO i3 = 1, n3
530 179338112 : DO i1 = 1, nfft
531 171803570 : pot1 = scal*REAL(zw(i1, i3), dp)
532 179026764 : zf(i1, i3) = pot1
533 : END DO
534 : END DO
535 :
536 311348 : END SUBROUTINE P_unfill_downcorn
537 :
538 : ! **************************************************************************************************
539 : !> \brief ...
540 : !> \param md1 ...
541 : !> \param md3 ...
542 : !> \param lot ...
543 : !> \param nfft ...
544 : !> \param n3 ...
545 : !> \param zf ...
546 : !> \param zw ...
547 : ! **************************************************************************************************
548 311348 : SUBROUTINE P_fill_upcorn(md1, md3, lot, nfft, n3, zf, zw)
549 : INTEGER, INTENT(in) :: md1, md3, lot, nfft, n3
550 : REAL(KIND=dp), DIMENSION(md1, md3), INTENT(in) :: zf
551 : COMPLEX(KIND=dp), DIMENSION(lot, n3), &
552 : INTENT(inout) :: zw
553 :
554 : INTEGER :: i1, i3
555 :
556 7534542 : DO i3 = 1, n3
557 179338112 : DO i1 = 1, nfft
558 179026764 : zw(i1, i3) = CMPLX(zf(i1, i3), 0.0_dp, dp)
559 : END DO
560 : END DO
561 :
562 311348 : END SUBROUTINE P_fill_upcorn
563 :
564 : ! **************************************************************************************************
565 : !> \brief (Based on suitable modifications of S.Goedecker routines)
566 : !> Assign the correct planes to the work array zmpi2
567 : !> in order to prepare for interprocessor data transposition.
568 : !> \param i1 Starting points of the plane and number of remaining lines
569 : !> \param j2 Starting points of the plane and number of remaining lines
570 : !> \param lot Starting points of the plane and number of remaining lines
571 : !> \param nfft Starting points of the plane and number of remaining lines
572 : !> \param n1 logical dimension of the FFT transform, reference for work arrays
573 : !> \param n3 logical dimension of the FFT transform, reference for work arrays
574 : !> \param md2 Dimensions of real grid
575 : !> \param nproc ...
576 : !> \param nd3 Dimensions of the kernel
577 : !> \param zw Work array (input)
578 : !> \param zmpi2 Work array for multiprocessor manipulation (output)
579 : !> \date February 2006
580 : !> \author S. Goedecker, L. Genovese
581 : !> \note
582 : !> RESTRICTIONS on USAGE
583 : !> Copyright (C) Stefan Goedecker, Cornell University, Ithaca, USA, 1994
584 : !> Copyright (C) Stefan Goedecker, MPI Stuttgart, Germany, 1999
585 : !> Copyright (C) 2002 Stefan Goedecker, CEA Grenoble
586 : !> This file is distributed under the terms of the
587 : !> GNU General Public License, see http://www.gnu.org/copyleft/gpl.txt .
588 : ! **************************************************************************************************
589 311348 : SUBROUTINE scramble_P(i1, j2, lot, nfft, n1, n3, md2, nproc, nd3, zw, zmpi2)
590 : INTEGER, INTENT(in) :: i1, j2, lot, nfft, n1, n3, md2, nproc, &
591 : nd3
592 : COMPLEX(KIND=dp), DIMENSION(lot, n3), INTENT(in) :: zw
593 : COMPLEX(KIND=dp), DIMENSION(n1, md2/nproc, nd3), &
594 : INTENT(inout) :: zmpi2
595 :
596 : INTEGER :: i, i3
597 :
598 4205680 : DO i3 = 1, n3/2 + 1
599 96304156 : DO i = 0, nfft - 1
600 95992808 : zmpi2(i1 + i, j2, i3) = zw(i + 1, i3)
601 : END DO
602 : END DO
603 :
604 311348 : END SUBROUTINE scramble_P
605 :
606 : ! **************************************************************************************************
607 : !> \brief (Based on suitable modifications of S.Goedecker routines)
608 : !> Insert the correct planes of the work array zmpi2
609 : !> in order to prepare for backward FFT transform
610 : !> \param i1 Starting points of the plane and number of remaining lines
611 : !> \param j2 Starting points of the plane and number of remaining lines
612 : !> \param lot Starting points of the plane and number of remaining lines
613 : !> \param nfft Starting points of the plane and number of remaining lines
614 : !> \param n1 logical dimension of the FFT transform, reference for work arrays
615 : !> \param n3 logical dimension of the FFT transform, reference for work arrays
616 : !> \param md2 Dimensions of real grid
617 : !> \param nproc ...
618 : !> \param nd3 Dimensions of the kernel
619 : !> \param zmpi2 Work array for multiprocessor manipulation (output)
620 : !> \param zw Work array (input)
621 : !> \date February 2006
622 : !> \author S. Goedecker, L. Genovese
623 : !> \note
624 : !> RESTRICTIONS on USAGE
625 : !> Copyright (C) Stefan Goedecker, Cornell University, Ithaca, USA, 1994
626 : !> Copyright (C) Stefan Goedecker, MPI Stuttgart, Germany, 1999
627 : !> Copyright (C) 2002 Stefan Goedecker, CEA Grenoble
628 : !> This file is distributed under the terms of the
629 : !> GNU General Public License, see http://www.gnu.org/copyleft/gpl.txt .
630 : ! **************************************************************************************************
631 311348 : SUBROUTINE unscramble_P(i1, j2, lot, nfft, n1, n3, md2, nproc, nd3, zmpi2, zw)
632 : INTEGER, INTENT(in) :: i1, j2, lot, nfft, n1, n3, md2, nproc, &
633 : nd3
634 : COMPLEX(KIND=dp), DIMENSION(n1, md2/nproc, nd3), &
635 : INTENT(in) :: zmpi2
636 : COMPLEX(KIND=dp), DIMENSION(lot, n3), &
637 : INTENT(inout) :: zw
638 :
639 : INTEGER :: i, i3, j3
640 :
641 311348 : i3 = 1
642 7047570 : DO i = 0, nfft - 1
643 7047570 : zw(i + 1, i3) = zmpi2(i1 + i, j2, i3)
644 : END DO
645 :
646 3894332 : DO i3 = 2, n3/2 + 1
647 3582984 : j3 = n3 + 2 - i3
648 89256586 : DO i = 0, nfft - 1
649 85362254 : zw(i + 1, j3) = CONJG(zmpi2(i1 + i, j2, i3))
650 88945238 : zw(i + 1, i3) = zmpi2(i1 + i, j2, i3)
651 : END DO
652 : END DO
653 :
654 311348 : END SUBROUTINE unscramble_P
655 :
656 : ! **************************************************************************************************
657 : !> \brief (Based on suitable modifications of S.Goedecker routines)
658 : !> Multiply with the kernel taking into account its symmetry
659 : !> Conceived to be used into convolution loops
660 : !> \param n1 ...
661 : !> \param n2 ...
662 : !> \param n3 ...
663 : !> \param lot ...
664 : !> \param nfft ...
665 : !> \param jS ...
666 : !> \param i3 ...
667 : !> \param zw Work array (input/output)
668 : !> n1,n2: logical dimension of the FFT transform, reference for zw
669 : !> nd1,nd2: Dimensions of POT
670 : !> jS,j3,nfft: starting point of the plane and number of remaining lines
671 : !>
672 : !> RESTRICTIONS on USAGE
673 : !> Copyright (C) Stefan Goedecker, Cornell University, Ithaca, USA, 1994
674 : !> Copyright (C) Stefan Goedecker, MPI Stuttgart, Germany, 1999
675 : !> Copyright (C) 2002 Stefan Goedecker, CEA Grenoble
676 : !> This file is distributed under the terms of the
677 : !> GNU General Public License, see http://www.gnu.org/copyleft/gpl.txt .
678 : !> \param hx ...
679 : !> \param hy ...
680 : !> \param hz ...
681 : !> \date February 2006
682 : !> \author S. Goedecker, L. Genovese
683 : ! **************************************************************************************************
684 169146 : SUBROUTINE P_multkernel(n1, n2, n3, lot, nfft, jS, i3, zw, hx, hy, hz)
685 : INTEGER, INTENT(in) :: n1, n2, n3, lot, nfft, jS, i3
686 : COMPLEX(KIND=dp), DIMENSION(lot, n2), &
687 : INTENT(inout) :: zw
688 : REAL(KIND=dp), INTENT(in) :: hx, hy, hz
689 :
690 : INTEGER :: i1, i2, j1, j2, j3
691 : REAL(KIND=dp) :: fourpi2, ker, mu3, p1, p2
692 :
693 169146 : fourpi2 = 4._dp*pi**2
694 169146 : j3 = i3 !n3/2+1-abs(n3/2+2-i3)
695 169146 : mu3 = REAL(j3 - 1, KIND=dp)/REAL(n3, KIND=dp)
696 169146 : mu3 = (mu3/hy)**2 !beware of the exchanged dimension
697 : !Body
698 : !generic case
699 4063478 : DO i2 = 1, n2
700 96161954 : DO i1 = 1, nfft
701 92098476 : j1 = i1 + jS - 1
702 92098476 : j1 = j1 - (j1/(n1/2 + 2))*n1 !n1/2+1-abs(n1/2+2-jS-i1)
703 92098476 : j2 = i2 - (i2/(n2/2 + 2))*n2 !n2/2+1-abs(n2/2+1-i2)
704 92098476 : p1 = REAL(j1 - 1, KIND=dp)/REAL(n1, KIND=dp)
705 92098476 : p2 = REAL(j2 - 1, KIND=dp)/REAL(n2, KIND=dp)
706 92098476 : ker = -fourpi2*((p1/hx)**2 + (p2/hz)**2 + mu3) !beware of the exchanged dimension
707 92098476 : IF (ker /= 0._dp) ker = 1._dp/ker
708 95992808 : zw(i1, i2) = zw(i1, i2)*ker
709 : END DO
710 : END DO
711 :
712 169146 : END SUBROUTINE P_multkernel
713 :
714 : ! **************************************************************************************************
715 : !> \brief (Based on suitable modifications of S.Goedecker routines)
716 : !> Multiply with the kernel taking into account its symmetry
717 : !> Conceived to be used into convolution loops
718 : !> \param nd1 ...
719 : !> \param nd2 ...
720 : !> \param n1 ...
721 : !> \param n2 ...
722 : !> \param lot ...
723 : !> \param nfft ...
724 : !> \param jS ...
725 : !> \param pot Kernel, symmetric and real, half the length
726 : !> \param zw Work array (input/output)
727 : !> n1,n2: logical dimension of the FFT transform, reference for zw
728 : !> nd1,nd2: Dimensions of POT
729 : !> jS, nfft: starting point of the plane and number of remaining lines
730 : !>
731 : !> RESTRICTIONS on USAGE
732 : !> Copyright (C) Stefan Goedecker, Cornell University, Ithaca, USA, 1994
733 : !> Copyright (C) Stefan Goedecker, MPI Stuttgart, Germany, 1999
734 : !> Copyright (C) 2002 Stefan Goedecker, CEA Grenoble
735 : !> This file is distributed under the terms of the
736 : !> GNU General Public License, see http://www.gnu.org/copyleft/gpl.txt .
737 : !> \date February 2006
738 : !> \author S. Goedecker, L. Genovese
739 : ! **************************************************************************************************
740 2246238 : SUBROUTINE multkernel(nd1, nd2, n1, n2, lot, nfft, jS, pot, zw)
741 : INTEGER, INTENT(in) :: nd1, nd2, n1, n2, lot, nfft, jS
742 : REAL(KIND=dp), DIMENSION(nd1, nd2), INTENT(in) :: pot
743 : COMPLEX(KIND=dp), DIMENSION(lot, n2), &
744 : INTENT(inout) :: zw
745 :
746 : INTEGER :: i2, j, j1, j2
747 :
748 42306128 : DO j = 1, nfft
749 40059890 : j1 = j + jS - 1
750 40059890 : j1 = j1 + (j1/(n1/2 + 2))*(n1 + 2 - 2*j1)
751 42306128 : zw(j, 1) = zw(j, 1)*pot(j1, 1)
752 : END DO
753 :
754 : !generic case
755 123417162 : DO i2 = 2, n2/2
756 2060343990 : DO j = 1, nfft
757 1936926828 : j1 = j + jS - 1
758 1936926828 : j1 = j1 + (j1/(n1/2 + 2))*(n1 + 2 - 2*j1)
759 1936926828 : j2 = n2 + 2 - i2
760 1936926828 : zw(j, i2) = zw(j, i2)*pot(j1, i2)
761 2058097752 : zw(j, j2) = zw(j, j2)*pot(j1, i2)
762 : END DO
763 : END DO
764 :
765 : !case i2=n2/2+1
766 42306128 : DO j = 1, nfft
767 40059890 : j1 = j + jS - 1
768 40059890 : j1 = j1 + (j1/(n1/2 + 2))*(n1 + 2 - 2*j1)
769 40059890 : j2 = n2/2 + 1
770 42306128 : zw(j, j2) = zw(j, j2)*pot(j1, j2)
771 : END DO
772 :
773 2246238 : END SUBROUTINE multkernel
774 :
775 : ! **************************************************************************************************
776 : !> \brief !HERE POT MUST BE THE KERNEL (BEWARE THE HALF DIMENSION)
777 : !> ****h* BigDFT/S_PoissonSolver
778 : !> (Based on suitable modifications of S.Goedecker routines)
779 : !> Applies the local FFT space Kernel to the density in Real space.
780 : !> Does NOT calculate the LDA exchange-correlation terms
781 : !> \param n1 logical dimension of the transform.
782 : !> \param n2 logical dimension of the transform.
783 : !> \param n3 logical dimension of the transform.
784 : !> \param nd1 Dimension of POT
785 : !> \param nd2 Dimension of POT
786 : !> \param nd3 Dimension of POT
787 : !> \param md1 Dimension of ZF
788 : !> \param md2 Dimension of ZF
789 : !> \param md3 Dimension of ZF
790 : !> \param nproc number of processors used as returned by MPI_COMM_SIZE
791 : !> \param iproc [0:nproc-1] number of processor as returned by MPI_COMM_RANK
792 : !> \param pot Kernel, only the distributed part (REAL)
793 : !> POT(i1,i2,i3)
794 : !> i1=1,nd1 , i2=1,nd2 , i3=1,nd3/nproc
795 : !> \param zf Density (input/output)
796 : !> ZF(i1,i3,i2)
797 : !> i1=1,md1 , i2=1,md2/nproc , i3=1,md3
798 : !> \param scal factor of renormalization of the FFT in order to acheve unitarity
799 : !> and the correct dimension
800 : !> \param mpi_group ...
801 : !> \date October 2006
802 : !> \author S. Goedecker, L. Genovese
803 : !> \note
804 : !> RESTRICTIONS on USAGE
805 : !> Copyright (C) Stefan Goedecker, Cornell University, Ithaca, USA, 1994
806 : !> Copyright (C) Stefan Goedecker, MPI Stuttgart, Germany, 1999
807 : !> Copyright (C) 2002 Stefan Goedecker, CEA Grenoble
808 : !> This file is distributed under the terms of the
809 : !> GNU General Public License, see http://www.gnu.org/copyleft/gpl.txt .
810 : ! **************************************************************************************************
811 54 : SUBROUTINE S_PoissonSolver(n1, n2, n3, nd1, nd2, nd3, md1, md2, md3, nproc, iproc, pot, zf, &
812 : scal, mpi_group)
813 : INTEGER, INTENT(in) :: n1, n2, n3, nd1, nd2, nd3, md1, md2, &
814 : md3, nproc, iproc
815 : REAL(KIND=dp), DIMENSION(nd1, nd2, nd3/nproc), &
816 : INTENT(in) :: pot
817 : REAL(KIND=dp), DIMENSION(md1, md3, md2/nproc), &
818 : INTENT(inout) :: zf
819 : REAL(KIND=dp), INTENT(in) :: scal
820 :
821 : CLASS(mp_comm_type), INTENT(in) :: mpi_group
822 :
823 : CHARACTER(len=*), PARAMETER :: routineN = 'S_PoissonSolver'
824 : INTEGER, PARAMETER :: ncache_optimal = 8*1024
825 :
826 : INTEGER :: handle, i1, i3, j, j2, J2stb, J2stf, j3, Jp2stb, &
827 : Jp2stf, lot1, lot2, lot3, lzt, ma, mb, ncache, nfft, stat, &
828 : final_chunk_size1, final_chunk_size2, final_chunk_size3
829 : REAL(kind=dp) :: twopion
830 54 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: cosinarr
831 54 : COMPLEX(KIND=dp), POINTER, CONTIGUOUS, DIMENSION(:, :) :: zt
832 54 : COMPLEX(KIND=dp), POINTER, CONTIGUOUS, DIMENSION(:) :: zw1, zw2
833 : COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: zmpi2
834 : COMPLEX(KIND=dp), ALLOCATABLE, &
835 54 : DIMENSION(:, :, :, :) :: zmpi1
836 : TYPE(fft_plan_type) :: fft_plan_bw3, fft_plan_bw3_last, fft_plan_fw3, fft_plan_fw3_last, &
837 : fft_plan_bw1, fft_plan_bw1_last, fft_plan_fw1, fft_plan_fw1_last, &
838 : fft_plan_bw2, fft_plan_bw2_last, fft_plan_fw2, fft_plan_fw2_last
839 :
840 54 : CALL timeset(routineN, handle)
841 : ! check input
842 54 : IF (MOD(n3, 2) /= 0) CPABORT("Parallel convolution:ERROR:n3")
843 54 : IF (nd1 < n1/2 + 1) CPABORT("Parallel convolution:ERROR:nd1")
844 54 : IF (nd2 < n2/2 + 1) CPABORT("Parallel convolution:ERROR:nd2")
845 54 : IF (nd3 < n3/2 + 1) CPABORT("Parallel convolution:ERROR:nd3")
846 54 : IF (md1 < n1) CPABORT("Parallel convolution:ERROR:md1")
847 54 : IF (md2 < n2) CPABORT("Parallel convolution:ERROR:md2")
848 54 : IF (md3 < n3/2) CPABORT("Parallel convolution:ERROR:md3")
849 54 : IF (MOD(nd3, nproc) /= 0) CPABORT("Parallel convolution:ERROR:nd3")
850 54 : IF (MOD(md2, nproc) /= 0) CPABORT("Parallel convolution:ERROR:md2")
851 :
852 : !defining work arrays dimensions
853 54 : ncache = ncache_optimal
854 54 : IF (ncache <= MAX(n1, n2, n3/2)*4) ncache = MAX(n1, n2, n3/2)*4
855 :
856 54 : lzt = n2
857 54 : IF (MOD(n2, 2) == 0) lzt = lzt + 1
858 54 : IF (MOD(n2, 4) == 0) lzt = lzt + 1 !maybe this is useless
859 :
860 108 : CALL fft_alloc(zw1, [ncache/4])
861 54 : zw1 = CMPLX(0.0_dp, 0.0_dp, KIND=dp)
862 108 : CALL fft_alloc(zw2, [ncache/4])
863 54 : zw2 = CMPLX(0.0_dp, 0.0_dp, KIND=dp)
864 162 : CALL fft_alloc(zt, [lzt, n1])
865 54 : zt = CMPLX(0.0_dp, 0.0_dp, dp)
866 270 : ALLOCATE (zmpi2(n1, md2/nproc, nd3), SOURCE=CMPLX(0.0_dp, 0.0_dp, dp))
867 216 : ALLOCATE (cosinarr(2, n3/2))
868 324 : IF (nproc > 1) ALLOCATE (zmpi1(n1, md2/nproc, nd3/nproc, nproc), SOURCE=CMPLX(0.0_dp, 0.0_dp, dp))
869 :
870 : !Calculating array of phases for HalFFT decoding
871 54 : twopion = 8._dp*ATAN(1._dp)/REAL(n3, KIND=dp)
872 2970 : DO i3 = 1, n3/2
873 2916 : cosinarr(1, i3) = COS(twopion*(i3 - 1))
874 2970 : cosinarr(2, i3) = -SIN(twopion*(i3 - 1))
875 : END DO
876 :
877 : !initializing integral
878 :
879 : ! transform along z axis
880 54 : lot1 = ncache/(4*n1)
881 54 : lot2 = ncache/(4*n2)
882 54 : lot3 = ncache/(2*n3)
883 :
884 : ! The size of the last chunk
885 54 : final_chunk_size1 = MOD(n2, lot1)
886 54 : final_chunk_size2 = MOD(n1, lot2)
887 54 : final_chunk_size3 = MOD(n1, lot3)
888 :
889 : ! Prevent OOB-access if n2 < lot1
890 54 : IF (n2 >= lot1) THEN
891 54 : CALL fft_create_plan_1d(fft_plan_bw1, BWFFT, .TRUE., .TRUE., lot1, lzt, n1, lot1, zw1, zt)
892 54 : CALL fft_create_plan_1d(fft_plan_fw1, FWFFT, .TRUE., .TRUE., lzt, lot1, n1, lot1, zt, zw1)
893 : END IF
894 54 : IF (final_chunk_size1 > 0) THEN
895 : CALL fft_create_plan_1d(fft_plan_bw1_last, BWFFT, .TRUE., .TRUE., lot1, lzt, n1, &
896 54 : final_chunk_size1, zw1, zt)
897 : CALL fft_create_plan_1d(fft_plan_fw1_last, FWFFT, .TRUE., .TRUE., lzt, lot1, n1, &
898 54 : final_chunk_size1, zt, zw1)
899 : END IF
900 :
901 : ! Prevent OOB-access if n2 < lot1
902 54 : IF (n1 >= lot2) THEN
903 54 : CALL fft_create_plan_1d(fft_plan_bw2, BWFFT, .TRUE., .TRUE., lot2, lot2, n2, lot2, zw1, zw2)
904 54 : CALL fft_create_plan_1d(fft_plan_fw2, FWFFT, .TRUE., .TRUE., lot2, lot2, n2, lot2, zw2, zw1)
905 : END IF
906 54 : IF (final_chunk_size2 > 0) THEN
907 : CALL fft_create_plan_1d(fft_plan_bw2_last, BWFFT, .TRUE., .TRUE., lot2, lot2, n2, &
908 54 : final_chunk_size2, zw1, zw2)
909 : CALL fft_create_plan_1d(fft_plan_fw2_last, FWFFT, .TRUE., .TRUE., lot2, lot2, n2, &
910 54 : final_chunk_size2, zw2, zw1)
911 : END IF
912 :
913 : ! Prevent OOB-access if n1 < lot3
914 54 : IF (n1 >= lot3) THEN
915 54 : CALL fft_create_plan_1d(fft_plan_fw3, FWFFT, .TRUE., .TRUE., lot3, lot3, n3/2, lot3, zw1, zw2)
916 54 : CALL fft_create_plan_1d(fft_plan_bw3, BWFFT, .TRUE., .TRUE., lot3, lot3, n3/2, lot3, zw1, zw2)
917 : END IF
918 54 : IF (final_chunk_size3 > 0) THEN
919 : CALL fft_create_plan_1d(fft_plan_fw3_last, FWFFT, .TRUE., .TRUE., &
920 54 : lot3, lot3, n3/2, final_chunk_size3, zw1, zw2)
921 : CALL fft_create_plan_1d(fft_plan_bw3_last, BWFFT, .TRUE., .TRUE., &
922 54 : lot3, lot3, n3/2, final_chunk_size3, zw1, zw2)
923 : END IF
924 :
925 1512 : DO j2 = 1, md2/nproc
926 : !this condition ensures that we manage only the interesting part for the FFT
927 1512 : IF (iproc*(md2/nproc) + j2 <= n2) THEN
928 4374 : DO i1 = 1, n1, lot3
929 2916 : ma = i1
930 2916 : mb = MIN(i1 + (lot3 - 1), n1)
931 2916 : nfft = mb - ma + 1
932 :
933 : !inserting real data into complex array of half length
934 2916 : CALL halfill_upcorn(md1, md3, lot3, nfft, n3, zf(i1, 1, j2), zw1)
935 :
936 : !performing FFT
937 : !input: I1,I3,J2,(Jp2)
938 : ! This is equivalent to
939 2916 : IF (nfft == lot3) THEN
940 1458 : CALL fft_1d(fft_plan_bw3, zw1, zw2, 1.0_dp, stat)
941 : ELSE
942 1458 : CALL fft_1d(fft_plan_bw3_last, zw1, zw2, 1.0_dp, stat)
943 : END IF
944 : !output: I1,i3,J2,(Jp2)
945 : !unpacking FFT in order to restore correct result,
946 : !while exchanging components
947 : !input: I1,i3,J2,(Jp2)
948 4374 : CALL scramble_unpack(i1, j2, lot3, nfft, n1, n3, md2, nproc, nd3, zw2, zmpi2, cosinarr)
949 : !output: I1,J2,i3,(Jp2)
950 : END DO
951 : END IF
952 : END DO
953 : !Interprocessor data transposition
954 : !input: I1,J2,j3,jp3,(Jp2)
955 54 : IF (nproc > 1) THEN
956 54 : CALL mpi_group%alltoall(zmpi2, zmpi1, n1*(md2/nproc)*(nd3/nproc))
957 : END IF
958 : !output: I1,J2,j3,Jp2,(jp3)
959 :
960 : !now each process perform complete convolution of its planes
961 1566 : DO j3 = 1, nd3/nproc
962 : !this condition ensures that we manage only the interesting part for the FFT
963 1566 : IF (iproc*(nd3/nproc) + j3 <= n3/2 + 1) THEN
964 1485 : Jp2stb = 1
965 1485 : J2stb = 1
966 1485 : Jp2stf = 1
967 1485 : J2stf = 1
968 :
969 : ! transform along x axis
970 :
971 4455 : DO j = 1, n2, lot1
972 2970 : ma = j
973 2970 : mb = MIN(j + (lot1 - 1), n2)
974 2970 : nfft = mb - ma + 1
975 :
976 : !reverse index ordering, leaving the planes to be transformed at the end
977 : !input: I1,J2,j3,Jp2,(jp3)
978 2970 : IF (nproc == 1) THEN
979 0 : CALL S_mpiswitch_upcorn(j3, nfft, Jp2stb, J2stb, lot1, n1, md2, nd3, nproc, zmpi2, zw1)
980 : ELSE
981 2970 : CALL S_mpiswitch_upcorn(j3, nfft, Jp2stb, J2stb, lot1, n1, md2, nd3, nproc, zmpi1, zw1)
982 : END IF
983 : !output: J2,Jp2,I1,j3,(jp3)
984 :
985 : !performing FFT
986 : !input: I2,I1,j3,(jp3)
987 : ! This is equivalent to
988 4455 : IF (nfft == lot1) THEN
989 1485 : CALL fft_1d(fft_plan_bw1, zw1, zt(j:, 1), 1.0_dp, stat)
990 : ELSE
991 1485 : CALL fft_1d(fft_plan_bw1_last, zw1, zt(j:, 1), 1.0_dp, stat)
992 : END IF
993 : !output: I2,i1,j3,(jp3)
994 : END DO
995 :
996 : !transform along y axis
997 :
998 4455 : DO j = 1, n1, lot2
999 2970 : ma = j
1000 2970 : mb = MIN(j + (lot2 - 1), n1)
1001 2970 : nfft = mb - ma + 1
1002 :
1003 : !reverse ordering
1004 : !input: I2,i1,j3,(jp3)
1005 2970 : CALL S_switch_upcorn(nfft, n2, lot2, n1, lzt, zt(:, j), zw1)
1006 : !output: i1,I2,j3,(jp3)
1007 :
1008 : !performing FFT
1009 : !input: i1,I2,j3,(jp3)
1010 : ! This is equivalent to
1011 2970 : IF (nfft == lot2) THEN
1012 1485 : CALL fft_1d(fft_plan_bw2, zw1, zw2, 1.0_dp, stat)
1013 : ELSE
1014 1485 : CALL fft_1d(fft_plan_bw2_last, zw1, zw2, 1.0_dp, stat)
1015 : END IF
1016 : !output: i1,i2,j3,(jp3)
1017 :
1018 : !Multiply with kernel in fourier space
1019 2970 : CALL multkernel(nd1, nd2, n1, n2, lot2, nfft, j, pot(1, 1, j3), zw2)
1020 :
1021 : !TRANSFORM BACK IN REAL SPACE
1022 :
1023 : !transform along y axis
1024 : !input: i1,i2,j3,(jp3)
1025 : ! This is equivalent to
1026 2970 : IF (nfft == lot2) THEN
1027 1485 : CALL fft_1d(fft_plan_fw2, zw2, zw1, 1.0_dp, stat)
1028 : ELSE
1029 1485 : CALL fft_1d(fft_plan_fw2_last, zw2, zw1, 1.0_dp, stat)
1030 : END IF
1031 :
1032 : !reverse ordering
1033 : !input: i1,I2,j3,(jp3)
1034 4455 : CALL S_unswitch_downcorn(nfft, n2, lot2, n1, lzt, zw1, zt(:, j))
1035 : !output: I2,i1,j3,(jp3)
1036 : END DO
1037 :
1038 : !transform along x axis
1039 : !input: I2,i1,j3,(jp3)
1040 4455 : DO j = 1, n2, lot1
1041 2970 : ma = j
1042 2970 : mb = MIN(j + (lot1 - 1), n2)
1043 2970 : nfft = mb - ma + 1
1044 :
1045 : !performing FFT
1046 : ! This is equivalent to
1047 2970 : IF (nfft == lot1) THEN
1048 1485 : CALL fft_1d(fft_plan_fw1, zt(j:, 1), zw2, 1.0_dp, stat)
1049 : ELSE
1050 1485 : CALL fft_1d(fft_plan_fw1_last, zt(j:, 1), zw2, 1.0_dp, stat)
1051 : END IF
1052 : !output: I2,I1,j3,(jp3)
1053 :
1054 : !reverse ordering
1055 : !input: J2,Jp2,I1,j3,(jp3)
1056 4455 : IF (nproc == 1) THEN
1057 0 : CALL S_unmpiswitch_downcorn(j3, nfft, Jp2stf, J2stf, lot1, n1, md2, nd3, nproc, zw2, zmpi2)
1058 : ELSE
1059 2970 : CALL S_unmpiswitch_downcorn(j3, nfft, Jp2stf, J2stf, lot1, n1, md2, nd3, nproc, zw2, zmpi1)
1060 : END IF
1061 : ! output: I1,J2,j3,Jp2,(jp3)
1062 : END DO
1063 : END IF
1064 : END DO
1065 :
1066 : !Interprocessor data transposition
1067 : !input: I1,J2,j3,Jp2,(jp3)
1068 54 : IF (nproc > 1) THEN
1069 : !communication scheduling
1070 54 : CALL mpi_group%alltoall(zmpi1, zmpi2, n1*(md2/nproc)*(nd3/nproc))
1071 : END IF
1072 :
1073 : !output: I1,J2,j3,jp3,(Jp2)
1074 :
1075 : !transform along z axis
1076 : !input: I1,J2,i3,(Jp2)
1077 1512 : DO j2 = 1, md2/nproc
1078 : !this condition ensures that we manage only the interesting part for the FFT
1079 1512 : IF (iproc*(md2/nproc) + j2 <= n2) THEN
1080 4374 : DO i1 = 1, n1, lot3
1081 2916 : ma = i1
1082 2916 : mb = MIN(i1 + (lot3 - 1), n1)
1083 2916 : nfft = mb - ma + 1
1084 :
1085 : !reverse ordering and repack the FFT data in order to be backward HalFFT transformed
1086 : !input: I1,J2,i3,(Jp2)
1087 2916 : CALL unscramble_pack(i1, j2, lot3, nfft, n1, n3, md2, nproc, nd3, zmpi2, zw1, cosinarr)
1088 : !output: I1,i3,J2,(Jp2)
1089 :
1090 : !performing FFT
1091 : !input: I1,i3,J2,(Jp2)
1092 : ! This is equivalent to
1093 2916 : IF (nfft == lot3) THEN
1094 1458 : CALL fft_1d(fft_plan_fw3, zw1, zw2, 1.0_dp, stat)
1095 : ELSE
1096 1458 : CALL fft_1d(fft_plan_fw3_last, zw1, zw2, 1.0_dp, stat)
1097 : END IF
1098 : !output: I1,I3,J2,(Jp2)
1099 :
1100 : !rebuild the output array
1101 4374 : CALL unfill_downcorn(md1, md3, lot3, nfft, n3, zw2, zf(i1, 1, j2), scal)
1102 :
1103 : !integrate local pieces together
1104 : !ehartree=ehartree+0.5_dp*ehartreetmp*hx*hy*hz
1105 : END DO
1106 : END IF
1107 : END DO
1108 :
1109 54 : IF (n2 >= lot1) CALL fft_destroy_plan(fft_plan_bw1)
1110 54 : IF (final_chunk_size1 > 0) CALL fft_destroy_plan(fft_plan_bw1_last)
1111 54 : IF (n2 >= lot1) CALL fft_destroy_plan(fft_plan_fw1)
1112 54 : IF (final_chunk_size1 > 0) CALL fft_destroy_plan(fft_plan_fw1_last)
1113 :
1114 54 : IF (n1 >= lot2) CALL fft_destroy_plan(fft_plan_bw2)
1115 54 : IF (final_chunk_size2 > 0) CALL fft_destroy_plan(fft_plan_bw2_last)
1116 54 : IF (n1 >= lot2) CALL fft_destroy_plan(fft_plan_fw2)
1117 54 : IF (final_chunk_size2 > 0) CALL fft_destroy_plan(fft_plan_fw2_last)
1118 :
1119 54 : IF (n1 >= lot3) CALL fft_destroy_plan(fft_plan_fw3)
1120 54 : IF (final_chunk_size3 > 0) CALL fft_destroy_plan(fft_plan_fw3_last)
1121 54 : IF (n1 >= lot3) CALL fft_destroy_plan(fft_plan_bw3)
1122 54 : IF (final_chunk_size3 > 0) CALL fft_destroy_plan(fft_plan_bw3_last)
1123 :
1124 : !De-allocations
1125 54 : DEALLOCATE (zmpi2)
1126 54 : CALL fft_dealloc(zw1)
1127 54 : CALL fft_dealloc(zw2)
1128 54 : CALL fft_dealloc(zt)
1129 54 : DEALLOCATE (cosinarr)
1130 54 : IF (nproc > 1) DEALLOCATE (zmpi1)
1131 :
1132 54 : CALL timestop(handle)
1133 2052 : END SUBROUTINE S_PoissonSolver
1134 :
1135 : ! **************************************************************************************************
1136 : !> \brief ...
1137 : !> \param j3 ...
1138 : !> \param nfft ...
1139 : !> \param Jp2stb ...
1140 : !> \param J2stb ...
1141 : !> \param lot ...
1142 : !> \param n1 ...
1143 : !> \param md2 ...
1144 : !> \param nd3 ...
1145 : !> \param nproc ...
1146 : !> \param zmpi1 ...
1147 : !> \param zw ...
1148 : ! **************************************************************************************************
1149 2970 : SUBROUTINE S_mpiswitch_upcorn(j3, nfft, Jp2stb, J2stb, lot, n1, md2, nd3, nproc, zmpi1, zw)
1150 : INTEGER, INTENT(in) :: j3, nfft
1151 : INTEGER, INTENT(inout) :: Jp2stb, J2stb
1152 : INTEGER, INTENT(in) :: lot, n1, md2, nd3, nproc
1153 : COMPLEX(KIND=dp), &
1154 : DIMENSION(n1, md2/nproc, nd3/nproc, nproc), &
1155 : INTENT(in) :: zmpi1
1156 : COMPLEX(KIND=dp), DIMENSION(lot, n1), &
1157 : INTENT(inout) :: zw
1158 :
1159 : INTEGER :: I1, J2, Jp2, mfft
1160 :
1161 2970 : mfft = 0
1162 5940 : DO Jp2 = Jp2stb, nproc
1163 84645 : DO J2 = J2stb, md2/nproc
1164 81675 : mfft = mfft + 1
1165 81675 : IF (mfft > nfft) THEN
1166 1485 : Jp2stb = Jp2
1167 1485 : J2stb = J2
1168 1485 : RETURN
1169 : END IF
1170 4413420 : DO I1 = 1, n1
1171 4410450 : zw(mfft, I1) = zmpi1(I1, J2, j3, Jp2)
1172 : END DO
1173 : END DO
1174 4455 : J2stb = 1
1175 : END DO
1176 : END SUBROUTINE S_mpiswitch_upcorn
1177 :
1178 : ! **************************************************************************************************
1179 : !> \brief ...
1180 : !> \param nfft ...
1181 : !> \param n2 ...
1182 : !> \param lot ...
1183 : !> \param n1 ...
1184 : !> \param lzt ...
1185 : !> \param zt ...
1186 : !> \param zw ...
1187 : ! **************************************************************************************************
1188 2970 : SUBROUTINE S_switch_upcorn(nfft, n2, lot, n1, lzt, zt, zw)
1189 : INTEGER, INTENT(in) :: nfft, n2, lot, n1, lzt
1190 : COMPLEX(KIND=dp), DIMENSION(lzt, n1), INTENT(in) :: zt
1191 : COMPLEX(KIND=dp), DIMENSION(lot, n2), &
1192 : INTENT(inout) :: zw
1193 :
1194 : INTEGER :: i, j
1195 :
1196 83160 : DO j = 1, nfft
1197 4413420 : DO i = 1, n2
1198 4410450 : zw(j, i) = zt(i, j)
1199 : END DO
1200 : END DO
1201 2970 : END SUBROUTINE S_switch_upcorn
1202 :
1203 : ! **************************************************************************************************
1204 : !> \brief ...
1205 : !> \param nfft ...
1206 : !> \param n2 ...
1207 : !> \param lot ...
1208 : !> \param n1 ...
1209 : !> \param lzt ...
1210 : !> \param zw ...
1211 : !> \param zt ...
1212 : ! **************************************************************************************************
1213 2970 : SUBROUTINE S_unswitch_downcorn(nfft, n2, lot, n1, lzt, zw, zt)
1214 : INTEGER, INTENT(in) :: nfft, n2, lot, n1, lzt
1215 : COMPLEX(KIND=dp), DIMENSION(lot, n2), INTENT(in) :: zw
1216 : COMPLEX(KIND=dp), DIMENSION(lzt, n1), &
1217 : INTENT(inout) :: zt
1218 :
1219 : INTEGER :: i, j
1220 :
1221 83160 : DO j = 1, nfft
1222 4413420 : DO i = 1, n2
1223 4410450 : zt(i, j) = zw(j, i)
1224 : END DO
1225 : END DO
1226 2970 : END SUBROUTINE S_unswitch_downcorn
1227 :
1228 : ! **************************************************************************************************
1229 : !> \brief ...
1230 : !> \param j3 ...
1231 : !> \param nfft ...
1232 : !> \param Jp2stf ...
1233 : !> \param J2stf ...
1234 : !> \param lot ...
1235 : !> \param n1 ...
1236 : !> \param md2 ...
1237 : !> \param nd3 ...
1238 : !> \param nproc ...
1239 : !> \param zw ...
1240 : !> \param zmpi1 ...
1241 : ! **************************************************************************************************
1242 2970 : SUBROUTINE S_unmpiswitch_downcorn(j3, nfft, Jp2stf, J2stf, lot, n1, md2, nd3, nproc, zw, zmpi1)
1243 : INTEGER, INTENT(in) :: j3, nfft
1244 : INTEGER, INTENT(inout) :: Jp2stf, J2stf
1245 : INTEGER, INTENT(in) :: lot, n1, md2, nd3, nproc
1246 : COMPLEX(KIND=dp), DIMENSION(lot, n1), INTENT(in) :: zw
1247 : COMPLEX(KIND=dp), &
1248 : DIMENSION(n1, md2/nproc, nd3/nproc, nproc), &
1249 : INTENT(inout) :: zmpi1
1250 :
1251 : INTEGER :: I1, J2, Jp2, mfft
1252 :
1253 2970 : mfft = 0
1254 5940 : DO Jp2 = Jp2stf, nproc
1255 84645 : DO J2 = J2stf, md2/nproc
1256 81675 : mfft = mfft + 1
1257 81675 : IF (mfft > nfft) THEN
1258 1485 : Jp2stf = Jp2
1259 1485 : J2stf = J2
1260 1485 : RETURN
1261 : END IF
1262 4413420 : DO I1 = 1, n1
1263 4410450 : zmpi1(I1, J2, j3, Jp2) = zw(mfft, I1)
1264 : END DO
1265 : END DO
1266 4455 : J2stf = 1
1267 : END DO
1268 : END SUBROUTINE S_unmpiswitch_downcorn
1269 :
1270 : ! **************************************************************************************************
1271 : !> \brief (Based on suitable modifications of S.Goedecker routines)
1272 : !> Restore data into output array, calculating in the meanwhile
1273 : !> Hartree energy of the potential
1274 : !> \param md1 Dimensions of the undistributed part of the real grid
1275 : !> \param md3 Dimensions of the undistributed part of the real grid
1276 : !> \param lot ...
1277 : !> \param nfft number of planes
1278 : !> \param n3 (twice the) dimension of the last FFTtransform.
1279 : !> \param zw FFT work array
1280 : !> \param zf Original distributed density as well as
1281 : !> Distributed solution of the poisson equation (inout)
1282 : !> \param scal Needed to achieve unitarity and correct dimensions
1283 : !> \date February 2006
1284 : !> \author S. Goedecker, L. Genovese
1285 : !> \note Assuming that high frequencies are in the corners
1286 : !> and that n3 is multiple of 4
1287 : !>
1288 : !> RESTRICTIONS on USAGE
1289 : !> Copyright (C) Stefan Goedecker, Cornell University, Ithaca, USA, 1994
1290 : !> Copyright (C) Stefan Goedecker, MPI Stuttgart, Germany, 1999
1291 : !> Copyright (C) 2002 Stefan Goedecker, CEA Grenoble
1292 : !> This file is distributed under the terms of the
1293 : !> GNU General Public License, see http://www.gnu.org/copyleft/gpl.txt .
1294 : ! **************************************************************************************************
1295 676327 : SUBROUTINE unfill_downcorn(md1, md3, lot, nfft, n3, zw, zf, scal)
1296 : INTEGER, INTENT(in) :: md1, md3, lot, nfft, n3
1297 : COMPLEX(KIND=dp), DIMENSION(lot, n3/2), INTENT(in) :: zw
1298 : REAL(KIND=dp), DIMENSION(md1, md3), INTENT(inout) :: zf
1299 : REAL(KIND=dp), INTENT(in) :: scal
1300 :
1301 : INTEGER :: i1, i3
1302 : REAL(KIND=dp) :: pot1
1303 :
1304 18469469 : DO i3 = 1, n3/4
1305 504746046 : DO i1 = 1, nfft
1306 486276577 : pot1 = scal*REAL(zw(i1, i3), dp)
1307 : !ehartreetmp =ehartreetmp + pot1* zf(i1,2*i3-1)
1308 486276577 : zf(i1, 2*i3 - 1) = pot1
1309 486276577 : pot1 = scal*AIMAG(zw(i1, i3))
1310 : !ehartreetmp =ehartreetmp + pot1* zf(i1,2*i3)
1311 504069719 : zf(i1, 2*i3) = pot1
1312 : END DO
1313 : END DO
1314 676327 : END SUBROUTINE unfill_downcorn
1315 :
1316 : ! **************************************************************************************************
1317 : !> \brief ...
1318 : !> \param md1 ...
1319 : !> \param md3 ...
1320 : !> \param lot ...
1321 : !> \param nfft ...
1322 : !> \param n3 ...
1323 : !> \param zf ...
1324 : !> \param zw ...
1325 : ! **************************************************************************************************
1326 676327 : SUBROUTINE halfill_upcorn(md1, md3, lot, nfft, n3, zf, zw)
1327 : INTEGER :: md1, md3, lot, nfft, n3
1328 : REAL(KIND=dp) :: zf(md1, md3)
1329 : COMPLEX(KIND=dp) :: zw(lot, n3/2)
1330 :
1331 : INTEGER :: i1, i3
1332 :
1333 18469469 : DO i3 = 1, n3/4
1334 : ! WARNING: Assuming that high frequencies are in the corners
1335 : ! and that n3 is multiple of 4
1336 : !in principle we can relax this condition
1337 504746046 : DO i1 = 1, nfft
1338 504069719 : zw(i1, i3) = CMPLX(0.0_dp, 0.0_dp, dp)
1339 : END DO
1340 : END DO
1341 18469469 : DO i3 = n3/4 + 1, n3/2
1342 504746046 : DO i1 = 1, nfft
1343 504069719 : zw(i1, i3) = CMPLX(zf(i1, 2*i3 - 1 - n3/2), zf(i1, 2*i3 - n3/2), dp)
1344 : END DO
1345 : END DO
1346 :
1347 676327 : END SUBROUTINE halfill_upcorn
1348 :
1349 : ! **************************************************************************************************
1350 : !> \brief (Based on suitable modifications of S.Goedecker routines)
1351 : !> Assign the correct planes to the work array zmpi2
1352 : !> in order to prepare for interprocessor data transposition.
1353 : !> In the meanwhile, it unpacks the data of the HalFFT in order to prepare for
1354 : !> multiplication with the kernel
1355 : !> \param i1 Starting points of the plane and number of remaining lines
1356 : !> \param j2 Starting points of the plane and number of remaining lines
1357 : !> \param lot Starting points of the plane and number of remaining lines
1358 : !> \param nfft Starting points of the plane and number of remaining lines
1359 : !> \param n1 logical dimension of the FFT transform, reference for work arrays
1360 : !> \param n3 logical dimension of the FFT transform, reference for work arrays
1361 : !> \param md2 Dimensions of real grid
1362 : !> \param nproc ...
1363 : !> \param nd3 Dimensions of the kernel
1364 : !> \param zw Work array (input)
1365 : !> \param zmpi2 Work array for multiprocessor manipulation (output)
1366 : !> \param cosinarr Array of the phases needed for unpacking
1367 : !> \date February 2006
1368 : !> \author S. Goedecker, L. Genovese
1369 : !> \note
1370 : !> RESTRICTIONS on USAGE
1371 : !> Copyright (C) Stefan Goedecker, Cornell University, Ithaca, USA, 1994
1372 : !> Copyright (C) Stefan Goedecker, MPI Stuttgart, Germany, 1999
1373 : !> Copyright (C) 2002 Stefan Goedecker, CEA Grenoble
1374 : !> This file is distributed under the terms of the
1375 : !> GNU General Public License, see http://www.gnu.org/copyleft/gpl.txt .
1376 : ! **************************************************************************************************
1377 781605 : SUBROUTINE scramble_unpack(i1, j2, lot, nfft, n1, n3, md2, nproc, nd3, zw, zmpi2, cosinarr)
1378 : INTEGER, INTENT(in) :: i1, j2, lot, nfft, n1, n3, md2, nproc, &
1379 : nd3
1380 : COMPLEX(KIND=dp), DIMENSION(lot, n3/2), INTENT(in) :: zw
1381 : COMPLEX(KIND=dp), DIMENSION(n1, md2/nproc, nd3), &
1382 : INTENT(inout) :: zmpi2
1383 : REAL(KIND=dp), DIMENSION(2, n3/2), INTENT(in) :: cosinarr
1384 :
1385 : INTEGER :: i, i3, ind1, ind2
1386 : REAL(KIND=dp) :: a, b, c, cp, d, feI, feR, fI, foI, foR, &
1387 : fR, sp
1388 :
1389 : !case i3=1 and i3=n3/2+1
1390 :
1391 23214805 : DO i = 0, nfft - 1
1392 22433200 : a = REAL(zw(i + 1, 1), dp)
1393 22433200 : b = AIMAG(zw(i + 1, 1))
1394 22433200 : zmpi2(i1 + i, j2, 1) = CMPLX(a + b, 0.0_dp, dp)
1395 23214805 : zmpi2(i1 + i, j2, n3/2 + 1) = CMPLX(a - b, 0.0_dp, dp)
1396 : END DO
1397 : !case 2<=i3<=n3/2
1398 42417300 : DO i3 = 2, n3/2
1399 41635695 : ind1 = i3
1400 41635695 : ind2 = n3/2 - i3 + 2
1401 41635695 : cp = cosinarr(1, i3)
1402 41635695 : sp = cosinarr(2, i3)
1403 1182671990 : DO i = 0, nfft - 1
1404 1140254690 : a = REAL(zw(i + 1, ind1), dp)
1405 1140254690 : b = AIMAG(zw(i + 1, ind1))
1406 1140254690 : c = REAL(zw(i + 1, ind2), dp)
1407 1140254690 : d = AIMAG(zw(i + 1, ind2))
1408 1140254690 : feR = .5_dp*(a + c)
1409 1140254690 : feI = .5_dp*(b - d)
1410 1140254690 : foR = .5_dp*(a - c)
1411 1140254690 : foI = .5_dp*(b + d)
1412 1140254690 : fR = feR + cp*foI - sp*foR
1413 1140254690 : fI = feI - cp*foR - sp*foI
1414 1181890385 : zmpi2(i1 + i, j2, ind1) = CMPLX(fR, fI, dp)
1415 : END DO
1416 : END DO
1417 :
1418 781605 : END SUBROUTINE scramble_unpack
1419 :
1420 : ! **************************************************************************************************
1421 : !> \brief (Based on suitable modifications of S.Goedecker routines)
1422 : !> Insert the correct planes of the work array zmpi2
1423 : !> in order to prepare for backward FFT transform
1424 : !> In the meanwhile, it packs the data in order to be transformed with the HalFFT
1425 : !> procedure
1426 : !> \param i1 Starting points of the plane and number of remaining lines
1427 : !> \param j2 Starting points of the plane and number of remaining lines
1428 : !> \param lot Starting points of the plane and number of remaining lines
1429 : !> \param nfft Starting points of the plane and number of remaining lines
1430 : !> \param n1 logical dimension of the FFT transform, reference for work arrays
1431 : !> \param n3 logical dimension of the FFT transform, reference for work arrays
1432 : !> \param md2 Dimensions of real grid
1433 : !> \param nproc ...
1434 : !> \param nd3 Dimensions of the kernel
1435 : !> \param zmpi2 Work array for multiprocessor manipulation (output)
1436 : !> \param zw Work array (inout)
1437 : !> \param cosinarr Array of the phases needed for packing
1438 : !> \date February 2006
1439 : !> \author S. Goedecker, L. Genovese
1440 : !> \note
1441 : !> RESTRICTIONS on USAGE
1442 : !> Copyright (C) Stefan Goedecker, Cornell University, Ithaca, USA, 1994
1443 : !> Copyright (C) Stefan Goedecker, MPI Stuttgart, Germany, 1999
1444 : !> Copyright (C) 2002 Stefan Goedecker, CEA Grenoble
1445 : !> This file is distributed under the terms of the
1446 : !> GNU General Public License, see http://www.gnu.org/copyleft/gpl.txt .
1447 : ! **************************************************************************************************
1448 676327 : SUBROUTINE unscramble_pack(i1, j2, lot, nfft, n1, n3, md2, nproc, nd3, zmpi2, zw, cosinarr)
1449 : INTEGER, INTENT(in) :: i1, j2, lot, nfft, n1, n3, md2, nproc, &
1450 : nd3
1451 : COMPLEX(KIND=dp), DIMENSION(n1, md2/nproc, nd3), &
1452 : INTENT(in) :: zmpi2
1453 : COMPLEX(KIND=dp), DIMENSION(lot, n3/2), &
1454 : INTENT(inout) :: zw
1455 : REAL(KIND=dp), DIMENSION(2, n3/2), INTENT(in) :: cosinarr
1456 :
1457 : INTEGER :: i, i3, indA, indB
1458 : REAL(KIND=dp) :: a, b, c, cp, d, ie, ih, io, re, rh, ro, &
1459 : sp
1460 :
1461 36262611 : DO i3 = 1, n3/2
1462 35586284 : indA = i3
1463 35586284 : indB = n3/2 + 2 - i3
1464 35586284 : cp = cosinarr(1, i3)
1465 35586284 : sp = cosinarr(2, i3)
1466 1008815765 : DO i = 0, nfft - 1
1467 972553154 : a = REAL(zmpi2(i1 + i, j2, indA), dp)
1468 972553154 : b = AIMAG(zmpi2(i1 + i, j2, indA))
1469 972553154 : c = REAL(zmpi2(i1 + i, j2, indB), dp)
1470 972553154 : d = -AIMAG(zmpi2(i1 + i, j2, indB))
1471 972553154 : re = (a + c)
1472 972553154 : ie = (b + d)
1473 972553154 : ro = (a - c)*cp - (b - d)*sp
1474 972553154 : io = (a - c)*sp + (b - d)*cp
1475 972553154 : rh = re - io
1476 972553154 : ih = ie + ro
1477 1008139438 : zw(i + 1, indA) = CMPLX(rh, ih, dp)
1478 : END DO
1479 : END DO
1480 :
1481 676327 : END SUBROUTINE unscramble_pack
1482 :
1483 : ! **************************************************************************************************
1484 : !> \brief (Based on suitable modifications of S.Goedecker routines)
1485 : !> Applies the local FFT space Kernel to the density in Real space.
1486 : !> Calculates also the LDA exchange-correlation terms
1487 : !> \param n1 logical dimension of the transform.
1488 : !> \param n2 logical dimension of the transform.
1489 : !> \param n3 logical dimension of the transform.
1490 : !> \param nd1 Dimension of POT
1491 : !> \param nd2 Dimension of POT
1492 : !> \param nd3 Dimension of POT
1493 : !> \param md1 Dimension of ZF
1494 : !> \param md2 Dimension of ZF
1495 : !> \param md3 Dimension of ZF
1496 : !> \param nproc number of processors used as returned by MPI_COMM_SIZE
1497 : !> \param iproc [0:nproc-1] number of processor as returned by MPI_COMM_RANK
1498 : !> \param pot Kernel, only the distributed part (REAL)
1499 : !> POT(i1,i2,i3)
1500 : !> i1=1,nd1 , i2=1,nd2 , i3=1,nd3/nproc
1501 : !> \param zf Density (input/output)
1502 : !> ZF(i1,i3,i2)
1503 : !> i1=1,md1 , i2=1,md2/nproc , i3=1,md3
1504 : !> \param scal factor of renormalization of the FFT in order to acheve unitarity
1505 : !> and the correct dimension
1506 : !> \param mpi_group ...
1507 : !> \date February 2006
1508 : !> \author S. Goedecker, L. Genovese
1509 : !> \note
1510 : !> RESTRICTIONS on USAGE
1511 : !> Copyright (C) Stefan Goedecker, Cornell University, Ithaca, USA, 1994
1512 : !> Copyright (C) Stefan Goedecker, MPI Stuttgart, Germany, 1999
1513 : !> Copyright (C) 2002 Stefan Goedecker, CEA Grenoble
1514 : !> This file is distributed under the terms of the
1515 : !> GNU General Public License, see http://www.gnu.org/copyleft/gpl.txt .
1516 : ! **************************************************************************************************
1517 16922 : SUBROUTINE F_PoissonSolver(n1, n2, n3, nd1, nd2, nd3, md1, md2, md3, nproc, iproc, pot, zf, &
1518 : scal, mpi_group)
1519 : INTEGER, INTENT(in) :: n1, n2, n3, nd1, nd2, nd3, md1, md2, &
1520 : md3, nproc, iproc
1521 : REAL(KIND=dp), DIMENSION(nd1, nd2, nd3/nproc), &
1522 : INTENT(in) :: pot
1523 : REAL(KIND=dp), DIMENSION(md1, md3, md2/nproc), &
1524 : INTENT(inout) :: zf
1525 : REAL(KIND=dp), INTENT(in) :: scal
1526 :
1527 : CLASS(mp_comm_type), INTENT(in) :: mpi_group
1528 :
1529 : INTEGER, PARAMETER :: ncache_optimal = 8*1024
1530 :
1531 : INTEGER :: i1, i3, j, j2, &
1532 : J2stb, J2stf, j3, Jp2stb, Jp2stf, lot1, lot2, lot3, &
1533 : lzt, ma, mb, ncache, nfft, stat, &
1534 : final_chunk_size1, final_chunk_size2, final_chunk_size3
1535 : REAL(kind=dp) :: twopion
1536 16922 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: cosinarr
1537 16922 : COMPLEX(KIND=dp), POINTER, CONTIGUOUS, DIMENSION(:, :) :: zt
1538 16922 : COMPLEX(KIND=dp), POINTER, CONTIGUOUS, DIMENSION(:) :: zw1, zw2
1539 : COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: zmpi2
1540 : COMPLEX(KIND=dp), ALLOCATABLE, &
1541 16922 : DIMENSION(:, :, :, :) :: zmpi1
1542 : TYPE(fft_plan_type) :: fft_plan_bw3, fft_plan_bw3_last, fft_plan_fw3, fft_plan_fw3_last, &
1543 : fft_plan_bw1, fft_plan_bw1_last, fft_plan_fw1, fft_plan_fw1_last, &
1544 : fft_plan_bw2, fft_plan_bw2_last, fft_plan_fw2, fft_plan_fw2_last
1545 :
1546 0 : IF (MOD(n1, 2) /= 0) CPABORT("Parallel convolution:ERROR:n1")
1547 16922 : IF (MOD(n2, 2) /= 0) CPABORT("Parallel convolution:ERROR:n2")
1548 16922 : IF (MOD(n3, 2) /= 0) CPABORT("Parallel convolution:ERROR:n3")
1549 16922 : IF (nd1 < n1/2 + 1) CPABORT("Parallel convolution:ERROR:nd1")
1550 16922 : IF (nd2 < n2/2 + 1) CPABORT("Parallel convolution:ERROR:nd2")
1551 16922 : IF (nd3 < n3/2 + 1) CPABORT("Parallel convolution:ERROR:nd3")
1552 16922 : IF (md1 < n1/2) CPABORT("Parallel convolution:ERROR:md1")
1553 16922 : IF (md2 < n2/2) CPABORT("Parallel convolution:ERROR:md2")
1554 16922 : IF (md3 < n3/2) CPABORT("Parallel convolution:ERROR:md3")
1555 16922 : IF (MOD(nd3, nproc) /= 0) CPABORT("Parallel convolution:ERROR:nd3")
1556 16922 : IF (MOD(md2, nproc) /= 0) CPABORT("Parallel convolution:ERROR:md2")
1557 :
1558 : !defining work arrays dimensions
1559 :
1560 16922 : ncache = ncache_optimal
1561 16922 : IF (ncache <= MAX(n1, n2, n3/2)*4) ncache = MAX(n1, n2, n3/2)*4
1562 16922 : lzt = n2/2
1563 16922 : IF (MOD(n2/2, 2) == 0) lzt = lzt + 1
1564 16922 : IF (MOD(n2/2, 4) == 0) lzt = lzt + 1
1565 :
1566 : !Allocations
1567 33844 : CALL fft_alloc(zw1, [ncache/4])
1568 16922 : zw1 = CMPLX(0.0_dp, 0.0_dp, KIND=dp)
1569 33844 : CALL fft_alloc(zw2, [ncache/4])
1570 16922 : zw2 = CMPLX(0.0_dp, 0.0_dp, KIND=dp)
1571 50766 : CALL fft_alloc(zt, [lzt, n1])
1572 16922 : zt = CMPLX(0.0_dp, 0.0_dp, KIND=dp)
1573 84610 : ALLOCATE (zmpi2(n1, md2/nproc, nd3), SOURCE=CMPLX(0.0_dp, 0.0_dp, dp))
1574 67688 : ALLOCATE (cosinarr(2, n3/2), SOURCE=0.0_dp)
1575 63702 : IF (nproc > 1) ALLOCATE (zmpi1(n1, md2/nproc, nd3/nproc, nproc), SOURCE=CMPLX(0.0_dp, 0.0_dp, dp))
1576 :
1577 : !Calculating array of phases for HalFFT decoding
1578 16922 : twopion = 8._dp*ATAN(1._dp)/REAL(n3, KIND=dp)
1579 698018 : DO i3 = 1, n3/2
1580 681096 : cosinarr(1, i3) = COS(twopion*(i3 - 1))
1581 698018 : cosinarr(2, i3) = -SIN(twopion*(i3 - 1))
1582 : END DO
1583 :
1584 : ! transform along z axis
1585 16922 : lot1 = ncache/(4*n1)
1586 16922 : lot2 = ncache/(4*n2)
1587 16922 : lot3 = ncache/(2*n3)
1588 :
1589 : ! The size of the last chunk
1590 16922 : final_chunk_size1 = MOD(n2/2, lot1)
1591 16922 : final_chunk_size2 = MOD(n1, lot2)
1592 16922 : final_chunk_size3 = MOD(n1/2, lot3)
1593 :
1594 : ! Prevent OOB-access if n2 < lot1
1595 16922 : IF (n2/2 >= lot1) THEN
1596 11623 : CALL fft_create_plan_1d(fft_plan_bw1, BWFFT, .TRUE., .TRUE., lot1, lzt, n1, lot1, zw1, zt)
1597 11623 : CALL fft_create_plan_1d(fft_plan_fw1, FWFFT, .TRUE., .TRUE., lzt, lot1, n1, lot1, zt, zw1)
1598 : END IF
1599 16922 : IF (final_chunk_size1 > 0) THEN
1600 : CALL fft_create_plan_1d(fft_plan_bw1_last, BWFFT, .TRUE., .TRUE., lot1, lzt, n1, &
1601 14071 : final_chunk_size1, zw1, zt)
1602 : CALL fft_create_plan_1d(fft_plan_fw1_last, FWFFT, .TRUE., .TRUE., lzt, lot1, n1, &
1603 14071 : final_chunk_size1, zt, zw1)
1604 : END IF
1605 :
1606 : ! Prevent OOB-access if n2 < lot1
1607 16922 : IF (n1 >= lot2) THEN
1608 14154 : CALL fft_create_plan_1d(fft_plan_bw2, BWFFT, .TRUE., .TRUE., lot2, lot2, n2, lot2, zw1, zw2)
1609 14154 : CALL fft_create_plan_1d(fft_plan_fw2, FWFFT, .TRUE., .TRUE., lot2, lot2, n2, lot2, zw2, zw1)
1610 : END IF
1611 16922 : IF (final_chunk_size2 > 0) THEN
1612 : CALL fft_create_plan_1d(fft_plan_bw2_last, BWFFT, .TRUE., .TRUE., lot2, lot2, n2, &
1613 14071 : final_chunk_size2, zw1, zw2)
1614 : CALL fft_create_plan_1d(fft_plan_fw2_last, FWFFT, .TRUE., .TRUE., lot2, lot2, n2, &
1615 14071 : final_chunk_size2, zw2, zw1)
1616 : END IF
1617 :
1618 : ! Prevent OOB-access if n1 < lot3
1619 16922 : IF (n1/2 >= lot3) THEN
1620 4976 : CALL fft_create_plan_1d(fft_plan_fw3, FWFFT, .TRUE., .TRUE., lot3, lot3, n3/2, lot3, zw1, zw2)
1621 4976 : CALL fft_create_plan_1d(fft_plan_bw3, BWFFT, .TRUE., .TRUE., lot3, lot3, n3/2, lot3, zw1, zw2)
1622 : END IF
1623 16922 : IF (final_chunk_size3 > 0) THEN
1624 : CALL fft_create_plan_1d(fft_plan_fw3_last, FWFFT, .TRUE., .TRUE., &
1625 15900 : lot3, lot3, n3/2, final_chunk_size3, zw1, zw2)
1626 : CALL fft_create_plan_1d(fft_plan_bw3_last, BWFFT, .TRUE., .TRUE., &
1627 15900 : lot3, lot3, n3/2, final_chunk_size3, zw1, zw2)
1628 : END IF
1629 :
1630 464202 : DO j2 = 1, md2/nproc
1631 : !this condition ensures that we manage only the interesting part for the FFT
1632 464202 : IF (iproc*(md2/nproc) + j2 <= n2/2) THEN
1633 1119135 : DO i1 = 1, (n1/2), lot3
1634 673411 : ma = i1
1635 673411 : mb = MIN(i1 + (lot3 - 1), (n1/2))
1636 673411 : nfft = mb - ma + 1
1637 :
1638 : !inserting real data into complex array of half length
1639 673411 : CALL halfill_upcorn(md1, md3, lot3, nfft, n3, zf(i1, 1, j2), zw1)
1640 :
1641 : !performing FFT
1642 : !input: I1,I3,J2,(Jp2)
1643 : ! This is equivalent to
1644 673411 : IF (nfft == lot3) THEN
1645 265846 : CALL fft_1d(fft_plan_bw3, zw1, zw2, 1.0_dp, stat)
1646 : ELSE
1647 407565 : CALL fft_1d(fft_plan_bw3_last, zw1, zw2, 1.0_dp, stat)
1648 : END IF
1649 : !output: I1,i3,J2,(Jp2)
1650 :
1651 : !unpacking FFT in order to restore correct result,
1652 : !while exchanging components
1653 : !input: I1,i3,J2,(Jp2)
1654 1119135 : CALL scramble_unpack(i1, j2, lot3, nfft, n1/2, n3, md2, nproc, nd3, zw2, zmpi2, cosinarr)
1655 : !output: I1,J2,i3,(Jp2)
1656 : END DO
1657 : END IF
1658 : END DO
1659 :
1660 : !Interprocessor data transposition
1661 : !input: I1,J2,j3,jp3,(Jp2)
1662 16922 : IF (nproc > 1) THEN
1663 : !communication scheduling
1664 9356 : CALL mpi_group%alltoall(zmpi2, zmpi1, n1/2*(md2/nproc)*(nd3/nproc))
1665 : END IF
1666 : !output: I1,J2,j3,Jp2,(jp3)
1667 :
1668 : !now each process perform complete convolution of its planes
1669 490112 : DO j3 = 1, nd3/nproc
1670 : !this condition ensures that we manage only the interesting part for the FFT
1671 490112 : IF (iproc*(nd3/nproc) + j3 <= n3/2 + 1) THEN
1672 468512 : Jp2stb = 1
1673 468512 : J2stb = 1
1674 468512 : Jp2stf = 1
1675 468512 : J2stf = 1
1676 :
1677 : ! transform along x axis
1678 :
1679 1656377 : DO j = 1, n2/2, lot1
1680 1187865 : ma = j
1681 1187865 : mb = MIN(j + (lot1 - 1), n2/2)
1682 1187865 : nfft = mb - ma + 1
1683 :
1684 : !reverse index ordering, leaving the planes to be transformed at the end
1685 : !input: I1,J2,j3,Jp2,(jp3)
1686 1187865 : IF (nproc == 1) THEN
1687 421221 : CALL mpiswitch_upcorn(j3, nfft, Jp2stb, J2stb, lot1, n1, md2, nd3, nproc, zmpi2, zw1)
1688 : ELSE
1689 766644 : CALL mpiswitch_upcorn(j3, nfft, Jp2stb, J2stb, lot1, n1, md2, nd3, nproc, zmpi1, zw1)
1690 : END IF
1691 : !output: J2,Jp2,I1,j3,(jp3)
1692 :
1693 : !performing FFT
1694 : !input: I2,I1,j3,(jp3)
1695 : ! This is equivalent to
1696 1656377 : IF (nfft == lot1) THEN
1697 805720 : CALL fft_1d(fft_plan_bw1, zw1, zt(j:, 1), 1.0_dp, stat)
1698 : ELSE
1699 382145 : CALL fft_1d(fft_plan_bw1_last, zw1, zt(j:, 1), 1.0_dp, stat)
1700 : END IF
1701 : !output: I2,i1,j3,(jp3)
1702 : END DO
1703 :
1704 : !transform along y axis
1705 :
1706 2711780 : DO j = 1, n1, lot2
1707 2243268 : ma = j
1708 2243268 : mb = MIN(j + (lot2 - 1), n1)
1709 2243268 : nfft = mb - ma + 1
1710 :
1711 : !reverse ordering
1712 : !input: I2,i1,j3,(jp3)
1713 2243268 : CALL switch_upcorn(nfft, n2, lot2, n1, lzt, zt(:, j), zw1)
1714 : !output: i1,I2,j3,(jp3)
1715 :
1716 : !performing FFT
1717 : !input: i1,I2,j3,(jp3)
1718 : ! This is equivalent to
1719 2243268 : IF (nfft == lot2) THEN
1720 1861123 : CALL fft_1d(fft_plan_bw2, zw1, zw2, 1.0_dp, stat)
1721 : ELSE
1722 382145 : CALL fft_1d(fft_plan_bw2_last, zw1, zw2, 1.0_dp, stat)
1723 : END IF
1724 : !output: i1,i2,j3,(jp3)
1725 :
1726 : !Multiply with kernel in fourier space
1727 2243268 : CALL multkernel(nd1, nd2, n1, n2, lot2, nfft, j, pot(1, 1, j3), zw2)
1728 :
1729 : !TRANSFORM BACK IN REAL SPACE
1730 :
1731 : !transform along y axis
1732 : !input: i1,i2,j3,(jp3)
1733 : ! This is equivalent to
1734 2243268 : IF (nfft == lot2) THEN
1735 1861123 : CALL fft_1d(fft_plan_fw2, zw2, zw1, 1.0_dp, stat)
1736 : ELSE
1737 382145 : CALL fft_1d(fft_plan_fw2_last, zw2, zw1, 1.0_dp, stat)
1738 : END IF
1739 :
1740 : !reverse ordering
1741 : !input: i1,I2,j3,(jp3)
1742 2711780 : CALL unswitch_downcorn(nfft, n2, lot2, n1, lzt, zw1, zt(:, j))
1743 : !output: I2,i1,j3,(jp3)
1744 : END DO
1745 :
1746 : !transform along x axis
1747 : !input: I2,i1,j3,(jp3)
1748 1656377 : DO j = 1, n2/2, lot1
1749 1187865 : ma = j
1750 1187865 : mb = MIN(j + (lot1 - 1), n2/2)
1751 1187865 : nfft = mb - ma + 1
1752 :
1753 : !performing FFT
1754 : ! This is equivalent to
1755 1187865 : IF (nfft == lot1) THEN
1756 805720 : CALL fft_1d(fft_plan_fw1, zt(j:, 1), zw2, 1.0_dp, stat)
1757 : ELSE
1758 382145 : CALL fft_1d(fft_plan_fw1_last, zt(j:, 1), zw2, 1.0_dp, stat)
1759 : END IF
1760 : !output: I2,I1,j3,(jp3)
1761 :
1762 : !reverse ordering
1763 : !input: J2,Jp2,I1,j3,(jp3)
1764 1656377 : IF (nproc == 1) THEN
1765 421221 : CALL unmpiswitch_downcorn(j3, nfft, Jp2stf, J2stf, lot1, n1, md2, nd3, nproc, zw2, zmpi2)
1766 : ELSE
1767 766644 : CALL unmpiswitch_downcorn(j3, nfft, Jp2stf, J2stf, lot1, n1, md2, nd3, nproc, zw2, zmpi1)
1768 : END IF
1769 : ! output: I1,J2,j3,Jp2,(jp3)
1770 : END DO
1771 : END IF
1772 : END DO
1773 :
1774 : !Interprocessor data transposition
1775 : !input: I1,J2,j3,Jp2,(jp3)
1776 16922 : IF (nproc > 1) THEN
1777 : !communication scheduling
1778 9356 : CALL mpi_group%alltoall(zmpi1, zmpi2, n1/2*(md2/nproc)*(nd3/nproc))
1779 : !output: I1,J2,j3,jp3,(Jp2)
1780 : END IF
1781 :
1782 : !transform along z axis
1783 : !input: I1,J2,i3,(Jp2)
1784 464202 : DO j2 = 1, md2/nproc
1785 : !this condition ensures that we manage only the interesting part for the FFT
1786 464202 : IF (iproc*(md2/nproc) + j2 <= n2/2) THEN
1787 1119135 : DO i1 = 1, (n1/2), lot3
1788 673411 : ma = i1
1789 673411 : mb = MIN(i1 + (lot3 - 1), (n1/2))
1790 673411 : nfft = mb - ma + 1
1791 :
1792 : !reverse ordering and repack the FFT data in order to be backward HalFFT transformed
1793 : !input: I1,J2,i3,(Jp2)
1794 673411 : CALL unscramble_pack(i1, j2, lot3, nfft, n1/2, n3, md2, nproc, nd3, zmpi2, zw1, cosinarr)
1795 : !output: I1,i3,J2,(Jp2)
1796 :
1797 : !performing FFT
1798 : !input: I1,i3,J2,(Jp2)
1799 : ! This is equivalent to
1800 673411 : IF (nfft == lot3) THEN
1801 265846 : CALL fft_1d(fft_plan_fw3, zw1, zw2, 1.0_dp, stat)
1802 : ELSE
1803 407565 : CALL fft_1d(fft_plan_fw3_last, zw1, zw2, 1.0_dp, stat)
1804 : END IF
1805 : !output: I1,I3,J2,(Jp2)
1806 :
1807 : !calculates the exchange correlation terms locally and rebuild the output array
1808 1119135 : CALL unfill_downcorn(md1, md3, lot3, nfft, n3, zw2, zf(i1, 1, j2), scal)
1809 : END DO
1810 : END IF
1811 : END DO
1812 :
1813 16922 : IF (n2/2 >= lot1) CALL fft_destroy_plan(fft_plan_bw1)
1814 16922 : IF (final_chunk_size1 > 0) CALL fft_destroy_plan(fft_plan_bw1_last)
1815 16922 : IF (n2/2 >= lot1) CALL fft_destroy_plan(fft_plan_fw1)
1816 16922 : IF (final_chunk_size1 > 0) CALL fft_destroy_plan(fft_plan_fw1_last)
1817 :
1818 16922 : IF (n1 >= lot2) CALL fft_destroy_plan(fft_plan_bw2)
1819 16922 : IF (final_chunk_size2 > 0) CALL fft_destroy_plan(fft_plan_bw2_last)
1820 16922 : IF (n1 >= lot2) CALL fft_destroy_plan(fft_plan_fw2)
1821 16922 : IF (final_chunk_size2 > 0) CALL fft_destroy_plan(fft_plan_fw2_last)
1822 :
1823 16922 : IF (n1/2 >= lot3) CALL fft_destroy_plan(fft_plan_fw3)
1824 16922 : IF (final_chunk_size3 > 0) CALL fft_destroy_plan(fft_plan_fw3_last)
1825 16922 : IF (n1/2 >= lot3) CALL fft_destroy_plan(fft_plan_bw3)
1826 16922 : IF (final_chunk_size3 > 0) CALL fft_destroy_plan(fft_plan_bw3_last)
1827 :
1828 : !De-allocations
1829 16922 : DEALLOCATE (zmpi2)
1830 16922 : CALL fft_dealloc(zw1)
1831 16922 : CALL fft_dealloc(zw2)
1832 16922 : CALL fft_dealloc(zt)
1833 16922 : DEALLOCATE (cosinarr)
1834 16922 : IF (nproc > 1) DEALLOCATE (zmpi1)
1835 :
1836 643036 : END SUBROUTINE F_PoissonSolver
1837 :
1838 : ! **************************************************************************************************
1839 : !> \brief ...
1840 : !> \param nfft ...
1841 : !> \param n2 ...
1842 : !> \param lot ...
1843 : !> \param n1 ...
1844 : !> \param lzt ...
1845 : !> \param zt ...
1846 : !> \param zw ...
1847 : ! **************************************************************************************************
1848 2243268 : PURE SUBROUTINE switch_upcorn(nfft, n2, lot, n1, lzt, zt, zw)
1849 : INTEGER, INTENT(IN) :: nfft, n2, lot, n1, lzt
1850 : COMPLEX(KIND=dp), INTENT(IN) :: zt(lzt, n1)
1851 : COMPLEX(KIND=dp), INTENT(INOUT) :: zw(lot, n2)
1852 :
1853 : INTEGER :: i, j
1854 :
1855 : ! WARNING: Assuming that high frequencies are in the corners
1856 : ! and that n2 is multiple of 2
1857 : ! Low frequencies
1858 :
1859 42222968 : DO j = 1, nfft
1860 2017044556 : DO i = n2/2 + 1, n2
1861 2014801288 : zw(j, i) = zt(i - n2/2, j)
1862 : END DO
1863 : END DO
1864 : ! High frequencies
1865 125580240 : DO i = 1, n2/2
1866 2100401828 : DO j = 1, nfft
1867 2098158560 : zw(j, i) = CMPLX(0.0_dp, 0.0_dp, dp)
1868 : END DO
1869 : END DO
1870 2243268 : END SUBROUTINE switch_upcorn
1871 :
1872 : ! **************************************************************************************************
1873 : !> \brief ...
1874 : !> \param j3 ...
1875 : !> \param nfft ...
1876 : !> \param Jp2stb ...
1877 : !> \param J2stb ...
1878 : !> \param lot ...
1879 : !> \param n1 ...
1880 : !> \param md2 ...
1881 : !> \param nd3 ...
1882 : !> \param nproc ...
1883 : !> \param zmpi1 ...
1884 : !> \param zw ...
1885 : ! **************************************************************************************************
1886 1187865 : PURE SUBROUTINE mpiswitch_upcorn(j3, nfft, Jp2stb, J2stb, lot, n1, md2, nd3, nproc, zmpi1, zw)
1887 : INTEGER, INTENT(IN) :: j3, nfft
1888 : INTEGER, INTENT(INOUT) :: Jp2stb, J2stb
1889 : INTEGER, INTENT(IN) :: lot, n1, md2, nd3, nproc
1890 : COMPLEX(KIND=dp), INTENT(IN) :: zmpi1(n1/2, md2/nproc, nd3/nproc, nproc)
1891 : COMPLEX(KIND=dp), INTENT(INOUT) :: zw(lot, n1)
1892 :
1893 : INTEGER :: i1, j2, jp2, mfft
1894 :
1895 : ! WARNING: Assuming that high frequencies are in the corners
1896 : ! and that n1 is multiple of 2
1897 :
1898 1187865 : mfft = 0
1899 1808671 : Main: DO Jp2 = Jp2stb, nproc
1900 21407221 : DO J2 = J2stb, md2/nproc
1901 20786415 : mfft = mfft + 1
1902 20786415 : IF (mfft > nfft) THEN
1903 796565 : Jp2stb = Jp2
1904 796565 : J2stb = J2
1905 796565 : EXIT Main
1906 : END IF
1907 1007400644 : DO I1 = 1, n1/2
1908 1007400644 : zw(mfft, I1) = CMPLX(0.0_dp, 0.0_dp, dp)
1909 : END DO
1910 1008021450 : DO I1 = n1/2 + 1, n1
1911 1007400644 : zw(mfft, I1) = zmpi1(I1 - n1/2, J2, j3, Jp2)
1912 : END DO
1913 : END DO
1914 1012106 : J2stb = 1
1915 : END DO Main
1916 1187865 : END SUBROUTINE mpiswitch_upcorn
1917 :
1918 : ! **************************************************************************************************
1919 : !> \brief ...
1920 : !> \param nfft ...
1921 : !> \param n2 ...
1922 : !> \param lot ...
1923 : !> \param n1 ...
1924 : !> \param lzt ...
1925 : !> \param zw ...
1926 : !> \param zt ...
1927 : ! **************************************************************************************************
1928 2243268 : PURE SUBROUTINE unswitch_downcorn(nfft, n2, lot, n1, lzt, zw, zt)
1929 : INTEGER, INTENT(IN) :: nfft, n2, lot, n1, lzt
1930 : COMPLEX(KIND=dp), INTENT(IN) :: zw(lot, n2)
1931 : COMPLEX(KIND=dp), INTENT(INOUT) :: zt(lzt, n1)
1932 :
1933 : INTEGER :: i, j
1934 :
1935 : ! WARNING: Assuming that high frequencies are in the corners
1936 : ! and that n2 is multiple of 2
1937 : ! Low frequencies
1938 :
1939 42222968 : DO j = 1, nfft
1940 2017044556 : DO i = 1, n2/2
1941 2014801288 : zt(i, j) = zw(j, i)
1942 : END DO
1943 : END DO
1944 2243268 : RETURN
1945 : END SUBROUTINE unswitch_downcorn
1946 :
1947 : ! **************************************************************************************************
1948 : !> \brief ...
1949 : !> \param j3 ...
1950 : !> \param nfft ...
1951 : !> \param Jp2stf ...
1952 : !> \param J2stf ...
1953 : !> \param lot ...
1954 : !> \param n1 ...
1955 : !> \param md2 ...
1956 : !> \param nd3 ...
1957 : !> \param nproc ...
1958 : !> \param zw ...
1959 : !> \param zmpi1 ...
1960 : ! **************************************************************************************************
1961 1187865 : PURE SUBROUTINE unmpiswitch_downcorn(j3, nfft, Jp2stf, J2stf, lot, n1, md2, nd3, nproc, zw, zmpi1)
1962 : INTEGER, INTENT(IN) :: j3, nfft
1963 : INTEGER, INTENT(INOUT) :: Jp2stf, J2stf
1964 : INTEGER, INTENT(IN) :: lot, n1, md2, nd3, nproc
1965 : COMPLEX(KIND=dp), INTENT(IN) :: zw(lot, n1)
1966 : COMPLEX(KIND=dp), INTENT(INOUT) :: zmpi1(n1/2, md2/nproc, nd3/nproc, nproc)
1967 :
1968 : INTEGER :: i1, j2, jp2, mfft
1969 :
1970 : ! WARNING: Assuming that high frequencies are in the corners
1971 : ! and that n1 is multiple of 2
1972 :
1973 1187865 : mfft = 0
1974 1808671 : Main: DO Jp2 = Jp2stf, nproc
1975 21407221 : DO J2 = J2stf, md2/nproc
1976 20786415 : mfft = mfft + 1
1977 20786415 : IF (mfft > nfft) THEN
1978 796565 : Jp2stf = Jp2
1979 796565 : J2stf = J2
1980 796565 : EXIT Main
1981 : END IF
1982 1008021450 : DO I1 = 1, n1/2
1983 1007400644 : zmpi1(I1, J2, j3, Jp2) = zw(mfft, I1)
1984 : END DO
1985 : END DO
1986 1012106 : J2stf = 1
1987 : END DO Main
1988 1187865 : END SUBROUTINE unmpiswitch_downcorn
1989 :
1990 : ! **************************************************************************************************
1991 : !> \brief (Based on suitable modifications of S.Goedecker routines)
1992 : !> Restore data into output array, calculating in the meanwhile
1993 : !> Hartree energy of the potential
1994 : !> \param md1 Dimensions of the undistributed part of the real grid
1995 : !> \param md3 Dimensions of the undistributed part of the real grid
1996 : !> \param lot ...
1997 : !> \param nfft number of planes
1998 : !> \param n3 (twice the) dimension of the last FFTtransform.
1999 : !> \param zw FFT work array
2000 : !> \param zf Original distributed density as well as
2001 : !> Distributed solution of the poisson equation (inout)
2002 : !> \param scal Needed to achieve unitarity and correct dimensions
2003 : !> \param ehartreetmp Hartree energy
2004 : !> \date February 2006
2005 : !> \author S. Goedecker, L. Genovese
2006 : !> \note Assuming that high frequencies are in the corners
2007 : !> and that n3 is multiple of 4
2008 : !>
2009 : !> RESTRICTIONS on USAGE
2010 : !> Copyright (C) Stefan Goedecker, Cornell University, Ithaca, USA, 1994
2011 : !> Copyright (C) Stefan Goedecker, MPI Stuttgart, Germany, 1999
2012 : !> Copyright (C) 2002 Stefan Goedecker, CEA Grenoble
2013 : !> This file is distributed under the terms of the
2014 : !> GNU General Public License, see http://www.gnu.org/copyleft/gpl.txt .
2015 : ! **************************************************************************************************
2016 0 : PURE SUBROUTINE F_unfill_downcorn(md1, md3, lot, nfft, n3, zw, zf, scal, ehartreetmp)
2017 : INTEGER, INTENT(in) :: md1, md3, lot, nfft, n3
2018 : COMPLEX(KIND=dp), DIMENSION(lot, n3/2), INTENT(in) :: zw
2019 : REAL(KIND=dp), DIMENSION(md1, md3), INTENT(inout) :: zf
2020 : REAL(KIND=dp), INTENT(in) :: scal
2021 : REAL(KIND=dp), INTENT(out) :: ehartreetmp
2022 :
2023 : INTEGER :: i1, i3
2024 : REAL(KIND=dp) :: pot1
2025 :
2026 0 : ehartreetmp = 0._dp
2027 0 : DO i3 = 1, n3/4
2028 0 : DO i1 = 1, nfft
2029 0 : pot1 = scal*REAL(zw(i1, i3), dp)
2030 0 : ehartreetmp = ehartreetmp + pot1*zf(i1, 2*i3 - 1)
2031 0 : zf(i1, 2*i3 - 1) = pot1
2032 0 : pot1 = scal*AIMAG(zw(i1, i3))
2033 0 : ehartreetmp = ehartreetmp + pot1*zf(i1, 2*i3)
2034 0 : zf(i1, 2*i3) = pot1
2035 : END DO
2036 : END DO
2037 0 : END SUBROUTINE F_unfill_downcorn
2038 :
2039 : END MODULE ps_wavelet_base
|