Line data Source code
1 : !!****m* ABINIT/m_fftw3
2 : !! NAME
3 : !! m_fftw3
4 : !!
5 : !! FUNCTION
6 : !! This module provides wrappers for the FFTW3 routines: in-place and out-of-place version.
7 : !!
8 : !! COPYRIGHT
9 : !! Copyright (C) 2009-2026 ABINIT group (MG, FD)
10 : !! This file is distributed under the terms of the
11 : !! GNU General Public License, see ~abinit/COPYING
12 : !! or http://www.gnu.org/copyleft/gpl.txt .
13 : !!
14 : !! NOTES
15 : !! 1) MPI parallelism is in testing stage
16 : !! 2) For better performance the FFT divisions should contain small factors [2, 3, 5, 7, 11]
17 : !!
18 : !! SOURCE
19 :
20 : #if defined HAVE_CONFIG_H
21 : #include "config.h"
22 : #endif
23 :
24 : #include "abi_common.h"
25 :
26 : ! It seems that MKL wrappers do not like the advanced interfaces for
27 : ! r2c and c2r transforms although they work fine if the true FFTW3 library is used.
28 : !#define DEV_RC_BUG
29 : #undef DEV_RC_BUG
30 :
31 : #define FFTLIB "FFTW3"
32 : ! do not use FFT_PREF(name) since not working with NAG compiler
33 : #define FFT_PREF_fftrisc fftw3_fftrisc
34 : #define FFT_PREF_fftrisc_mixprec fftw3_fftrisc_mixprec
35 : #define FFT_PREF_fftpad fftw3_fftpad
36 : #define FFT_PREF_fftug_dp fftw3_fftug_dp
37 : #define FFT_PREF_fftur_dp fftw3_fftur_dp
38 : #define FFT_PREF_fftug fftw3_fftug
39 : #define FFT_PREF_fftur fftw3_fftur
40 :
41 :
42 :
43 : #define SPAWN_THREADS_HERE(ndat, nthreads) fftw3_spawn_threads_here(ndat, nthreads)
44 : #define FFT_DOUBLE 1
45 : #define FFT_SINGLE 2
46 : #define FFT_MIXPREC 3
47 :
48 : MODULE m_fftw3
49 :
50 : use defs_basis
51 : use m_abicore
52 : use m_errors
53 : use m_xomp
54 : use m_xmpi
55 : use m_hide_blas
56 : use m_cgtools
57 : use m_cplxtools
58 : use m_distribfft
59 : use m_fftcore
60 : use, intrinsic :: iso_c_binding
61 :
62 : use m_time, only : timab
63 : use m_numeric_tools, only : imax_loc
64 : use defs_abitypes, only : MPI_type
65 : use m_mpinfo, only : ptabs_fourwf
66 : use m_fstrings, only : strcat, itoa, sjoin
67 : use m_fft_mesh, only : zpad_t
68 :
69 : implicit none
70 :
71 : #ifdef HAVE_FFTW3_MPI
72 : include 'fftw3-mpi.f03'
73 : #endif
74 :
75 : !This should be done but MKL fftw hasn't always this include file
76 : !#ifdef HAVE_FFT_FFTW3
77 : ! include 'fftw3.f03'
78 : !#endif
79 :
80 : private
81 :
82 : ! Entry points for client code
83 : public :: fftw3_seqfourdp ! 3D FFT of lengths nx, ny, nz. Mainly used for densities or potentials.
84 : public :: fftw3_seqfourwf ! FFT transform of wavefunctions (high-level interface).
85 : public :: fftw3_fftrisc
86 : public :: fftw3_fftrisc_mixprec ! Mixed precision version of fftrisc: input/output in dp, computation done in sp.
87 : public :: fftw3_fftug ! G-->R. 3D zero-padded FFT of lengths nx, ny, nz. Mainly used for wavefunctions
88 : public :: fftw3_fftur ! R-->G, 3D zero-padded FFT of lengths nx, ny, nz. Mainly used for wavefunctions
89 : public :: fftw3_use_lib_threads
90 : public :: fftw3_spawn_threads_here
91 :
92 : public :: fftw3_mpifourdp
93 :
94 : ! Low-level routines.
95 : public :: fftw3_cleanup ! Reset FFTW to the pristine state it was in when you started your program,
96 : public :: fftw3_init_threads ! one-time initialization required to use FFTW3 threads.
97 : public :: fftw3_set_nthreads ! Set the number of threads you want FFTW3 to use when HAVE_FFT_FFTW3_THREADS is defined.
98 : public :: fftw3_r2c_op ! Real to complex transform (out-of-place version).
99 : public :: fftw3_c2r_op ! Complex to real transform (out-of-place version).
100 : public :: fftw3_c2c_op ! complex to complex transform (out-of-place version).
101 : public :: fftw3_c2c_ip ! complex to complex transform (in-place version).
102 : public :: fftw3_many_dft_op ! Driver routine for many out-of-place 3D complex-to-complex FFTs.
103 : public :: fftw3_many_dft_ip ! Driver routine for many in-place 3D complex-to-complex FFTs.
104 : public :: fftw3_fftpad ! Driver routines for zero-padded FFT of wavefunctions.
105 : public :: fftw3_fftpad_dp ! Driver routines for zero-padded FFT of wavefunctions.
106 : public :: fftw3_fftug_dp ! Driver routines for zero-padded FFT of wavefunctions.
107 : public :: fftw3_poisson ! Solve the poisson equation in G-space starting from n(r).
108 :
109 : ! MPI version
110 : public :: fftw3_mpiback_wf
111 : public :: fftw3_mpiback_manywf
112 : public :: fftw3_mpiforw_wf
113 : public :: fftw3_mpiforw_manywf
114 : public :: fftw3_mpiback
115 : public :: fftw3_mpiforw
116 : public :: fftw3_applypot
117 : public :: fftw3_applypot_many
118 : public :: fftw3_accrho
119 :
120 : #ifdef HAVE_FFTW3_MPI
121 : ! flags copied from fftw3.f
122 : integer,public,parameter :: ABI_FFTW_FORWARD = FFTW_FORWARD
123 : integer,public,parameter :: ABI_FFTW_BACKWARD = FFTW_BACKWARD
124 : integer,public,parameter :: ABI_FFTW_ESTIMATE = FFTW_ESTIMATE
125 : integer,public,parameter :: ABI_FFTW_MEASURE = FFTW_MEASURE
126 : ! end flags copied from fftw3.f
127 : integer,public,parameter :: ABI_FFTW_MPI_TRANSPOSED_IN = FFTW_MPI_TRANSPOSED_IN
128 : integer,public,parameter :: ABI_FFTW_MPI_TRANSPOSED_OUT = FFTW_MPI_TRANSPOSED_OUT
129 : ! end flags copies from fftw3-mpi.f03
130 : #else
131 : integer,public,parameter :: ABI_FFTW_FORWARD = -1
132 : integer,public,parameter :: ABI_FFTW_BACKWARD = +1
133 : integer,public,parameter :: ABI_FFTW_ESTIMATE = 64
134 : integer,public,parameter :: ABI_FFTW_MEASURE = 0
135 : ! end flags copied from fftw3.f
136 : integer,public,parameter :: ABI_FFTW_MPI_TRANSPOSED_IN = 536870912
137 : integer,public,parameter :: ABI_FFTW_MPI_TRANSPOSED_OUT = 1073741824
138 : ! end flags copies from fftw3-mpi.f03
139 : #endif
140 :
141 : ! ==========================================================================================
142 : ! ==== Variables introduced for the FFTW3 interface in abinit. Not belonging to fftw3.f ====
143 : ! ==========================================================================================
144 :
145 : integer,public,parameter :: NULL_PLAN = 0
146 : ! MKL wrappers might return NULL_PLAN if a particular FFTW3 feature is not available
147 :
148 : integer,public,parameter :: KIND_FFTW_PLAN = 8
149 : ! It should be at least integer*@SIZEOF_INT_P@
150 : ! MKL wrappers requires it to be integer*8, so do _not_ use C_INTPTR_T.
151 :
152 : #ifdef HAVE_FFTW3_THREADS
153 : integer,private,save :: THREADS_INITED = 0
154 : ! 1 if treads have been initialized. 0 otherwise.
155 : #endif
156 :
157 : logical,private,save :: USE_LIB_THREADS = .FALSE.
158 : !!***
159 :
160 : !----------------------------------------------------------------------
161 :
162 : !!****t* m_fftw3/fftw3_plan3_t
163 : !! NAME
164 : !! fftw3_plan3_t
165 : !!
166 : !! FUNCTION
167 : !! Structure storing the pointer to the FFTW plan as well as the options used to generate it.
168 : !!
169 : !! SOURCE
170 :
171 : type,private :: fftw3_plan3_t
172 : integer :: isign=0 ! Sign of the exponential in the FFT
173 : integer :: ndat=-1 ! Number of FFTs associated to the plan
174 : integer :: flags=-HUGE(0) ! FFTW3 flags used to construct the plan.
175 : integer(KIND_FFTW_PLAN) :: plan=NULL_PLAN ! FFTW3 plan.
176 : integer :: nthreads=1 ! The number of threads associated to the plan.
177 : integer :: idist=-1
178 : integer :: odist=-1
179 : integer :: istride=-1
180 : integer :: ostride=-1
181 : integer :: n(3)=-1 ! The number of FFT divisions.
182 : integer :: inembed(3)=-1
183 : integer :: onembed(3)=-1
184 : !integer(C_INT) :: alignment(2) ! The alignment of the arrays used to construct the plan.
185 : end type fftw3_plan3_t
186 : !!***
187 :
188 : interface fftw3_fftrisc
189 : module procedure fftw3_fftrisc_sp
190 : module procedure fftw3_fftrisc_dp
191 : end interface fftw3_fftrisc
192 :
193 : interface fftw3_fftug
194 : module procedure fftw3_fftug_dp
195 : module procedure fftw3_fftug_spc
196 : module procedure fftw3_fftug_dpc
197 : end interface fftw3_fftug
198 :
199 : interface fftw3_fftur
200 : module procedure fftw3_fftur_dp
201 : module procedure fftw3_fftur_spc
202 : module procedure fftw3_fftur_dpc
203 : end interface fftw3_fftur
204 :
205 : interface fftw3_c2c_op
206 : module procedure fftw3_c2c_op_spc
207 : module procedure fftw3_c2c_op_dpc
208 : end interface fftw3_c2c_op
209 :
210 : interface fftw3_c2c_ip
211 : module procedure fftw3_c2c_ip_spc
212 : module procedure fftw3_c2c_ip_dpc
213 : end interface fftw3_c2c_ip
214 :
215 : interface fftw3_fftpad
216 : module procedure fftw3_fftpad_dp
217 : module procedure fftw3_fftpad_spc
218 : module procedure fftw3_fftpad_dpc
219 : end interface fftw3_fftpad
220 :
221 : #ifdef HAVE_FFTW3
222 : ! Overloaded planner.
223 : interface fftw3_plan_many_dft
224 : module procedure dplan_many_dft_1D
225 : !module procedure dplan_many_dft_2D
226 : module procedure cplan_many_dft
227 : module procedure zplan_many_dft
228 : end interface fftw3_plan_many_dft
229 :
230 : interface fftw3_execute_dft
231 : module procedure fftw3_execute_dft_dp
232 : module procedure fftw3_execute_dft_spc
233 : module procedure fftw3_execute_dft_dpc
234 : end interface fftw3_execute_dft
235 :
236 : interface fftw3_alloc_real
237 : module procedure fftw3_alloc_real1d_dp
238 : module procedure fftw3_alloc_real2d_dp
239 : !module procedure fftw3_alloc_real3d_dp
240 : end interface fftw3_alloc_real
241 :
242 : interface fftw3_alloc_complex
243 : module procedure fftw3_alloc_complex1d_spc
244 : module procedure fftw3_alloc_complex1d_dpc
245 : end interface fftw3_alloc_complex
246 :
247 : !! FDahm :In case of ffw3-mpi flavor, one must include fftw3-mpi.F03 so
248 : !! the next few lines cause compiler errors because of name redefinition
249 : !! In deed, i think this should be avoid and replace by 'include fftw3.f03'
250 : !! MG: These bindings are needed when we use the FFTW3 wrappers provided by
251 : !! the MKL library. I agree that we should use the include file fftw3.F03
252 : !! but this implies that
253 : !! 1) we cannot use the procedures defined in this module to call the MKL wrappers
254 : !! 2) we drop support for FFTW3 versions < 3.2 since these version do not provide
255 : !! the F2003 interface
256 : !! I don't have any problem in dropping support for old versions of FFTW3
257 : !! We just have to handle the migration on the different slaves of the test farm
258 : !! builders with MKL should use m_dfti.F90
259 : !! builders with FFTW3 should provide a recent version of the library
260 : !!
261 : #ifndef HAVE_FFTW3_MPI
262 : ! Fortran binding for fftw_malloc
263 : interface fftw_malloc
264 : type(C_PTR) function fftw_malloc(alloc_size) bind(C, name='fftw_malloc')
265 : import
266 : integer(C_SIZE_T), value :: alloc_size
267 : end function fftw_malloc
268 : end interface fftw_malloc
269 : ! Fortran binding for fftw_free
270 : interface fftw_free
271 : subroutine fftw_free(cptr) bind(C, name='fftw_free')
272 : import
273 : type(C_PTR), value :: cptr
274 : end subroutine fftw_free
275 : end interface
276 : #endif
277 : #endif
278 :
279 : CONTAINS !===========================================================
280 :
281 : !!****f* m_fftw3/fftw3_seqfourdp
282 : !! NAME
283 : !! fftw3_seqfourdp
284 : !!
285 : !! FUNCTION
286 : !! Driver routine for 3D FFT of lengths nx, ny, nz. Mainly used for densities or potentials.
287 : !! FFT Transform is out-of-place
288 : !!
289 : !! INPUTS
290 : !! cplex=1 if fofr is real, 2 if fofr is complex
291 : !! nx,ny,nz=Number of point along the three directions.
292 : !! ldx,ldy,ldz=Leading dimension of the array.
293 : !! ndat = Number of FFTS
294 : !! isign= +1 : fofg(G) => fofr(R);
295 : !! -1 : fofr(R) => fofg(G)
296 : !! fofg(2,ldx*ldy*ldz*ndat)=The array to be transformed.
297 : !! [fftw_flags]=Flags used to create the plan. They can be combined with the "+" operator. Defaults to FFTW_ESTIMATE.
298 : !!
299 : !! OUTPUT
300 : !! fofr(cplex,ldx*ldy*ldz*ndat)=The FFT of fofg
301 : !!
302 : !! SOURCE
303 :
304 0 : subroutine fftw3_seqfourdp(cplex,nx,ny,nz,ldx,ldy,ldz,ndat,isign,fofg,fofr,fftw_flags)
305 :
306 : !Arguments ------------------------------------
307 : !scalars
308 : integer,intent(in) :: cplex,nx,ny,nz,ldx,ldy,ldz,ndat,isign
309 : integer,optional,intent(in) :: fftw_flags
310 : !arrays
311 : real(dp),intent(inout) :: fofg(2*ldx*ldy*ldz*ndat)
312 : real(dp),intent(inout) :: fofr(cplex*ldx*ldy*ldz*ndat)
313 :
314 : !Local variables-------------------------------
315 : !scalars
316 : integer,parameter :: iscale1 = 1
317 : integer :: my_flags,ii,jj
318 0 : complex(sp), allocatable :: work_sp(:)
319 : ! *************************************************************************
320 :
321 0 : my_flags = ABI_FFTW_ESTIMATE; if (PRESENT(fftw_flags)) my_flags= fftw_flags
322 :
323 0 : select case (cplex)
324 : case (2)
325 : ! Complex to Complex.
326 0 : if (fftcore_mixprec == 1) then
327 : ! Mixed precision: copy in + in-place + copyout
328 0 : ABI_MALLOC(work_sp, (ldx*ldy*ldz*ndat))
329 0 : if (isign == ABI_FFTW_BACKWARD) then ! +1
330 0 : work_sp(:) = cmplx(fofg(1::2), fofg(2::2), kind=sp)
331 0 : else if (isign == ABI_FFTW_FORWARD) then ! -1
332 0 : work_sp(:) = cmplx(fofr(1::2), fofr(2::2), kind=sp)
333 : else
334 0 : ABI_BUG("Wrong isign")
335 : end if
336 :
337 0 : call fftw3_c2c_ip_spc(nx, ny, nz, ldx, ldy, ldz, ndat, iscale1, isign, work_sp, fftw_flags=my_flags)
338 :
339 0 : if (isign == ABI_FFTW_BACKWARD) then ! +1
340 : jj = 1
341 0 : do ii=1,ldx*ldy*ldz*ndat
342 0 : fofr(jj) = real(work_sp(ii), kind=dp)
343 0 : fofr(jj+1) = aimag(work_sp(ii))
344 0 : jj = jj + 2
345 : end do
346 0 : else if (isign == ABI_FFTW_FORWARD) then ! -1
347 : jj = 1
348 0 : do ii=1,ldx*ldy*ldz*ndat
349 0 : fofg(jj) = real(work_sp(ii), kind=dp)
350 0 : fofg(jj+1) = aimag(work_sp(ii))
351 0 : jj = jj + 2
352 : end do
353 : end if
354 0 : ABI_FREE(work_sp)
355 :
356 : else
357 : ! double precision version.
358 0 : select case (isign)
359 : case (ABI_FFTW_BACKWARD) ! +1
360 0 : call fftw3_many_dft_op(nx,ny,nz,ldx,ldy,ldz,ndat,isign,fofg,fofr,fftw_flags=my_flags)
361 : case (ABI_FFTW_FORWARD) ! -1
362 0 : call fftw3_many_dft_op(nx,ny,nz,ldx,ldy,ldz,ndat,isign,fofr,fofg,fftw_flags=my_flags)
363 : case default
364 0 : ABI_BUG("Wrong isign")
365 : end select
366 : end if
367 :
368 : case (1)
369 : ! Real case.
370 0 : select case (isign)
371 : case (ABI_FFTW_FORWARD)
372 : ! -1; R --> G
373 0 : call fftw3_r2c_op(nx,ny,nz,ldx,ldy,ldz,ndat,fofr,fofg,fftw_flags=my_flags)
374 : case (ABI_FFTW_BACKWARD)
375 : ! +1; G --> R
376 0 : call fftw3_c2r_op(nx,ny,nz,ldx,ldy,ldz,ndat,fofg,fofr,fftw_flags=my_flags)
377 : case default
378 0 : ABI_BUG("Wrong isign")
379 : end select
380 :
381 : case default
382 0 : ABI_BUG(" Wrong value for cplex")
383 : end select
384 :
385 0 : end subroutine fftw3_seqfourdp
386 : !!***
387 :
388 : !----------------------------------------------------------------------
389 :
390 : !!****f* m_fftw3/fftw3_seqfourwf
391 : !! NAME
392 : !! fftw3_seqfourwf
393 : !!
394 : !! FUNCTION
395 : !! Carry out composite Fourier transforms between real and reciprocal (G) space.
396 : !! Wavefunctions, contained in a sphere in reciprocal space,
397 : !! can be FFT to real space. They can also be FFT from real space
398 : !! to a sphere. Also, the density maybe accumulated, and a local potential can be applied.
399 : !!
400 : !! The different options are :
401 : !! - option=0 --> reciprocal to real space and output the result.
402 : !! - option=1 --> reciprocal to real space and accumulate the density.
403 : !! - option=2 --> reciprocal to real space, apply the local potential to the wavefunction
404 : !! in real space and produce the result in reciprocal space.
405 : !! - option=3 --> real space to reciprocal space.
406 : !! NOTE that in this case, fftalg=1x1 MUST be used. This may be changed in the future.
407 : !!
408 : !! INPUTS
409 : !! cplex= if 1 , denpot is real, if 2 , denpot is complex
410 : !! (cplex=2 only allowed for option=2, and istwf_k=1)
411 : !! not relevant if option=0 or option=3, so cplex=0 can be used to minimize memory
412 : !! fofgin(2,npwin)=holds input wavefunction in G vector basis sphere.
413 : !! (intent(in) but the routine sphere can modify it for another iflag)
414 : !! gboundin(2*mgfft+8,2)=sphere boundary info for reciprocal to real space
415 : !! gboundout(2*mgfft+8,2)=sphere boundary info for real to reciprocal space
416 : !! istwf_k=option parameter that describes the storage of wfs
417 : !! kg_kin(3,npwin)=reduced planewave coordinates, input
418 : !! kg_kout(3,npwout)=reduced planewave coordinates, output
419 : !! mgfft=maximum size of 1D FFTs
420 : !! ndat=number of FFT to do in //
421 : !! ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
422 : !! npwin=number of elements in fofgin array (for option 0, 1 and 2)
423 : !! npwout=number of elements in fofgout array (for option 2 and 3)
424 : !! ldx,ldy,ldz=ngfft(4),ngfft(5),ngfft(6), dimensions of fofr.
425 : !! option= if 0: do direct FFT
426 : !! if 1: do direct FFT, then sum the density
427 : !! if 2: do direct FFT, multiply by the potential, then do reverse FFT
428 : !! if 3: do reverse FFT only
429 : !! weight_r=weight to be used for the accumulation of the density in real space
430 : !! (needed only when option=1)
431 : !!
432 : !! OUTPUT
433 : !! (see side effects)
434 : !!
435 : !! SIDE EFFECTS
436 : !! Input/Output
437 : !! for option==0, fofgin(2,npwin*ndat)=holds input wavefunction in G sphere;
438 : !! fofr(2,ldx*ldy*ldz) contains the output Fourier Transform of fofgin;
439 : !! no use of denpot, fofgout and npwout.
440 : !! for option==1, fofgin(2,npwin*ndat)=holds input wavefunction in G sphere;
441 : !! denpot(cplex*ldx,ldy,ldz) contains the input density at input,
442 : !! and the updated density at output (accumulated);
443 : !! no use of fofgout and npwout.
444 : !! for option==2, fofgin(2,npwin*ndat)=holds input wavefunction in G sphere;
445 : !! denpot(cplex*ldx,ldy,ldz) contains the input local potential;
446 : !! fofgout(2,npwout*ndat) contains the output function;
447 : !! for option==3, fofr(2,ldx*ldy*ldz*ndat) contains the input real space wavefunction;
448 : !! fofgout(2,npwout*ndat) contains its output Fourier transform;
449 : !! no use of fofgin and npwin.
450 : !!
451 : !! SOURCE
452 :
453 0 : subroutine fftw3_seqfourwf(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,istwf_k, &
454 0 : kg_kin,kg_kout,mgfft,ndat,ngfft,npwin,npwout,ldx,ldy,ldz,option,weight_r,weight_i)
455 :
456 : !Arguments ------------------------------------
457 : !scalars
458 : integer,intent(in) :: cplex,istwf_k,ldx,ldy,ldz,ndat,npwin,npwout,option,mgfft
459 : real(dp),intent(in) :: weight_i,weight_r
460 : !arrays
461 : integer,intent(in) :: gboundin(2*mgfft+8,2),gboundout(2*mgfft+8,2)
462 : integer,intent(in) :: kg_kin(3,npwin),kg_kout(3,npwout),ngfft(18)
463 : real(dp),intent(inout) :: denpot(cplex*ldx,ldy,ldz),fofgin(2,npwin*ndat)
464 : real(dp),intent(inout) :: fofr(2,ldx*ldy*ldz*ndat)
465 : real(dp),intent(out) :: fofgout(2,npwout*ndat)
466 :
467 : !Local variables-------------------------------
468 : !scalars
469 : integer,parameter :: me_g0=1,ndat1=1
470 : integer :: nx,ny,nz,fftalg,fftalga,fftalgc,fftcache,dat,ptg,ptr,ptgin,ptgout,nthreads
471 : character(len=500) :: msg
472 : logical :: use_fftrisc
473 : !arrays
474 : !real(dp),allocatable :: saveden(:,:,:)
475 : #if 0
476 : logical :: use_fftbox
477 : integer,parameter :: shiftg(3)=(/0,0,0/)
478 : integer :: symm(3,3)
479 : #endif
480 : ! *************************************************************************
481 :
482 0 : if (all(option /= [0, 1, 2, 3])) then
483 0 : write(msg,'(a,i0,a)')' Option:',option,' is not allowed. Only option=0, 1, 2 or 3 are allowed presently.'
484 0 : ABI_ERROR(msg)
485 : end if
486 :
487 0 : if (option == 1 .and. cplex /= 1) then
488 0 : ABI_ERROR(sjoin("With option number 1, cplex must be 1 but it is cplex:", itoa(cplex)))
489 : end if
490 :
491 0 : if (option==2 .and. (cplex/=1 .and. cplex/=2)) then
492 0 : ABI_ERROR(sjoin("With the option number 2, cplex must be 1 or 2, but it is cplex:", itoa(cplex)))
493 : end if
494 :
495 0 : nx=ngfft(1); ny=ngfft(2); nz=ngfft(3)
496 0 : fftalg=ngfft(7); fftalga=fftalg/100; fftalgc=mod(fftalg,10)
497 0 : fftcache=ngfft(8)
498 :
499 0 : use_fftrisc = (fftalgc==2)
500 0 : if (istwf_k==2.and.option==3) use_fftrisc = .FALSE.
501 0 : if (istwf_k>2.and.ANY(option==(/0,3/))) use_fftrisc = .FALSE.
502 :
503 : nthreads = xomp_get_num_threads(open_parallel=.TRUE.)
504 :
505 0 : if (use_fftrisc) then
506 : !call wrtout(std_out, calling fftw3_fftrisc")
507 :
508 0 : if (ndat == 1) then
509 0 : if (fftcore_mixprec == 0) then
510 : call fftw3_fftrisc_dp(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,istwf_k,kg_kin,kg_kout,&
511 0 : mgfft,ngfft,npwin,npwout,ldx,ldy,ldz,option,weight_r,weight_i)
512 : else
513 : call fftw3_fftrisc_mixprec(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,istwf_k,kg_kin,kg_kout,&
514 0 : mgfft,ngfft,npwin,npwout,ldx,ldy,ldz,option,weight_r,weight_i)
515 : end if
516 :
517 : else
518 : ! All this boilerplate code is needed because the caller might pass zero-sized arrays
519 : ! for the arguments that are not referenced and we don't want to have problems at run-time.
520 : ! Moreover option 1 requires a special treatment when threads are started at this level.
521 :
522 : SELECT CASE (option)
523 : CASE (0)
524 : !
525 : ! fofgin -> fofr, no use of denpot, fofgout and npwout.
526 : if (.not.fftw3_spawn_threads_here(ndat,nthreads)) then
527 0 : do dat=1,ndat
528 0 : ptg = 1 + (dat-1)*npwin
529 0 : ptr = 1 + (dat-1)*ldx*ldy*ldz
530 : call fftw3_fftrisc_dp(cplex,denpot,fofgin(1,ptg),fofgout,fofr(1,ptr),gboundin,gboundout,istwf_k,kg_kin,kg_kout,&
531 0 : mgfft,ngfft,npwin,npwout,ldx,ldy,ldz,option,weight_r,weight_i)
532 : end do
533 : else
534 : !$OMP PARALLEL DO PRIVATE(ptg,ptr)
535 : do dat=1,ndat
536 : ptg = 1 + (dat-1)*npwin
537 : ptr = 1 + (dat-1)*ldx*ldy*ldz
538 : call fftw3_fftrisc_dp(cplex,denpot,fofgin(1,ptg),fofgout,fofr(1,ptr),gboundin,gboundout,istwf_k,kg_kin,kg_kout,&
539 : mgfft,ngfft,npwin,npwout,ldx,ldy,ldz,option,weight_r,weight_i)
540 : end do
541 : end if
542 :
543 : CASE (1)
544 : !fofgin -> local ur and accumulate density in denpot
545 : ! TODO this is delicate part to do in parallel, as one should OMP reduce denpot.
546 : ! but this causes problems with the stack.
547 :
548 0 : do dat=1,ndat
549 0 : ptg = 1 + (dat-1)*npwin
550 0 : ptr = 1 + (dat-1)*ldx*ldy*ldz
551 : call fftw3_fftrisc_dp(cplex,denpot,fofgin(1,ptg),fofgout,fofr,gboundin,gboundout,istwf_k,kg_kin,kg_kout,&
552 0 : mgfft,ngfft,npwin,npwout,ldx,ldy,ldz,option,weight_r,weight_i)
553 : end do
554 :
555 : ! This version doesn't seem efficient
556 : !!! !$OMP PARALLEL PRIVATE(ptg,ptr,saveden)
557 : !!! ABI_MALLOC(saveden, (ldx,ldy,ldz))
558 : !!! saveden = zero
559 : !!! !$OMP DO
560 : !!! do dat=1,ndat
561 : !!! ptg = 1 + (dat-1)*npwin
562 : !!! ptr = 1 + (dat-1)*ldx*ldy*ldz
563 : !!! call fftw3_fftrisc_dp(cplex,saveden,fofgin(1,ptg),fofgout,fofr,gboundin,gboundout,istwf_k,kg_kin,kg_kout,&
564 : !!! & mgfft,ngfft,npwin,npwout,ldx,ldy,ldz,option,weight_r)
565 : !!! end do
566 : !!! !$OMP END DO NOWAIT
567 : !!! !$OMP CRITICAL (OMPC_addrho)
568 : !!! denpot = denpot + saveden
569 : !!! !$OMP END CRITICAL (OMPC_addrho)
570 : !!! ABI_FREE(saveden)
571 : !!! !$OMP END PARALLEL
572 :
573 : CASE (2)
574 : ! <G|vloc(r)|fofgin(r)> in fofgout
575 : if (.not.fftw3_spawn_threads_here(ndat,nthreads)) then
576 0 : do dat=1,ndat
577 0 : ptgin = 1 + (dat-1)*npwin
578 0 : ptgout = 1 + (dat-1)*npwout
579 0 : if (fftcore_mixprec == 0) then
580 : call fftw3_fftrisc_dp(cplex,denpot,fofgin(1,ptgin),fofgout(1,ptgout),fofr,gboundin,gboundout,&
581 0 : istwf_k,kg_kin,kg_kout,mgfft,ngfft,npwin,npwout,ldx,ldy,ldz,option,weight_r,weight_i)
582 : else
583 : call fftw3_fftrisc_mixprec(cplex,denpot,fofgin(1,ptgin),fofgout(1,ptgout),fofr,gboundin,gboundout,&
584 0 : istwf_k,kg_kin,kg_kout,mgfft,ngfft,npwin,npwout,ldx,ldy,ldz,option,weight_r,weight_i)
585 : end if
586 : end do
587 : else
588 : !$OMP PARALLEL DO PRIVATE(ptgin,ptgout)
589 : do dat=1,ndat
590 : ptgin = 1 + (dat-1)*npwin
591 : ptgout = 1 + (dat-1)*npwout
592 : call fftw3_fftrisc_dp(cplex,denpot,fofgin(1,ptgin),fofgout(1,ptgout),fofr,gboundin,gboundout,istwf_k,kg_kin,kg_kout,&
593 : mgfft,ngfft,npwin,npwout,ldx,ldy,ldz,option,weight_r,weight_i)
594 : end do
595 : end if
596 :
597 : CASE (3)
598 : ! fofr -> fofgout
599 0 : if (.not.fftw3_spawn_threads_here(ndat,nthreads)) then
600 0 : do dat=1,ndat
601 0 : ptr = 1 + (dat-1)*ldx*ldy*ldz
602 0 : ptgout = 1 + (dat-1)*npwout
603 : call fftw3_fftrisc_dp(cplex,denpot,fofgin,fofgout(1,ptgout),fofr(1,ptr),gboundin,gboundout,istwf_k,kg_kin,kg_kout,&
604 0 : mgfft,ngfft,npwin,npwout,ldx,ldy,ldz,option,weight_r,weight_i)
605 : end do
606 : else
607 : !$OMP PARALLEL DO PRIVATE(ptr,ptgout)
608 : do dat=1,ndat
609 : ptr = 1 + (dat-1)*ldx*ldy*ldz
610 : ptgout = 1 + (dat-1)*npwout
611 : call fftw3_fftrisc_dp(cplex,denpot,fofgin,fofgout(1,ptgout),fofr(1,ptr),gboundin,gboundout,istwf_k,kg_kin,kg_kout,&
612 : mgfft,ngfft,npwin,npwout,ldx,ldy,ldz,option,weight_r,weight_i)
613 : end do
614 : end if
615 :
616 : CASE DEFAULT
617 0 : write(msg,'(a,i0,a)')'Option',option,' is not allowed. Only option=0, 1, 2 or 3 are allowed presently.'
618 0 : ABI_ERROR(msg)
619 : END SELECT
620 :
621 : end if
622 :
623 : else
624 :
625 : #if 1
626 0 : SELECT CASE (option)
627 : CASE (0)
628 : !
629 : ! FFT u(g) --> u(r)
630 0 : if (.not.fftw3_spawn_threads_here(ndat,nthreads)) then
631 0 : call fftw3_fftug_dp(fftalg,fftcache,npwin,nx,ny,nz,ldx,ldy,ldz,ndat,istwf_k,mgfft,kg_kin,gboundin,fofgin,fofr)
632 : else
633 : !$OMP PARALLEL DO PRIVATE(ptg, ptr)
634 : do dat=1,ndat
635 : ptg = 1 + (dat-1)*npwin
636 : ptr = 1 + (dat-1)*ldx*ldy*ldz
637 : call fftw3_fftug_dp(fftalg,fftcache,npwin,nx,ny,nz,ldx,ldy,ldz,ndat1,&
638 : & istwf_k,mgfft,kg_kin,gboundin,fofgin(1,ptg),fofr(1,ptr))
639 : end do
640 : end if
641 :
642 : CASE (1)
643 : ! TODO this is delicate part to do in parallel, as one should OMP reduce denpot.
644 0 : call fftw3_fftug_dp(fftalg,fftcache,npwin,nx,ny,nz,ldx,ldy,ldz,ndat,istwf_k,mgfft,kg_kin,gboundin,fofgin,fofr)
645 0 : call cg_addtorho(nx,ny,nz,ldx,ldy,ldz,ndat,weight_r,weight_i,fofr,denpot)
646 :
647 : CASE (2)
648 :
649 0 : if (.not.fftw3_spawn_threads_here(ndat,nthreads)) then
650 0 : call fftw3_fftug_dp(fftalg,fftcache,npwin,nx,ny,nz,ldx,ldy,ldz,ndat,istwf_k,mgfft,kg_kin,gboundin,fofgin,fofr)
651 0 : call cg_vlocpsi(nx,ny,nz,ldx,ldy,ldz,ndat,cplex,denpot,fofr)
652 :
653 : ! The data for option==2 is now in fofr.
654 0 : call fftw3_fftpad_dp(fofr,nx,ny,nz,ldx,ldy,ldz,ndat,mgfft,-1,gboundout)
655 :
656 0 : call cg_box2gsph(nx,ny,nz,ldx,ldy,ldz,ndat,npwout,kg_kout,fofr,fofgout)
657 : else
658 :
659 : !$OMP PARALLEL DO PRIVATE(ptg, ptr)
660 : do dat=1,ndat
661 : ptg = 1 + (dat-1)*npwin
662 : ptr = 1 + (dat-1)*ldx*ldy*ldz
663 : call fftw3_fftug_dp(fftalg,fftcache,npwin,nx,ny,nz,ldx,ldy,ldz,ndat1,&
664 : istwf_k,mgfft,kg_kin,gboundin,fofgin(1,ptg),fofr(1,ptr))
665 :
666 : call cg_vlocpsi(nx,ny,nz,ldx,ldy,ldz,ndat1,cplex,denpot,fofr(1,ptr))
667 :
668 : ! The data for option==2 is now in fofr.
669 : call fftw3_fftpad_dp(fofr(1,ptr),nx,ny,nz,ldx,ldy,ldz,ndat1,mgfft,-1,gboundout)
670 :
671 : ptg = 1 + (dat-1)*npwout
672 : call cg_box2gsph(nx,ny,nz,ldx,ldy,ldz,ndat1,npwout,kg_kout,fofr(1,ptr),fofgout(1,ptg))
673 : end do
674 : end if
675 :
676 : CASE (3)
677 : ! The data for option==3 is already in fofr.
678 0 : if (.not.fftw3_spawn_threads_here(ndat,nthreads)) then
679 0 : call fftw3_fftpad_dp(fofr,nx,ny,nz,ldx,ldy,ldz,ndat,mgfft,-1,gboundout)
680 0 : call cg_box2gsph(nx,ny,nz,ldx,ldy,ldz,ndat,npwout,kg_kout,fofr,fofgout)
681 : else
682 : !$OMP PARALLEL DO PRIVATE(ptg, ptr)
683 : do dat=1,ndat
684 : ptg = 1 + (dat-1)*npwout
685 : ptr = 1 + (dat-1)*ldx*ldy*ldz
686 : call fftw3_fftpad_dp(fofr(1,ptr),nx,ny,nz,ldx,ldy,ldz,ndat1,mgfft,-1,gboundout)
687 : call cg_box2gsph(nx,ny,nz,ldx,ldy,ldz,ndat1,npwout,kg_kout,fofr(1,ptr),fofgout(1,ptg))
688 : end do
689 : end if
690 :
691 : CASE DEFAULT
692 0 : write(msg,'(a,i0,a)')'Option',option,' is not allowed. Only option=0, 1, 2 or 3 are allowed presently.'
693 0 : ABI_ERROR(msg)
694 : END SELECT
695 :
696 : #else
697 : symm=0; symm(1,1)=1; symm(2,2)=1; symm(3,3)=1
698 : use_fftbox = .FALSE.
699 : #ifdef HAVE_OPENMP
700 : use_fftbox = (ndat>1)
701 : #endif
702 : !use_fftbox = .TRUE.
703 :
704 : SELECT CASE (option)
705 : CASE (0)
706 : !
707 : ! FFT u(g) --> u(r)
708 : call sphere(fofgin,ndat,npwin,fofr,nx,ny,nz,ldx,ldy,ldz,kg_kin,istwf_k,1,me_g0,shiftg,symm,one)
709 :
710 : if (use_fftbox) then
711 : call fftw3_many_dft_ip(nx,ny,nz,ldx,ldy,ldz,ndat,ABI_FFTW_BACKWARD,fofr)
712 : else
713 : call fftw3_fftpad_dp(fofr,nx,ny,nz,ldx,ldy,ldz,ndat,mgfft,ABI_FFTW_BACKWARD,gboundin)
714 : end if
715 :
716 : CASE (1)
717 : ! TODO this is delicate part to do in parallel, as one should OMP reduce denpot.
718 :
719 : call sphere(fofgin,ndat,npwin,fofr,nx,ny,nz,ldx,ldy,ldz,kg_kin,istwf_k,1,me_g0,shiftg,symm,one)
720 :
721 : if (use_fftbox) then
722 : call fftw3_many_dft_ip(nx,ny,nz,ldx,ldy,ldz,ndat,ABI_FFTW_BACKWARD,fofr)
723 : else
724 : call fftw3_fftpad_dp(fofr,nx,ny,nz,ldx,ldy,ldz,ndat,mgfft,ABI_FFTW_BACKWARD,gboundin)
725 : end if
726 :
727 : call cg_addtorho(nx,ny,nz,ldx,ldy,ldz,ndat,weight_r,weight_i,fofr,denpot)
728 :
729 : CASE (2)
730 :
731 : call sphere(fofgin,ndat,npwin,fofr,nx,ny,nz,ldx,ldy,ldz,kg_kin,istwf_k,1,me_g0,shiftg,symm,one)
732 :
733 : if (use_fftbox) then
734 : call fftw3_many_dft_ip(nx,ny,nz,ldx,ldy,ldz,ndat,ABI_FFTW_BACKWARD,fofr)
735 : else
736 : call fftw3_fftpad_dp(fofr,nx,ny,nz,ldx,ldy,ldz,ndat,mgfft,ABI_FFTW_BACKWARD,gboundin)
737 : end if
738 :
739 : call cg_vlocpsi(nx,ny,nz,ldx,ldy,ldz,ndat,cplex,denpot,fofr)
740 :
741 : ! The data for option==2 is now in fofr.
742 : if (use_fftbox) then
743 : call fftw3_many_dft_ip(nx,ny,nz,ldx,ldy,ldz,ndat,ABI_FFTW_FORWARD,fofr)
744 : else
745 : call fftw3_fftpad_dp(fofr,nx,ny,nz,ldx,ldy,ldz,ndat,mgfft,ABI_FFTW_FORWARD,gboundout)
746 : end if
747 :
748 : call cg_box2gsph(nx,ny,nz,ldx,ldy,ldz,ndat,npwout,kg_kout,fofr,fofgout)
749 :
750 : CASE (3)
751 : ! The data for option==3 is already in fofr.
752 : call fftw3_fftpad_dp(fofr,nx,ny,nz,ldx,ldy,ldz,ndat,mgfft,ABI_FFTW_FORWARD,gboundout)
753 :
754 : call cg_box2gsph(nx,ny,nz,ldx,ldy,ldz,ndat,npwout,kg_kout,fofr,fofgout)
755 :
756 : CASE DEFAULT
757 : write(msg,'(a,i0,a)')'Option',option,' is not allowed. Only option=0, 1, 2 or 3 are allowed presently.'
758 : ABI_ERROR(msg)
759 : END SELECT
760 : #endif
761 : end if
762 :
763 0 : end subroutine fftw3_seqfourwf
764 : !!***
765 :
766 : !----------------------------------------------------------------------
767 :
768 : !!****f* m_fftw3/fftw3_fftrisc_sp
769 : !! NAME
770 : !! fftw3_fftrisc_sp
771 : !!
772 : !! FUNCTION
773 : !! Carry out Fourier transforms between real and reciprocal (G) space,
774 : !! for wavefunctions, contained in a sphere in reciprocal space,
775 : !! in both directions. Also accomplish some post-processing.
776 : !! See fftw3_fftrisc_dp for API doc.
777 : !!
778 : !! SOURCE
779 :
780 0 : subroutine fftw3_fftrisc_sp(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,istwf_k,kg_kin,kg_kout,&
781 : mgfft,ngfft,npwin,npwout,ldx,ldy,ldz,option, &
782 : weight_r,weight_i, abi_convention, iscale)
783 :
784 : !Arguments ------------------------------------
785 : !scalars
786 : integer,intent(in) :: cplex,istwf_k,mgfft,ldx,ldy,ldz,npwin,npwout,option
787 : real(dp),intent(in) :: weight_i,weight_r
788 : !arrays
789 : integer,intent(in) :: gboundin(2*mgfft+8,2),gboundout(2*mgfft+8,2)
790 : integer,intent(in) :: kg_kin(3,npwin),kg_kout(3,npwout),ngfft(18)
791 : real(sp),intent(in) :: fofgin(2,npwin)
792 : real(dp),intent(inout) :: denpot(cplex*ldx,ldy,ldz)
793 : real(sp),intent(inout) :: fofr(2,ldx*ldy*ldz)
794 : real(sp),intent(inout) :: fofgout(2,npwout)
795 : logical,optional,intent(in) :: abi_convention
796 : integer,optional,intent(in) :: iscale
797 : ! *************************************************************************
798 :
799 : #ifdef HAVE_FFTW3
800 :
801 : #undef FFT_PRECISION
802 : #undef MYKIND
803 : #undef MYCZERO
804 : #undef MYCMPLX
805 : #undef MYCONJG
806 :
807 : #define FFT_PRECISION FFT_SINGLE
808 : #define MYKIND SP
809 : #define MYCZERO (0._sp,0._sp)
810 : #define MYCMPLX CMPLX
811 : #define MYCONJG CONJG
812 :
813 : #include "fftw3_fftrisc.finc"
814 :
815 : #else
816 0 : ABI_ERROR("FFTW3 support not activated")
817 : ABI_UNUSED((/cplex,gboundin(1,1),gboundout(1,1),istwf_k,kg_kin(1,1),kg_kout(1,1)/))
818 : ABI_UNUSED((/mgfft,ngfft(1),npwin,npwout,ldx,ldy,ldz,option/))
819 : ABI_UNUSED((/denpot(1,1,1),weight_r,weight_i/))
820 : ABI_UNUSED((/fofgin(1,1),fofgout(1,1),fofr(1,1)/))
821 : #endif
822 :
823 0 : end subroutine fftw3_fftrisc_sp
824 : !!***
825 :
826 : !----------------------------------------------------------------------
827 :
828 : !!****f* m_fftw3/fftw3_fftrisc_dp
829 : !! NAME
830 : !! fftw3_fftrisc_dp
831 : !!
832 : !! FUNCTION
833 : !! Carry out Fourier transforms between real and reciprocal (G) space,
834 : !! for wavefunctions, contained in a sphere in reciprocal space,
835 : !! in both directions. Also accomplish some post-processing.
836 : !!
837 : !! NOTES
838 : !! Specifically uses rather sophisticated algorithms, based on S Goedecker
839 : !! routines, specialized for superscalar RISC architecture.
840 : !! Zero padding : saves 7/12 execution time
841 : !! Bi-dimensional data locality in most of the routine : cache reuse
842 : !! For k-point (0 0 0) : takes advantage of symmetry of data.
843 : !! Note however that no blocking is used, in both 1D z-transform
844 : !! or subsequent 2D transform. This should be improved.
845 : !!
846 : !! INPUTS
847 : !! cplex= if 1 , denpot is real, if 2 , denpot is complex
848 : !! (cplex=2 only allowed for option=2 when istwf_k=1)
849 : !! one can also use cplex=0 if option=0 or option=3
850 : !! fofgin(2,npwin)=holds input wavefunction in G vector basis sphere.
851 : !! gboundin(2*mgfft+8,2)=sphere boundary info for reciprocal to real space
852 : !! gboundout(2*mgfft+8,2)=sphere boundary info for real to reciprocal space
853 : !! istwf_k=option parameter that describes the storage of wfs
854 : !! kg_kin(3,npwin)=reduced planewave coordinates, input
855 : !! kg_kout(3,npwout)=reduced planewave coordinates, output
856 : !! mgfft=maximum size of 1D FFTs
857 : !! ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
858 : !! npwin=number of elements in fofgin array (for option 0, 1 and 2)
859 : !! npwout=number of elements in fofgout array (for option 2 and 3)
860 : !! ldx,ldy,ldz=ngfft(4),ngfft(5),ngfft(6), dimensions of fofr.
861 : !! option= if 0: do direct FFT
862 : !! if 1: do direct FFT, then sum the density
863 : !! if 2: do direct FFT, multiply by the potential, then do reverse FFT
864 : !! if 3: do reverse FFT only
865 : !! weight=weight to be used for the accumulation of the density in real space
866 : !! (needed only when option=1)
867 : !!
868 : !! OUTPUT
869 : !! (see side effects)
870 : !!
871 : !! OPTIONS
872 : !! The different options are:
873 : !! - reciprocal to real space and output the result (when option=0),
874 : !! - reciprocal to real space and accumulate the density (when option=1) or
875 : !! - reciprocal to real space, apply the local potential to the wavefunction
876 : !! in real space and produce the result in reciprocal space (when option=2)
877 : !! - real space to reciprocal space (when option=3).
878 : !! option=0 IS NOT ALLOWED when istwf_k>2
879 : !! option=3 IS NOT ALLOWED when istwf_k>=2
880 : !!
881 : !! SIDE EFFECTS
882 : !! for option==0, fofgin(2,npwin)=holds input wavefunction in G sphere;
883 : !! fofr(2,ldx,ldy,ldz) contains the Fourier Transform of fofgin;
884 : !! no use of denpot, fofgout and npwout.
885 : !! for option==1, fofgin(2,npwin)=holds input wavefunction in G sphere;
886 : !! denpot(cplex*ldx,ldy,ldz) contains the input density at input,
887 : !! and the updated density at output;
888 : !! no use of fofgout and npwout.
889 : !! for option==2, fofgin(2,npwin)=holds input wavefunction in G sphere;
890 : !! denpot(cplex*ldx,ldy,ldz) contains the input local potential;
891 : !! fofgout(2,npwout) contains the output function;
892 : !! for option==3, fofr(2,ldx,ldy,ldz) contains the real space wavefunction;
893 : !! fofgout(2,npwout) contains its Fourier transform;
894 : !! no use of fofgin and npwin.
895 : !!
896 : !! SOURCE
897 :
898 0 : subroutine fftw3_fftrisc_dp(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,istwf_k,kg_kin,kg_kout,&
899 : mgfft,ngfft,npwin,npwout,ldx,ldy,ldz,option, &
900 : weight_r, weight_i, abi_convention, iscale)
901 :
902 : !Arguments ------------------------------------
903 : !scalars
904 : integer,intent(in) :: cplex,istwf_k,mgfft,ldx,ldy,ldz,npwin,npwout,option
905 : real(dp),intent(in) :: weight_r,weight_i
906 : !arrays
907 : integer,intent(in) :: gboundin(2*mgfft+8,2),gboundout(2*mgfft+8,2)
908 : integer,intent(in) :: kg_kin(3,npwin),kg_kout(3,npwout),ngfft(18)
909 : real(dp),intent(in) :: fofgin(2,npwin)
910 : real(dp),intent(inout) :: denpot(cplex*ldx,ldy,ldz),fofr(2,ldx*ldy*ldz)
911 : real(dp),intent(inout) :: fofgout(2,npwout)
912 : logical,optional,intent(in) :: abi_convention
913 : integer,optional,intent(in) :: iscale
914 : ! *************************************************************************
915 :
916 : #ifdef HAVE_FFTW3
917 :
918 : #undef FFT_PRECISION
919 : #undef MYKIND
920 : #undef MYCZERO
921 : #undef MYCMPLX
922 : #undef MYCONJG
923 :
924 : #define FFT_PRECISION FFT_DOUBLE
925 : #define MYKIND DP
926 : #define MYCZERO (0._dp,0._dp)
927 : #define MYCMPLX DCMPLX
928 : #define MYCONJG DCONJG
929 :
930 : #include "fftw3_fftrisc.finc"
931 :
932 : #else
933 0 : ABI_ERROR("FFTW3 support not activated")
934 : ABI_UNUSED((/cplex,gboundin(1,1),gboundout(1,1),istwf_k,kg_kin(1,1),kg_kout(1,1)/))
935 : ABI_UNUSED((/mgfft,ngfft(1),npwin,npwout,ldx,ldy,ldz,option/))
936 : ABI_UNUSED((/denpot(1,1,1),fofgin(1,1),fofgout(1,1),fofr(1,1),weight_r,weight_i/))
937 : #endif
938 :
939 0 : end subroutine fftw3_fftrisc_dp
940 : !!***
941 :
942 : !----------------------------------------------------------------------
943 :
944 : !!****f* m_fftw3/fftw3_fftrisc_mixprec
945 : !! NAME
946 : !! fftw3_fftrisc_mixprec
947 : !!
948 : !! FUNCTION
949 : !! Mixed precision version of fftrisc: input/output in dp, computation done in sp.
950 : !! See fftw3_fftrisc_dp for API docs.
951 : !!
952 : !! SOURCE
953 :
954 0 : subroutine fftw3_fftrisc_mixprec(cplex,denpot,fofgin,fofgout,fofr,gboundin,gboundout,istwf_k,kg_kin,kg_kout,&
955 : mgfft,ngfft,npwin,npwout,ldx,ldy,ldz,option, &
956 : weight_r,weight_i, abi_convention, iscale) ! optional
957 :
958 : !Arguments ------------------------------------
959 : !scalars
960 : integer,intent(in) :: cplex,istwf_k,mgfft,ldx,ldy,ldz,npwin,npwout,option
961 : real(dp),intent(in) :: weight_r,weight_i
962 : !arrays
963 : integer,intent(in) :: gboundin(2*mgfft+8,2),gboundout(2*mgfft+8,2)
964 : integer,intent(in) :: kg_kin(3,npwin),kg_kout(3,npwout),ngfft(18)
965 : real(dp),intent(in) :: fofgin(2,npwin)
966 : real(dp),intent(inout) :: denpot(cplex*ldx,ldy,ldz),fofr(2,ldx*ldy*ldz)
967 : real(dp),intent(inout) :: fofgout(2,npwout)
968 : logical,optional,intent(in) :: abi_convention
969 : integer,optional,intent(in) :: iscale
970 : ! *************************************************************************
971 :
972 : #ifdef HAVE_FFTW3
973 :
974 : #undef FFT_PRECISION
975 : #undef MYKIND
976 : #undef MYCZERO
977 : #undef MYCMPLX
978 : #undef MYCONJG
979 :
980 : #define FFT_PRECISION FFT_MIXPREC
981 : #define MYKIND SP
982 : #define MYCZERO (0._sp,0._sp)
983 : #define MYCMPLX CMPLX
984 : #define MYCONJG CONJG
985 :
986 : #include "fftw3_fftrisc.finc"
987 :
988 : #else
989 0 : ABI_ERROR("FFTW3 support not activated")
990 : ABI_UNUSED((/cplex,gboundin(1,1),gboundout(1,1),istwf_k,kg_kin(1,1),kg_kout(1,1)/))
991 : ABI_UNUSED((/mgfft,ngfft(1),npwin,npwout,ldx,ldy,ldz,option/))
992 : ABI_UNUSED((/denpot(1,1,1),fofgin(1,1),fofgout(1,1),fofr(1,1),weight_r,weight_i/))
993 : #endif
994 :
995 0 : end subroutine fftw3_fftrisc_mixprec
996 : !!***
997 :
998 : !----------------------------------------------------------------------
999 :
1000 : !!****f* m_fftw3/fftw3_fftug_dp
1001 : !! NAME
1002 : !! fftw3_fftug_dp
1003 : !!
1004 : !! FUNCTION
1005 : !! Compute ndat zero-padded FFTs from G to R space.
1006 : !! Mainly used for the transform of wavefunctions.
1007 : !! TARGET: dp arrays with real and imaginary part
1008 : !!
1009 : !! INPUTS
1010 : !! fftalg=FFT algorithm (see input variable)
1011 : !! fftcache=size of the cache (kB)
1012 : !! npw_k=number of plane waves for this k-point.
1013 : !! nx,ny,nz=Number of point along the three directions.
1014 : !! ldx,ldy,ldz=Leading dimensions of the array.
1015 : !! ndat=Number of transforms
1016 : !! istwf_k=Option describing the storage of the wavefunction.
1017 : !! mgfft=Max number of FFT divisions (used to dimension gbound)
1018 : !! kg_k(3,npw_k)=G-vectors in reduced coordinates
1019 : !! gbound(2*mgfft+8,2)=Table for zero-padded FFT. See sphereboundary.
1020 : !! ug(npw_k*ndat)=wavefunctions in reciprocal space.
1021 : !!
1022 : !! OUTPUT
1023 : !! ur(ldx*ldy*ldz*ndat)=wavefunctions in real space.
1024 : !!
1025 : !! SOURCE
1026 :
1027 0 : subroutine fftw3_fftug_dp(fftalg, fftcache, npw_k, nx, ny, nz, ldx, ldy, ldz, ndat, &
1028 0 : istwf_k, mgfft, kg_k,gbound, ug, ur, &
1029 : isign, iscale) ! optional
1030 :
1031 : !Arguments ------------------------------------
1032 : !scalars
1033 : integer,intent(in) :: fftalg,fftcache
1034 : integer,intent(in) :: npw_k,nx,ny,nz,ldx,ldy,ldz,ndat,istwf_k,mgfft
1035 : !arrays
1036 : integer,intent(in) :: gbound(2*mgfft+8,2),kg_k(3,npw_k)
1037 : real(dp),target,intent(in) :: ug(2*npw_k*ndat)
1038 : real(dp),target,intent(inout) :: ur(2*ldx*ldy*ldz*ndat)
1039 : integer,optional,intent(in) :: isign, iscale
1040 :
1041 : #ifdef HAVE_FFTW3
1042 : !Local variables-------------------------------
1043 : !scalars
1044 : integer,parameter :: dist=2
1045 : integer :: iscale__, isign__
1046 : real(dp) :: fofgout(2,0)
1047 : real(dp),contiguous, pointer :: real_ug(:,:),real_ur(:,:)
1048 : ! *************************************************************************
1049 :
1050 : iscale__ = 0; if (present(iscale)) iscale__ = iscale
1051 : isign__ = +1; if (present(isign)) isign__ = isign
1052 :
1053 : #undef TK_PREF
1054 : #define TK_PREF(name) CONCAT(cg_,name)
1055 : #undef TK_PREF_box2gsph
1056 : #define TK_PREF_box2gsph cg_box2gsph
1057 : #undef TK_PREF_gsph2box
1058 : #define TK_PREF_gsph2box cg_gsph2box
1059 :
1060 : #undef FFT_PRECISION
1061 : #define FFT_PRECISION FFT_DOUBLE
1062 :
1063 : #include "fftug.finc"
1064 :
1065 : #undef FFT_PRECISION
1066 :
1067 : #else
1068 : ! Silence compiler warning
1069 0 : ABI_ERROR("FFT_FFTW3 support not activated")
1070 : ABI_UNUSED((/fftalg,fftcache,npw_k,nx,ny,nz,ldx,ldy,ldz,ndat,istwf_k,mgfft,kg_k(1,1),gbound(1,1),iscale,isign/))
1071 : ABI_UNUSED((/ug(1),ur(1)/))
1072 : #endif
1073 :
1074 0 : end subroutine fftw3_fftug_dp
1075 : !!***
1076 :
1077 : !----------------------------------------------------------------------
1078 :
1079 : !!****f* m_fftw3/fftw3_fftug_spc
1080 : !! NAME
1081 : !! fftw3_fftug_spc
1082 : !!
1083 : !! FUNCTION
1084 : !! Compute ndat zero-padded FFTs from G-->R.
1085 : !! Mainly used for the transform of wavefunctions.
1086 : !! TARGET: spc arrays
1087 : !! See fftw3_fftug_dp for API docs.
1088 : !!
1089 : !! SOURCE
1090 :
1091 0 : subroutine fftw3_fftug_spc(fftalg, fftcache, npw_k, nx, ny, nz, ldx, ldy, ldz, ndat, &
1092 0 : istwf_k, mgfft, kg_k, gbound, ug, ur, &
1093 : isign, iscale) ! optional
1094 :
1095 : !Arguments ------------------------------------
1096 : !scalars
1097 : integer,intent(in) :: fftalg,fftcache
1098 : integer,intent(in) :: npw_k,nx,ny,nz,ldx,ldy,ldz,ndat,istwf_k,mgfft
1099 : integer,optional,intent(in) :: isign, iscale
1100 : !arrays
1101 : integer,intent(in) :: gbound(2*mgfft+8,2),kg_k(3,npw_k)
1102 : complex(sp),target,intent(in) :: ug(npw_k*ndat)
1103 : complex(sp),target,intent(inout) :: ur(ldx*ldy*ldz*ndat)
1104 :
1105 : #ifdef HAVE_FFTW3
1106 : !Local variables-------------------------------
1107 : !scalars
1108 : integer,parameter :: dist=1
1109 : integer :: iscale__, isign__
1110 : !arrays
1111 : real(sp) :: fofgout(2,0)
1112 : real(sp),contiguous, pointer :: real_ug(:,:),real_ur(:,:)
1113 : ! *************************************************************************
1114 :
1115 : iscale__ = 0; if (present(iscale)) iscale__ = iscale
1116 : isign__ = +1; if (present(isign)) isign__ = isign
1117 :
1118 : #undef TK_PREF
1119 : #define TK_PREF(name) CONCAT(cplx_,name)
1120 : #undef TK_PREF_box2gsph
1121 : #define TK_PREF_box2gsph cplx_box2gsph
1122 : #undef TK_PREF_gsph2box
1123 : #define TK_PREF_gsph2box cplx_gsph2box
1124 :
1125 : #undef FFT_PRECISION
1126 : #define FFT_PRECISION FFT_SINGLE
1127 :
1128 : #include "fftug.finc"
1129 :
1130 : #undef FFT_PRECISION
1131 :
1132 : #else
1133 : ! Silence compiler warning
1134 0 : ABI_ERROR("FFTW3 support not activated")
1135 : ABI_UNUSED((/fftalg,fftcache,npw_k,nx,ny,nz,ldx,ldy,ldz,ndat,istwf_k,mgfft,kg_k(1,1),gbound(1,1)/))
1136 : ABI_UNUSED((/ug(1),ur(1)/))
1137 : #endif
1138 :
1139 0 : end subroutine fftw3_fftug_spc
1140 : !!***
1141 :
1142 : !----------------------------------------------------------------------
1143 :
1144 : !!****f* m_fftw3/fftw3_fftug_dpc
1145 : !! NAME
1146 : !! fftw3_fftug_dpc
1147 : !!
1148 : !! FUNCTION
1149 : !! Compute ndat zero-padded FFTs.
1150 : !! Mainly used for the transform of wavefunctions.
1151 : !! TARGET: DP arrays
1152 : !! See fftw3_fftug_dp for API docs.
1153 : !!
1154 : !! SOURCE
1155 :
1156 0 : subroutine fftw3_fftug_dpc(fftalg, fftcache, npw_k, nx, ny, nz, ldx, ldy, ldz, ndat, &
1157 0 : istwf_k, mgfft, kg_k, gbound, ug, ur, &
1158 : isign, iscale) ! optional
1159 :
1160 : !Arguments ------------------------------------
1161 : !scalars
1162 : integer,intent(in) :: fftalg,fftcache
1163 : integer,intent(in) :: npw_k,nx,ny,nz,ldx,ldy,ldz,ndat,istwf_k,mgfft
1164 : !arrays
1165 : integer,intent(in) :: gbound(2*mgfft+8,2),kg_k(3,npw_k)
1166 : complex(dp),target,intent(in) :: ug(npw_k*ndat)
1167 : complex(dp),target,intent(inout) :: ur(ldx*ldy*ldz*ndat)
1168 : integer,optional,intent(in) :: isign, iscale
1169 :
1170 : #ifdef HAVE_FFTW3
1171 : !Local variables-------------------------------
1172 : !scalars
1173 : integer,parameter :: dist=1
1174 : integer :: iscale__, isign__
1175 : !arrays
1176 : real(dp) :: fofgout(2,0)
1177 : real(dp),contiguous, pointer :: real_ug(:,:),real_ur(:,:)
1178 : ! *************************************************************************
1179 :
1180 : iscale__ = 0; if (present(iscale)) iscale__ = iscale
1181 : isign__ = +1; if (present(isign)) isign__ = isign
1182 :
1183 : #undef TK_PREF
1184 : #define TK_PREF(name) CONCAT(cplx_,name)
1185 : #undef TK_PREF_box2gsph
1186 : #define TK_PREF_box2gsph cplx_box2gsph
1187 : #undef TK_PREF_gsph2box
1188 : #define TK_PREF_gsph2box cplx_gsph2box
1189 :
1190 : #undef FFT_PRECISION
1191 : #define FFT_PRECISION FFT_DOUBLE
1192 :
1193 : #include "fftug.finc"
1194 :
1195 : #undef FFT_PRECISION
1196 :
1197 : #else
1198 : ! Silence compiler warning
1199 0 : ABI_ERROR("FFTW3 support not activated")
1200 : ABI_UNUSED((/fftalg,fftcache,npw_k,nx,ny,nz,ldx,ldy,ldz,ndat,istwf_k,mgfft,kg_k(1,1),gbound(1,1)/))
1201 : ABI_UNUSED((/ug(1),ur(1)/))
1202 : #endif
1203 :
1204 0 : end subroutine fftw3_fftug_dpc
1205 : !!***
1206 :
1207 : !----------------------------------------------------------------------
1208 :
1209 : !!****f* m_fftw3/fftw3_fftur_dp
1210 : !! NAME
1211 : !! fftw3_fftur_dp
1212 : !!
1213 : !! FUNCTION
1214 : !! Compute ndat zero-padded FFTs from R- to G-space .
1215 : !! Mainly used for the transform of wavefunctions.
1216 : !! TARGET: dp arrays
1217 : !!
1218 : !! INPUTS
1219 : !! fftalg=FFT algorithm (see input variable)
1220 : !! fftcache=size of the cache (kB)
1221 : !! npw_k=number of plane waves for this k-point.
1222 : !! nx,ny,nz=Number of point along the three directions.
1223 : !! ldx,ldy,ldz=Leading dimensions of the array.
1224 : !! ndat=Number of transforms
1225 : !! istwf_k=Option describing the storage of the wavefunction.
1226 : !! mgfft=Max number of FFT divisions (used to dimension gbound)
1227 : !! kg_k(3,npw_k)=G-vectors in reduced coordinates
1228 : !! gbound(2*mgfft+8,2)=Table for padded-FFT. See sphereboundary.
1229 : !!
1230 : !! SIDE EFFECT
1231 : !! ur(ldx*ldy*ldz*ndat)= In input: wavefunctions in real space.
1232 : !! Destroyed in output. Do not use it anymore!
1233 : !! OUTPUT
1234 : !! ug(npw_k*ndat)=wavefunctions in reciprocal space.
1235 : !!
1236 : !! SOURCE
1237 :
1238 0 : subroutine fftw3_fftur_dp(fftalg, fftcache, npw_k, nx, ny, nz, ldx, ldy, ldz, ndat, &
1239 0 : istwf_k, mgfft, kg_k, gbound, ur, ug, &
1240 : isign, iscale) ! optional
1241 :
1242 : !Arguments ------------------------------------
1243 : !scalars
1244 : integer,intent(in) :: fftalg,fftcache
1245 : integer,intent(in) :: npw_k,nx,ny,nz,ldx,ldy,ldz,ndat,istwf_k,mgfft
1246 : integer,optional,intent(in) :: isign, iscale
1247 : !arrays
1248 : integer,intent(in) :: gbound(2*mgfft+8,2),kg_k(3,npw_k)
1249 : real(dp),target,intent(inout) :: ur(2*ldx*ldy*ldz*ndat)
1250 : real(dp),target,intent(inout) :: ug(2*npw_k*ndat)
1251 :
1252 : #ifdef HAVE_FFTW3
1253 : !Local variables-------------------------------
1254 : !scalars
1255 : integer,parameter :: dist=2
1256 : integer :: iscale__, isign__
1257 : !arrays
1258 : real(dp) :: dum_ugin(2,0)
1259 : real(dp),contiguous, pointer :: real_ug(:,:),real_ur(:,:)
1260 : ! *************************************************************************
1261 :
1262 : iscale__ = 1; if (present(iscale)) iscale__ = iscale
1263 : isign__ = -1; if (present(isign)) isign__ = isign
1264 :
1265 : #undef TK_PREF
1266 : #define TK_PREF(name) CONCAT(cg_,name)
1267 : #undef TK_PREF_box2gsph
1268 : #define TK_PREF_box2gsph cg_box2gsph
1269 : #undef TK_PREF_gsph2box
1270 : #define TK_PREF_gsph2box cg_gsph2box
1271 :
1272 : #undef FFT_PRECISION
1273 : #define FFT_PRECISION FFT_DOUBLE
1274 :
1275 : #include "fftur.finc"
1276 :
1277 : #undef FFT_PRECISION
1278 :
1279 : #else
1280 : ! Silence compiler warning
1281 0 : ABI_ERROR("FFTW3 support not activated")
1282 : ABI_UNUSED((/fftalg,fftcache/))
1283 : ABI_UNUSED((/npw_k,nx,ny,nz,ldx,ldy,ldz,ndat,istwf_k,mgfft,kg_k(1,1),gbound(1,1)/))
1284 : ABI_UNUSED((/ug(1),ur(1)/))
1285 : #endif
1286 :
1287 0 : end subroutine fftw3_fftur_dp
1288 : !!***
1289 :
1290 : !----------------------------------------------------------------------
1291 :
1292 : !!****f* m_fftw3/fftw3_fftur_spc
1293 : !! NAME
1294 : !! fftw3_fftur_spc
1295 : !!
1296 : !! FUNCTION
1297 : !! Compute ndat zero-padded FFTs from R- to G-space .
1298 : !! Mainly used for the transform of wavefunctions.
1299 : !! TARGET: spc arrays
1300 : !! See fftw3_fftur_dp for API doc.
1301 : !!
1302 : !! SOURCE
1303 :
1304 0 : subroutine fftw3_fftur_spc(fftalg, fftcache, npw_k, nx, ny, nz, ldx, ldy, ldz, ndat, &
1305 0 : istwf_k, mgfft, kg_k, gbound, ur, ug, &
1306 : isign, iscale) ! optional
1307 :
1308 : !Arguments ------------------------------------
1309 : !scalars
1310 : integer,intent(in) :: fftalg,fftcache
1311 : integer,intent(in) :: npw_k,nx,ny,nz,ldx,ldy,ldz,ndat,istwf_k,mgfft
1312 : integer,optional,intent(in) :: isign, iscale
1313 : !arrays
1314 : integer,intent(in) :: gbound(2*mgfft+8,2),kg_k(3,npw_k)
1315 : complex(sp),target,intent(inout) :: ur(ldx*ldy*ldz*ndat)
1316 : complex(sp),target,intent(inout) :: ug(npw_k*ndat)
1317 :
1318 : #ifdef HAVE_FFTW3
1319 : !Local variables-------------------------------
1320 : !scalars
1321 : integer,parameter :: dist=1
1322 : integer :: iscale__, isign__
1323 : !arrays
1324 : real(sp) :: dum_ugin(2,0)
1325 : real(sp),contiguous, pointer :: real_ug(:,:),real_ur(:,:)
1326 : ! *************************************************************************
1327 :
1328 : iscale__ = 1; if (present(iscale)) iscale__ = iscale
1329 : isign__ = -1; if (present(isign)) isign__ = isign
1330 :
1331 : #undef TK_PREF
1332 : #define TK_PREF(name) CONCAT(cplx_,name)
1333 : #undef TK_PREF_box2gsph
1334 : #define TK_PREF_box2gsph cplx_box2gsph
1335 : #undef TK_PREF_gsph2box
1336 : #define TK_PREF_gsph2box cplx_gsph2box
1337 :
1338 : #undef FFT_PRECISION
1339 : #define FFT_PRECISION FFT_SINGLE
1340 :
1341 : #include "fftur.finc"
1342 :
1343 : #undef FFT_PRECISION
1344 :
1345 : #else
1346 : ! Silence compiler warning
1347 0 : ABI_ERROR("FFTW3 support not activated")
1348 : ABI_UNUSED((/fftalg,fftcache/))
1349 : ABI_UNUSED((/npw_k,nx,ny,nz,ldx,ldy,ldz,ndat,istwf_k,mgfft,kg_k(1,1),gbound(1,1)/))
1350 : ABI_UNUSED((/ug(1),ur(1)/))
1351 : #endif
1352 :
1353 0 : end subroutine fftw3_fftur_spc
1354 : !!***
1355 :
1356 : !----------------------------------------------------------------------
1357 :
1358 : !!****f* m_fftw3/fftw3_fftur_dpc
1359 : !! NAME
1360 : !! fftw3_fftur_dpc
1361 : !!
1362 : !! FUNCTION
1363 : !! Compute ndat zero-padded FFTs from R ro G.
1364 : !! Mainly used for the transform of wavefunctions.
1365 : !! TARGET: DP arrays
1366 : !! See fftw3_fftur_dp for API doc.
1367 : !!
1368 : !! SOURCE
1369 :
1370 0 : subroutine fftw3_fftur_dpc(fftalg, fftcache, npw_k, nx, ny, nz, ldx, ldy, ldz, ndat, &
1371 0 : istwf_k, mgfft, kg_k, gbound, ur, ug, &
1372 : isign, iscale) ! optional
1373 :
1374 : !Arguments ------------------------------------
1375 : !scalars
1376 : integer,intent(in) :: fftalg,fftcache
1377 : integer,intent(in) :: npw_k,nx,ny,nz,ldx,ldy,ldz,ndat,istwf_k,mgfft
1378 : integer,optional,intent(in) :: isign, iscale
1379 : !arrays
1380 : integer,intent(in) :: gbound(2*mgfft+8,2),kg_k(3,npw_k)
1381 : complex(dp),target,intent(inout) :: ur(ldx*ldy*ldz*ndat)
1382 : complex(dp),target,intent(inout) :: ug(npw_k*ndat)
1383 :
1384 : #ifdef HAVE_FFTW3
1385 : !Local variables-------------------------------
1386 : !scalars
1387 : integer,parameter :: dist=1
1388 : integer :: iscale__, isign__
1389 : !arrays
1390 : real(dp) :: dum_ugin(2,0)
1391 : real(dp),contiguous, pointer :: real_ug(:,:),real_ur(:,:)
1392 : ! *************************************************************************
1393 :
1394 : iscale__ = 1; if (present(iscale)) iscale__ = iscale
1395 : isign__ = -1; if (present(isign)) isign__ = isign
1396 :
1397 : #undef TK_PREF
1398 : #define TK_PREF(name) CONCAT(cplx_,name)
1399 : #undef TK_PREF_box2gsph
1400 : #define TK_PREF_box2gsph cplx_box2gsph
1401 : #undef TK_PREF_gsph2box
1402 : #define TK_PREF_gsph2box cplx_gsph2box
1403 :
1404 : #undef FFT_PRECISION
1405 : #define FFT_PRECISION FFT_DOUBLE
1406 :
1407 : #include "fftur.finc"
1408 :
1409 : #undef FFT_PRECISION
1410 :
1411 : #else
1412 : ! Silence compiler warning
1413 0 : ABI_ERROR("FFTW3 support not activated")
1414 : ABI_UNUSED((/fftalg,fftcache/))
1415 : ABI_UNUSED((/npw_k,nx,ny,nz,ldx,ldy,ldz,ndat,istwf_k,mgfft,kg_k(1,1),gbound(1,1)/))
1416 : ABI_UNUSED((/ug(1),ur(1)/))
1417 : #endif
1418 :
1419 0 : end subroutine fftw3_fftur_dpc
1420 : !!***
1421 :
1422 : !----------------------------------------------------------------------
1423 :
1424 : !!****f* m_fftw3/fftw3_c2c_ip_spc
1425 : !! NAME
1426 : !! fftw3_c2c_ip_spc
1427 : !!
1428 : !! FUNCTION
1429 : !! Driver routine for in-place 3D complex-complex FFT.
1430 : !! TARGET: Simple precision complex arrays.
1431 : !!
1432 : !! INPUTS
1433 : !! nx,ny,nz=Number of points along the three directions.
1434 : !! ldx,ldy,ldz=Physical dimensions of the array.
1435 : !! ndat=Number of FFTs to be done.
1436 : !! iscale=0 if G --> R FFT should not be scaled.
1437 : !! isign= +1 : ff(G) => ff(R); -1 : ff(R) => ff(G)
1438 : !! [fftw_flags]=Flags used to create the plan. They can be combined with the "+" operator.
1439 : !! Defaults to ABI_FFTW_ESTIMATE.
1440 : !!
1441 : !! SIDE EFFECTS
1442 : !! ff(ldx*ldy*ldz*ndat)=
1443 : !! In input: the complex array to be transformed.
1444 : !! In output: the Fourier transformed in the space specified by isign.
1445 : !!
1446 : !! SOURCE
1447 :
1448 0 : subroutine fftw3_c2c_ip_spc(nx, ny, nz, ldx, ldy, ldz, ndat, iscale, isign, ff, fftw_flags)
1449 :
1450 : !Arguments ------------------------------------
1451 : !scalars
1452 : integer,intent(in) :: nx,ny,nz,ldx,ldy,ldz,ndat,iscale,isign
1453 : integer,optional,intent(in) :: fftw_flags
1454 : !arrays
1455 : complex(sp),intent(inout) :: ff(ldx*ldy*ldz*ndat)
1456 :
1457 : #ifdef HAVE_FFTW3
1458 : !Local variables-------------------------------
1459 : !scalars
1460 : integer,parameter :: rank3=3,nt_all=-1
1461 : integer :: my_flags,dist,stride
1462 : integer(KIND_FFTW_PLAN) :: my_plan
1463 : !arrays
1464 : integer :: embed(rank3),n(rank3)
1465 : ! *************************************************************************
1466 :
1467 : my_flags=ABI_FFTW_ESTIMATE; if (PRESENT(fftw_flags)) my_flags=fftw_flags
1468 :
1469 : stride = 1
1470 : dist = ldx*ldy*ldz
1471 : embed = [ldx, ldy, ldz]
1472 : n = [nx, ny, nz]
1473 :
1474 : my_plan = fftw3_plan_many_dft(rank3, n, ndat, ff, embed, stride, dist, ff, embed, stride, dist, isign, my_flags, nt_all)
1475 :
1476 : ! Now perform the 3D FFT via FFTW.
1477 : call sfftw_execute_dft(my_plan, ff, ff)
1478 :
1479 : call fftw3_destroy_plan(my_plan)
1480 :
1481 : if (isign == ABI_FFTW_FORWARD .and. iscale /= 0) then ! -1, FFTW returns not normalized FTs
1482 : call xscal(ldx*ldy*ldz*ndat, REAL(one/(nx*ny*nz),KIND=sp), ff, 1)
1483 : end if
1484 :
1485 : #else
1486 0 : ABI_ERROR("FFTW3 support not activated")
1487 : ABI_UNUSED((/nx,ny,nz,ldx,ldy,ldz,isign/))
1488 : ABI_UNUSED(ff)
1489 : if (PRESENT(fftw_flags)) then
1490 : ABI_UNUSED(fftw_flags)
1491 : end if
1492 : #endif
1493 :
1494 0 : end subroutine fftw3_c2c_ip_spc
1495 : !!***
1496 :
1497 : !----------------------------------------------------------------------
1498 :
1499 : !!****f* m_fftw3/fftw3_fftpad_spc
1500 : !! NAME
1501 : !! fftw3_fftpad_spc
1502 : !!
1503 : !! FUNCTION
1504 : !! This routine transforms wavefunctions using 3D zero-padded FFTs with FFTW3.
1505 : !! The 3D ffts are computed only on lines and planes which have non zero elements.
1506 : !! These lines and planes are defined by the two vectors do_fft_x(ldy*nz) and do_fft_y(nz)
1507 : !! FFT transform is in-place. Target: complex arrays.
1508 : !!
1509 : !! INPUTS
1510 : !! nx,ny,nz=Logical dimensions of the FFT mesh.
1511 : !! ldx,ldy,ldz=Physical dimension of the f array (to avoid cache conflicts).
1512 : !! ndat=Number of FFT transforms.
1513 : !! mgfft=MAX(nx,ny,nz), only used to dimension gbound.
1514 : !! isign=The sign of the transform.
1515 : !! gbound(2*mgfft+8,2)= The boundaries of the basis sphere of G vectors at a given k-point.
1516 : !! See sphereboundary for more info.
1517 : !!
1518 : !! SIDE EFFECTS
1519 : !! ff(ldx*ldy*ldz*ndat)=
1520 : !! input: The array with the data to be transformed.
1521 : !! output: The results of the FFT.
1522 : !!
1523 : !! SOURCE
1524 :
1525 0 : subroutine fftw3_fftpad_spc(ff, nx, ny, nz, ldx, ldy, ldz, ndat, mgfft, isign, gbound, iscale)
1526 :
1527 : !Arguments ------------------------------------
1528 : !scalars
1529 : integer,intent(in) :: nx,ny,nz,ldx,ldy,ldz,ndat,mgfft,isign
1530 : !arrays
1531 : integer,intent(in) :: gbound(2*mgfft+8,2)
1532 : complex(sp),intent(inout) :: ff(ldx*ldy*ldz*ndat)
1533 : integer,optional,intent(in) :: iscale
1534 :
1535 : #ifdef HAVE_FFTW3
1536 : !Local variables-------------------------------
1537 : integer,parameter :: dst=1
1538 : integer :: iscale__
1539 : real(sp) :: fact
1540 : ! *************************************************************************
1541 :
1542 : iscale__ = merge(1, 0, isign == -1); if (present(iscale)) iscale__ = iscale
1543 :
1544 : #include "fftw3_fftpad.finc"
1545 :
1546 : #else
1547 0 : ABI_ERROR("FFTW3 support not activated")
1548 : ABI_UNUSED((/nx,ny,nz,ldx,ldy,ldz,ndat,mgfft,isign/))
1549 : ABI_UNUSED(gbound(1,1))
1550 : ABI_UNUSED(ff(1))
1551 : #endif
1552 :
1553 0 : end subroutine fftw3_fftpad_spc
1554 : !!***
1555 :
1556 : !----------------------------------------------------------------------
1557 :
1558 : !!****f* m_fftw3/fftw3_c2c_ip_dpc
1559 : !! NAME
1560 : !! fftw3_c2c_ip_dpc
1561 : !!
1562 : !! FUNCTION
1563 : !! Driver routine for in-place 3D complex-complex FFT.
1564 : !!
1565 : !! INPUTS
1566 : !! nx,ny,nz=Number of points along the three directions.
1567 : !! ldx,ldy,ldz=Physical dimensions of the array.
1568 : !! ndat=Number of FFTs to be done.
1569 : !! iscale=0 if G --> R FFT should not be scaled.
1570 : !! isign= +1 : ff(G) => ff(R); -1 : ff(R) => ff(G)
1571 : !! [fftw_flags]=Flags used to create the plan. They can be combined with the "+" operator.
1572 : !! Defaults to ABI_FFTW_ESTIMATE.
1573 : !!
1574 : !! SIDE EFFECTS
1575 : !! ff(ldx*ldy*ldz*ndat)=
1576 : !! In input: the complex array to be transformed.
1577 : !! In output: the Fourier transformed in the space specified by isign.
1578 : !!
1579 : !! SOURCE
1580 :
1581 0 : subroutine fftw3_c2c_ip_dpc(nx, ny, nz, ldx, ldy, ldz, ndat, iscale, isign, ff, fftw_flags)
1582 :
1583 : !Arguments ------------------------------------
1584 : !scalars
1585 : integer,intent(in) :: nx,ny,nz,ldx,ldy,ldz,ndat,iscale,isign
1586 : integer,optional,intent(in) :: fftw_flags
1587 : !arrays
1588 : complex(dp),intent(inout) :: ff(ldx*ldy*ldz*ndat)
1589 :
1590 : #ifdef HAVE_FFTW3
1591 : !Local variables-------------------------------
1592 : !scalars
1593 : integer,parameter :: rank3=3,nt_all=-1
1594 : integer :: my_flags,dist,stride
1595 : integer(KIND_FFTW_PLAN) :: my_plan
1596 : !arrays
1597 : integer :: embed(rank3),n(rank3)
1598 : ! *************************************************************************
1599 :
1600 : my_flags=ABI_FFTW_ESTIMATE; if (PRESENT(fftw_flags)) my_flags=fftw_flags
1601 :
1602 : stride = 1
1603 : dist = ldx*ldy*ldz
1604 : embed = [ldx, ldy, ldz]
1605 : n = [nx, ny, nz]
1606 :
1607 : my_plan = fftw3_plan_many_dft(rank3, n, ndat, ff, embed, stride, dist, ff, embed, stride, dist, isign, my_flags, nt_all)
1608 :
1609 : ! Now perform the 3D FFT via FFTW.
1610 : call dfftw_execute_dft(my_plan, ff, ff)
1611 :
1612 : call fftw3_destroy_plan(my_plan)
1613 :
1614 : ! -1, FFTW returns not normalized FTs
1615 : if (isign == ABI_FFTW_FORWARD .and. iscale /= 0) then
1616 : call ZDSCAL(ldx*ldy*ldz*ndat, one/(nx*ny*nz), ff, 1)
1617 : end if
1618 :
1619 : #else
1620 0 : ABI_ERROR("FFTW3 support not activated")
1621 : ABI_UNUSED((/nx,ny,nz,ldx,ldy,ldz,isign/))
1622 : ABI_UNUSED(ff)
1623 : if (PRESENT(fftw_flags)) then
1624 : ABI_UNUSED(fftw_flags)
1625 : end if
1626 : #endif
1627 :
1628 0 : end subroutine fftw3_c2c_ip_dpc
1629 : !!***
1630 :
1631 : !----------------------------------------------------------------------
1632 :
1633 : !!****f* m_fftw3/fftw3_c2c_op_spc
1634 : !! NAME
1635 : !! fftw3_c2c_op_spc
1636 : !!
1637 : !! FUNCTION
1638 : !! Driver routine for out-of-place 3D complex-complex FFT of lengths nx, ny, nz.
1639 : !! TARGET: single precision complex arrays
1640 : !!
1641 : !! INPUTS
1642 : !! nx,ny,nz=Number of points along the three directions.
1643 : !! ldx,ldy,ldz=Physical dimensions of the array.
1644 : !! ndat=Number of FFTs to be done.
1645 : !! iscale=0 if G --> R FFT should not be scaled.
1646 : !! isign= +1 : ff(G) => gg(R); -1 : ff(R) => gg(G)
1647 : !! ff(ldx*ldy*ldz*ndat)=The array to be transformed.
1648 : !! [fftw_flags]=Flags used to create the plan. They can be combined with the "+" operator.
1649 : !! Defaults to ABI_FFTW_ESTIMATE.
1650 : !!
1651 : !! OUTPUT
1652 : !! gg(ldx*ldy*ldz*ndat)=The FFT of ff.
1653 : !!
1654 : !! SOURCE
1655 :
1656 0 : subroutine fftw3_c2c_op_spc(nx, ny, nz, ldx, ldy, ldz, ndat, iscale, isign, ff, gg, fftw_flags)
1657 :
1658 : !Arguments ------------------------------------
1659 : !scalars
1660 : integer,intent(in) :: nx,ny,nz,ldx,ldy,ldz,iscale,isign,ndat
1661 : integer,optional,intent(in) :: fftw_flags
1662 : !arrays
1663 : complex(sp),intent(in) :: ff(ldx*ldy*ldz*ndat)
1664 : complex(sp),intent(out) :: gg(ldx*ldy*ldz*ndat)
1665 :
1666 : #ifdef HAVE_FFTW3
1667 : !Local variables-------------------------------
1668 : !scalars
1669 : integer,parameter :: rank3=3,nt_all=-1
1670 : integer :: my_flags,dist,stride
1671 : integer(KIND_FFTW_PLAN) :: my_plan
1672 : !arrays
1673 : integer :: embed(rank3),n(rank3)
1674 : ! *************************************************************************
1675 :
1676 : my_flags=ABI_FFTW_ESTIMATE; if (PRESENT(fftw_flags)) my_flags= fftw_flags
1677 :
1678 : stride = 1
1679 : dist = ldx*ldy*ldz
1680 : embed = [ldx, ldy, ldz]
1681 : n = [nx, ny, nz]
1682 :
1683 : my_plan = fftw3_plan_many_dft(rank3, n, ndat, ff, embed, stride, dist, gg, embed, stride, dist, isign, my_flags, nt_all)
1684 :
1685 : ! Now perform the 3D FFT via FFTW.
1686 : call sfftw_execute_dft(my_plan, ff, gg)
1687 :
1688 : call fftw3_destroy_plan(my_plan)
1689 :
1690 : if (isign == ABI_FFTW_FORWARD .and. iscale /= 0) then ! -1, FFTW returns not normalized FTs
1691 : call xscal(ldx*ldy*ldz*ndat, REAL(one/(nx*ny*nz), KIND=sp), gg, 1)
1692 : end if
1693 :
1694 : #else
1695 0 : ABI_ERROR("FFTW3 support not activated")
1696 : ABI_UNUSED((/nx,ny,nz,ldx,ldy,ldz,isign/))
1697 : ABI_UNUSED(ff)
1698 : ABI_UNUSED(gg)
1699 : if (PRESENT(fftw_flags)) then
1700 : ABI_UNUSED(fftw_flags)
1701 : end if
1702 : #endif
1703 :
1704 0 : end subroutine fftw3_c2c_op_spc
1705 : !!***
1706 :
1707 : !----------------------------------------------------------------------
1708 :
1709 : !!****f* m_fftw3/fftw3_c2c_op_dpc
1710 : !! NAME
1711 : !! fftw3_c2c_op_dpc
1712 : !!
1713 : !! FUNCTION
1714 : !! Driver routine for out-of-place 3D complex-complex FFT of lengths nx, ny, nz.
1715 : !! TARGET: single precision complex arrays
1716 : !!
1717 : !! INPUTS
1718 : !! nx,ny,nz=Number of points along the three directions.
1719 : !! ldx,ldy,ldz=Physical dimensions of the array.
1720 : !! ndat=Number of FFTs to be done.
1721 : !! iscale=0 if G --> R FFT should not be scaled.
1722 : !! isign= +1 : ff(G) => gg(R); -1 : ff(R) => gg(G)
1723 : !! ff(ldx*ldy*ldz*ndat)=The array to be transformed.
1724 : !! [fftw_flags]=Flags used to create the plan. They can be combined with the "+" operator.
1725 : !! Defaults to ABI_FFTW_ESTIMATE.
1726 : !!
1727 : !! OUTPUT
1728 : !! gg(ldx*ldy*ldz*ndat)=The FFT of ff.
1729 : !!
1730 : !! SOURCE
1731 :
1732 0 : subroutine fftw3_c2c_op_dpc(nx, ny, nz, ldx, ldy, ldz, ndat, iscale, isign, ff, gg, fftw_flags)
1733 :
1734 : !Arguments ------------------------------------
1735 : !scalars
1736 : integer,intent(in) :: nx,ny,nz,ldx,ldy,ldz,isign,ndat,iscale
1737 : integer,optional,intent(in) :: fftw_flags
1738 : !arrays
1739 : complex(dp),intent(in) :: ff(ldx*ldy*ldz*ndat)
1740 : complex(dp),intent(out) :: gg(ldx*ldy*ldz*ndat)
1741 :
1742 : #ifdef HAVE_FFTW3
1743 : !Local variables-------------------------------
1744 : !scalars
1745 : integer,parameter :: rank3=3,nt_all=-1
1746 : integer :: my_flags,dist,stride
1747 : integer(KIND_FFTW_PLAN) :: my_plan
1748 : !arrays
1749 : integer :: embed(rank3),n(rank3)
1750 : ! *************************************************************************
1751 :
1752 : my_flags=ABI_FFTW_ESTIMATE; if (PRESENT(fftw_flags)) my_flags= fftw_flags
1753 :
1754 : stride = 1
1755 : dist = ldx*ldy*ldz
1756 : embed = [ldx, ldy, ldz]
1757 : n = [nx, ny, nz]
1758 :
1759 : my_plan = fftw3_plan_many_dft(rank3, n, ndat, ff, embed, stride, dist, gg, embed, stride, dist, isign, my_flags, nt_all)
1760 :
1761 : ! Now perform the 3D FFT via FFTW.
1762 : call dfftw_execute_dft(my_plan, ff, gg)
1763 :
1764 : call fftw3_destroy_plan(my_plan)
1765 :
1766 : if (isign == ABI_FFTW_FORWARD .and. iscale /= 0) then ! -1, FFTW returns not normalized FTs
1767 : call xscal(ldx*ldy*ldz*ndat, one/(nx*ny*nz), gg, 1)
1768 : end if
1769 :
1770 : #else
1771 0 : ABI_ERROR("FFTW3 support not activated")
1772 : ABI_UNUSED((/nx,ny,nz,ldx,ldy,ldz,isign/))
1773 : ABI_UNUSED(ff)
1774 : ABI_UNUSED(gg)
1775 : if (PRESENT(fftw_flags)) then
1776 : ABI_UNUSED(fftw_flags)
1777 : end if
1778 : #endif
1779 :
1780 0 : end subroutine fftw3_c2c_op_dpc
1781 : !!***
1782 :
1783 : !----------------------------------------------------------------------
1784 :
1785 : !!****f* m_fftw3/fftw3_r2c_op
1786 : !! NAME
1787 : !! fftw3_r2c_op
1788 : !!
1789 : !! FUNCTION
1790 : !! Driver routine for out-of-place 3D real-to-complex FFT of lengths nx, ny, nz.
1791 : !!
1792 : !! INPUTS
1793 : !! nx,ny,nz=Number of points along the three directions.
1794 : !! ldx,ldy,ldz=Physical dimensions of the f array (to avoid cache conflicts).
1795 : !! ff(ldx*ldy*ldz*ndat)=The real array to be transformed.
1796 : !! ndat=Number of FFTs to be done.
1797 : !! [fftw_flags]=Flags used to create the plan. They can be combined with the "+" operator.
1798 : !! Defaults to ABI_FFTW_ESTIMATE.
1799 : !!
1800 : !! OUTPUT
1801 : !! gg(2,nx*ny*nz*ndat)=The forward FFT of ff.
1802 : !!
1803 : !! NOTES
1804 : !! FIXME For the time-being. No augmentation of the mesh to reduce memory conflicts, as MKL crashes
1805 : !! if the advanced interface is used.
1806 : !!
1807 : !! SOURCE
1808 :
1809 0 : subroutine fftw3_r2c_op(nx,ny,nz,ldx,ldy,ldz,ndat,ff,gg,fftw_flags)
1810 :
1811 : !Arguments ------------------------------------
1812 : !scalars
1813 : integer,intent(in) :: nx,ny,nz,ldx,ldy,ldz,ndat
1814 : integer,optional,intent(in) :: fftw_flags
1815 : !arrays
1816 : real(dp),intent(in) :: ff(ldx*ldy*ldz*ndat)
1817 : real(dp),intent(out) :: gg(2,ldx*ldy*ldz*ndat)
1818 :
1819 : #ifdef HAVE_FFTW3
1820 : !Local variables-------------------------------
1821 : !scalars
1822 : integer,parameter :: rank3=3,nt_all=-1
1823 : integer :: nhp,my_flags,idist,odist,padx,i1,i2,i3,igp,igf,imgf,stride
1824 : integer :: i1inv,i2inv,i3inv,idat,padatf
1825 : integer(KIND_FFTW_PLAN) :: my_plan
1826 : !arrays
1827 : integer :: inembed(rank3),onembed(rank3),n(rank3)
1828 : integer,allocatable :: i1inver(:),i2inver(:),i3inver(:)
1829 : real(dp),allocatable :: gg_hp(:,:)
1830 : ! *************************************************************************
1831 :
1832 : my_flags=ABI_FFTW_ESTIMATE; if (PRESENT(fftw_flags)) my_flags= fftw_flags
1833 :
1834 : idist = ldx*ldy*ldz
1835 : nhp = (nx/2+1)*ny*nz
1836 : odist = nhp
1837 :
1838 : stride = 1
1839 : n = (/nx,ny,nz/)
1840 : inembed= (/ldx,ldy,ldz/)
1841 : onembed= (/(nx/2+1),ny,nz/)
1842 :
1843 : ABI_MALLOC(gg_hp,(2,nhp*ndat))
1844 :
1845 : #ifdef DEV_RC_BUG
1846 : if (ndat/=1) ABI_ERROR("ndat/=1 + MKL not coded")
1847 :
1848 : if (ANY( n /= inembed )) then
1849 : ABI_ERROR("Augmentation not supported")
1850 : end if
1851 :
1852 : call dfftw_plan_dft_r2c_3d(my_plan, nx, ny, nz, ff, gg_hp, my_flags)
1853 : if (my_plan==NULL_PLAN) then
1854 : ABI_ERROR("dfftw_plan_dft_r2c_3d returned NULL_PLAN")
1855 : end if
1856 :
1857 : !fftw_plan fftw_plan_many_dft_r2c(int rank3, const int *n, int howmany,
1858 : ! double *in, const int *inembed, int istride, int idist,
1859 : ! fftw_complex *out, const int *onembed, int ostride, int odist, unsigned flags);
1860 : #else
1861 : my_plan = dplan_many_dft_r2c(rank3, n, ndat, ff, inembed, stride, idist, gg_hp, onembed, stride, odist, my_flags, nt_all)
1862 : #endif
1863 :
1864 : ! Now perform the 3D FFT via FFTW. r2c are always ABI_FFTW_FORWARD
1865 : call dfftw_execute_dft_r2c(my_plan, ff, gg_hp)
1866 :
1867 : call fftw3_destroy_plan(my_plan)
1868 :
1869 : ! FFTW returns not normalized FTs
1870 : call ZDSCAL(nhp*ndat, one/(nx*ny*nz), gg_hp, 1)
1871 :
1872 : ! Reconstruct full FFT: Hermitian redundancy: out[i] is the conjugate of out[n-i]
1873 : padx = (nx/2+1)
1874 : ABI_MALLOC(i1inver,(padx))
1875 : ABI_MALLOC(i2inver,(ny))
1876 : ABI_MALLOC(i3inver,(nz))
1877 :
1878 : i1inver(1)=1
1879 : do i1=2,padx
1880 : i1inver(i1)=nx+2-i1
1881 : end do
1882 :
1883 : i2inver(1)=1
1884 : do i2=2,ny
1885 : i2inver(i2)=ny+2-i2
1886 : end do
1887 :
1888 : i3inver(1)=1
1889 : do i3=2,nz
1890 : i3inver(i3)=nz+2-i3
1891 : end do
1892 :
1893 : igp=0
1894 : do idat=1,ndat
1895 : padatf = (idat-1)*ldx*ldy*ldz
1896 : do i3=1,nz
1897 : i3inv = i3inver(i3)
1898 : do i2=1,ny
1899 : i2inv = i2inver(i2)
1900 : do i1=1,padx
1901 : igp = igp+1
1902 : igf = i1 + (i3-1)*ldx*ldy + (i2-1)*ldx + padatf
1903 : gg(:,igf) = gg_hp(:,igp)
1904 : i1inv = i1inver(i1)
1905 : if (i1inv/=i1) then
1906 : imgf = i1inv + (i3inv-1)*ldx*ldy + (i2inv-1)*ldx + padatf
1907 : gg(1,imgf) = gg_hp(1,igp)
1908 : gg(2,imgf) = -gg_hp(2,igp)
1909 : end if
1910 : end do
1911 : end do
1912 : end do
1913 : end do
1914 :
1915 : ABI_FREE(i1inver)
1916 : ABI_FREE(i2inver)
1917 : ABI_FREE(i3inver)
1918 : ABI_FREE(gg_hp)
1919 :
1920 : #else
1921 0 : ABI_ERROR("FFTW3 support not activated")
1922 : ABI_UNUSED((/nx,ny,nz,ldx,ldy,ldz/))
1923 : ABI_UNUSED(ff)
1924 : ABI_UNUSED(gg(1,1))
1925 : if (PRESENT(fftw_flags)) then
1926 : ABI_UNUSED(fftw_flags)
1927 : end if
1928 : #endif
1929 :
1930 0 : end subroutine fftw3_r2c_op
1931 : !!***
1932 :
1933 : !----------------------------------------------------------------------
1934 :
1935 : !!****f* m_fftw3/fftw3_c2r_op
1936 : !! NAME
1937 : !! fftw3_c2r_op
1938 : !!
1939 : !! FUNCTION
1940 : !! Driver routine for out-of-place 3D complex-to-real FFT of lengths nx, ny, nz.
1941 : !!
1942 : !! INPUTS
1943 : !! nx,ny,nz=Number of point along the three directions.
1944 : !! ldx,ldy,ldz=Physical dimension of the f array (to avoid cache conflicts).
1945 : !! ndat=Number of FFTs to be done.
1946 : !! ff(2*ldx*ldy*ldz*ndat)=The complex array to be transformed.
1947 : !! [fftw_flags]=Flags used to create the plan. They can be combined with the "+" operator.
1948 : !! Defaults to ABI_FFTW_ESTIMATE.
1949 : !!
1950 : !! OUTPUT
1951 : !! gg(ldx*ldy*ldz*ndat)=The backwards real FFT of ff.
1952 : !!
1953 : !! NOTES
1954 : !! FIXME For the time-being. No augmentation of the mesh to reduce memory conflicts, as MKL crashes
1955 : !! if the advanced interface is used.
1956 : !!
1957 : !! SOURCE
1958 :
1959 0 : subroutine fftw3_c2r_op(nx,ny,nz,ldx,ldy,ldz,ndat,ff,gg,fftw_flags)
1960 :
1961 : !Arguments ------------------------------------
1962 : !scalars
1963 : integer,intent(in) :: nx,ny,nz,ldx,ldy,ldz,ndat
1964 : integer,optional,intent(in) :: fftw_flags
1965 : !arrays
1966 : real(dp),intent(in) :: ff(2,ldx*ldy*ldz*ndat)
1967 : real(dp),intent(out) :: gg(ldx*ldy*ldz*ndat)
1968 :
1969 : #ifdef HAVE_FFTW3
1970 : !Local variables-------------------------------
1971 : !scalars
1972 : integer,parameter :: rank3=3,nt_all=-1
1973 : integer :: nhp,my_flags,padx,i2,i3,igp,igf,idat,padatf,padatp,idist,odist,stride
1974 : integer(KIND_FFTW_PLAN) :: my_plan
1975 : !arrays
1976 : integer :: inembed(rank3),onembed(rank3),n(rank3)
1977 : real(dp),allocatable :: ff_hp(:,:)
1978 : ! *************************************************************************
1979 :
1980 : #ifdef DEV_RC_BUG
1981 : if (ANY( (/nx,ny,nz/) /= (/ldx,ldy,ldz/) )) then
1982 : ABI_ERROR("Augmentation not supported")
1983 : end if
1984 : #endif
1985 :
1986 : my_flags=ABI_FFTW_ESTIMATE; if (PRESENT(fftw_flags)) my_flags= fftw_flags
1987 :
1988 : stride = 1
1989 : nhp = (nx/2+1)*ny*nz
1990 : idist = nhp
1991 : odist = ldx*ldy*ldz
1992 : n = (/nx,ny,nz/)
1993 : inembed = (/(nx/2+1),ny,nz/)
1994 : onembed = (/ldx,ldy,ldz/)
1995 :
1996 : ! Fill the Hermitian part: Hermitian redundancy: out[i] is the conjugate of out[n-i]
1997 : ABI_MALLOC(ff_hp,(2,nhp*ndat))
1998 :
1999 : padx = (nx/2+1)
2000 : do idat=1,ndat
2001 : padatf=(idat-1)*ldx*ldy*ldz
2002 : padatp=(idat-1)*padx*ny*nz
2003 : !$OMP PARALLEL DO PRIVATE(igf,igp)
2004 : do i3=1,nz
2005 : do i2=1,ny
2006 : igf = (i3-1)*ldx*ldy + (i2-1)*ldx + padatf
2007 : igp = (i3-1)*padx*ny + (i2-1)*padx + padatp
2008 : ff_hp(:,igp+1:igp+padx) = ff(:,igf+1:igf+padx)
2009 : end do
2010 : end do
2011 : end do
2012 :
2013 : ! NOTE: The c2r transform destroys its input array even for out-of-place transforms.
2014 : #ifdef DEV_RC_BUG
2015 : if (ndat/=1) ABI_ERROR("ndat/=1 + MKL not coded")
2016 : call dfftw_plan_dft_c2r_3d(my_plan, nx, ny, nz, ff_hp, gg, my_flags)
2017 : if (my_plan==NULL_PLAN) then
2018 : ABI_ERROR("dfftw_plan_dft_c2r_3d returned NULL_PLAN")
2019 : end if
2020 : #else
2021 : my_plan = dplan_many_dft_c2r(rank3, n, ndat, ff_hp, inembed, stride, idist, gg, onembed, stride, odist, my_flags, nt_all)
2022 : #endif
2023 :
2024 : ! Now perform the 3D FFT via FFTW. c2r are always ABI_FFTW_BACKWARD
2025 : call dfftw_execute_dft_c2r(my_plan, ff_hp, gg)
2026 :
2027 : call fftw3_destroy_plan(my_plan)
2028 : ABI_FREE(ff_hp)
2029 :
2030 : #else
2031 0 : ABI_ERROR("FFTW3 support not activated")
2032 : ABI_UNUSED((/nx,ny,nz,ldx,ldy,ldz/))
2033 : ABI_UNUSED(ff(1,1))
2034 : ABI_UNUSED(gg(1))
2035 : if (PRESENT(fftw_flags)) then
2036 : ABI_UNUSED(fftw_flags)
2037 : end if
2038 : #endif
2039 :
2040 0 : end subroutine fftw3_c2r_op
2041 : !!***
2042 :
2043 : !----------------------------------------------------------------------
2044 :
2045 : !!****f* m_fftw3/fftw3_many_dft_op
2046 : !! NAME
2047 : !! fftw3_many_dft_op
2048 : !!
2049 : !! FUNCTION
2050 : !! Driver routine for many out-of-place 3D complex-to-complex FFTs of lengths nx, ny, nz.
2051 : !!
2052 : !! INPUTS
2053 : !! nx,ny,nz=Number of points along the three directions.
2054 : !! ldx,ldy,ldz=Physical dimension of the fin and fout arrays (to avoid cache conflicts).
2055 : !! ndat=Number of FFTs to be done.
2056 : !! fin(2*ldx*ldy*ldz*ndat)=The complex array to be transformed.
2057 : !! isign=sign of Fourier transform exponent: current convention uses
2058 : !! +1 for transforming from G to r,
2059 : !! -1 for transforming from r to G.
2060 : !! [fftw_flags]=Flags used to create the plan. They can be combined with the "+" operator.
2061 : !! Defaults to ABI_FFTW_ESTIMATE.
2062 : !!
2063 : !! OUTPUT
2064 : !! fout(2,ldx*ldy*ldz*ndat)=The Fourier transform of fin.
2065 : !!
2066 : !! SOURCE
2067 :
2068 0 : subroutine fftw3_many_dft_op(nx,ny,nz,ldx,ldy,ldz,ndat,isign,fin,fout,fftw_flags)
2069 :
2070 : !Arguments ------------------------------------
2071 : !scalars
2072 : integer,intent(in) :: nx,ny,nz,ldx,ldy,ldz,ndat,isign
2073 : integer,optional,intent(in) :: fftw_flags
2074 : !arrays
2075 : real(dp),intent(in) :: fin(2*ldx*ldy*ldz*ndat)
2076 : real(dp),intent(out) :: fout(2*ldx*ldy*ldz*ndat)
2077 :
2078 : #ifdef HAVE_FFTW3
2079 : !Local variables-------------------------------
2080 : !scalars
2081 : integer,parameter :: rank3=3,nt_all=-1
2082 : integer :: my_flags,dist,stride
2083 : integer(KIND_FFTW_PLAN) :: my_plan
2084 : !arrays
2085 : integer :: embed(rank3),n(rank3)
2086 : ! *************************************************************************
2087 :
2088 : my_flags=ABI_FFTW_ESTIMATE; if (PRESENT(fftw_flags)) my_flags= fftw_flags
2089 :
2090 : stride = 1
2091 : dist = ldx*ldy*ldz
2092 : embed = [ldx, ldy, ldz]
2093 : n = [nx, ny, nz]
2094 :
2095 : my_plan = fftw3_plan_many_dft(rank3, n, ndat, fin, embed, stride, dist, fout, embed, stride, dist, isign, my_flags, nt_all)
2096 :
2097 : ! Now perform the 3D FFT via FFTW.
2098 : call dfftw_execute_dft(my_plan, fin, fout)
2099 :
2100 : call fftw3_destroy_plan(my_plan)
2101 :
2102 : ! -1, FFTW returns not normalized FTs
2103 : if (isign == ABI_FFTW_FORWARD) then
2104 : call ZDSCAL(ldx*ldy*ldz*ndat, one/(nx*ny*nz), fout, 1)
2105 : end if
2106 :
2107 : #else
2108 0 : ABI_ERROR("FFTW3 support not activated")
2109 : ABI_UNUSED((/nx,ny,nz,ldx,ldy,ldz,ndat,isign/))
2110 : if (PRESENT(fftw_flags)) then
2111 : ABI_UNUSED(fftw_flags)
2112 : end if
2113 : ABI_UNUSED(fin(1))
2114 : ABI_UNUSED(fout(1))
2115 : #endif
2116 :
2117 0 : end subroutine fftw3_many_dft_op
2118 : !!***
2119 :
2120 : !----------------------------------------------------------------------
2121 :
2122 : !!****f* m_fftw3/fftw3_many_dft_ip
2123 : !! NAME
2124 : !! fftw3_many_dft_ip
2125 : !!
2126 : !! FUNCTION
2127 : !! Driver routine for many in-place 3D complex-to-complex FFTs of lengths nx, ny, nz.
2128 : !!
2129 : !! INPUTS
2130 : !! nx,ny,nz=Number of points along the three directions.
2131 : !! ldx,ldy,ldz=Physical dimension of the finout array (to avoid cache conflicts).
2132 : !! ndat=Number of FFTs to be done.
2133 : !! isign=sign of Fourier transform exponent: current convention uses
2134 : !! +1 for transforming from G to r,
2135 : !! -1 for transforming from r to G.
2136 : !! [fftw_flags]=Flags used to create the plan. They can be combined with the "+" operator.
2137 : !! Defaults to ABI_FFTW_ESTIMATE.
2138 : !!
2139 : !! OUTPUT
2140 : !! finout(2,ldx*ldy*ldz*ndat)=
2141 : !! In input: The complex array to be transformed.
2142 : !! In output: The FFT results.
2143 : !!
2144 : !! SOURCE
2145 :
2146 0 : subroutine fftw3_many_dft_ip(nx,ny,nz,ldx,ldy,ldz,ndat,isign,finout,fftw_flags)
2147 :
2148 : !Arguments ------------------------------------
2149 : !scalars
2150 : integer,intent(in) :: nx,ny,nz,ldx,ldy,ldz,ndat,isign
2151 : integer,optional,intent(in) :: fftw_flags
2152 : !arrays
2153 : real(dp),intent(inout) :: finout(2*ldx*ldy*ldz*ndat)
2154 :
2155 : #ifdef HAVE_FFTW3
2156 : !Local variables-------------------------------
2157 : !scalars
2158 : integer,parameter :: rank3=3,nt_all=-1
2159 : integer :: my_flags,dist,stride
2160 : integer(KIND_FFTW_PLAN) :: my_plan
2161 : !arrays
2162 : integer :: embed(rank3),n(rank3)
2163 : ! *************************************************************************
2164 :
2165 : my_flags=ABI_FFTW_ESTIMATE; if (PRESENT(fftw_flags)) my_flags= fftw_flags
2166 :
2167 : stride = 1
2168 : dist = ldx*ldy*ldz
2169 : embed = [ldx, ldy, ldz]
2170 : n = [nx, ny, nz]
2171 :
2172 : my_plan = fftw3_plan_many_dft(rank3, n, ndat, finout, embed, stride, dist, finout, embed, stride, dist, isign, my_flags, nt_all)
2173 :
2174 : ! Now perform the 3D FFT via FFTW.
2175 : call dfftw_execute_dft(my_plan, finout, finout)
2176 : call fftw3_destroy_plan(my_plan)
2177 :
2178 : ! -1, FFTW returns not normalized FTs
2179 : if (isign == ABI_FFTW_FORWARD) then
2180 : call ZDSCAL(ldx*ldy*ldz*ndat, one/(nx*ny*nz), finout, 1)
2181 : end if
2182 :
2183 : #else
2184 0 : ABI_ERROR("FFTW3 support not activated")
2185 : ABI_UNUSED((/nx,ny,nz,ldx,ldy,ldz,ndat,isign/))
2186 : if (PRESENT(fftw_flags)) then
2187 : ABI_UNUSED(fftw_flags)
2188 : end if
2189 : ABI_UNUSED(finout(1))
2190 : #endif
2191 :
2192 0 : end subroutine fftw3_many_dft_ip
2193 : !!***
2194 :
2195 : !----------------------------------------------------------------------
2196 :
2197 : !!****f* m_fftw3/fftw3_cleanup
2198 : !! NAME
2199 : !! fftw3_cleanup
2200 : !!
2201 : !! FUNCTION
2202 : !! Reset FFTW to the pristine state it was in when you started your program,
2203 : !! All existing plans become undefined.
2204 : !!
2205 : !! NOTES
2206 : !! FFTW planner saves some other persistent data, such as the accumulated wisdom and a list of
2207 : !! algorithms available in the current configuration. If you want to deallocate all of that and reset
2208 : !! FFTW to the pristine state it was in when you started your program, you can call fftw3_cleanup();
2209 : !! After calling fftw3_cleanup, all existing plans become undefined, and you should not attempt to
2210 : !! execute them nor to destroy them. You can however create and execute/destroy new plans, in which case
2211 : !! FFTW starts accumulating wisdom information again.
2212 : !! fftw3_cleanup does not deallocate your plans, however. To prevent memory leaks, you must still call
2213 : !! fftw_destroy_plan before executing fftw3_cleanup
2214 : !!
2215 : !! SOURCE
2216 :
2217 0 : subroutine fftw3_cleanup()
2218 :
2219 : #ifdef HAVE_FFTW3_MPI
2220 : call fftw_mpi_cleanup()
2221 : #endif
2222 : #ifdef HAVE_FFTW3_THREADS
2223 : if (THREADS_INITED==1) then
2224 : call dfftw_cleanup_threads()
2225 : THREADS_INITED = 0
2226 : end if
2227 : #elif defined HAVE_FFTW3
2228 : call dfftw_cleanup()
2229 : #else
2230 0 : ABI_ERROR("FFTW3 support not activated")
2231 : #endif
2232 :
2233 0 : end subroutine fftw3_cleanup
2234 : !!***
2235 :
2236 : !----------------------------------------------------------------------
2237 :
2238 : !!****f* m_fftw3/fftw3_destroy_plan
2239 : !! NAME
2240 : !! fftw3_destroy_plan
2241 : !!
2242 : !! FUNCTION
2243 : !! Release the memory allocate for the plan.
2244 : !!
2245 : !! INPUTS
2246 : !!
2247 : !! SOURCE
2248 :
2249 : subroutine fftw3_destroy_plan(plan)
2250 :
2251 : !Arguments ------------------------------------
2252 : !scalars
2253 : integer(KIND_FFTW_PLAN),intent(in) :: plan
2254 : ! *************************************************************************
2255 :
2256 : #ifdef HAVE_FFTW3
2257 : !$OMP CRITICAL (OMPC_fftw3_destroy_plan)
2258 : call dfftw_destroy_plan(plan)
2259 : !$OMP END CRITICAL (OMPC_fftw3_destroy_plan)
2260 :
2261 : #else
2262 : if (.FALSE.) write(std_out,*)plan
2263 : #endif
2264 :
2265 : end subroutine fftw3_destroy_plan
2266 : !!***
2267 :
2268 : !----------------------------------------------------------------------
2269 :
2270 : !!****f* m_fftw3/fftw3_init_threads
2271 : !! NAME
2272 : !! fftw3_init_threads
2273 : !!
2274 : !! FUNCTION
2275 : !! This function performs the one-time initialization required to use FFTW3 threads.
2276 : !! It does nothing if HAVE_FFT_FFTW3_THREADS is not defined.
2277 : !!
2278 : !! INPUTS
2279 : !!
2280 : !! SIDE EFFECTS
2281 : !! The one-time initialization required to use FFTW3 threads is performed when the routine
2282 : !! is called for the first time.
2283 : !!
2284 : !! SOURCE
2285 :
2286 0 : subroutine fftw3_init_threads()
2287 :
2288 : !Local variables ------------------------------
2289 : !scalars
2290 : #ifdef HAVE_FFTW3_THREADS
2291 : integer :: iret
2292 : #endif
2293 : ! *************************************************************************
2294 :
2295 : #ifdef HAVE_FFTW3_THREADS
2296 : if (THREADS_INITED==0) then
2297 : !call wrtout(std_out,"Calling dfftw_init_threads()")
2298 : call dfftw_init_threads(iret)
2299 :
2300 : if (iret==0) then
2301 : ABI_WARNING(" dfftw_init_threads returned 0; threaded FFTW3 is not being used!")
2302 : else
2303 : THREADS_INITED=1
2304 : end if
2305 : call fftw3_set_nthreads()
2306 : end if
2307 :
2308 : #ifndef HAVE_OPENMP
2309 : ABI_WARNING("Using FFTW3 with threads but HAVE_OPENMP is not defined!")
2310 : #endif
2311 : #endif
2312 :
2313 : #ifdef HAVE_FFTW3_MPI
2314 : !call wrtout(std_out,"Calling fftw_mpi_init()")
2315 : call fftw_mpi_init()
2316 : #endif
2317 :
2318 0 : end subroutine fftw3_init_threads
2319 : !!***
2320 :
2321 : !----------------------------------------------------------------------
2322 :
2323 : !!****f* m_fftw3/fftw3_set_nthreads
2324 : !! NAME
2325 : !! fftw3_set_nthreads
2326 : !!
2327 : !! FUNCTION
2328 : !! This function sets the number of threads you want FFTW3 to use (or actually, the maximum number).
2329 : !! It also performs any one-time initialization required to use FFTW3 threads.
2330 : !! All plans subsequently created with any planner routine will use nthreads threads.
2331 : !! If you pass an nthreads argument of 1 (the default), threads are disabled for subsequent plans.
2332 : !! It does nothing if HAVE_FFT_FFTW3_THREADS is not defined.
2333 : !!
2334 : !! INPUTS
2335 : !! [nthreads]=The number of threads you want FFTW3 to use. Default xomp_get_max_threads()
2336 : !!
2337 : !! SOURCE
2338 :
2339 0 : subroutine fftw3_set_nthreads(nthreads)
2340 :
2341 : !Arguments ------------------------------------
2342 : integer,optional,intent(in) :: nthreads
2343 :
2344 : !Local variables ------------------------------
2345 : !scalars
2346 : #ifdef HAVE_FFTW3_THREADS
2347 : integer :: istat,nt
2348 : integer,parameter :: enough=1
2349 : integer,save :: nwarns=0
2350 : #endif
2351 : ! *************************************************************************
2352 :
2353 : #ifdef HAVE_FFTW3_THREADS
2354 : if (THREADS_INITED==0) then
2355 : ABI_WARNING("Threads are not initialized")
2356 : end if
2357 :
2358 : if (PRESENT(nthreads)) then
2359 : if (nthreads<=0) then
2360 : nt = xomp_get_max_threads()
2361 : else
2362 : nt = nthreads
2363 : end if
2364 : else
2365 : nt = xomp_get_max_threads()
2366 : end if
2367 :
2368 : call dfftw_plan_with_nthreads(nt)
2369 :
2370 : #ifndef HAVE_OPENMP
2371 : if (nwarns <= enough) then
2372 : nwarns = nwarns + 1
2373 : ABI_WARNING("Using FFTW3 with threads but HAVE_OPENMP is not defined!")
2374 : end if
2375 : #endif
2376 :
2377 : #else
2378 : if (PRESENT(nthreads)) then
2379 : ABI_UNUSED(nthreads)
2380 : end if
2381 : #endif
2382 :
2383 0 : end subroutine fftw3_set_nthreads
2384 : !!***
2385 :
2386 : !----------------------------------------------------------------------
2387 :
2388 : !!****f* m_fftw3/fftw3_fftpad_dp
2389 : !! NAME
2390 : !! fftw3_fftpad_dp
2391 : !!
2392 : !! FUNCTION
2393 : !! This routine transforms wavefunctions using 3D zero-padded FFTs with FFTW3.
2394 : !! The 3D ffts are computed only on lines and planes which have non zero elements.
2395 : !! These lines and planes are defined by the two vectors do_fft_x(ldy*nz) and do_fft_y(nz)
2396 : !! FFT transform is in-place.
2397 : !!
2398 : !! INPUTS
2399 : !! nx,ny,nz=Logical dimensions of the FFT mesh.
2400 : !! ldx,ldy,ldz=Physical dimension of the f array (to avoid cache conflicts).
2401 : !! ndat=Number of FFT transforms.
2402 : !! mgfft=MAX(nx,ny,nz), only used to dimension gbound
2403 : !! isign=The sign of the transform.
2404 : !! gbound(2*mgfft+8,2)= The boundaries of the basis sphere of G vectors at a given k-point.
2405 : !! See sphereboundary for more info.
2406 : !!
2407 : !! SIDE EFFECTS
2408 : !! ff(2*ldx*ldy*ldz*ndat)=
2409 : !! input: The array with the data to be transformed.
2410 : !! output: The results of the FFT.
2411 : !!
2412 : !! SOURCE
2413 :
2414 0 : subroutine fftw3_fftpad_dp(ff, nx, ny, nz, ldx, ldy, ldz, ndat, mgfft, isign, gbound, iscale)
2415 :
2416 : !Arguments ------------------------------------
2417 : !scalars
2418 : integer,intent(in) :: nx,ny,nz,ldx,ldy,ldz,ndat,mgfft,isign
2419 : !arrays
2420 : integer,intent(in) :: gbound(2*mgfft+8,2)
2421 : real(dp),intent(inout) :: ff(2*ldx*ldy*ldz*ndat)
2422 : integer,optional,intent(in) :: iscale
2423 :
2424 : !Local variables-------------------------------
2425 : !scalars
2426 : #ifdef HAVE_FFTW3
2427 : integer,parameter :: dst=2
2428 : integer :: iscale__
2429 : real(dp) :: fact
2430 : ! *************************************************************************
2431 :
2432 : iscale__ = merge(1, 0, isign == -1); if (present(iscale)) iscale__ = iscale
2433 :
2434 : #include "fftw3_fftpad.finc"
2435 :
2436 : #else
2437 0 : ABI_ERROR("FFTW3 support not activated")
2438 : ABI_UNUSED((/nx,ny,nz,ldx,ldy,ldz,mgfft,isign/))
2439 : ABI_UNUSED(gbound(1,1))
2440 : ABI_UNUSED(ff(1))
2441 : #endif
2442 :
2443 0 : end subroutine fftw3_fftpad_dp
2444 : !!***
2445 :
2446 : !----------------------------------------------------------------------
2447 :
2448 : !!****f* m_fftw3/fftw3_fftpad_dpc
2449 : !! NAME
2450 : !! fftw3_fftpad_dpc
2451 : !!
2452 : !! FUNCTION
2453 : !! This routine transforms wavefunctions using 3D zero-padded FFTs with FFTW3.
2454 : !! The 3D ffts are computed only on lines and planes which have non zero elements.
2455 : !! These lines and planes are defined by the two vectors do_fft_x(ldy*nz) and do_fft_y(nz)
2456 : !! FFT transform is in-place. Target: complex arrays.
2457 : !!
2458 : !! INPUTS
2459 : !! nx,ny,nz=Logical dimensions of the FFT mesh.
2460 : !! ldx,ldy,ldz=Physical dimension of the f array (to avoid cache conflicts).
2461 : !! ndat=Number of FFT transforms.
2462 : !! mgfft=MAX(nx,ny,nz), only used to dimension gbound.
2463 : !! isign=The sign of the transform.
2464 : !! gbound(2*mgfft+8,2)= The boundaries of the basis sphere of G vectors at a given k-point.
2465 : !! See sphereboundary for more info.
2466 : !!
2467 : !! SIDE EFFECTS
2468 : !! ff(ldx*ldy*ldz*ndat)=
2469 : !! input: The array with the data to be transformed.
2470 : !! output: The results of the FFT.
2471 : !!
2472 : !! SOURCE
2473 :
2474 0 : subroutine fftw3_fftpad_dpc(ff, nx, ny, nz, ldx, ldy, ldz, ndat, mgfft, isign, gbound, iscale)
2475 :
2476 : !Arguments ------------------------------------
2477 : !scalars
2478 : integer,intent(in) :: nx,ny,nz,ldx,ldy,ldz,ndat,mgfft,isign
2479 : integer,optional,intent(in) :: iscale
2480 : !arrays
2481 : integer,intent(in) :: gbound(2*mgfft+8,2)
2482 : complex(dp),intent(inout) :: ff(ldx*ldy*ldz*ndat)
2483 :
2484 : #ifdef HAVE_FFTW3
2485 : !Local variables-------------------------------
2486 : integer,parameter :: dst=1
2487 : integer :: iscale__
2488 : real(dp) :: fact
2489 : ! *************************************************************************
2490 :
2491 : iscale__ = merge(1, 0, isign == -1); if (present(iscale)) iscale__ = iscale
2492 :
2493 : #include "fftw3_fftpad.finc"
2494 :
2495 : #else
2496 0 : ABI_ERROR("FFTW3 support not activated")
2497 : ABI_UNUSED((/nx,ny,nz,ldx,ldy,ldz,ndat,mgfft,isign/))
2498 : ABI_UNUSED(gbound(1,1))
2499 : ABI_UNUSED(ff(1))
2500 : #endif
2501 :
2502 0 : end subroutine fftw3_fftpad_dpc
2503 : !!***
2504 :
2505 : #ifdef HAVE_FFTW3
2506 :
2507 : !----------------------------------------------------------------------
2508 :
2509 : !!****f* m_fftw3/dplan_many_dft_1D
2510 : !! NAME
2511 : !!
2512 : !! FUNCTION
2513 : !!
2514 : !! INPUTS
2515 : !!
2516 : !! SIDE EFFECTS
2517 : !!
2518 : !! SOURCE
2519 :
2520 : function dplan_many_dft_1D(rank,n,howmany,fin,inembed,istride,idist,fout,onembed,ostride,odist,sign,flags,nthreads) result(plan)
2521 :
2522 : !Arguments ------------------------------------
2523 : !scalars
2524 : integer,intent(in) :: rank,howmany,istride,ostride, sign,flags,idist,odist,nthreads
2525 : integer,intent(in) :: n(rank),inembed(rank),onembed(rank)
2526 : integer(KIND_FFTW_PLAN) :: plan
2527 : !arrays
2528 : real(dp) :: fin(*),fout(*)
2529 :
2530 : !Local variables-------------------------------
2531 : character(len=500) :: msg,frmt
2532 : ! *************************************************************************
2533 :
2534 : !$OMP CRITICAL (OMPC_dfftw_plan_many_dft_1D)
2535 : call fftw3_set_nthreads(nthreads)
2536 :
2537 : call dfftw_plan_many_dft(plan, rank, n, howmany, &
2538 : fin, inembed, istride, idist, fout, onembed, ostride, odist, sign, flags)
2539 : !$OMP END CRITICAL (OMPC_dfftw_plan_many_dft_1D)
2540 :
2541 : if (plan==NULL_PLAN) then
2542 : call wrtout(std_out, "dfftw_plan_many_dft returned NULL_PLAN!")
2543 : write(frmt,*)"(a,",rank,"(1x,i0),3(a,i0),a,2(a,",rank,"(1x,i0),2(a,i0),a))"
2544 : write(msg,frmt)&
2545 : " n= ",n," howmany= ",howmany," sign= ",sign," flags= ",flags,ch10,&
2546 : " inembed= ",inembed," istride= ",istride," idist=",idist,ch10, &
2547 : " onembed= ",onembed," ostride= ",ostride," odist=",idist,ch10
2548 : call wrtout(std_out, msg)
2549 : ABI_ERROR("Check FFTW library and/or abinit code")
2550 : end if
2551 :
2552 : end function dplan_many_dft_1D
2553 : !!***
2554 :
2555 : !----------------------------------------------------------------------
2556 :
2557 : !!****f* m_fftw3/dplan_many_dft_2D
2558 : !! NAME
2559 : !!
2560 : !! FUNCTION
2561 : !!
2562 : !! INPUTS
2563 : !!
2564 : !! SOURCE
2565 :
2566 : function dplan_many_dft_2D(rank,n,howmany,fin,inembed,istride,idist,fout,onembed,ostride,odist,sign,flags,nthreads) result(plan)
2567 :
2568 : !Arguments ------------------------------------
2569 : !scalars
2570 : integer,intent(in) :: rank,howmany,istride,ostride, sign,flags,idist,odist,nthreads
2571 : integer,intent(in) :: n(rank),inembed(rank),onembed(rank)
2572 : integer(KIND_FFTW_PLAN) :: plan
2573 : !arrays
2574 : real(dp) :: fin(2,*),fout(2,*)
2575 :
2576 : !Local variables-------------------------------
2577 : character(len=500) :: msg,frmt
2578 : ! *************************************************************************
2579 :
2580 : !$OMP CRITICAL (OMPC_dfftw_plan_many_dft_2D)
2581 : call fftw3_set_nthreads(nthreads)
2582 :
2583 : call dfftw_plan_many_dft(plan, rank, n, howmany, &
2584 : fin, inembed, istride, idist, fout, onembed, ostride, odist, sign, flags)
2585 : !$OMP END CRITICAL (OMPC_dfftw_plan_many_dft_2D)
2586 :
2587 : if (plan==NULL_PLAN) then
2588 : call wrtout(std_out, "dfftw_plan_many_dft returned NULL_PLAN!")
2589 : write(frmt,*)"(a,",rank,"(1x,i0),3(a,i0),a,2(a,",rank,"(1x,i0),2(a,i0),a))"
2590 : write(msg,frmt)&
2591 : " n= ",n," howmany= ",howmany," sign= ",sign," flags= ",flags,ch10,&
2592 : " inembed= ",inembed," istride= ",istride," idist=",idist,ch10, &
2593 : " onembed= ",onembed," ostride= ",ostride," odist=",idist,ch10
2594 : call wrtout(std_out, msg)
2595 : ABI_ERROR("Check FFTW library and/or abinit code")
2596 : end if
2597 :
2598 : end function dplan_many_dft_2D
2599 : !!***
2600 :
2601 : !----------------------------------------------------------------------
2602 :
2603 : !!****f* m_fftw3/cplan_many_dft
2604 : !! NAME
2605 : !!
2606 : !! FUNCTION
2607 : !!
2608 : !! INPUTS
2609 : !!
2610 : !! SIDE EFFECTS
2611 : !!
2612 : !! SOURCE
2613 : !! FIXME technically it should be intent(inout) since FFTW3 can destroy the input for particular flags.
2614 :
2615 : function cplan_many_dft(rank,n,howmany,fin,inembed,istride,idist,fout,onembed,ostride,odist,sign,flags,nthreads) result(plan)
2616 :
2617 : !Arguments ------------------------------------
2618 : !scalars
2619 : integer,intent(in) :: rank,howmany,istride,ostride, sign,flags,idist,odist,nthreads
2620 : integer,intent(in) :: n(rank),inembed(rank),onembed(rank)
2621 : integer(KIND_FFTW_PLAN) :: plan
2622 : !arrays
2623 : complex(sp) :: fin(*),fout(*)
2624 :
2625 : !Local variables-------------------------------
2626 : character(len=500) :: msg,frmt
2627 : ! *************************************************************************
2628 :
2629 : !$OMP CRITICAL (OMPC_cplan_many_dft)
2630 : call fftw3_set_nthreads(nthreads)
2631 :
2632 : call sfftw_plan_many_dft(plan, rank, n, howmany, &
2633 : fin, inembed, istride, idist, fout, onembed, ostride, odist, sign, flags)
2634 : !$OMP END CRITICAL (OMPC_cplan_many_dft)
2635 :
2636 : if (plan==NULL_PLAN) then ! handle the error
2637 : call wrtout(std_out, "sfftw_plan_many_dft returned NULL_PLAN (complex version)")
2638 : write(frmt,*)"(a,",rank,"(1x,i0),3(a,i0),a,2(a,",rank,"(1x,i0),2(a,i0),a))"
2639 : write(msg,frmt)&
2640 : " n = ",n," howmany = ",howmany," sign = ",sign," flags = ",flags,ch10,&
2641 : " inembed = ",inembed," istride = ",istride," idist =",idist,ch10, &
2642 : " onembed = ",onembed," ostride = ",ostride," odist =",idist,ch10
2643 : call wrtout(std_out, msg)
2644 : ABI_ERROR("Check FFTW library and/or abinit code")
2645 : end if
2646 :
2647 : end function cplan_many_dft
2648 : !!***
2649 :
2650 : !----------------------------------------------------------------------
2651 :
2652 : !!****f* m_fftw3/zplan_many_dft
2653 : !! NAME
2654 : !!
2655 : !! FUNCTION
2656 : !!
2657 : !! INPUTS
2658 : !!
2659 : !! SIDE EFFECTS
2660 : !!
2661 : !! SOURCE
2662 : !! FIXME technically it should be intent(inout) since FFTW3 can destroy the input for particular flags.
2663 :
2664 : function zplan_many_dft(rank,n,howmany,fin,inembed,istride,idist,fout,onembed,ostride,odist,sign,flags,nthreads) result(plan)
2665 :
2666 : !Arguments ------------------------------------
2667 : !scalars
2668 : integer,intent(in) :: rank,howmany,istride,ostride, sign,flags,idist,odist,nthreads
2669 : integer,intent(in) :: n(rank),inembed(rank),onembed(rank)
2670 : integer(KIND_FFTW_PLAN) :: plan
2671 : !arrays
2672 : complex(dp) :: fin(*),fout(*)
2673 :
2674 : !Local variables-------------------------------
2675 : character(len=500) :: msg,frmt
2676 : ! *************************************************************************
2677 :
2678 : !$OMP CRITICAL (OMPC_zplan_many_dft)
2679 : call fftw3_set_nthreads(nthreads)
2680 :
2681 : call dfftw_plan_many_dft(plan, rank, n, howmany, &
2682 : fin, inembed, istride, idist, fout, onembed, ostride, odist, sign, flags)
2683 : !$OMP END CRITICAL (OMPC_zplan_many_dft)
2684 :
2685 : if (plan==NULL_PLAN) then ! handle the error
2686 : call wrtout(std_out, "dfftw_plan_many_dft returned NULL_PLAN (complex version)")
2687 : write(frmt,*)"(a,",rank,"(1x,i0),3(a,i0),a,2(a,",rank,"(1x,i0),2(a,i0),a))"
2688 : write(msg,frmt)&
2689 : " n = ",n," howmany = ",howmany," sign = ",sign," flags = ",flags,ch10,&
2690 : " inembed = ",inembed," istride = ",istride," idist =",idist,ch10, &
2691 : " onembed = ",onembed," ostride = ",ostride," odist =",idist,ch10
2692 : call wrtout(std_out, msg)
2693 : ABI_ERROR("Check FFTW library and/or abinit code")
2694 : end if
2695 :
2696 : end function zplan_many_dft
2697 : !!***
2698 :
2699 : !----------------------------------------------------------------------
2700 :
2701 : !!****f* m_fftw3/dplan_many_dft_r2c
2702 : !! NAME
2703 : !!
2704 : !! FUNCTION
2705 : !!
2706 : !! INPUTS
2707 : !!
2708 : !! SIDE EFFECTS
2709 : !!
2710 : !! SOURCE
2711 : !! FIXME technically it should be intent(inout) since FFTW3 can destroy the input
2712 : !! for particular flags.
2713 :
2714 : function dplan_many_dft_r2c(rank,n,howmany,fin,inembed,istride,idist,fout,onembed,ostride,odist,flags,nthreads) result(plan)
2715 :
2716 : !Arguments ------------------------------------
2717 : !scalars
2718 : integer,intent(in) :: rank,howmany,istride,ostride,flags,idist,odist,nthreads
2719 : integer,intent(in) :: n(rank),inembed(rank),onembed(rank)
2720 : integer(KIND_FFTW_PLAN) :: plan
2721 : !arrays
2722 : real(dp) :: fin(*),fout(*)
2723 :
2724 : !Local variables-------------------------------
2725 : character(len=500) :: msg,frmt
2726 : ! *************************************************************************
2727 :
2728 : !$OMP CRITICAL (OMPC_dplan_many_dft_r2c)
2729 : call fftw3_set_nthreads(nthreads)
2730 :
2731 : call dfftw_plan_many_dft_r2c(plan, rank, n, howmany, &
2732 : fin, inembed, istride, idist, fout, onembed, ostride, odist, flags)
2733 : !$OMP END CRITICAL (OMPC_dplan_many_dft_r2c)
2734 :
2735 : if (plan==NULL_PLAN) then ! handle the error.
2736 : call wrtout(std_out, "dfftw_plan_many_dft_r2c returned NULL_PLAN")
2737 : write(frmt,*)"(a,",rank,"(1x,i0),2(a,i0),a,2(a,",rank,"(1x,i0),2(a,i0),a))"
2738 : write(msg,frmt)&
2739 : " n = ",n," howmany = ",howmany," flags = ",flags,ch10,&
2740 : " inembed = ",inembed," istride = ",istride," idist = ",idist,ch10,&
2741 : " onembed = ",onembed," ostride = ",ostride," odist = ",idist,ch10
2742 : call wrtout(std_out, msg)
2743 : ABI_ERROR("Check FFTW library and/or abinit code")
2744 : end if
2745 :
2746 : end function dplan_many_dft_r2c
2747 : !!***
2748 :
2749 : !----------------------------------------------------------------------
2750 :
2751 : !!****f* m_fftw3/dplan_many_dft_c2r
2752 : !! NAME
2753 : !!
2754 : !! FUNCTION
2755 : !!
2756 : !! INPUTS
2757 : !!
2758 : !! SIDE EFFECTS
2759 : !!
2760 : !! SOURCE
2761 :
2762 : function dplan_many_dft_c2r(rank,n,howmany,fin,inembed,istride,idist,fout,onembed,ostride,odist,flags, nthreads) result(plan)
2763 :
2764 : !Arguments ------------------------------------
2765 : !scalars
2766 : integer,intent(in) :: rank,howmany,istride,ostride,flags,idist,odist,nthreads
2767 : integer,intent(in) :: n(rank),inembed(rank),onembed(rank)
2768 : integer(KIND_FFTW_PLAN) :: plan
2769 : !arrays
2770 : real(dp) :: fin(*),fout(*)
2771 :
2772 : !Local variables-------------------------------
2773 : character(len=500) :: msg,frmt
2774 : ! *************************************************************************
2775 :
2776 : !$OMP CRITICAL (OMPC_dplan_many_dft_c2r)
2777 : call fftw3_set_nthreads(nthreads)
2778 :
2779 : call dfftw_plan_many_dft_c2r(plan, rank, n, howmany, &
2780 : fin, inembed, istride, idist, fout, onembed, ostride, odist, flags)
2781 : !$OMP END CRITICAL (OMPC_dplan_many_dft_c2r)
2782 :
2783 : if (plan==NULL_PLAN) then ! handle the error.
2784 : call wrtout(std_out, "dfftw_plan_many_dft_c2r returned NULL_PLAN")
2785 : write(frmt,*)"(a,",rank,"(1x,i0),2(a,i0),a,2(a,",rank,"(1x,i0),2(a,i0),a))"
2786 : write(msg,frmt)&
2787 : " n = ",n," howmany = ",howmany," flags = ",flags,ch10,&
2788 : " inembed = ",inembed," istride = ",istride," idist = ",idist,ch10,&
2789 : " onembed = ",onembed," ostride = ",ostride," odist = ",idist,ch10
2790 : call wrtout(std_out, msg)
2791 : ABI_ERROR("Check FFTW library and/or abinit code")
2792 : end if
2793 :
2794 : end function dplan_many_dft_c2r
2795 : !!***
2796 :
2797 : #endif
2798 :
2799 : !----------------------------------------------------------------------
2800 :
2801 : !!****f* m_fftw3/fftw3_execute_dft_dp
2802 : !! NAME
2803 : !! fftw3_execute_dft_dp
2804 : !!
2805 : !! FUNCTION
2806 : !!
2807 : !! INPUTS
2808 : !!
2809 : !! OUTPUT
2810 : !!
2811 : !! NOTES
2812 : !! This interface is used to perform complex to complex FFT with real arrays
2813 : !! containing the real and imaginary part. I have to admit that this interface
2814 : !! is a bit ambiguous since FFTW3 provides routines for real-to-real transforms.
2815 : !!
2816 : !! SOURCE
2817 :
2818 : #ifdef HAVE_FFTW3
2819 :
2820 : subroutine fftw3_execute_dft_dp(plan, in, out)
2821 :
2822 : !Arguments ------------------------------------
2823 : !scalars
2824 : integer(KIND_FFTW_PLAN),intent(in) :: plan
2825 : real(C_DOUBLE),intent(inout) :: in(*)
2826 : real(C_DOUBLE),intent(out) :: out(*)
2827 : ! *************************************************************************
2828 :
2829 : call dfftw_execute_dft(plan, in, out)
2830 :
2831 : end subroutine fftw3_execute_dft_dp
2832 : !!***
2833 :
2834 : #endif
2835 :
2836 : !----------------------------------------------------------------------
2837 :
2838 : !!****f* m_fftw3/fftw3_execute_dft_spc
2839 : !! NAME
2840 : !! fftw3_execute_dft_spc
2841 : !!
2842 : !! SOURCE
2843 :
2844 : #ifdef HAVE_FFTW3
2845 :
2846 : subroutine fftw3_execute_dft_spc(plan, in, out)
2847 :
2848 : !Arguments ------------------------------------
2849 : !scalars
2850 : integer(KIND_FFTW_PLAN),intent(in) :: plan
2851 : complex(C_FLOAT_COMPLEX),intent(inout) :: in(*)
2852 : complex(C_FLOAT_COMPLEX),intent(out) :: out(*)
2853 : ! *************************************************************************
2854 :
2855 : call sfftw_execute_dft(plan, in, out)
2856 :
2857 : end subroutine fftw3_execute_dft_spc
2858 : !!***
2859 :
2860 : #endif
2861 :
2862 : !----------------------------------------------------------------------
2863 :
2864 : !!****f* m_fftw3/fftw3_execute_dft_dpc
2865 : !! NAME
2866 : !! fftw3_execute_dft_dpc
2867 : !!
2868 : !! SOURCE
2869 :
2870 : #ifdef HAVE_FFTW3
2871 :
2872 : subroutine fftw3_execute_dft_dpc(plan, in, out)
2873 :
2874 : !Arguments ------------------------------------
2875 : !scalars
2876 : integer(KIND_FFTW_PLAN),intent(in) :: plan
2877 : complex(C_DOUBLE_COMPLEX),intent(inout) :: in(*)
2878 : complex(C_DOUBLE_COMPLEX),intent(out) :: out(*)
2879 : ! *************************************************************************
2880 :
2881 : call dfftw_execute_dft(plan, in, out)
2882 :
2883 : end subroutine fftw3_execute_dft_dpc
2884 : !!***
2885 :
2886 : #endif
2887 :
2888 : !----------------------------------------------------------------------
2889 :
2890 : !!****f* m_fftw3/fftw3_alloc_real1d_dp
2891 : !! NAME
2892 : !! fftw3_alloc_real1d_dp
2893 : !!
2894 : !! FUNCTION
2895 : !!
2896 : !! SOURCE
2897 :
2898 : #ifdef HAVE_FFTW3
2899 :
2900 : subroutine fftw3_alloc_real1d_dp(size,cptr,fptr)
2901 :
2902 : !Arguments ------------------------------------
2903 : !scalars
2904 : integer,intent(in) :: size
2905 : real(dp),contiguous, pointer :: fptr(:)
2906 : type(C_PTR),intent(out) :: cptr
2907 : ! *************************************************************************
2908 :
2909 : cptr = fftw_malloc( INT(size*C_DOUBLE, KIND=C_SIZE_T))
2910 : if (.not. C_ASSOCIATED(cptr)) then
2911 : ABI_ERROR("fftw_malloc returned NULL!")
2912 : end if
2913 :
2914 : call c_f_pointer(cptr, fptr, [size])
2915 :
2916 : end subroutine fftw3_alloc_real1d_dp
2917 : !!***
2918 :
2919 : #endif
2920 :
2921 : !----------------------------------------------------------------------
2922 :
2923 : !!****f* m_fftw3/fftw3_alloc_real2d_dp
2924 : !! NAME
2925 : !! fftw3_alloc_real2d_dp
2926 : !!
2927 : !! SOURCE
2928 :
2929 : #ifdef HAVE_FFTW3
2930 :
2931 : subroutine fftw3_alloc_real2d_dp(shape,cptr,fptr)
2932 :
2933 : !Arguments ------------------------------------
2934 : !scalars
2935 : integer,intent(in) :: shape(2)
2936 : real(dp),contiguous, pointer :: fptr(:,:)
2937 : type(C_PTR),intent(out) :: cptr
2938 : ! *************************************************************************
2939 :
2940 : cptr = fftw_malloc( INT(product(shape)*C_DOUBLE, KIND=C_SIZE_T))
2941 : if (.not. C_ASSOCIATED(cptr)) then
2942 : ABI_ERROR("fftw_malloc returned NULL!")
2943 : end if
2944 :
2945 : call c_f_pointer(cptr, fptr, shape)
2946 :
2947 : end subroutine fftw3_alloc_real2d_dp
2948 : !!***
2949 :
2950 : #endif
2951 :
2952 : !----------------------------------------------------------------------
2953 :
2954 : !!****f* m_fftw3/fftw3_alloc_complex1d_spc
2955 : !! NAME
2956 : !! fftw3_alloc_complex1d_spc
2957 : !!
2958 : !! SOURCE
2959 :
2960 : #ifdef HAVE_FFTW3
2961 :
2962 : subroutine fftw3_alloc_complex1d_spc(size,cptr,fptr)
2963 :
2964 : !Arguments ------------------------------------
2965 : !scalars
2966 : integer,intent(in) :: size
2967 : complex(sp),contiguous, pointer :: fptr(:)
2968 : type(C_PTR),intent(out) :: cptr
2969 : ! *************************************************************************
2970 :
2971 : cptr = fftw_malloc( INT(2*size*C_FLOAT, KIND=C_SIZE_T))
2972 : if (.not. C_ASSOCIATED(cptr)) then
2973 : ABI_ERROR("fftw_malloc returned NULL!")
2974 : end if
2975 :
2976 : call c_f_pointer(cptr, fptr, [size])
2977 :
2978 : end subroutine fftw3_alloc_complex1d_spc
2979 : !!***
2980 :
2981 : #endif
2982 :
2983 : !----------------------------------------------------------------------
2984 :
2985 : !!****f* m_fftw3/fftw3_alloc_complex1d_dpc
2986 : !! NAME
2987 : !! fftw3_alloc_complex1d_dpc
2988 : !!
2989 : !! SOURCE
2990 :
2991 : #ifdef HAVE_FFTW3
2992 :
2993 : subroutine fftw3_alloc_complex1d_dpc(size,cptr,fptr)
2994 :
2995 : !Arguments ------------------------------------
2996 : !scalars
2997 : integer,intent(in) :: size
2998 : complex(dp),contiguous, pointer :: fptr(:)
2999 : type(C_PTR),intent(out) :: cptr
3000 : ! *************************************************************************
3001 :
3002 : cptr = fftw_malloc( INT(2*size*C_DOUBLE, KIND=C_SIZE_T))
3003 : if (.not. C_ASSOCIATED(cptr)) then
3004 : ABI_ERROR("fftw_malloc returned NULL!")
3005 : end if
3006 :
3007 : call c_f_pointer(cptr, fptr, [size])
3008 :
3009 : end subroutine fftw3_alloc_complex1d_dpc
3010 : !!***
3011 :
3012 : #endif
3013 :
3014 : !----------------------------------------------------------------------
3015 :
3016 : !!****f* m_fftw3/fftw3_spawn_threads_here
3017 : !! NAME
3018 : !! fftw3_spawn_threads_here
3019 : !!
3020 : !! FUNCTION
3021 : !! Helper function that returns true if FFT calls should be OMP
3022 : !! parallelized in the client code.
3023 : !!
3024 : !! INPUTS
3025 : !! ndat=Number of FFT transforms to do
3026 : !! nthreads = Number of threads available
3027 : !!
3028 : !! SOURCE
3029 :
3030 0 : function fftw3_spawn_threads_here(ndat,nthreads) result(ans)
3031 :
3032 : !Arguments ------------------------------------
3033 : !scalars
3034 : integer,intent(in) :: ndat,nthreads
3035 : logical :: ans
3036 : ! *************************************************************************
3037 :
3038 0 : ans = .FALSE.
3039 : #ifdef HAVE_OPENMP
3040 : ans = (nthreads > 1 .and. MOD(ndat,nthreads) == 0 .and. .not. USE_LIB_THREADS)
3041 : #else
3042 : ABI_UNUSED((/ndat,nthreads/))
3043 : #endif
3044 :
3045 0 : end function fftw3_spawn_threads_here
3046 : !!***
3047 :
3048 : !----------------------------------------------------------------------
3049 :
3050 : !!****f* m_fftw3/fftw3_use_lib_threads
3051 : !! NAME
3052 : !! fftw3_use_lib_threads
3053 : !!
3054 : !! FUNCTION
3055 : !!
3056 : !! INPUTS
3057 : !!
3058 : !! SOURCE
3059 :
3060 19 : subroutine fftw3_use_lib_threads(logvar)
3061 :
3062 : !Arguments ------------------------------------
3063 : logical,intent(in) :: logvar
3064 : ! *************************************************************************
3065 :
3066 19 : USE_LIB_THREADS = logvar
3067 :
3068 19 : end subroutine fftw3_use_lib_threads
3069 : !!***
3070 :
3071 : !----------------------------------------------------------------------
3072 :
3073 : !!****f* m_fftw3/fftwmpi_get_work_array
3074 : !! NAME
3075 : !! fftwmpi_get_work_array
3076 : !!
3077 : !! FUNCTION
3078 : !! Driver routine for allocate fftw work array for 3D complex-to-complex FFTs of lengths nx, ny, nz.
3079 : !!
3080 : !! INPUTS
3081 : !! nx,ny,nz=Number of points along the three directions.
3082 : !! ndat=Number of FFTs to be done.
3083 : !! comm_fft=MPI communicator.
3084 : !!
3085 : !! OUTPUT
3086 : !! cdata_f,cdata_r: C pointers to use for fourier andreal data
3087 : !! n0,n0_tr : local size on the shared dimension (nz or ny if transposed mode is used)
3088 : !! offset,offset_tr : offset per process in continuous tabx
3089 : !!
3090 : !! SOURCE
3091 :
3092 : subroutine fftwmpi_get_work_array(cdata_f,cdata_r,rank,nx,ny,nz,ndat,comm_fft,n0,offset,n0_tr,offset_tr)
3093 :
3094 : !Arguments ------------------------------------
3095 : !scalars
3096 : integer,intent(in) :: nx,ny,nz,ndat,rank,comm_fft
3097 : integer(C_INTPTR_T), intent(out) :: n0, offset, n0_tr, offset_tr
3098 : type(C_PTR), intent(out) :: cdata_f,cdata_r
3099 :
3100 : !Local variables-------------------------------
3101 : #ifdef HAVE_FFTW3_MPI
3102 : !scalars
3103 : integer(C_INTPTR_T) :: alloc_local
3104 : !arrays
3105 : integer(C_INTPTR_T) :: fft_sizes(4)
3106 : ! *************************************************************************
3107 :
3108 : ! Dimensions are inverted here (C interface).
3109 : fft_sizes(1)=nz
3110 : fft_sizes(2)=ny
3111 : fft_sizes(3)=nx
3112 : fft_sizes(4)=ndat
3113 :
3114 : alloc_local = fftw_mpi_local_size_many_transposed(rank,fft_sizes(1:3),fft_sizes(4), &
3115 : & FFTW_MPI_DEFAULT_BLOCK,FFTW_MPI_DEFAULT_BLOCK, comm_fft, &
3116 : & n0,offset, &
3117 : & n0_tr,offset_tr)
3118 :
3119 : cdata_f = fftw_alloc_complex(alloc_local)
3120 : cdata_r = fftw_alloc_complex(alloc_local)
3121 :
3122 : #else
3123 : ABI_ERROR("FFTW3_MPI support not activated")
3124 : ABI_UNUSED((/nx,ny,nz,ndat,rank,comm_fft/))
3125 : cdata_f = C_NULL_PTR; cdata_r = C_NULL_PTR
3126 : n0 = 0; offset = 0; n0_tr = 0; offset_tr = 0
3127 : #endif
3128 :
3129 : end subroutine fftwmpi_get_work_array
3130 : !!***
3131 :
3132 : !----------------------------------------------------------------------
3133 :
3134 : !!****f* m_fftw3/fftwmpi_free_work_array
3135 : !! NAME
3136 : !! fftwmpi_free_work_array
3137 : !!
3138 : !! FUNCTION
3139 : !! routine for freeing fftw work array
3140 : !!
3141 : !! INPUTS
3142 : !!
3143 : !! OUTPUT
3144 : !! cdata_f,cdata_r: C pointers to free for fourier andreal data
3145 : !!
3146 : !! SOURCE
3147 :
3148 : subroutine fftwmpi_free_work_array(cdata_f,cdata_r)
3149 :
3150 : !Arguments ------------------------------------
3151 : !scalars
3152 : type(C_PTR), intent(inout) :: cdata_f,cdata_r
3153 : ! *************************************************************************
3154 :
3155 : #ifdef HAVE_FFTW3_MPI
3156 : call fftw_free(cdata_r)
3157 : call fftw_free(cdata_f)
3158 : #else
3159 : ABI_ERROR("FFTW3_MPI support not activated")
3160 : if(.false.) then
3161 : cdata_r = C_NULL_PTR; cdata_f = C_NULL_PTR
3162 : end if
3163 : #endif
3164 :
3165 : end subroutine fftwmpi_free_work_array
3166 : !!***
3167 :
3168 : !----------------------------------------------------------------------
3169 :
3170 : !!****f* m_fftw3/fftw3mpi_many_dft_ip
3171 : !! NAME
3172 : !! fftw3mpi_many_dft_ip
3173 : !!
3174 : !! FUNCTION
3175 : !! Driver routine for many out-of-place 3D complex-to-complex FFTs of lengths nx, ny, nz.
3176 : !!
3177 : !! INPUTS
3178 : !! nx,ny,nz=Number of points along the three directions.
3179 : !! ldx,ldy,ldz=Physical dimension of the fin and fout arrays (to avoid cache conflicts).
3180 : !! ndat=Number of FFTs to be done.
3181 : !! fin(2*ldx*ldy*ldz*ndat)=The complex array to be transformed.
3182 : !! isign=sign of Fourier transform exponent: current convention uses
3183 : !! +1 for transforming from G to r,
3184 : !! -1 for transforming from r to G.
3185 : !! comm_fft=MPI communicator for the FFT
3186 : !! [fftw_flags]=Flags used to create the plan. They can be combined with the "+" operator.
3187 : !! Defaults to ABI_FFTW_ESTIMATE.
3188 : !!
3189 : !! TODO
3190 : !! Remove me
3191 : !!
3192 : !! OUTPUT
3193 : !! fout(2,ldx*ldy*ldz*ndat)=The Fourier transform of fin.
3194 : !!
3195 : !! SOURCE
3196 :
3197 : subroutine fftw3mpi_many_dft_ip(nx,ny,nz,ldx,ldy,ldz,ndat,isign,fin,fout,comm_fft,fftw_flags)
3198 :
3199 : !Arguments ------------------------------------
3200 : !scalars
3201 : integer,intent(in) :: nx,ny,nz,ldx,ldy,ldz,ndat,isign,comm_fft
3202 : integer,optional,intent(in) :: fftw_flags
3203 : !arrays
3204 : real(dp),intent(in) :: fin(2,ldx,ldy,ldz*ndat)
3205 : real(dp),intent(out) :: fout(2,ldx,ldy,ldz*ndat)
3206 :
3207 : #ifdef HAVE_FFTW3_MPI
3208 : !Local variables-------------------------------
3209 : !scalars
3210 : integer,parameter :: rank3=3
3211 : integer :: my_flags
3212 : real(dp):: factor_fft
3213 : !arrays
3214 : type(C_PTR) :: plan, cdata
3215 : complex(C_DOUBLE_COMPLEX), contiguous, pointer :: data(:,:,:)
3216 : integer(C_INTPTR_T) :: i, j, k, alloc_local, local_n0, local_0_start,fft_sizes(4)
3217 : !*************************************************************************
3218 :
3219 : my_flags=ABI_FFTW_ESTIMATE; if (PRESENT(fftw_flags)) my_flags= fftw_flags
3220 :
3221 : ! get local data size and allocate (note dimension reversal)
3222 : fft_sizes = [nz,ny,nx,ndat]
3223 :
3224 : alloc_local = fftw_mpi_local_size_many( &
3225 : rank3,fft_sizes(1:3),fft_sizes(4),&
3226 : FFTW_MPI_DEFAULT_BLOCK, comm_fft, &
3227 : local_n0,local_0_start)
3228 :
3229 : ! Allocate cdata, build the plane and copy data: fin --> data
3230 : cdata = fftw_alloc_complex(alloc_local)
3231 : call c_f_pointer(cdata, data, [fft_sizes(3),fft_sizes(2), local_n0])
3232 :
3233 : plan = fftw_mpi_plan_many_dft(rank3,fft_sizes(1:3),fft_sizes(4), &
3234 : FFTW_MPI_DEFAULT_BLOCK,FFTW_MPI_DEFAULT_BLOCK, &
3235 : data,data,comm_fft,isign,my_flags)
3236 :
3237 : do k=1, local_n0*ndat
3238 : do j=1, ny
3239 : do i=1, nx
3240 : data(i,j,k) = CMPLX( fin(1,i,j,k),fin(2,i,j,k),C_DOUBLE_COMPLEX)
3241 : end do
3242 : end do
3243 : end do
3244 :
3245 : ! Compute transform.
3246 : call fftw_mpi_execute_dft(plan, data, data)
3247 :
3248 : if(isign==ABI_FFTW_FORWARD) then
3249 : ! Scale results.
3250 : factor_fft = one / (nx*ny*nz)
3251 : do k=1, local_n0*ndat
3252 : do j=1, ny
3253 : do i=1, nx
3254 : fout(1,i,j,k) = real(data(i,j,k)) * factor_fft
3255 : fout(2,i,j,k) = aimag(data(i,j,k)) * factor_fft
3256 : end do
3257 : end do
3258 : end do
3259 : end if
3260 :
3261 : call fftw_destroy_plan(plan)
3262 : call fftw_free(cdata)
3263 :
3264 : #else
3265 : ABI_ERROR("FFTW3_MPI support not activated")
3266 : ABI_UNUSED((/nx,ny,nz,ldx,ldy,ldz,ndat,isign/))
3267 : ABI_UNUSED(comm_fft)
3268 : if (PRESENT(fftw_flags)) then
3269 : ABI_UNUSED(fftw_flags)
3270 : end if
3271 : ABI_UNUSED(fin(1,1,1,1))
3272 : ABI_UNUSED(fout(1,1,1,1))
3273 : #endif
3274 :
3275 : end subroutine fftw3mpi_many_dft_ip
3276 : !!***
3277 :
3278 : !----------------------------------------------------------------------
3279 :
3280 : !!****f* m_fftw3/fftw3mpi_many_dft_tr
3281 : !! NAME
3282 : !! fftw3mpi_many_dft_tr
3283 : !!
3284 : !! FUNCTION
3285 : !! Driver routine for many out-of-place 3D complex-to-complex FFTs of lengths nx, ny, nz.
3286 : !!
3287 : !! INPUTS
3288 : !! nx,ny,nz=Number of points along the three directions.
3289 : !! ldx,ldy,ldz=Physical dimension of the fin and fout arrays (to avoid cache conflicts).
3290 : !! ndat=Number of FFTs to be done.
3291 : !! fin(2*ldx*ldy*ldz*ndat)=The complex array to be transformed.
3292 : !! isign=sign of Fourier transform exponent: current convention uses
3293 : !! +1 for transforming from G to r,
3294 : !! -1 for transforming from r to G.
3295 : !! comm_fft=MPI communicator for the FFT.
3296 : !! [fftw_flags]=Flags used to create the plan. They can be combined with the "+" operator.
3297 : !! Defaults to ABI_FFTW_ESTIMATE.
3298 : !!
3299 : !! TODO
3300 : !! Remove me
3301 : !!
3302 : !! OUTPUT
3303 : !! fout(2,ldx*ldy*ldz*ndat)=The Fourier transform of fin.
3304 : !!
3305 : !! SOURCE
3306 :
3307 : subroutine fftw3mpi_many_dft_tr(nx,ny,nz,ndat,isign,fin,fout,comm_fft,fftw_flags)
3308 :
3309 : !Arguments ------------------------------------
3310 : !scalars
3311 : integer,intent(in) :: nx,ny,nz,ndat,isign,comm_fft
3312 : integer,optional,intent(in) :: fftw_flags
3313 : !arrays
3314 : complex(C_DOUBLE_COMPLEX),contiguous, pointer :: fin(:,:,:)
3315 : complex(C_DOUBLE_COMPLEX),contiguous, pointer :: fout(:,:,:)
3316 :
3317 : !Local variables-------------------------------
3318 : #ifdef HAVE_FFTW3_MPI
3319 : !scalars
3320 : integer :: my_flags
3321 : !FFTWMPI stuff
3322 : type(C_PTR) :: plan
3323 : integer(C_INTPTR_T) :: fft_sizes(4)
3324 : !*************************************************************************
3325 :
3326 : my_flags=ABI_FFTW_ESTIMATE; if (PRESENT(fftw_flags)) my_flags= fftw_flags
3327 : my_flags = ior(my_flags,FFTW_DESTROY_INPUT)
3328 :
3329 : fft_sizes(1)=nz
3330 : fft_sizes(2)=ny
3331 : fft_sizes(3)=nx
3332 : fft_sizes(4)=ndat
3333 :
3334 : plan = fftw_mpi_plan_many_dft(3,fft_sizes(1:3),fft_sizes(4), &
3335 : & FFTW_MPI_DEFAULT_BLOCK,FFTW_MPI_DEFAULT_BLOCK, &
3336 : & fin,fout,comm_fft,isign,my_flags)
3337 :
3338 : !Compute transform (as many times as desired)
3339 : call fftw_mpi_execute_dft(plan, fin, fout)
3340 : call fftw_destroy_plan(plan)
3341 :
3342 : #else
3343 : ABI_ERROR("FFTW3_MPI support not activated")
3344 : ABI_UNUSED((/nx,ny,nz,ndat,isign,comm_fft/))
3345 : if (PRESENT(fftw_flags)) then
3346 : ABI_UNUSED(fftw_flags)
3347 : end if
3348 : ABI_UNUSED(fin(1,1,1))
3349 : ABI_UNUSED(fout(1,1,1))
3350 : #endif
3351 :
3352 : end subroutine fftw3mpi_many_dft_tr
3353 : !!***
3354 :
3355 : !----------------------------------------------------------------------
3356 :
3357 : !!****f* m_fftw3/fftw3_mpifourdp_c2r
3358 : !! NAME
3359 : !! fftw3_mpifourdp_c2r
3360 : !!
3361 : !! FUNCTION
3362 : !! Driver routine for transposed out-of-place 3D complex-to-real FFT of lengths nx, ny, nz.
3363 : !!
3364 : !! INPUTS
3365 : !! nx,ny,nz=Number of point along the three directions.
3366 : !! ndat=Number of FFTs to be done.
3367 : !! fofg(2,nx*ny*nz*ndat)=The complex array to be transformed.
3368 : !! comm_fft=MPI communicator.
3369 : !! [fftw_flags]=Flags used to create the plan. They can be combined with the "+" operator.
3370 : !! Defaults to ABI_FFTW_ESTIMATE.
3371 : !!
3372 : !! OUTPUT
3373 : !! fofr(2,nx*ny*nz*ndat)=The backwards real FFT of ff.
3374 : !!
3375 : !! NOTES
3376 : !! LOCAL DATA IN FOURIER SPACE : TRANSPOSED ORDER
3377 : !! real space --> dim = [ nx | ny | nz/np_fft]
3378 : !! fourier space --> dim = [ nx/2 | nz | ny/np_ff ]
3379 : !!
3380 : !! SOURCE
3381 :
3382 : subroutine fftw3_mpifourdp_c2r(nfft,ngfft,ndat,&
3383 : fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft,fftw_flags)
3384 :
3385 : !Arguments ------------------------------------
3386 : !scalars
3387 : integer,intent(in) :: nfft,ndat,comm_fft
3388 : integer,optional,intent(in) :: fftw_flags
3389 : !arrays
3390 : integer,intent(in) :: ngfft(18)
3391 : integer,intent(in) :: fftn2_distrib(ngfft(2)),ffti2_local(ngfft(2))
3392 : integer,intent(in) :: fftn3_distrib(ngfft(3)),ffti3_local(ngfft(3))
3393 : real(dp),intent(in) :: fofg(2,nfft*ndat)
3394 : real(dp),intent(out) :: fofr(nfft*ndat)
3395 :
3396 : !Local variables-------------------------------
3397 : #ifdef HAVE_FFTW3_MPI
3398 : !scalars
3399 : integer,parameter :: rank3=3
3400 : integer :: nx,ny,nz,nproc_fft
3401 : type(C_PTR) :: plan_bw, cdata_cplx,cdata_real
3402 : integer(C_INTPTR_T) :: i,j,jdat,k,alloc_local,fft_sizes(4),demi_nx,base,idat,kdat
3403 : integer(C_INTPTR_T) :: local_n0, local_0_start, local_n1, local_1_start
3404 : !arrays
3405 : complex(C_DOUBLE_COMPLEX), contiguous, pointer :: data_cplx(:,:,:)
3406 : real(C_DOUBLE), contiguous, pointer :: data_real(:,:,:)
3407 : ! *************************************************************************
3408 :
3409 : !ABI_CHECK(ndat==1, "ndat > 1 not implemented yet")
3410 :
3411 : nx=ngfft(1); ny=ngfft(2); nz=ngfft(3)
3412 : nproc_fft = xmpi_comm_size(comm_fft)
3413 :
3414 : demi_nx = nx/2 + 1
3415 : fft_sizes(1)=nz
3416 : fft_sizes(2)=ny
3417 : fft_sizes(3)=demi_nx
3418 : fft_sizes(4)=ndat
3419 :
3420 : alloc_local = fftw_mpi_local_size_many_transposed(&
3421 : rank3,fft_sizes(1:3),fft_sizes(4), &
3422 : FFTW_MPI_DEFAULT_BLOCK,FFTW_MPI_DEFAULT_BLOCK, comm_fft, &
3423 : local_n0,local_0_start, &
3424 : local_n1,local_1_start)
3425 :
3426 : cdata_cplx = fftw_alloc_complex(alloc_local)
3427 : cdata_real = fftw_alloc_real(alloc_local*2)
3428 :
3429 : ! OLD BY FDHAM
3430 : ! dimensions are (x/2,z,y) in Fourier's Space
3431 : call c_f_pointer(cdata_cplx, data_cplx, [demi_nx ,fft_sizes(1),local_n1])
3432 : ! dimensions in real space : (nx,ny,nz/nproc)
3433 : call c_f_pointer(cdata_real, data_real, [2*demi_nx,fft_sizes(2),local_n0])
3434 :
3435 : ! dimensions are (x/2,z,y) in Fourier's Space
3436 : !call c_f_pointer(cdata_cplx, data_cplx, [demi_nx ,fft_sizes(1),local_n0])
3437 :
3438 : !! dimensions in real space : (nx,ny,nz/nproc)
3439 : !call c_f_pointer(cdata_real, data_real, [2*demi_nx,fft_sizes(2),local_n1])
3440 :
3441 : fft_sizes(3)=nx
3442 : plan_bw = fftw_mpi_plan_many_dft_c2r(&
3443 : rank3,fft_sizes(1:3),fft_sizes(4), &
3444 : FFTW_MPI_DEFAULT_BLOCK,FFTW_MPI_DEFAULT_BLOCK, &
3445 : data_cplx, data_real , &
3446 : comm_fft,ior(ABI_FFTW_ESTIMATE,ABI_FFTW_MPI_TRANSPOSED_IN))
3447 :
3448 : do idat=1,ndat
3449 : do k=1, nz
3450 : do j=1, ny / nproc_fft
3451 : jdat = j + (idat-1) * ny / nproc_fft
3452 : base = nx*((j-1) + (ny/nproc_fft)*(k-1)) + (idat-1) * nfft
3453 : do i=1, demi_nx
3454 : data_cplx(i,k,jdat) = CMPLX(fofg(1, i + base), fofg(2, i + base), kind=C_DOUBLE_COMPLEX)
3455 : end do
3456 : end do
3457 : end do
3458 : end do
3459 :
3460 : ! compute transform (as many times as desired)
3461 : call fftw_mpi_execute_dft_c2r(plan_bw, data_cplx, data_real)
3462 :
3463 : do idat=1,ndat
3464 : do k=1,local_n0
3465 : kdat = k + (idat - 1) * local_n0
3466 : do j=1,ny
3467 : base = nx*((j-1) + ny*(k-1)) + (idat - 1) * nfft
3468 : do i=1,nx
3469 : fofr(i+base) = data_real(i,j,kdat)
3470 : end do
3471 : end do
3472 : end do
3473 : end do
3474 :
3475 : call fftw_destroy_plan(plan_bw)
3476 : call fftw_free(cdata_cplx)
3477 : call fftw_free(cdata_real)
3478 :
3479 : #else
3480 : ABI_ERROR("FFTW3_MPI support not activated")
3481 : ABI_UNUSED((/nfft,ngfft(1),ndat,comm_fft/))
3482 : ABI_UNUSED((/fftn2_distrib(1),ffti2_local(1)/))
3483 : ABI_UNUSED((/fftn3_distrib(1),ffti3_local(1)/))
3484 : if (PRESENT(fftw_flags)) then
3485 : ABI_UNUSED(fftw_flags)
3486 : end if
3487 : ABI_UNUSED(fofg(1,1))
3488 : ABI_UNUSED(fofr(1))
3489 : #endif
3490 :
3491 : end subroutine fftw3_mpifourdp_c2r
3492 : !!***
3493 :
3494 : !----------------------------------------------------------------------
3495 :
3496 : !!****f* m_fftw3/fftw3_mpifourdp_r2c
3497 : !! NAME
3498 : !! fftw3_mpifourdp_r2c
3499 : !!
3500 : !! FUNCTION
3501 : !! Driver routine for out-of-place 3D real-to-complex FFT of lengths nx, ny, nz.
3502 : !!
3503 : !! INPUTS
3504 : !! fofr(nx*ny*nz*ndat)=The real array to be transformed.
3505 : !! ndat=Number of FFTs to be done.
3506 : !! comm_fft=MPI communicator for the FFT.
3507 : !! [fftw_flags]=Flags used to create the plan. They can be combined with the "+" operator.
3508 : !! Defaults to ABI_FFTW_ESTIMATE.
3509 : !!
3510 : !! OUTPUT
3511 : !! fofg(2,nx*ny*nz*ndat)=The forward FFT of ff.
3512 : !!
3513 : !! NOTES
3514 : !! LOCAL DATA FOR FOURIER TRANSFORMS : TRANSPOSED ORDER AND DISTRIBUTED
3515 : !! real space --> dim = [ nx | ny | nz/np_fft ]
3516 : !! fourier space --> dim = [ nx | nz | ny/np_fft ]
3517 : !! we can't take in account the symmetric of the real case because after
3518 : !! fft have been computed, the symmetric data needed are dispatched over
3519 : !! other process in parallel
3520 : !!
3521 : !! SOURCE
3522 :
3523 : subroutine fftw3_mpifourdp_r2c(nfft,ngfft,ndat,&
3524 : fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft,fftw_flags)
3525 :
3526 : !Arguments ------------------------------------
3527 : !scalars
3528 : integer,intent(in) :: nfft,ndat,comm_fft
3529 : integer,optional,intent(in) :: fftw_flags
3530 : !arrays
3531 : integer,intent(in) :: ngfft(18)
3532 : integer,intent(in) :: fftn2_distrib(ngfft(2)),ffti2_local(ngfft(2))
3533 : integer,intent(in) :: fftn3_distrib(ngfft(3)),ffti3_local(ngfft(3))
3534 : real(dp),intent(in) :: fofr(nfft*ndat)
3535 : real(dp),intent(out) :: fofg(2,nfft*ndat)
3536 :
3537 : !Local variables-------------------------------
3538 : #ifdef HAVE_FFTW3_MPI
3539 : !scalars
3540 : integer,parameter :: rank3=3
3541 : integer :: my_flags,nproc_fft,nx,ny,nz
3542 : integer(C_INTPTR_T) :: i,j,k,base,alloc_local,i1,i2,i3,igf,idat,kdat,i2dat,padatf
3543 : integer(C_INTPTR_T) :: local_n0,local_0_start,local_n1,local_1_start
3544 : real(dp) :: factor_fft
3545 : type(C_PTR) :: plan_fw,cdata_cplx,cdata_real
3546 : !arrays
3547 : complex(C_DOUBLE_COMPLEX), contiguous, pointer :: data_cplx(:,:,:),data_real(:,:,:)
3548 : integer(C_INTPTR_T) :: fft_sizes(4)
3549 : ! *************************************************************************
3550 :
3551 : nproc_fft = xmpi_comm_size(comm_fft)
3552 :
3553 : nx=ngfft(1); ny=ngfft(2); nz=ngfft(3)
3554 :
3555 : my_flags=ABI_FFTW_ESTIMATE; if (PRESENT(fftw_flags)) my_flags= fftw_flags
3556 :
3557 : fft_sizes(1)=nz
3558 : fft_sizes(2)=ny
3559 : fft_sizes(3)=nx
3560 : fft_sizes(4)=ndat
3561 :
3562 : ! Get parallel sizes
3563 : alloc_local = fftw_mpi_local_size_many_transposed(&
3564 : rank3,fft_sizes(1:3),fft_sizes(4), &
3565 : FFTW_MPI_DEFAULT_BLOCK,FFTW_MPI_DEFAULT_BLOCK, comm_fft, &
3566 : local_n0,local_0_start, &
3567 : local_n1,local_1_start)
3568 :
3569 : ! Allocate data and reference it
3570 :
3571 : ! local data in real space --> dim = [nx | ny | nz/nproc_fft]
3572 : cdata_real = fftw_alloc_complex(alloc_local)
3573 : call c_f_pointer(cdata_real, data_real, [fft_sizes(3),fft_sizes(2),local_n0])
3574 :
3575 : ! local data in Fourier space --> dim = [nx | nz | ny/nproc_fft]
3576 : cdata_cplx = fftw_alloc_complex(alloc_local)
3577 : call c_f_pointer(cdata_cplx, data_cplx, [fft_sizes(3),fft_sizes(1),local_n1])
3578 :
3579 : ! TODO: Use true real to complex API!
3580 : ! Create Plan C2C (nx,ny,nz)
3581 : plan_fw = fftw_mpi_plan_many_dft(&
3582 : rank3,fft_sizes(1:3),fft_sizes(4), &
3583 : FFTW_MPI_DEFAULT_BLOCK,FFTW_MPI_DEFAULT_BLOCK, &
3584 : data_real, data_cplx , &
3585 : comm_fft,ABI_FFTW_FORWARD,ior(ABI_FFTW_ESTIMATE,ABI_FFTW_MPI_TRANSPOSED_OUT))
3586 :
3587 : ! Copy input data in correct format
3588 : do idat=1,ndat
3589 : do k=1,local_n0
3590 : kdat = k + (idat-1) * local_n0
3591 : do j=1, ny
3592 : base = nx*((j-1) + ny*(k-1)) + (idat-1) * nfft
3593 : do i=1, nx
3594 : data_real(i,j,kdat) = CMPLX(fofr(i+base),zero, kind=C_DOUBLE_COMPLEX)
3595 : end do
3596 : end do
3597 : end do
3598 : end do
3599 :
3600 : ! Compute transform
3601 : call fftw_mpi_execute_dft(plan_fw, data_real, data_cplx)
3602 :
3603 : factor_fft = one / (nx*ny*nz)
3604 :
3605 : do idat=1,ndat
3606 : padatf=(idat-1)*nfft
3607 : do i3=1,nz
3608 : do i2=1,ny/nproc_fft ! equivalent a local_n1
3609 : i2dat = i2 + (idat-1) * ny/nproc_fft
3610 : do i1=1,nx
3611 : igf = i1 + nx*( (i2-1) + (i3-1)*ny/nproc_fft ) + padatf
3612 : fofg(1,igf) = real(data_cplx(i1,i3,i2dat)) * factor_fft
3613 : fofg(2,igf) =aimag(data_cplx(i1,i3,i2dat)) * factor_fft
3614 : end do
3615 : end do
3616 : end do
3617 : end do
3618 :
3619 : call fftw_destroy_plan(plan_fw)
3620 : call fftw_free(cdata_cplx)
3621 : call fftw_free(cdata_real)
3622 :
3623 : #else
3624 : ABI_ERROR("FFTW3_MPI support not activated")
3625 : ABI_UNUSED((/nfft,ngfft(1),ndat,comm_fft/))
3626 : ABI_UNUSED((/fftn2_distrib(1),ffti2_local(1)/))
3627 : ABI_UNUSED((/fftn3_distrib(1),ffti3_local(1)/))
3628 : if (PRESENT(fftw_flags)) then
3629 : ABI_UNUSED(fftw_flags)
3630 : end if
3631 : ABI_UNUSED(fofg(1,1))
3632 : ABI_UNUSED(fofr(1))
3633 : #endif
3634 :
3635 : end subroutine fftw3_mpifourdp_r2c
3636 : !!***
3637 :
3638 : !----------------------------------------------------------------------
3639 :
3640 : !!****f* m_fftw3/old_fftw3_mpifourdp
3641 : !! NAME
3642 : !! old_fftw3_mpifourdp
3643 : !!
3644 : !! FUNCTION
3645 : !!
3646 : !! INPUTS
3647 : !! cplex=1 if fofr is real, 2 if fofr is complex
3648 : !! nfft=(effective) number of FFT grid points (for this processor)
3649 : !! ndat=Number of FFTs to be done.
3650 : !! isign= +1 : fofg(G) => fofr(R);
3651 : !! -1 : fofr(R) => fofg(G)
3652 : !! fftn2_distrib(n2)= rank of the processor which own fft planes in 2nd dimension for fourdp
3653 : !! ffti2_local(n2) = local i2 indices in fourdp
3654 : !! fftn3_distrib(n3) = rank of the processor which own fft planes in 3rd dimension for fourdp
3655 : !! ffti3_local(n3) = local i3 indices in fourdp
3656 : !! comm_fft=MPI communicator for the FFT
3657 : !! [fftw_flags]=Flags used to create the plan. They can be combined with the "+" operator.
3658 : !!
3659 : !! SIDE EFFECTS
3660 : !! Input/Output
3661 : !! fofg(2,nfft*ndat)=f(G), complex.
3662 : !! fofr(cplex*nfft*ndat)=input function f(r) (real or complex)
3663 : !!
3664 : !! SOURCE
3665 :
3666 : subroutine old_fftw3_mpifourdp(cplex,nfft,ngfft,ndat,isign,&
3667 : fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft,fftw_flags)
3668 :
3669 : !Arguments ------------------------------------
3670 : !scalars
3671 : integer,intent(in) :: cplex,nfft,ndat,isign,comm_fft
3672 : integer,optional,intent(in) :: fftw_flags
3673 : !arrays
3674 : integer,intent(in) :: ngfft(18)
3675 : integer,intent(in) :: fftn2_distrib(ngfft(2)),ffti2_local(ngfft(2))
3676 : integer,intent(in) :: fftn3_distrib(ngfft(3)),ffti3_local(ngfft(3))
3677 : real(dp),intent(inout) :: fofg(2,nfft*ndat),fofr(cplex*nfft*ndat)
3678 :
3679 : #ifdef HAVE_FFTW3_MPI
3680 : !Local variables-------------------------------
3681 : !scalars
3682 : integer :: nx,ny,nz,my_flags
3683 : ! *************************************************************************
3684 :
3685 : my_flags=ABI_FFTW_ESTIMATE; if (PRESENT(fftw_flags)) my_flags= fftw_flags
3686 :
3687 : nx=ngfft(1); ny=ngfft(2); nz=ngfft(3)
3688 : !me_fft=ngfft(11); nproc_fft=ngfft(10)
3689 :
3690 : select case (cplex)
3691 :
3692 : case (1)
3693 :
3694 : ! Complex to Complex.
3695 : ! This one is ok when ndat > 1
3696 : !call fftw3_mpifourdp_c2c(cplex,nfft,ngfft,ndat,isign,&
3697 : !& fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft,fftw_flags=my_flags)
3698 : !return
3699 :
3700 : ! r2c or c2r case.
3701 : ! FIXME this one is buggy when ndat > 1
3702 : select case (isign)
3703 : case (ABI_FFTW_FORWARD)
3704 : ! +1; R --> G
3705 : call fftw3_mpifourdp_r2c(nfft,ngfft,ndat,fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,&
3706 : & fofg,fofr,comm_fft,fftw_flags=my_flags)
3707 :
3708 : case (ABI_FFTW_BACKWARD)
3709 : ! -1; G --> R
3710 : call fftw3_mpifourdp_c2r(nfft,ngfft,ndat,fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,&
3711 : fofg,fofr,comm_fft,fftw_flags=my_flags)
3712 :
3713 : case default
3714 : ABI_BUG("Wrong isign")
3715 : end select
3716 :
3717 : case (2)
3718 : ! Complex to Complex.
3719 : call fftw3_mpifourdp_c2c(cplex,nfft,ngfft,ndat,isign,&
3720 : fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft,fftw_flags=my_flags)
3721 :
3722 : case default
3723 : ABI_BUG(" Wrong value for cplex")
3724 : end select
3725 :
3726 : #else
3727 : ABI_ERROR("FFTW3_MPI support not activated")
3728 : ABI_UNUSED((/cplex,nfft,ngfft(1),ndat,isign,comm_fft/))
3729 : ABI_UNUSED((/fftn2_distrib(1),ffti2_local(1)/))
3730 : ABI_UNUSED((/fftn3_distrib(1),ffti3_local(1)/))
3731 : if (PRESENT(fftw_flags)) then
3732 : ABI_UNUSED(fftw_flags)
3733 : end if
3734 : ABI_UNUSED(fofg(1,1))
3735 : ABI_UNUSED(fofr(1))
3736 : #endif
3737 :
3738 : end subroutine old_fftw3_mpifourdp
3739 : !!***
3740 :
3741 : !----------------------------------------------------------------------
3742 :
3743 : !!****f* m_fftw3/fftw3_mpifourdp_c2c
3744 : !! NAME
3745 : !! fftw3_mpifourdp_c2c
3746 : !!
3747 : !! FUNCTION
3748 : !! Driver routine for many out-of-place 3D complex-to-complex FFTs of lengths n1, n2, n3.
3749 : !!
3750 : !! INPUTS
3751 : !! cplex=1 if fofr is real, 2 if fofr is complex
3752 : !! nfft=(effective) number of FFT grid points (for this processor)
3753 : !! ndat=Number of FFTs to be done.
3754 : !! isign=sign of Fourier transform exponent: current convention uses
3755 : !! +1 for transforming from G to r,
3756 : !! -1 for transforming from r to G.
3757 : !! fftn2_distrib(n2)= rank of the processor which own fft planes in 2nd dimension for fourdp
3758 : !! ffti2_local(n2) = local i2 indices in fourdp
3759 : !! fftn3_distrib(n3) = rank of the processor which own fft planes in 3rd dimension for fourdp
3760 : !! ffti3_local(n3) = local i3 indices in fourdp
3761 : !! comm_fft=MPI communicator for the FFT
3762 : !! [fftw_flags]=Flags used to create the plan. They can be combined with the "+" operator.
3763 : !! fin(2*ldx*ldy*ldz*ndat)=The complex array to be transformed.
3764 : !!
3765 : !! TODO
3766 : !! Add c2r and r2c version.
3767 : !!
3768 : !! SIDE EFFECTS
3769 : !! Input/Output
3770 : !! fofg(2,nfft*ndat)=f(G), complex.
3771 : !! fofr(cplex*nfft*ndat)=input function f(r) (real or complex)
3772 : !!
3773 : !! SOURCE
3774 :
3775 : subroutine fftw3_mpifourdp_c2c(cplex,nfft,ngfft,ndat,isign,&
3776 : fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft,fftw_flags)
3777 :
3778 : !Arguments ------------------------------------
3779 : !scalars
3780 : integer,intent(in) :: cplex,isign,nfft,ndat,comm_fft
3781 : integer,optional,intent(in) :: fftw_flags
3782 : !arrays
3783 : integer,intent(in) :: ngfft(18)
3784 : integer,intent(in) :: fftn2_distrib(ngfft(2)),ffti2_local(ngfft(2))
3785 : integer,intent(in) :: fftn3_distrib(ngfft(3)),ffti3_local(ngfft(3))
3786 : real(dp),intent(inout) :: fofg(2,nfft*ndat),fofr(cplex*nfft*ndat)
3787 :
3788 : #ifdef HAVE_FFTW3_MPI
3789 : !Local variables-------------------------------
3790 : !scalars
3791 : integer,parameter :: rank3=3
3792 : integer :: n1,n2,n3,n4,n5,n6,nd2proc,nd3proc,my_flags,me_fft,nproc_fft
3793 : integer(C_INTPTR_T) :: alloc_local,local_n0,local_0_start,local_n1,local_1_start
3794 : type(C_PTR) :: plan,cptr_cdata
3795 : !arrays
3796 : integer(C_INTPTR_T) :: fft_sizes(4)
3797 : complex(C_DOUBLE_COMPLEX), contiguous, pointer :: f03_cdata(:)
3798 : !*************************************************************************
3799 :
3800 : my_flags=ABI_FFTW_ESTIMATE; if (PRESENT(fftw_flags)) my_flags= fftw_flags
3801 :
3802 : n1=ngfft(1); n2=ngfft(2); n3=ngfft(3)
3803 : ! No augmentation as FFTW3 does not support it
3804 : n4=n1; n5=n2; n6=n3
3805 : me_fft=ngfft(11); nproc_fft=ngfft(10)
3806 :
3807 : nd2proc=((n2-1)/nproc_fft) +1
3808 : nd3proc=((n6-1)/nproc_fft) +1
3809 :
3810 : ! Get local data size and allocate (note dimension reversal, we call the C interface directly!)
3811 : fft_sizes = [n3,n2,n1,ndat]
3812 :
3813 : ! Use TRANSPOSED_OUT
3814 : my_flags = ior(ABI_FFTW_ESTIMATE, ABI_FFTW_MPI_TRANSPOSED_OUT)
3815 :
3816 : if (isign == ABI_FFTW_BACKWARD) then
3817 : ! G --> R, Exchange n2 and n3
3818 : fft_sizes = [n2,n3,n1,ndat]
3819 : !my_flags = ior(ABI_FFTW_ESTIMATE, ABI_FFTW_MPI_TRANSPOSED_IN)
3820 : end if
3821 :
3822 : alloc_local = fftw_mpi_local_size_many_transposed(&
3823 : rank3,fft_sizes(1:3),fft_sizes(4), &
3824 : FFTW_MPI_DEFAULT_BLOCK,FFTW_MPI_DEFAULT_BLOCK, comm_fft, &
3825 : local_n0,local_0_start, &
3826 : local_n1,local_1_start)
3827 :
3828 : ! C to F
3829 : !local_0_start = local_0_start + 1
3830 : !local_1_start = local_1_start + 1
3831 : !write(std_out,*)"local_n0,local_0_start,alloc_local",local_n0,local_0_start,alloc_local
3832 : !write(std_out,*)"local_n1,local_1_start,alloc_local",local_n1,local_1_start,alloc_local
3833 :
3834 : ! Allocate cptr_cdata, associate to F pointer and build the plane.
3835 : cptr_cdata = fftw_alloc_complex(alloc_local)
3836 :
3837 : call c_f_pointer(cptr_cdata, f03_cdata, [alloc_local])
3838 :
3839 : plan = fftw_mpi_plan_many_dft(rank3,fft_sizes(1:3),fft_sizes(4), &
3840 : FFTW_MPI_DEFAULT_BLOCK,FFTW_MPI_DEFAULT_BLOCK, &
3841 : f03_cdata,f03_cdata,comm_fft,isign,my_flags)
3842 :
3843 : select case (isign)
3844 : case (ABI_FFTW_BACKWARD)
3845 : ! G --> R
3846 : ABI_CHECK(local_n0 == nd2proc, "local_n0 != nd2proc")
3847 :
3848 : call mpifft_fg2dbox_dpc(nfft,ndat,fofg,n1,n2,n3,n4,nd2proc,n6,fftn2_distrib,ffti2_local,me_fft,f03_cdata)
3849 :
3850 : ! Compute transform.
3851 : call fftw_mpi_execute_dft(plan, f03_cdata, f03_cdata)
3852 :
3853 : call mpifft_dbox2fr_dpc(n1,n2,n3,n4,n5,nd3proc,ndat,fftn3_distrib,ffti3_local,me_fft,f03_cdata,cplex,nfft,fofr)
3854 :
3855 : case (ABI_FFTW_FORWARD)
3856 : ! R --> G
3857 : ABI_CHECK(local_n0 == nd3proc, "local_n0 != nd3proc")
3858 :
3859 : call mpifft_fr2dbox_dpc(cplex,nfft,ndat,fofr,n1,n2,n3,n4,n5,nd3proc,fftn3_distrib,ffti3_local,me_fft,f03_cdata)
3860 :
3861 : ! Compute transform.
3862 : call fftw_mpi_execute_dft(plan, f03_cdata, f03_cdata)
3863 :
3864 : ! Scale results.
3865 : call mpifft_dbox2fg_dpc(n1,n2,n3,n4,nd2proc,n6,ndat,fftn2_distrib,ffti2_local,me_fft,f03_cdata,nfft,fofg)
3866 :
3867 : case default
3868 : ABI_ERROR("Wrong sign")
3869 : end select
3870 :
3871 : call fftw_destroy_plan(plan)
3872 : call fftw_free(cptr_cdata)
3873 :
3874 : #else
3875 : ABI_ERROR("FFTW3_MPI support not activated")
3876 : ABI_UNUSED((/cplex,nfft,ngfft(1),ndat,isign,comm_fft/))
3877 : ABI_UNUSED((/fftn2_distrib(1),ffti2_local(1)/))
3878 : ABI_UNUSED((/fftn3_distrib(1),ffti3_local(1)/))
3879 : if (PRESENT(fftw_flags)) then
3880 : ABI_UNUSED(fftw_flags)
3881 : end if
3882 : ABI_UNUSED(fofg(1,1))
3883 : ABI_UNUSED(fofr(1))
3884 : #endif
3885 :
3886 : end subroutine fftw3_mpifourdp_c2c
3887 : !!***
3888 :
3889 : !----------------------------------------------------------------------
3890 :
3891 : !!****f* m_fftw3/fftw3_mpiback_wf
3892 : !! NAME
3893 : !! fftw3_mpiback_wf
3894 : !!
3895 : !! FUNCTION
3896 : !! Does multiple 3-dim backward FFTs from Fourier into real space
3897 : !! Adopt standard convention that isign=1 for backward transform
3898 : !!
3899 : !! CALCULATES THE DISCRETE FOURIER TRANSFORM ZF(I1,I2,I3)=
3900 : !!
3901 : !! S_(j1,j2,j3) EXP(isign*i*2*pi*(j1*i1/n1+j2*i2/n2+j3*i3/n3)) ZF(j1,j3,j2)
3902 : !!
3903 : !! in parallel using MPI/OpenMP.
3904 : !!
3905 : !! INPUTS:
3906 : !! cplexwf=1 if wavefunction is real, 2 if complex
3907 : !! ndat=Number of wavefunctions to transform.
3908 : !! n1,n2,n3: logical dimension of the transform. As transform lengths
3909 : !! most products of the prime factors 2,3,5 are allowed.
3910 : !! The detailed table with allowed transform lengths can be found in subroutine CTRIG
3911 : !! nd1,nd2,nd3: Leading Dimension of ZR
3912 : !! nd3proc=((nd3-1)/nproc_fft)+1 maximal number of big box 3rd dim slices for one proc
3913 : !! max1 is positive or zero; m1 >=max1+1
3914 : !! i1= 1... max1+1 corresponds to positive and zero wavevectors 0 ... max1
3915 : !! then, if m1 > max1+1, one has min1=max1-m1+1 and
3916 : !! i1= max1+2 ... m1 corresponds to negative wavevectors min1 ... -1
3917 : !! max2 and max3 have a similar definition of range
3918 : !! m1,m2,m3=Size of the box enclosing the G-sphere.
3919 : !! md1,md2,md3: Dimension of ZF given on the **small** FFT box.
3920 : !! md2proc=((md2-1)/nproc_fft)+1 maximal number of small box 2nd dim slices for one proc
3921 : !! nproc_fft: number of processors used as returned by MPI_COMM_SIZE
3922 : !! comm_fft=MPI communicator for the FFT.
3923 : !! ZF: input array (note the switch of i2 and i3)
3924 : !! real(F(i1,i3,i2,idat))=ZF(1,i1,i3,i2,idat)
3925 : !! imag(F(i1,i3,i2,idat))=ZF(2,i1,i3,i2,idat)
3926 : !!
3927 : !! OUTPUTS
3928 : !! ZR: output array
3929 : !! ZR(1,i1,i2,i3,idat)=real(R(i1,i2,i3,idat))
3930 : !! ZR(2,i1,i2,i3,idat)=imag(R(i1,i2,i3,idat))
3931 : !! i1=1,n1 , i2=1,n2 , i3=1,n3 , idat=1,ndat
3932 : !!
3933 : !! NOTES
3934 : !! The maximum number of processors that can reasonably be used is max(n2/2,n3/2)
3935 : !!
3936 : !! It is very important to find the optimal
3937 : !! value of NCACHE. NCACHE determines the size of the work array ZW, that
3938 : !! has to fit into cache. It has therefore to be chosen to equal roughly
3939 : !! half the size of the physical cache in units of real*8 numbers.
3940 : !! The optimal value of ncache can easily be determined by numerical
3941 : !! experimentation. A too large value of ncache leads to a dramatic
3942 : !! and sudden decrease of performance, a too small value to a to a
3943 : !! slow and less dramatic decrease of performance. If NCACHE is set
3944 : !! to a value so small, that not even a single one dimensional transform
3945 : !! can be done in the workarray zw, the program stops with an error message.
3946 : !!
3947 : !! SOURCE
3948 :
3949 0 : subroutine fftw3_mpiback_wf(cplexwf,ndat,n1,n2,n3,nd1,nd2,nd3proc,&
3950 0 : max1,max2,max3,m1,m2,m3,md1,md2proc,md3,zf,zr,comm_fft)
3951 :
3952 : !Arguments ------------------------------------
3953 : integer,intent(in) :: cplexwf,ndat,n1,n2,n3,nd1,nd2,nd3proc
3954 : integer,intent(in) :: max1,max2,max3,m1,m2,m3,md1,md2proc,md3,comm_fft
3955 : real(dp),intent(in) :: zf(2,md1,md3,md2proc,ndat)
3956 : real(dp),intent(out) :: zr(2,nd1,nd2,nd3proc,ndat)
3957 :
3958 : #ifdef HAVE_FFTW3
3959 : !Local variables-------------------------------
3960 : integer,parameter :: nt1=1
3961 : integer :: j,i1,i2,idat,ierr,includelast
3962 : integer :: ioption,j2,j3,j2st,jp2st,jeff,lzt,m1zt,ma,mb,n1dfft,nnd3
3963 : integer :: lot1,lot2,lot3
3964 : integer :: m2eff,ncache,n1eff,n1half,nproc_fft,me_fft,nthreads
3965 : integer(KIND_FFTW_PLAN) :: bw_plan1_lot,bw_plan1_rest
3966 : integer(KIND_FFTW_PLAN) :: bw_plan2_lot,bw_plan2_rest
3967 : integer(KIND_FFTW_PLAN) :: bw_plan3_lot,bw_plan3_rest
3968 : !type(C_PTR) :: zw_cptr,zt_cptr
3969 : character(len=500) :: msg
3970 : !arrays
3971 : real(dp),allocatable :: zmpi1(:,:,:,:),zmpi2(:,:,:,:) ! work arrays for MPI
3972 : real(dp),allocatable :: zw(:,:),zt(:,:,:) ! cache work array and array for transpositions
3973 : !real(dp),contiguous, pointer :: zw(:,:),zt(:,:,:)
3974 : ! FFT work arrays
3975 : real(dp) :: tsec(2)
3976 : ! *************************************************************************
3977 :
3978 : !call wrtout(std_out,"mpiback standard ALLTOALL + FFTW3")
3979 :
3980 : ! FIXME must provide a default value but which one?
3981 : ! ioption = 0
3982 : ioption = 1
3983 : !if (paral_kgb==1) ioption=1
3984 :
3985 : nproc_fft = xmpi_comm_size(comm_fft); me_fft = xmpi_comm_rank(comm_fft)
3986 :
3987 : ! Find cache size that gives optimal performance on machine
3988 : ncache=2*max(n1,n2,n3,1024)
3989 : if (ncache/(2*max(n1,n2,n3))<1) then
3990 : write(msg,"(5a)") &
3991 : 'ncache has to be enlarged to be able to hold at',ch10, &
3992 : 'least one 1-d FFT of each size even though this will',ch10,&
3993 : 'reduce the performance for shorter transform lengths'
3994 : ABI_ERROR(msg)
3995 : end if
3996 :
3997 : ! Effective m1 and m2 (complex-to-complex or real-to-complex)
3998 : n1eff=n1; m2eff=m2; m1zt=n1
3999 : if (cplexwf==1) then
4000 : n1eff=(n1+1)/2; m2eff=m2/2+1; m1zt=2*(n1/2+1)
4001 : end if
4002 :
4003 : lzt=m2eff
4004 : if (mod(m2eff,2)==0) lzt=lzt+1
4005 : if (mod(m2eff,4)==0) lzt=lzt+1
4006 :
4007 : ! maximal number of big box 3rd dim slices for all procs
4008 : nnd3=nd3proc*nproc_fft
4009 :
4010 : ! Allocate cache work array and work arrays for MPI transpositions.
4011 : ABI_MALLOC(zw,(2,ncache/2))
4012 : ABI_MALLOC(zt,(2,lzt,m1zt))
4013 :
4014 : !call fftw3_alloc_real([2,ncache/2],zw_cptr,zw)
4015 : !call fftw3_alloc_real([2,lzt,m1zt],zt_cptr,zt)
4016 :
4017 : ABI_MALLOC(zmpi2,(2,md1,md2proc,nnd3))
4018 : if (nproc_fft>1) then
4019 : ABI_MALLOC(zmpi1,(2,md1,md2proc,nnd3))
4020 : end if
4021 :
4022 : !DEBUG
4023 : ! write(std_out,'(2a,3i4)' )itoa(me_fft),': fftw3_mpiback_wf,zf n1,n2,n3',n1,n2,n3
4024 : ! write(std_out,'(2a,3i4)' )itoa(me_fft),': nd1,nd2,nd3proc',nd1,nd2,nd3proc
4025 : ! write(std_out,'(2a,3i4)' )itoa(me_fft),': m1,m2,m3',m1,m2,m3
4026 : ! write(std_out,'(2a,3i4)' )itoa(me_fft),': max1,max2,max3',max1,max2,max3
4027 : ! write(std_out,'(2a,3i4)' )itoa(me_fft),': md1,md2proc,md3',md1,md2proc,md3
4028 : ! write(std_out,'(2a,3i4)' )itoa(me_fft),'n1eff,m2eff,m1zt',n1eff,m2eff,m1zt
4029 : !ENDDEBUG
4030 :
4031 : ! Create plans.
4032 : ! The prototype for sfftw_plan_many_dft is:
4033 : ! sfftw_plan_many_dft(rank, n, howmany,
4034 : ! fin, iembed, istride, idist,
4035 : ! fout, oembed, ostride, odist, isign, my_flags)
4036 :
4037 : lot3=ncache/(2*n3)
4038 : lot1=ncache/(2*n1)
4039 : lot2=ncache/(2*n2)
4040 :
4041 : nthreads = xomp_get_num_threads(open_parallel=.TRUE.)
4042 : !nthreads = 1
4043 :
4044 : bw_plan3_lot = dplan_many_dft_2D(1, [n3], lot3, &
4045 : zw, [ncache/2], lot3, 1, &
4046 : zw, [ncache/2], lot3, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
4047 :
4048 : if (mod(m1, lot3) /= 0) then
4049 : bw_plan3_rest = dplan_many_dft_2D(1, [n3], mod(m1, lot3), &
4050 : zw, [ncache/2], lot3, 1, &
4051 : zw, [ncache/2], lot3, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
4052 : end if
4053 :
4054 : bw_plan1_lot = dplan_many_dft_2D(1, [n1], lot1, &
4055 : zw, [ncache/2], lot1, 1, &
4056 : zt, [lzt, m1zt], lzt, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
4057 :
4058 : if (mod(m2eff, lot1) /= 0) then
4059 : bw_plan1_rest = dplan_many_dft_2D(1, [n1], mod(m2eff, lot1), &
4060 : zw, [ncache/2], lot1, 1, &
4061 : zt, [lzt, m1zt], lzt, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
4062 : end if
4063 :
4064 : bw_plan2_lot = dplan_many_dft_2D(1, [n2], lot2, &
4065 : zw, [ncache/2], lot2, 1, &
4066 : zr, [nd1,nd2,nd3proc,ndat], nd1, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
4067 :
4068 : if (mod(n1eff, lot2) /= 0) then
4069 : bw_plan2_rest = dplan_many_dft_2D(1, [n2], mod(n1eff,lot2), &
4070 : zw, [ncache/2], lot2, 1, &
4071 : zr, [nd1,nd2,nd3proc,ndat], nd1, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
4072 : end if
4073 :
4074 : do idat=1,ndat
4075 : ! transform along z axis
4076 : ! input: G1,G3,G2,(Gp2)
4077 :
4078 : ! Loop over the y planes treated by this node and transform n1ddft G_z lines.
4079 : do j2=1,md2proc
4080 : ! if (me_fft*md2proc+j2<=m2eff) then !a faire plus tard
4081 : do i1=1,m1,lot3
4082 : ma=i1
4083 : mb=min(i1+(lot3-1),m1)
4084 : n1dfft=mb-ma+1
4085 :
4086 : ! zero-pad n1dfft G_z lines
4087 : ! input: G1,G3,G2,(Gp2)
4088 : ! output: G1,R3,G2,(Gp2)
4089 : call fill_cent(md1,md3,lot3,n1dfft,max3,m3,n3,zf(1,i1,1,j2,idat),zw)
4090 :
4091 : ! Transform along z.
4092 : if (n1dfft == lot3) then
4093 : call dfftw_execute_dft(bw_plan3_lot, zw, zw)
4094 : else
4095 : call dfftw_execute_dft(bw_plan3_rest, zw, zw)
4096 : end if
4097 :
4098 : ! Local rotation.
4099 : ! input: G1,R3,G2,(Gp2)
4100 : ! output: G1,G2,R3,(Gp2)
4101 : call scramble(i1,j2,lot3,n1dfft,md1,n3,md2proc,nnd3,zw,zmpi2)
4102 : end do
4103 : end do ! j2
4104 :
4105 : ! Interprocessor data transposition
4106 : ! input: G1,G2,R3,Rp3,(Gp2)
4107 : ! output: G1,G2,R3,Gp2,(Rp3)
4108 : if (nproc_fft>1) then
4109 : call timab(543,1,tsec)
4110 : call xmpi_alltoall(zmpi2,2*md1*md2proc*nd3proc, &
4111 : zmpi1,2*md1*md2proc*nd3proc,comm_fft,ierr)
4112 : call timab(543,2,tsec)
4113 : end if
4114 :
4115 : ! Loop over the z treated by this node.
4116 : do j3=1,nd3proc
4117 : if (me_fft*nd3proc+j3 <= n3) then
4118 : Jp2st=1; J2st=1
4119 :
4120 : ! Loop over G_y in the small box.
4121 : do j=1,m2eff,lot1
4122 : ma=j
4123 : mb=min(j+(lot1-1),m2eff)
4124 : n1dfft=mb-ma+1
4125 :
4126 : ! Zero-pad input.
4127 : ! input: G1,G2,R3,JG2,(Rp3)
4128 : ! output: G2,G1,R3,JG2,(Rp3)
4129 : if (nproc_fft==1) then
4130 : call mpiswitch_cent(j3,n1dfft,Jp2st,J2st,lot1,max1,md1,m1,n1,&
4131 : md2proc,nd3proc,nproc_fft,ioption,zmpi2,zw,max2,m2,n2)
4132 : else
4133 : call mpiswitch_cent(j3,n1dfft,Jp2st,J2st,lot1,max1,md1,m1,n1,&
4134 : md2proc,nd3proc,nproc_fft,ioption,zmpi1,zw,max2,m2,n2)
4135 : end if
4136 :
4137 : ! Transform along x
4138 : ! input: G2,G1,R3,(Rp3)
4139 : ! output: G2,R1,R3,(Rp3)
4140 : if (n1dfft == lot1) then
4141 : call dfftw_execute_dft(bw_plan1_lot, zw, zt(1,j,1))
4142 : else
4143 : call dfftw_execute_dft(bw_plan1_rest, zw, zt(1,j,1))
4144 : end if
4145 :
4146 : end do ! j
4147 :
4148 : ! Transform along y axis (take into account c2c or c2r case).
4149 : ! Must loop over the full box.
4150 : do j=1,n1eff,lot2
4151 : ma=j
4152 : mb=min(j+(lot2-1),n1eff)
4153 : n1dfft=mb-ma+1
4154 : includelast=1
4155 :
4156 : if (cplexwf==1) then
4157 : jeff=2*j-1
4158 : if (mb==n1eff .and. n1eff*2/=n1) includelast=0
4159 : end if
4160 :
4161 : ! Zero-pad the input.
4162 : ! input: G2,R1,R3,(Rp3)
4163 : ! output: R1,G2,R3,(Rp3)
4164 : if (cplexwf==2) then
4165 : call switch_cent(n1dfft,max2,m2,n2,lot2,n1,lzt,zt(1,1,j),zw)
4166 : else
4167 : call switchreal_cent(includelast,n1dfft,max2,n2,lot2,m1zt,lzt,zt(1,1,jeff),zw)
4168 : end if
4169 :
4170 : ! input: R1,G2,R3,(Rp3)
4171 : ! output: R1,R2,R3,(Rp3)
4172 : if (n1dfft == lot2) then
4173 : call dfftw_execute_dft(bw_plan2_lot, zw, zr(1,j,1,j3,idat))
4174 : else
4175 : call dfftw_execute_dft(bw_plan2_rest, zw, zr(1,j,1,j3,idat))
4176 : end if
4177 :
4178 : end do
4179 :
4180 : ! Treat real wavefunctions.
4181 : if (cplexwf==1) then
4182 : n1half=n1/2
4183 : ! If odd
4184 : if (n1half*2/=n1) then
4185 : do i2=1,n2
4186 : zr(1,n1,i2,j3,idat)=zr(1,n1eff,i2,j3,idat)
4187 : zr(2,n1,i2,j3,idat)=zero
4188 : end do
4189 : end if
4190 : do i2=1,n2
4191 : do i1=n1half,1,-1
4192 : zr(1,2*i1-1,i2,j3,idat)=zr(1,i1,i2,j3,idat)
4193 : zr(1,2*i1 ,i2,j3,idat)=zr(2,i1,i2,j3,idat)
4194 : zr(2,2*i1-1,i2,j3,idat)=zero
4195 : zr(2,2*i1 ,i2,j3,idat)=zero
4196 : end do
4197 : end do
4198 : end if
4199 :
4200 : end if
4201 : end do ! j3
4202 : end do ! idat
4203 :
4204 : call dfftw_destroy_plan(bw_plan3_lot)
4205 : if (mod(m1, lot3) /= 0) call dfftw_destroy_plan(bw_plan3_rest)
4206 :
4207 : call dfftw_destroy_plan(bw_plan1_lot)
4208 : if (mod(m2eff, lot1) /= 0) call dfftw_destroy_plan(bw_plan1_rest)
4209 :
4210 : call dfftw_destroy_plan(bw_plan2_lot)
4211 : if (mod(n1eff, lot2) /= 0) call dfftw_destroy_plan(bw_plan2_rest)
4212 :
4213 : ABI_FREE(zmpi2)
4214 : ABI_FREE(zw)
4215 : ABI_FREE(zt)
4216 : if (nproc_fft>1) then
4217 : ABI_FREE(zmpi1)
4218 : end if
4219 :
4220 : #else
4221 0 : ABI_ERROR("FFTW3 support not activated")
4222 : ABI_UNUSED((/cplexwf,ndat,n1,n2,n3,nd1,nd2,nd3proc/))
4223 : ABI_UNUSED((/ max1,max2,max3,m1,m2,m3,md1,md2proc,md3,comm_fft/))
4224 : ABI_UNUSED((/zf(1,1,1,1,1),zr(1,1,1,1,1)/))
4225 : #endif
4226 :
4227 0 : end subroutine fftw3_mpiback_wf
4228 : !!***
4229 :
4230 : !----------------------------------------------------------------------
4231 :
4232 : !!****f* m_fftw3/fftw3_mpiforw_wf
4233 : !! NAME
4234 : !! fftw3_mpiforw_wf
4235 : !!
4236 : !! FUNCTION
4237 : !! Does multiple 3-dim backward FFTs from real into Fourier space
4238 : !! Adopt standard convention that isign=-1 for forward transform
4239 : !! CALCULATES THE DISCRETE FOURIERTRANSFORM
4240 : !!
4241 : !! ZF(I1,I3,I2)=S_(j1,j2,j3) EXP(isign*i*2*pi*(j1*i1/n1+j2*i2/n2+j3*i3/n3)) ZR(j1,j2,j3)
4242 : !!
4243 : !! in parallel using MPI/OpenMP.
4244 : !!
4245 : !! INPUT:
4246 : !! ZR: input array
4247 : !! ZR(1,i1,i2,i3,idat)=real(R(i1,i2,i3,idat))
4248 : !! ZR(2,i1,i2,i3,idat)=imag(R(i1,i2,i3,idat))
4249 : !! i1=1,n1 , i2=1,n2 , i3=1,n3 , idat=1,ndat
4250 : !! NOTE that ZR is changed by the routine
4251 : !!
4252 : !! n1,n2,n3: logical dimension of the transform. As transform lengths
4253 : !! most products of the prime factors 2,3,5 are allowed.
4254 : !! The detailed table with allowed transform lengths can
4255 : !! be found in subroutine CTRIG
4256 : !! nd1,nd2,nd3: Dimension of ZR
4257 : !! nd3proc=((nd3-1)/nproc_fft)+1 maximal number of big box 3rd dim slices for one proc
4258 : !!
4259 : !! OUTPUT:
4260 : !! ZF: output array (note the switch of i2 and i3)
4261 : !! real(F(i1,i3,i2,idat))=ZF(1,i1,i3,i2,idat)
4262 : !! imag(F(i1,i3,i2,idat))=ZF(2,i1,i3,i2,idat)
4263 : !! max1 is positive or zero ; m1 >=max1+1
4264 : !! i1= 1... max1+1 corresponds to positive and zero wavevectors 0 ... max1
4265 : !! then, if m1 > max1+1, one has min1=max1-m1+1 and
4266 : !! i1= max1+2 ... m1 corresponds to negative wavevectors min1 ... -1
4267 : !! i2 and i3 have a similar definition of range
4268 : !! idat=1,ndat
4269 : !! md1,md2,md3: Dimension of ZF
4270 : !! md2proc=((md2-1)/nproc_fft)+1 maximal number of small box 2nd dim slices for one proc
4271 : !! nproc_fft: number of processors used as returned by MPI_COMM_SIZE
4272 : !! me_fft: [0:nproc-1] rank of the processor in the FFT communicator.
4273 : !! comm_fft=MPI communicator for parallel FFT.
4274 : !!
4275 : !! NOTES
4276 : !! The maximum number of processors that can reasonably be used is max(n2/2,n3/2)
4277 : !!
4278 : !! It is very important to find the optimal
4279 : !! value of NCACHE. NCACHE determines the size of the work array ZW, that
4280 : !! has to fit into cache. It has therefore to be chosen to equal roughly
4281 : !! half the size of the physical cache in units of real*8 numbers.
4282 : !! The optimal value of ncache can easily be determined by numerical
4283 : !! experimentation. A too large value of ncache leads to a dramatic
4284 : !! and sudden decrease of performance, a too small value to a to a
4285 : !! slow and less dramatic decrease of performance. If NCACHE is set
4286 : !! to a value so small, that not even a single one dimensional transform
4287 : !! can be done in the workarray zw, the program stops with an error message.
4288 : !!
4289 : !! SOURCE
4290 :
4291 0 : subroutine fftw3_mpiforw_wf(cplexwf,ndat,n1,n2,n3,nd1,nd2,nd3proc,&
4292 0 : & max1,max2,max3,m1,m2,m3,md1,md2proc,md3,zr,zf,comm_fft)
4293 :
4294 : !Arguments ------------------------------------
4295 : !scalars
4296 : integer,intent(in) :: cplexwf,ndat,n1,n2,n3,nd1,nd2,nd3proc
4297 : integer,intent(in) :: max1,max2,max3,m1,m2,m3,md1,md2proc,md3,comm_fft
4298 : !arrays
4299 : real(dp),intent(inout) :: zr(2,nd1,nd2,nd3proc,ndat)
4300 : real(dp),intent(out) :: zf(2,md1,md3,md2proc,ndat)
4301 :
4302 : !Local variables-------------------------------
4303 : !scalars
4304 : #ifdef HAVE_FFTW3
4305 : integer :: j,i1,i2,i3,idat,ierr,nproc_fft,me_fft,nthreads
4306 : integer :: ioption,j2,j3,j2st,jp2st,lot1,lot2,lot3,lzt,m1zt,ma,mb,n1dfft,nnd3
4307 : integer :: m2eff,ncache,n1eff,n1half,i1inv,i2inv,i3inv
4308 : integer(KIND_FFTW_PLAN) :: fw_plan1_lot,fw_plan1_rest
4309 : integer(KIND_FFTW_PLAN) :: fw_plan2_lot,fw_plan2_rest
4310 : integer(KIND_FFTW_PLAN) :: fw_plan3_lot,fw_plan3_rest
4311 : character(len=500) :: msg
4312 : !arrays
4313 : real(dp), allocatable :: zmpi1(:,:,:,:),zmpi2(:,:,:,:) ! work arrays for MPI
4314 : real(dp),allocatable :: zw(:,:),zt(:,:,:) ! cache work array and array for transpositions
4315 : ! FFT work arrays
4316 : real(dp) :: tsec(2)
4317 : ! *************************************************************************
4318 :
4319 : ! FIXME must provide a default value but which one?
4320 : !ioption = 0
4321 : ioption = 1
4322 : !if (paral_kgb==1) ioption=1
4323 :
4324 : nproc_fft = xmpi_comm_size(comm_fft); me_fft = xmpi_comm_rank(comm_fft)
4325 :
4326 : ! find cache size that gives optimal performance on machine
4327 : ncache=2*max(n1,n2,n3,1024)
4328 : !ncache=2*max(n1,n2,n3,16*1024)
4329 :
4330 : if (ncache/(2*max(n1,n2,n3))<1) then
4331 : write(msg,'(5a)') &
4332 : 'ncache has to be enlarged to be able to hold at',ch10, &
4333 : 'least one 1-d FFT of each size even though this will',ch10,&
4334 : 'reduce the performance for shorter transform lengths'
4335 : ABI_ERROR(msg)
4336 : end if
4337 :
4338 : ! Effective m1 and m2 (complex-to-complex or real-to-complex)
4339 : n1eff=n1; m2eff=m2; m1zt=n1
4340 : if (cplexwf==1) then
4341 : n1eff=(n1+1)/2; m2eff=m2/2+1; m1zt=2*(n1/2+1)
4342 : end if
4343 :
4344 : lzt=m2eff
4345 : if (mod(m2eff,2)==0) lzt=lzt+1
4346 : if (mod(m2eff,4)==0) lzt=lzt+1
4347 :
4348 : ! maximal number of big box 3rd dim slices for all procs
4349 : nnd3=nd3proc*nproc_fft
4350 :
4351 : ABI_MALLOC(zw,(2,ncache/2))
4352 : ABI_MALLOC(zt,(2,lzt,m1zt))
4353 : ABI_MALLOC(zmpi2,(2,md1,md2proc,nnd3))
4354 : if (nproc_fft>1) then
4355 : ABI_MALLOC(zmpi1,(2,md1,md2proc,nnd3))
4356 : end if
4357 :
4358 : !DEBUG
4359 : ! write(std_out,'(2a,3i4)' )itoa(me_fft),'fftw3_mpiforw_wf, enter, i1,i2,i3,zr,n1,n2,n3',n1,n2,n3
4360 : ! write(std_out,'(2a,3i4)' )itoa(me_fft),'nd1,nd2,nd3proc',nd1,nd2,nd3proc
4361 : ! write(std_out,'(2a,3i4)' )itoa(me_fft),'m1,m2,m3',m1,m2,m3
4362 : ! write(std_out,'(2a,3i4)' )itoa(me_fft),'max1,max2,max3',max1,max2,max3
4363 : ! write(std_out,'(2a,3i4)' )itoa(me_fft),'md1,md2proc,md3',md1,md2proc,md3
4364 : ! write(std_out,'(2a,3i4)' )itoa(me_fft),'n1eff,m2eff,m1zt',n1eff,m2eff,m1zt
4365 : !ENDDEBUG
4366 :
4367 : ! Create plans.
4368 : ! The prototype for sfftw_plan_many_dft is:
4369 : ! sfftw_plan_many_dft(rank, n, howmany,
4370 : ! fin, iembed, istride, idist,
4371 : ! fout, oembed, ostride, odist, isign, my_flags)
4372 :
4373 : lot2=ncache/(2*n2)
4374 : lot1=ncache/(2*n1)
4375 : lot3=ncache/(2*n3)
4376 :
4377 : nthreads = xomp_get_num_threads(open_parallel=.TRUE.)
4378 : !nthreads = 1
4379 :
4380 : fw_plan3_lot = dplan_many_dft_2D(1, [n3], lot3, &
4381 : zw, [ncache/2], lot3, 1, &
4382 : zw, [ncache/2], lot3, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE,nthreads)
4383 :
4384 : if (mod(m1, lot3) /= 0) then
4385 : fw_plan3_rest = dplan_many_dft_2D(1, [n3], mod(m1, lot3), &
4386 : zw, [ncache/2], lot3, 1, &
4387 : zw, [ncache/2], lot3, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
4388 : end if
4389 :
4390 : fw_plan1_lot = dplan_many_dft_2D(1, [n1], lot1, &
4391 : zt, [lzt, m1zt], lzt, 1, &
4392 : zw, [ncache/2], lot1, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
4393 :
4394 : if (mod(m2eff, lot1) /= 0) then
4395 : fw_plan1_rest = dplan_many_dft_2D(1, [n1], mod(m2eff, lot1), &
4396 : zt, [lzt, m1zt], lzt, 1, &
4397 : zw, [ncache/2], lot1, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
4398 : end if
4399 :
4400 : fw_plan2_lot = dplan_many_dft_2D(1, [n2], lot2, &
4401 : zr, [nd1,nd2,nd3proc,ndat], nd1, 1, &
4402 : zw, [ncache/2], lot2, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
4403 :
4404 : if (mod(n1eff, lot2) /= 0) then
4405 : fw_plan2_rest = dplan_many_dft_2D(1, [n2], mod(n1eff,lot2), &
4406 : zr, [nd1,nd2,nd3proc,ndat], nd1, 1, &
4407 : zw, [ncache/2], lot2, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
4408 : end if
4409 :
4410 : do idat=1,ndat
4411 : ! Loop over the z-planes treated by this node
4412 : do j3=1,nd3proc
4413 :
4414 : if (me_fft*nd3proc+j3 <= n3) then
4415 : Jp2st=1
4416 : J2st=1
4417 :
4418 : ! Treat real wavefunctions.
4419 : if (cplexwf==1) then
4420 : n1half=n1/2
4421 : do i2=1,n2
4422 : do i1=1,n1half
4423 : zr(1,i1,i2,j3,idat)=zr(1,2*i1-1,i2,j3,idat)
4424 : zr(2,i1,i2,j3,idat)=zr(1,2*i1 ,i2,j3,idat)
4425 : end do
4426 : end do
4427 : ! If odd
4428 : if(n1half*2/=n1)then
4429 : do i2=1,n2
4430 : zr(1,n1eff,i2,j3,idat)=zr(1,n1,i2,j3,idat)
4431 : zr(2,n1eff,i2,j3,idat)=zero
4432 : end do
4433 : end if
4434 : end if
4435 :
4436 : ! transform along y axis
4437 : ! input: R1,R2,R3,(Rp3)
4438 : ! input: R1,G2,R3,(Rp3)
4439 : do j=1,n1eff,lot2
4440 : ma=j
4441 : mb=min(j+(lot2-1),n1eff)
4442 : n1dfft=mb-ma+1
4443 :
4444 : if (n1dfft == lot2) then
4445 : call dfftw_execute_dft(fw_plan2_lot, zr(1,j,1,j3,idat), zw)
4446 : else
4447 : call dfftw_execute_dft(fw_plan2_rest, zr(1,j,1,j3,idat), zw)
4448 : end if
4449 :
4450 : ! input: R1,G2,R3,(Rp3)
4451 : ! output: G2,R1,R3,(Rp3)
4452 : if (cplexwf==2) then
4453 : call unswitch_cent(n1dfft,max2,m2,n2,lot2,n1,lzt,zw,zt(1,1,j))
4454 : else
4455 : call unswitchreal_cent(n1dfft,max2,n2,lot2,n1,lzt,zw,zt(1,1,2*j-1))
4456 : end if
4457 : end do
4458 :
4459 : ! transform along x axis
4460 : ! input: G2,R1,R3,(Rp3)
4461 : do j=1,m2eff,lot1
4462 : ma=j
4463 : mb=min(j+(lot1-1),m2eff)
4464 : n1dfft=mb-ma+1
4465 :
4466 : if (n1dfft == lot1) then
4467 : call dfftw_execute_dft(fw_plan1_lot, zt(1,j,1), zw)
4468 : else
4469 : call dfftw_execute_dft(fw_plan1_rest, zt(1,j,1), zw)
4470 : end if
4471 : ! output: G2,G1,R3,(Rp3)
4472 :
4473 : ! input: G2,G1,R3,Gp2,(Rp3)
4474 : ! output: G1,G2,R3,Gp2,(Rp3)
4475 : if (nproc_fft==1) then
4476 : call unmpiswitch_cent(j3,n1dfft,Jp2st,J2st,lot1,max1,md1,m1,n1,&
4477 : md2proc,nd3proc,nproc_fft,ioption,zw,zmpi2)
4478 : else
4479 : call unmpiswitch_cent(j3,n1dfft,Jp2st,J2st,lot1,max1,md1,m1,n1,&
4480 : md2proc,nd3proc,nproc_fft,ioption,zw,zmpi1)
4481 : end if
4482 : end do
4483 :
4484 : end if
4485 : end do ! j3
4486 :
4487 : ! Interprocessor data transposition
4488 : ! input: G1,G2,R3,Gp2,(Rp3)
4489 : ! output: G1,G2,R3,Rp3,(Gp2)
4490 : if (nproc_fft>1) then
4491 : call timab(544,1,tsec)
4492 : call xmpi_alltoall(zmpi1,2*md1*md2proc*nd3proc, &
4493 : zmpi2,2*md1*md2proc*nd3proc,comm_fft,ierr)
4494 : call timab(544,2,tsec)
4495 : end if
4496 :
4497 : ! transform along z axis
4498 : ! input: G1,G2,R3,(Gp2)
4499 :
4500 : do j2=1,md2proc
4501 : if (me_fft*md2proc+j2 <= m2eff) then
4502 : ! write(std_out,*)' forwf_wf : before unscramble, j2,md2proc,me_fft,m2=',j2,md2proc,me_fft,m2
4503 : do i1=1,m1,lot3
4504 : ma=i1
4505 : mb=min(i1+(lot3-1),m1)
4506 : n1dfft=mb-ma+1
4507 :
4508 : ! input: G1,G2,R3,(Gp2)
4509 : ! output: G1,R3,G2,(Gp2)
4510 : call unscramble(i1,j2,lot3,n1dfft,md1,n3,md2proc,nnd3,zmpi2,zw)
4511 :
4512 : if (n1dfft == lot3) then
4513 : call dfftw_execute_dft(fw_plan3_lot, zw, zw)
4514 : else
4515 : call dfftw_execute_dft(fw_plan3_rest, zw, zw)
4516 : end if
4517 :
4518 : call unfill_cent(md1,md3,lot3,n1dfft,max3,m3,n3,zw,zf(1,i1,1,j2,idat))
4519 : ! output: G1,G3,G2,(Gp2)
4520 : end do
4521 : end if
4522 : end do
4523 :
4524 : if (cplexwf==1) then
4525 : ! Complete missing values with complex conjugate
4526 : ! Inverse of ix is located at nx+2-ix , except for ix=1, for which it is 1.
4527 : do i3=1,m3
4528 : i3inv=m3+2-i3
4529 : if(i3==1)i3inv=1
4530 :
4531 : if (m2eff>1) then
4532 : do i2=2,m2eff
4533 : i2inv=m2+2-i2
4534 : zf(1,1,i3inv,i2inv,idat)= zf(1,1,i3,i2,idat)
4535 : zf(2,1,i3inv,i2inv,idat)=-zf(2,1,i3,i2,idat)
4536 : do i1=2,m1
4537 : i1inv=m1+2-i1
4538 : zf(1,i1inv,i3inv,i2inv,idat)= zf(1,i1,i3,i2,idat)
4539 : zf(2,i1inv,i3inv,i2inv,idat)=-zf(2,i1,i3,i2,idat)
4540 : end do
4541 : end do
4542 : end if
4543 : end do
4544 : end if
4545 :
4546 : end do ! idat
4547 :
4548 : call dfftw_destroy_plan(fw_plan3_lot)
4549 : if (mod(m1, lot3) /= 0) call dfftw_destroy_plan(fw_plan3_rest)
4550 :
4551 : call dfftw_destroy_plan(fw_plan1_lot)
4552 : if (mod(m2eff, lot1) /= 0) call dfftw_destroy_plan(fw_plan1_rest)
4553 :
4554 : call dfftw_destroy_plan(fw_plan2_lot)
4555 : if (mod(n1eff, lot2) /= 0) call dfftw_destroy_plan(fw_plan2_rest)
4556 :
4557 : ABI_FREE(zmpi2)
4558 : ABI_FREE(zw)
4559 : ABI_FREE(zt)
4560 : if (nproc_fft>1) then
4561 : ABI_FREE(zmpi1)
4562 : end if
4563 :
4564 : #else
4565 0 : ABI_ERROR("FFTW3 support not activated")
4566 : ABI_UNUSED((/cplexwf,ndat,n1,n2,n3,nd1,nd2,nd3proc/))
4567 : ABI_UNUSED((/max1,max2,max3,m1,m2,m3,md1,md2proc,md3,comm_fft/))
4568 : ABI_UNUSED((/zf(1,1,1,1,1),zr(1,1,1,1,1)/))
4569 : #endif
4570 :
4571 0 : end subroutine fftw3_mpiforw_wf
4572 : !!***
4573 :
4574 : !----------------------------------------------------------------------
4575 :
4576 : !!****f* m_fftw3/fftw3_mpiback
4577 : !! NAME
4578 : !! fftw3_mpiback
4579 : !!
4580 : !! FUNCTION
4581 : !! CALCULATES THE DISCRETE FOURIER TRANSFORM in parallel using MPI/OpenMP
4582 : !!
4583 : !! ZR(I1,I2,I3)= \sum_(j1,j2,j3) EXP(isign*i*2*pi*(j1*i1/n1+j2*i2/n2+j3*i3/n3)) ZF(j1,j3,j2)
4584 : !!
4585 : !! Adopt standard convention that isign=1 for backward transform
4586 : !!
4587 : !! INPUTS:
4588 : !! option= 1 if call from fourwf, 2 if call from other routine
4589 : !! cplex=1 for real --> complex, 2 for complex --> complex
4590 : !! ZF: input array in G-space (note the switch of i2 and i3)
4591 : !!
4592 : !! real(F(i1,i3,i2,idat))=ZF(1,i1,i3,i2,idat)
4593 : !! imag(F(i1,i3,i2,idat))=ZF(2,i1,i3,i2,idat)
4594 : !!
4595 : !! i1=1,n1 , i2=1,n2 , i3=1,n3 , idat=1,ndat
4596 : !! OUTPUTS:
4597 : !! ZR: output array in R space.
4598 : !!
4599 : !! ZR(1,i1,i2,i3,idat)=real(R(i1,i2,i3,idat))
4600 : !! ZR(2,i1,i2,i3,idat)=imag(R(i1,i2,i3,idat))
4601 : !!
4602 : !! i1=1,n1 , i2=1,n2 , i3=1,n3 , idat=1,ndat
4603 : !!
4604 : !! nproc_fft: number of processors used as returned by MPI_COMM_SIZE
4605 : !! me_fft: [0:nproc_fft-1] number of processor as returned by MPI_COMM_RANK
4606 : !! n1,n2,n3: logical dimension of the transform. As transform lengths
4607 : !! most products of the prime factors 2,3,5 are allowed.
4608 : !! The detailed table with allowed transform lengths can
4609 : !! be found in subroutine CTRIG
4610 : !! nd1,nd2,nd3: Dimension of ZF and ZR
4611 : !! nd2proc=((nd2-1)/nproc_fft)+1 maximal number of 2nd dim slices
4612 : !! nd3proc=((nd3-1)/nproc_fft)+1 maximal number of 3rd dim slices
4613 : !!
4614 : !! NOTES:
4615 : !! The maximum number of processors that can reasonably be used is max(n2,n3)
4616 : !! It is very important to find the optimal
4617 : !! value of NCACHE. NCACHE determines the size of the work array ZW, that
4618 : !! has to fit into cache. It has therefore to be chosen to equal roughly
4619 : !! half the size of the physical cache in units of real*8 numbers.
4620 : !! The optimal value of ncache can easily be determined by numerical
4621 : !! experimentation. A too large value of ncache leads to a dramatic
4622 : !! and sudden decrease of performance, a too small value to a to a
4623 : !! slow and less dramatic decrease of performance. If NCACHE is set
4624 : !! to a value so small, that not even a single one dimensional transform
4625 : !! can be done in the workarray zw, the program stops with an error message.
4626 : !!
4627 : !! SOURCE
4628 :
4629 0 : subroutine fftw3_mpiback(cplex,ndat,n1,n2,n3,nd1,nd2,nd3,nd1eff,nd2proc,nd3proc,option,zf,zr,comm_fft)
4630 :
4631 : !Arguments ------------------------------------
4632 : ! real space input
4633 : integer,intent(in) :: cplex,ndat,n1,n2,n3,nd1,nd2,nd3,nd1eff,nd2proc,nd3proc,option,comm_fft
4634 : real(dp),intent(in) :: zf(2,nd1,nd3,nd2proc,ndat)
4635 : real(dp),intent(out) :: zr(2,nd1eff,nd2,nd3proc,ndat)
4636 :
4637 : !Local variables-------------------------------
4638 : !scalaras
4639 : #ifdef HAVE_FFTW3
4640 : integer :: j,i1,idat,ierr,includelast,j2,j2st,j3,jeff,jp2st,lzt,nthreads
4641 : integer :: ma,mb,n1dfft,n1eff,n2eff,n1zt,ncache,nnd3,nproc_fft,me_fft,lot1,lot2,lot3
4642 : integer(KIND_FFTW_PLAN) :: bw_plan1_lot,bw_plan1_rest
4643 : integer(KIND_FFTW_PLAN) :: bw_plan2_lot,bw_plan2_rest
4644 : integer(KIND_FFTW_PLAN) :: bw_plan3_lot,bw_plan3_rest
4645 : character(len=500) :: msg
4646 : !arrays
4647 : real(dp), allocatable :: zmpi1(:,:,:,:),zmpi2(:,:,:,:) ! work arrays for MPI
4648 : real(dp),allocatable :: zw(:,:),zt(:,:,:) ! cache work array and array for transpositions
4649 : ! *************************************************************************
4650 :
4651 : nproc_fft = xmpi_comm_size(comm_fft); me_fft = xmpi_comm_rank(comm_fft)
4652 :
4653 : ! find cache size that gives optimal performance on machine
4654 : ncache=2*max(n1,n2,n3,1024)
4655 :
4656 : if (ncache/(2*max(n1,n2,n3))<1) then
4657 : write(msg,'(5a)') &
4658 : 'ncache has to be enlarged to be able to hold at',ch10, &
4659 : 'least one 1-d FFT of each size even though this will',ch10,&
4660 : 'reduce the performance for shorter transform lengths'
4661 : ABI_ERROR(msg)
4662 : end if
4663 :
4664 : ! check input
4665 : if (nd1<n1 .or. nd2<n2 .or. nd3<n3) then
4666 : ABI_ERROR("nd1<n1 .or. nd2<n2 .or. nd3<n3")
4667 : end if
4668 :
4669 : ! Effective n1 and n2 (complex-to-complex or real-to-complex)
4670 : n1eff=n1; n2eff=n2; n1zt=n1
4671 : if (cplex==1) then
4672 : n1eff=(n1+1)/2; n2eff=n2/2+1 ; n1zt=2*(n1/2+1)
4673 : end if
4674 :
4675 : lzt=n2eff
4676 : if (mod(n2eff,2) == 0) lzt=lzt+1
4677 : if (mod(n2eff,4) == 0) lzt=lzt+1
4678 :
4679 : ! maximal number of big box 3rd dim slices for all procs
4680 : nnd3=nd3proc*nproc_fft
4681 :
4682 : ABI_MALLOC(zw,(2,ncache/2))
4683 : ABI_MALLOC(zt,(2,lzt,n1zt))
4684 : ABI_MALLOC(zmpi2,(2,n1,nd2proc,nnd3))
4685 : if (nproc_fft>1) then
4686 : ABI_MALLOC(zmpi1,(2,n1,nd2proc,nnd3))
4687 : end if
4688 :
4689 : !DEBUG
4690 : ! write(std_out,'(a,3i4)' )'back,zf n1,n2,n3',n1,n2,n3
4691 : ! write(std_out,'(a,3i4)' )'nd1,nd2,nd3proc',nd1,nd2,nd3proc
4692 : ! write(std_out,'(a,3i4)' )'m1,m2,m3',m1,m2,m3
4693 : ! write(std_out,'(a,3i4)' )'max1,max2,max3',max1,max2,max3
4694 : ! write(std_out,'(a,3i4)' )'md1,md2proc,md3',md1,md2proc,md3
4695 : ! write(std_out,'(a,3i4)' )'n1eff,m2eff,m1zt',n1eff,m2eff,m1zt
4696 : !ENDDEBUG
4697 :
4698 : ! Create plans.
4699 : ! The prototype for sfftw_plan_many_dft is:
4700 : ! sfftw_plan_many_dft(rank, n, howmany,
4701 : ! fin, iembed, istride, idist,
4702 : ! fout, oembed, ostride, odist, isign, my_flags)
4703 :
4704 : lot3=ncache/(2*n3)
4705 : lot1=ncache/(2*n1)
4706 : lot2=ncache/(2*n2)
4707 :
4708 : nthreads = xomp_get_num_threads(open_parallel=.TRUE.)
4709 : !nthreads = 1
4710 :
4711 : bw_plan3_lot = dplan_many_dft_2D(1, [n3], lot3, &
4712 : zw, [ncache/2], lot3, 1, &
4713 : zw, [ncache/2], lot3, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
4714 :
4715 : if (mod(n1, lot3) /= 0) then
4716 : bw_plan3_rest = dplan_many_dft_2D(1, [n3], mod(n1, lot3), &
4717 : zw, [ncache/2], lot3, 1, &
4718 : zw, [ncache/2], lot3, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
4719 : end if
4720 :
4721 : bw_plan1_lot = dplan_many_dft_2D(1, [n1], lot1, &
4722 : zw, [ncache/2], lot1, 1, &
4723 : zt, [lzt, n1zt], lzt, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
4724 :
4725 : if (mod(n2eff, lot1) /= 0) then
4726 : bw_plan1_rest = dplan_many_dft_2D(1, [n1], mod(n2eff, lot1), &
4727 : zw, [ncache/2], lot1, 1, &
4728 : zt, [lzt, n1zt], lzt, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
4729 : end if
4730 :
4731 : bw_plan2_lot = dplan_many_dft_2D(1, [n2], lot2, &
4732 : zw, [ncache/2], lot2, 1, &
4733 : zr, [nd1eff,nd2,nd3proc,ndat], nd1eff, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
4734 :
4735 : if (mod(n1eff, lot2) /= 0) then
4736 : bw_plan2_rest = dplan_many_dft_2D(1, [n2], mod(n1eff,lot2), &
4737 : zw, [ncache/2], lot2, 1, &
4738 : zr, [nd1eff,nd2,nd3proc,ndat], nd1eff, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
4739 : end if
4740 :
4741 : do idat=1,ndat
4742 : ! transform along z axis
4743 : ! input: I1,I3,J2,(Jp2)
4744 :
4745 : do j2=1,nd2proc
4746 : if (me_fft*nd2proc+j2 <= n2eff) then
4747 :
4748 : do i1=1,n1,lot3
4749 : ma=i1
4750 : mb=min(i1+(lot3-1),n1)
4751 : n1dfft=mb-ma+1
4752 :
4753 : ! input: G1,G3,G2,(Gp2)
4754 : ! output: G1,R3,G2,(Gp2)
4755 : call fill(nd1,nd3,lot3,n1dfft,n3,zf(1,i1,1,j2,idat),zw)
4756 :
4757 : if (n1dfft == lot3) then
4758 : call dfftw_execute_dft(bw_plan3_lot, zw, zw)
4759 : else
4760 : call dfftw_execute_dft(bw_plan3_rest, zw, zw)
4761 : end if
4762 :
4763 : ! input: G1,R3,G2,(Gp2)
4764 : ! output: G1,G2,R3,(Gp2)
4765 : call scramble(i1,j2,lot3,n1dfft,n1,n3,nd2proc,nd3,zw,zmpi2)
4766 : end do
4767 : end if
4768 : end do
4769 :
4770 : ! Interprocessor data transposition
4771 : ! input: G1,G2,R3,Rp3,(Gp2)
4772 : ! output: G1,G2,G3,Gp2,(Rp3)
4773 : if (nproc_fft>1) then
4774 : call xmpi_alltoall(zmpi2,2*n1*nd2proc*nd3proc, &
4775 : zmpi1,2*n1*nd2proc*nd3proc,comm_fft,ierr)
4776 : end if
4777 :
4778 : do j3=1,nd3proc
4779 : if (me_fft*nd3proc+j3 <= n3) then
4780 : Jp2st=1; J2st=1
4781 :
4782 : ! transform along x axis
4783 : do j=1,n2eff,lot1
4784 : ma=j
4785 : mb=min(j+(lot1-1),n2eff)
4786 : n1dfft=mb-ma+1
4787 :
4788 : ! input: G1,G2,R3,Gp2,(Rp3)
4789 : ! output: G2,G1,R3,Jp2,(Rp3)
4790 : if (nproc_fft == 1) then
4791 : call mpiswitch(j3,n1dfft,Jp2st,J2st,lot1,n1,nd2proc,nd3proc,nproc_fft,option,zmpi2,zw)
4792 : else
4793 : call mpiswitch(j3,n1dfft,Jp2st,J2st,lot1,n1,nd2proc,nd3proc,nproc_fft,option,zmpi1,zw)
4794 : end if
4795 :
4796 : ! input: G2,G1,R3,(Rp3)
4797 : ! output: G2,R1,R3,(Rp3)
4798 : if (n1dfft == lot1) then
4799 : call dfftw_execute_dft(bw_plan1_lot, zw, zt(1,j,1))
4800 : else
4801 : call dfftw_execute_dft(bw_plan1_rest, zw, zt(1,j,1))
4802 : end if
4803 :
4804 : end do
4805 :
4806 : ! transform along y axis
4807 : do j=1,n1eff,lot2
4808 : ma=j
4809 : mb=min(j+(lot2-1),n1eff)
4810 : n1dfft=mb-ma+1
4811 : includelast=1
4812 : if (cplex==1) then
4813 : jeff=2*j-1
4814 : includelast=1
4815 : if (mb==n1eff .and. n1eff*2/=n1) includelast=0
4816 : end if
4817 :
4818 : ! input: G2,R1,R3,(Rp3)
4819 : ! output: R1,G2,R3,(Rp3)
4820 : if (cplex==2) then
4821 : call switch(n1dfft,n2,lot2,n1,lzt,zt(1,1,j),zw)
4822 : else
4823 : call switchreal(includelast,n1dfft,n2,n2eff,lot2,n1zt,lzt,zt(1,1,jeff),zw)
4824 : end if
4825 :
4826 : if (n1dfft == lot2) then
4827 : call dfftw_execute_dft(bw_plan2_lot, zw, zr(1,j,1,j3,idat))
4828 : else
4829 : call dfftw_execute_dft(bw_plan2_rest, zw, zr(1,j,1,j3,idat))
4830 : end if
4831 : end do
4832 : ! output: R1,R2,R3,(Rp3)
4833 :
4834 : end if
4835 : end do
4836 : end do ! idat
4837 :
4838 : call dfftw_destroy_plan(bw_plan3_lot)
4839 : if (mod(n1, lot3) /= 0) call dfftw_destroy_plan(bw_plan3_rest)
4840 :
4841 : call dfftw_destroy_plan(bw_plan1_lot)
4842 : if (mod(n2eff, lot1) /= 0) call dfftw_destroy_plan(bw_plan1_rest)
4843 :
4844 : call dfftw_destroy_plan(bw_plan2_lot)
4845 : if (mod(n1eff, lot2) /= 0) call dfftw_destroy_plan(bw_plan2_rest)
4846 :
4847 : ABI_FREE(zmpi2)
4848 : ABI_FREE(zw)
4849 : ABI_FREE(zt)
4850 : if (nproc_fft>1) then
4851 : ABI_FREE(zmpi1)
4852 : end if
4853 :
4854 : #else
4855 0 : ABI_ERROR("FFTW3 support not activated")
4856 : ABI_UNUSED((/cplex,ndat,n1,n2,n3,nd1,nd2,nd1eff,nd2proc,nd3proc,option,comm_fft/))
4857 : ABI_UNUSED((/zf(1,1,1,1,1),zr(1,1,1,1,1)/))
4858 : #endif
4859 :
4860 0 : end subroutine fftw3_mpiback
4861 : !!***
4862 :
4863 : !----------------------------------------------------------------------
4864 :
4865 : !!****f* m_fftw3/fftw3_mpiforw
4866 : !! NAME
4867 : !! fftw3_mpiforw
4868 : !!
4869 : !! FUNCTION
4870 : !! Adopt standard convention that isign=-1 for forward transform
4871 : !! CALCULATES THE DISCRETE FOURIERTRANSFORM ZF(I1,I3,I2)=
4872 : !! S_(j1,j2,j3) EXP(isign*i*2*pi*(j1*i1/n1+j2*i2/n2+j3*i3/n3)) ZR(j1,j2,j3)
4873 : !! in parallel using MPI/OpenMP and BLAS library calls.
4874 : !!
4875 : !! INPUTS
4876 : !! ZR: input array
4877 : !! ZR(1,i1,i2,i3,idat)=real(R(i1,i2,i3,idat))
4878 : !! ZR(2,i1,i2,i3,idat)=imag(R(i1,i2,i3,idat))
4879 : !! i1=1,n1 , i2=1,n2 , i3=1,n3 , idat=1,ndat
4880 : !! OUTPUTS
4881 : !! ZF: output array (note the switch of i2 and i3)
4882 : !! real(F(i1,i3,i2,idat))=ZF(1,i1,i3,i2,idat)
4883 : !! imag(F(i1,i3,i2,idat))=ZF(2,i1,i3,i2,idat)
4884 : !! i1=1,n1 , i2=1,n2 , i3=1,n3 , idat=1,ndat
4885 : !! nproc_fft: number of processors used as returned by MPI_COMM_SIZE
4886 : !! me_fft: [0:nproc_fft-1] number of processor as returned by MPI_COMM_RANK
4887 : !! n1,n2,n3: logical dimension of the transform. As transform lengths
4888 : !! most products of the prime factors 2,3,5 are allowed.
4889 : !! The detailed table with allowed transform lengths can
4890 : !! be found in subroutine CTRIG
4891 : !! nd1,nd2,nd3: Dimension of ZR and ZF
4892 : !! nd2proc=((nd2-1)/nproc_fft)+1 maximal number of 2nd dim slices
4893 : !! nd3proc=((nd3-1)/nproc_fft)+1 maximal number of 3rd dim slices
4894 : !!
4895 : !! NOTES
4896 : !! SHOULD describe nd1eff
4897 : !! SHOULD put cplex and nd1eff in OMP declarations
4898 : !! SHOULD describe the change of value of nd2prod
4899 : !!
4900 : !! The maximum number of processors that can reasonably be used is max(n2,n3)
4901 : !!
4902 : !! It is very important to find the optimal
4903 : !! value of NCACHE. NCACHE determines the size of the work array ZW, that
4904 : !! has to fit into cache. It has therefore to be chosen to equal roughly
4905 : !! half the size of the physical cache in units of real*8 numbers.
4906 : !! The optimal value of ncache can easily be determined by numerical
4907 : !! experimentation. A too large value of ncache leads to a dramatic
4908 : !! and sudden decrease of performance, a too small value to a to a
4909 : !! slow and less dramatic decrease of performance. If NCACHE is set
4910 : !! to a value so small, that not even a single one dimensional transform
4911 : !! can be done in the workarray zw, the program stops with an error message.
4912 : !!
4913 : !! SOURCE
4914 :
4915 0 : subroutine fftw3_mpiforw(cplex,ndat,n1,n2,n3,nd1,nd2,nd3,nd1eff,nd2proc,nd3proc,option,zr,zf,comm_fft)
4916 :
4917 : !Arguments ------------------------------------
4918 : !scalars
4919 : integer,intent(in) :: cplex,comm_fft
4920 : integer,intent(in) :: ndat,n1,n2,n3,nd1,nd2,nd3,nd1eff,nd2proc,nd3proc,option
4921 : !arrays
4922 : real(dp),intent(in) :: zr(2,nd1eff,nd2,nd3proc,ndat)
4923 : real(dp),intent(out) :: zf(2,nd1,nd3,nd2proc,ndat)
4924 :
4925 : !Local variables-------------------------------
4926 : !scalars
4927 : #ifdef HAVE_FFTW3
4928 : integer :: j,i1,idat,ierr,j2,j2st,j3,jp2st,lzt,nthreads
4929 : integer :: ma,mb,n1dfft,n1eff,n2eff,n1zt,ncache,nnd3,nproc_fft,me_fft,lot1,lot2,lot3
4930 : integer(KIND_FFTW_PLAN) :: fw_plan1_lot,fw_plan1_rest
4931 : integer(KIND_FFTW_PLAN) :: fw_plan2_lot,fw_plan2_rest
4932 : integer(KIND_FFTW_PLAN) :: fw_plan3_lot,fw_plan3_rest
4933 : character(len=500) :: msg
4934 : !arrays
4935 : real(dp), allocatable :: zmpi1(:,:,:,:),zmpi2(:,:,:,:) ! work arrays for MPI
4936 : real(dp),allocatable :: zw(:,:),zt(:,:,:) ! cache work array and array for transpositions
4937 : ! *************************************************************************
4938 :
4939 : nproc_fft = xmpi_comm_size(comm_fft); me_fft = xmpi_comm_rank(comm_fft)
4940 :
4941 : ! find cache size that gives optimal performance on machine
4942 : ncache=2*max(n1,n2,n3,1024)
4943 : if (ncache/(2*max(n1,n2,n3))<1) then
4944 : write(msg,'(5a)')&
4945 : 'ncache has to be enlarged to be able to hold at',ch10, &
4946 : 'least one 1-d FFT of each size even though this will',ch10,&
4947 : 'reduce the performance for shorter transform lengths'
4948 : ABI_ERROR(msg)
4949 : end if
4950 :
4951 : ! check input
4952 : if (nd1<n1 .or. nd2<n2 .or. nd3<n3) then
4953 : ABI_ERROR("forw: assertion error nd1<n1 .or. nd2<n2 .or. nd3<n3")
4954 : end if
4955 :
4956 : !Effective n1 and n2 (complex-to-complex or real-to-complex)
4957 : n1eff=n1; n2eff=n2; n1zt=n1
4958 : if (cplex==1) then
4959 : n1eff=(n1+1)/2; n2eff=n2/2+1; n1zt=2*(n1/2+1)
4960 : end if
4961 :
4962 : lzt=n2eff
4963 : if (mod(n2eff,2) == 0) lzt=lzt+1
4964 : if (mod(n2eff,4) == 0) lzt=lzt+1
4965 :
4966 : ! maximal number of big box 3rd dim slices for all procs
4967 : nnd3=nd3proc*nproc_fft
4968 :
4969 : ABI_MALLOC(zw,(2,ncache/2))
4970 : ABI_MALLOC(zt,(2,lzt,n1zt))
4971 : ABI_MALLOC(zmpi2,(2,n1,nd2proc,nnd3))
4972 : if (nproc_fft>1) then
4973 : ABI_MALLOC(zmpi1,(2,n1,nd2proc,nnd3))
4974 : end if
4975 :
4976 : ! Create plans.
4977 : ! The prototype for sfftw_plan_many_dft is:
4978 : ! sfftw_plan_many_dft(rank, n, howmany,
4979 : ! fin, iembed, istride, idist,
4980 : ! fout, oembed, ostride, odist, isign, my_flags)
4981 :
4982 : lot1=ncache/(2*n1)
4983 : lot2=ncache/(2*n2)
4984 : lot3=ncache/(2*n3)
4985 :
4986 : nthreads = xomp_get_num_threads(open_parallel=.TRUE.)
4987 : !nthreads = 1
4988 :
4989 : fw_plan3_lot = dplan_many_dft_2D(1, [n3], lot3, &
4990 : zw, [ncache/2], lot3, 1, &
4991 : zw, [ncache/2], lot3, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
4992 :
4993 : if (mod(n1, lot3) /= 0) then
4994 : fw_plan3_rest = dplan_many_dft_2D(1, [n3], mod(n1, lot3), &
4995 : zw, [ncache/2], lot3, 1, &
4996 : zw, [ncache/2], lot3, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
4997 : end if
4998 :
4999 : fw_plan1_lot = dplan_many_dft_2D(1, [n1], lot1, &
5000 : zt, [lzt, n1zt], lzt, 1, &
5001 : zw, [ncache/2], lot1, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
5002 :
5003 : if (mod(n2eff, lot1) /= 0) then
5004 : fw_plan1_rest = dplan_many_dft_2D(1, [n1], mod(n2eff, lot1), &
5005 : zt, [lzt, n1zt], lzt, 1, &
5006 : zw, [ncache/2], lot1, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
5007 : end if
5008 :
5009 : fw_plan2_lot = dplan_many_dft_2D(1, [n2], lot2, &
5010 : zr, [nd1eff,nd2,nd3proc,ndat], nd1eff, 1, &
5011 : zw, [ncache/2], lot2, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
5012 :
5013 : if (mod(n1eff, lot2) /= 0) then
5014 : fw_plan2_rest = dplan_many_dft_2D(1, [n2], mod(n1eff,lot2), &
5015 : zr, [nd1eff,nd2,nd3proc,ndat], nd1eff, 1, &
5016 : zw, [ncache/2], lot2, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
5017 : end if
5018 :
5019 : do idat=1,ndat
5020 :
5021 : do j3=1,nd3proc
5022 : if (me_fft*(nd3proc)+j3 <= n3) then
5023 : Jp2st=1; J2st=1
5024 :
5025 : ! transform along y axis
5026 : ! input: R1,R2,R3,(Rp3)
5027 : do j=1,n1eff,lot2
5028 : ma=j
5029 : mb=min(j+(lot2-1),n1eff)
5030 : n1dfft=mb-ma+1
5031 :
5032 : if (n1dfft == lot2) then
5033 : call dfftw_execute_dft(fw_plan2_lot, zr(1,j,1,j3,idat), zw)
5034 : else
5035 : call dfftw_execute_dft(fw_plan2_rest, zr(1,j,1,j3,idat), zw)
5036 : end if
5037 :
5038 : ! input: R1,G2,R3,(Rp3)
5039 : ! output: G2,R1,R3,(Rp3)
5040 : if (cplex==2) then
5041 : call unswitch(n1dfft,n2,lot2,n1zt,lzt,zw,zt(1,1,j))
5042 : else
5043 : call unswitchreal(n1dfft,n2,n2eff,lot2,n1zt,lzt,zw,zt(1,1,2*j-1))
5044 : end if
5045 : end do
5046 :
5047 : ! transform along x axis
5048 : ! input: G2,R1,R3,(Rp3)
5049 : do j=1,n2eff,lot1
5050 : ma=j
5051 : mb=min(j+(lot1-1),n2eff)
5052 : n1dfft=mb-ma+1
5053 :
5054 : if (n1dfft == lot1) then
5055 : call dfftw_execute_dft(fw_plan1_lot, zt(1,j,1), zw)
5056 : else
5057 : call dfftw_execute_dft(fw_plan1_rest, zt(1,j,1), zw)
5058 : end if
5059 :
5060 : ! input: G2,G1,R3,Gp2,(Rp3)
5061 : ! output: G1,G2,R3,Gp2,(Rp3)
5062 : ! write(std_out,*) 'J2st,Jp2st',J2st,Jp2st
5063 : if (nproc_fft == 1) then
5064 : call unmpiswitch(j3,n1dfft,Jp2st,J2st,lot1,n1,nd2proc,nd3proc,nproc_fft,option,zw,zmpi2)
5065 : else
5066 : call unmpiswitch(j3,n1dfft,Jp2st,J2st,lot1,n1,nd2proc,nd3proc,nproc_fft,option,zw,zmpi1)
5067 : end if
5068 : end do
5069 :
5070 : end if
5071 : end do ! j3
5072 :
5073 : ! Interprocessor data transposition
5074 : ! input: G1,G2,R3,Gp2,(Rp3)
5075 : ! output: G1,G2,R3,Rp3,(Gp2)
5076 : if (nproc_fft>1) then
5077 : call xmpi_alltoall(zmpi1,2*n1*nd2proc*nd3proc, &
5078 : zmpi2,2*n1*nd2proc*nd3proc,comm_fft,ierr)
5079 : end if
5080 :
5081 : ! transform along z axis
5082 : ! input: G1,G2,R3,(Gp2)
5083 :
5084 : do j2=1,nd2proc
5085 : if (me_fft*(nd2proc)+j2 <= n2eff) then
5086 : do i1=1,n1,lot3
5087 : ma=i1
5088 : mb=min(i1+(lot3-1),n1)
5089 : n1dfft=mb-ma+1
5090 :
5091 : ! input: G1,G2,R3,(Gp2)
5092 : ! output: G1,R3,G2,(Gp2)
5093 : call unscramble(i1,j2,lot3,n1dfft,n1,n3,nd2proc,nd3,zmpi2,zw)
5094 :
5095 : if (n1dfft == lot3) then
5096 : call dfftw_execute_dft(fw_plan3_lot, zw, zw)
5097 : else
5098 : call dfftw_execute_dft(fw_plan3_rest, zw, zw)
5099 : end if
5100 :
5101 : call unfill(nd1,nd3,lot3,n1dfft,n3,zw,zf(1,i1,1,j2,idat))
5102 : ! output: G1,G3,G2,(Gp2)
5103 : end do
5104 : end if
5105 : end do
5106 :
5107 : end do ! idat
5108 :
5109 : call dfftw_destroy_plan(fw_plan3_lot)
5110 : if (mod(n1, lot3) /= 0) call dfftw_destroy_plan(fw_plan3_rest)
5111 :
5112 : call dfftw_destroy_plan(fw_plan1_lot)
5113 : if (mod(n2eff, lot1) /= 0) call dfftw_destroy_plan(fw_plan1_rest)
5114 :
5115 : call dfftw_destroy_plan(fw_plan2_lot)
5116 : if (mod(n1eff, lot2) /= 0) call dfftw_destroy_plan(fw_plan2_rest)
5117 :
5118 : ABI_FREE(zmpi2)
5119 : ABI_FREE(zw)
5120 : ABI_FREE(zt)
5121 : if (nproc_fft>1) then
5122 : ABI_FREE(zmpi1)
5123 : end if
5124 :
5125 : #else
5126 0 : ABI_ERROR("FFTW3 support not activated")
5127 : ABI_UNUSED((/cplex,ndat,n1,n2,n3,nd1,nd2,nd1eff,nd2proc,nd3proc,option,comm_fft/))
5128 : ABI_UNUSED((/zf(1,1,1,1,1),zr(1,1,1,1,1)/))
5129 : #endif
5130 :
5131 0 : end subroutine fftw3_mpiforw
5132 : !!***
5133 :
5134 : !----------------------------------------------------------------------
5135 :
5136 : !!****f* m_m_fftw3/fftw3_mpifourdp
5137 : !! NAME
5138 : !! fftw3_mpifourdp
5139 : !!
5140 : !! FUNCTION
5141 : !! Conduct Fourier transform of REAL or COMPLEX function f(r)=fofr defined on
5142 : !! fft grid in real space, to create complex f(G)=fofg defined on full fft grid
5143 : !! in reciprocal space, in full storage mode, or the reverse operation.
5144 : !! For the reverse operation, the final data is divided by nfftot.
5145 : !! REAL case when cplex=1, COMPLEX case when cplex=2
5146 : !! Usually used for density and potentials.
5147 : !!
5148 : !! INPUTS
5149 : !! cplex=1 if fofr is real, 2 if fofr is complex
5150 : !! nfft=(effective) number of FFT grid points (for this processor)
5151 : !! ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
5152 : !! ndat=Number of FFT transforms
5153 : !! isign=sign of Fourier transform exponent: current convention uses
5154 : !! +1 for transforming from G to r
5155 : !! -1 for transforming from r to G.
5156 : !! fftn2_distrib(2),ffti2_local(2)
5157 : !! fftn3_distrib(3),ffti3_local(3)
5158 : !! comm_fft=MPI communicator
5159 : !!
5160 : !! SIDE EFFECTS
5161 : !! Input/Output
5162 : !! fofg(2,nfft)=f(G), complex.
5163 : !! fofr(cplex*nfft)=input function f(r) (real or complex)
5164 : !!
5165 : !! SOURCE
5166 :
5167 0 : subroutine fftw3_mpifourdp(cplex,nfft,ngfft,ndat,isign,&
5168 0 : fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local,fofg,fofr,comm_fft)
5169 :
5170 : !Arguments ------------------------------------
5171 : !scalars
5172 : integer,intent(in) :: cplex,isign,nfft,ndat,comm_fft
5173 : !arrays
5174 : integer,intent(in) :: ngfft(18)
5175 : integer,intent(in) :: fftn2_distrib(ngfft(2)),ffti2_local(ngfft(2))
5176 : integer,intent(in) :: fftn3_distrib(ngfft(3)),ffti3_local(ngfft(3))
5177 : real(dp),intent(inout) :: fofg(2,nfft*ndat),fofr(cplex*nfft*ndat)
5178 :
5179 : !Local variables-------------------------------
5180 : !scalars
5181 : integer :: n1,n2,n3,n4,n5,n6,nd2proc,nd3proc,nproc_fft,me_fft
5182 : !arrays
5183 0 : real(dp),allocatable :: workf(:,:,:,:,:),workr(:,:,:,:,:)
5184 : ! *************************************************************************
5185 :
5186 : ! Note the only c2c is supported in parallel.
5187 0 : n1=ngfft(1); n2=ngfft(2); n3=ngfft(3)
5188 0 : n4=ngfft(4); n5=ngfft(5); n6=ngfft(6)
5189 0 : me_fft=ngfft(11); nproc_fft=ngfft(10)
5190 :
5191 0 : nd2proc=((n2-1)/nproc_fft) +1
5192 0 : nd3proc=((n6-1)/nproc_fft) +1
5193 0 : ABI_MALLOC(workr,(2,n4,n5,nd3proc,ndat))
5194 0 : ABI_MALLOC(workf,(2,n4,n6,nd2proc,ndat))
5195 :
5196 : ! Complex to Complex
5197 : ! TODO: Complex to Real
5198 0 : select case (isign)
5199 : case (1)
5200 : ! G --> R
5201 0 : call mpifft_fg2dbox(nfft,ndat,fofg,n1,n2,n3,n4,nd2proc,n6,fftn2_distrib,ffti2_local,me_fft,workf)
5202 :
5203 0 : call fftw3_mpiback(2,ndat,n1,n2,n3,n4,n5,n6,n4,nd2proc,nd3proc,2,workf,workr,comm_fft)
5204 :
5205 0 : call mpifft_dbox2fr(n1,n2,n3,n4,n5,nd3proc,ndat,fftn3_distrib,ffti3_local,me_fft,workr,cplex,nfft,fofr)
5206 :
5207 : case (-1)
5208 : ! R --> G
5209 0 : call mpifft_fr2dbox(cplex,nfft,ndat,fofr,n1,n2,n3,n4,n5,nd3proc,fftn3_distrib,ffti3_local,me_fft,workr)
5210 :
5211 0 : call fftw3_mpiforw(2,ndat,n1,n2,n3,n4,n5,n6,n4,nd2proc,nd3proc,2,workr,workf,comm_fft)
5212 :
5213 : ! Transfer FFT output to the original fft box.
5214 0 : call mpifft_dbox2fg(n1,n2,n3,n4,nd2proc,n6,ndat,fftn2_distrib,ffti2_local,me_fft,workf,nfft,fofg)
5215 :
5216 : case default
5217 0 : ABI_BUG("Wrong isign")
5218 : end select
5219 :
5220 0 : ABI_FREE(workr)
5221 0 : ABI_FREE(workf)
5222 :
5223 0 : end subroutine fftw3_mpifourdp
5224 : !!***
5225 :
5226 : !----------------------------------------------------------------------
5227 :
5228 : !!****f* m_fftw3/fftw3_applypot
5229 : !! NAME
5230 : !! fftw3_applypot
5231 : !!
5232 : !! FUNCTION
5233 : !! Applies the local real space potential to multiple wavefunctions in Fourier space
5234 : !!
5235 : !! INPUTS
5236 : !! ZF: Wavefunction (input/output) (note the switch of i2 and i3)
5237 : !! real(F(i1,i3,i2,idat))=ZF(1,i1,i3,i2,idat)
5238 : !! imag(F(i1,i3,i2,idat))=ZF(2,i1,i3,i2,idat)
5239 : !! max1 is positive or zero ; m1 >=max1+1
5240 : !! i1= 1... max1+1 corresponds to positive and zero wavevectors 0 ... max1
5241 : !! then, if m1 > max1+1, one has min1=max1-m1+1 and
5242 : !! i1= max1+2 ... m1 corresponds to negative wavevectors min1 ... -1
5243 : !! i2 and i3 have a similar definition of range
5244 : !! idat=1,ndat
5245 : !! md1,md2,md3: Dimension of ZF (input as well as output), distributed on different procs
5246 : !! md2proc=((md2-1)/nproc_fft)+1 maximal number of small box 2nd dim slices for one proc
5247 : !!
5248 : !! POT: Potential
5249 : !! POT(cplex*i1,i2,i3)
5250 : !! cplex=1 or 2 , i1=1,n1 , i2=1,n2 , i3=1,n3
5251 : !! nd1,nd2,nd3: dimension of pot
5252 : !! comm_fft: MPI communicator
5253 : !! nproc_fft: number of processors used as returned by MPI_COMM_SIZE
5254 : !! me_fft: [0:nproc_fft-1] number of processor as returned by MPI_COMM_RANK
5255 : !! n1,n2,n3: logical dimension of the transform. As transform lengths
5256 : !! most products of the prime factors 2,3,5 are allowed.
5257 : !! The detailed table with allowed transform lengths can
5258 : !! be found in subroutine CTRIG
5259 : !!
5260 : !! NOTES:
5261 : !! PERFORMANCE CONSIDERATIONS:
5262 : !! The maximum number of processors that can reasonably be used is max(n2/2,n3/2)
5263 : !!
5264 : !! It is very important to find the optimal
5265 : !! value of NCACHE. NCACHE determines the size of the work array ZW, that
5266 : !! has to fit into cache. It has therefore to be chosen to equal roughly
5267 : !! half the size of the physical cache in units of real*8 numbers.
5268 : !! The optimal value of ncache can easily be determined by numerical
5269 : !! experimentation. A too large value of ncache leads to a dramatic
5270 : !! and sudden decrease of performance, a too small value to a to a
5271 : !! slow and less dramatic decrease of performance. If NCACHE is set
5272 : !! to a value so small, that not even a single one dimensional transform
5273 : !! can be done in the workarray zw, the program stops with an error message.
5274 : !!
5275 : !! SOURCE
5276 :
5277 :
5278 0 : subroutine fftw3_applypot(cplexwf,cplex,ndat,n1,n2,n3,nd1,nd2,nd3,nd3proc,&
5279 : & max1i,max2i,max3i,m1i,m2i,m3i,md1,md2proc,md3,&
5280 0 : & max1o,max2o,max3o,m1o,m2o,m3o,comm_fft,nproc_fft,me_fft,pot,zf)
5281 :
5282 : !Arguments ------------------------------------
5283 : integer,intent(in) :: cplexwf,cplex,ndat,n1,n2,n3,nd1,nd2,nd3,nd3proc
5284 : integer,intent(in) :: max1i,max2i,max3i,m1i,m2i,m3i,md1,md2proc,md3
5285 : integer,intent(in) :: max1o,max2o,max3o,m1o,m2o,m3o,comm_fft,nproc_fft,me_fft
5286 : real(dp),intent(in) :: pot(cplex*nd1,nd2,nd3)
5287 : real(dp),intent(inout) :: zf(2,md1,md3,md2proc,ndat)
5288 :
5289 : !Local variables-------------------------------
5290 : !scalars
5291 : #ifdef HAVE_FFTW3
5292 : integer,parameter :: unused0=0
5293 : integer :: j,i1,i2,i3,idat,ierr,j3glob,nthreads
5294 : integer :: ioption,j2,j3,lzt,m1zt,ma,mb,n1dfft,nnd3,lot1,lot2,lot3
5295 : integer :: m2eff,ncache,n1eff,i1inv,i2inv,i3inv,jeff,includelast,j2stb
5296 : integer :: jx,j2stf,Jp2stb,Jp2stf,m2ieff,m2oeff
5297 : integer(KIND_FFTW_PLAN) :: bw_plan1_lot,bw_plan1_rest
5298 : integer(KIND_FFTW_PLAN) :: bw_plan2_lot,bw_plan2_rest
5299 : integer(KIND_FFTW_PLAN) :: bw_plan3_lot,bw_plan3_rest
5300 : integer(KIND_FFTW_PLAN) :: fw_plan1_lot,fw_plan1_rest
5301 : integer(KIND_FFTW_PLAN) :: fw_plan2_lot,fw_plan2_rest
5302 : integer(KIND_FFTW_PLAN) :: fw_plan3_lot,fw_plan3_rest
5303 : character(len=500) :: msg
5304 : !arrays
5305 : real(dp) :: tsec(2)
5306 : real(dp), allocatable :: zmpi1(:,:,:,:),zmpi2(:,:,:,:) ! work arrays for MPI
5307 : real(dp),allocatable :: zw(:,:),zt(:,:,:) ! cache work array and array for transpositions
5308 : ! FFT work arrays
5309 : ! *************************************************************************
5310 :
5311 : !ioption=0 ! This was in the old version.
5312 : ioption=1 ! This one is needed to be compatible with paral_kgb
5313 :
5314 : ncache=2*max(n1,n2,n3,1024)
5315 : if (ncache/(2*max(n1,n2,n3)) < 1) then
5316 : write(msg,"(5a)") &
5317 : 'ncache has to be enlarged to be able to hold at',ch10,&
5318 : 'least one 1-d FFT of each size even though this will',ch10,&
5319 : 'reduce the performance for shorter transform lengths'
5320 : ABI_ERROR(msg)
5321 : end if
5322 :
5323 : !call wrtout(std_out,"applypot standard ALLTOALL + FFTW3")
5324 :
5325 : ! Effective m1 and m2 (complex-to-complex or real-to-complex)
5326 : n1eff=n1; m2ieff=m2i; m2oeff=m2o; m1zt=n1
5327 : if (cplexwf==1) then
5328 : n1eff=(n1+1)/2; m2ieff=m2i/2+1; m2oeff=m2o/2+1; m1zt=2*(n1/2+1)
5329 : end if
5330 :
5331 : m2eff=max(m2ieff,m2oeff)
5332 : lzt=m2eff
5333 : if (mod(m2eff,2) == 0) lzt=lzt+1
5334 : if (mod(m2eff,4) == 0) lzt=lzt+1
5335 :
5336 : ! maximal number of big box 3rd dim slices for all procs
5337 : nnd3=nd3proc*nproc_fft
5338 :
5339 : ABI_MALLOC(zw,(2,ncache/2))
5340 : ABI_MALLOC(zt,(2,lzt,m1zt))
5341 : ABI_MALLOC(zmpi2,(2,md1,md2proc,nnd3))
5342 : if (nproc_fft > 1) then
5343 : ABI_MALLOC(zmpi1,(2,md1,md2proc,nnd3))
5344 : end if
5345 :
5346 : lot3=ncache/(2*n3)
5347 : lot1=ncache/(2*n1)
5348 : lot2=ncache/(2*n2)
5349 :
5350 : ! The prototype for sfftw_plan_many_dft is:
5351 : ! sfftw_plan_many_dft(rank, n, howmany,
5352 : ! fin, iembed, istride, idist,
5353 : ! fout, oembed, ostride, odist, isign, my_flags)
5354 :
5355 : nthreads = xomp_get_num_threads(open_parallel=.TRUE.)
5356 : !nthreads = 1
5357 :
5358 : ! Create plans for G --> R (see back_wf)
5359 : bw_plan3_lot = dplan_many_dft_2D(1, [n3], lot3, &
5360 : zw, [ncache/2], lot3, 1, &
5361 : zw, [ncache/2], lot3, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
5362 :
5363 : if (mod(m1i, lot3) /= 0) then
5364 : bw_plan3_rest = dplan_many_dft_2D(1, [n3], mod(m1i, lot3),&
5365 : zw, [ncache/2], lot3, 1, &
5366 : zw, [ncache/2], lot3, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
5367 : end if
5368 :
5369 : bw_plan1_lot = dplan_many_dft_2D(1, [n1], lot1, &
5370 : zw, [ncache/2], lot1, 1, &
5371 : zt, [lzt, m1zt], lzt, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
5372 :
5373 : if (mod(m2ieff, lot1) /= 0) then
5374 : bw_plan1_rest = dplan_many_dft_2D(1, [n1], mod(m2ieff, lot1), &
5375 : zw, [ncache/2], lot1, 1, &
5376 : zt, [lzt, m1zt], lzt, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
5377 : end if
5378 :
5379 : !TODO this won't work if iclexwf==1
5380 : ! Recheck this
5381 : bw_plan2_lot = dplan_many_dft_2D(1, [n2], lot2, &
5382 : zw, [ncache/2], lot2, 1, &
5383 : zw, [ncache/2], lot2, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
5384 :
5385 : if (mod(n1eff, lot2) /= 0) then
5386 : bw_plan2_rest = dplan_many_dft_2D(1, [n2], mod(n1eff,lot2), &
5387 : zw, [ncache/2], lot2, 1, &
5388 : zw, [ncache/2], lot2, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
5389 : end if
5390 :
5391 : ! Create plans for G --> R (see forw_wf)
5392 : fw_plan3_lot = dplan_many_dft_2D(1, [n3], lot3, &
5393 : zw, [ncache/2], lot3, 1, &
5394 : zw, [ncache/2], lot3, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
5395 :
5396 : if (mod(m1o, lot3) /= 0) then
5397 : fw_plan3_rest = dplan_many_dft_2D(1, [n3], mod(m1o, lot3),&
5398 : zw, [ncache/2], lot3, 1, &
5399 : zw, [ncache/2], lot3, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
5400 : end if
5401 :
5402 : fw_plan1_lot = dplan_many_dft_2D(1, [n1], lot1,&
5403 : zt, [lzt, m1zt], lzt, 1, &
5404 : zw, [ncache/2], lot1, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
5405 :
5406 : if (mod(m2oeff, lot1) /= 0) then
5407 : fw_plan1_rest = dplan_many_dft_2D(1, [n1], mod(m2oeff, lot1),&
5408 : zt, [lzt, m1zt], lzt, 1, &
5409 : zw, [ncache/2], lot1, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
5410 : end if
5411 :
5412 : fw_plan2_lot = dplan_many_dft_2D(1, [n2], lot2,&
5413 : zw, [ncache/2], lot2, 1, &
5414 : zw, [ncache/2], lot2, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
5415 :
5416 : if (mod(n1eff, lot2) /= 0) then
5417 : fw_plan2_rest = dplan_many_dft_2D(1, [n2], mod(n1eff,lot2),&
5418 : zw, [ncache/2], lot2, 1, &
5419 : zw, [ncache/2], lot2, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
5420 : end if
5421 :
5422 : do idat=1,ndat
5423 : !
5424 : ! transform along z axis
5425 : ! input: G1,G3,G2,(Gp2)
5426 : do j2=1,md2proc
5427 : if (me_fft*md2proc+j2 <= m2ieff) then
5428 : do i1=1,m1i,lot3
5429 : ma=i1
5430 : mb=min(i1+(lot3-1),m1i)
5431 : n1dfft=mb-ma+1
5432 :
5433 : ! zero-pad n1dfft G_z lines
5434 : ! input: G1,G3,G2,(Gp2)
5435 : call fill_cent(md1,md3,lot3,n1dfft,max3i,m3i,n3,zf(1,i1,1,j2,idat),zw)
5436 :
5437 : if (n1dfft == lot3) then
5438 : call dfftw_execute_dft(bw_plan3_lot, zw, zw)
5439 : else
5440 : call dfftw_execute_dft(bw_plan3_rest, zw, zw)
5441 : end if
5442 :
5443 : ! Local rotation.
5444 : ! input: G1,R3,G2,(Gp2)
5445 : ! output: G1,G2,R3,(Gp2)
5446 : call scramble(i1,j2,lot3,n1dfft,md1,n3,md2proc,nnd3,zw,zmpi2)
5447 : end do
5448 : end if
5449 : end do
5450 :
5451 : ! Interprocessor data transposition
5452 : ! input: G1,G2,R3,Rp3,(Gp2)
5453 : ! output: G1,G2,R3,Gp2,(Rp3)
5454 : if (nproc_fft > 1) then
5455 : call timab(543,1,tsec)
5456 : call xmpi_alltoall(zmpi2,2*md1*md2proc*nd3proc,&
5457 : zmpi1,2*md1*md2proc*nd3proc,comm_fft,ierr)
5458 : call timab(543,2,tsec)
5459 : end if
5460 :
5461 : do j3=1,nd3proc
5462 : j3glob = j3 + me_fft*nd3proc
5463 : if (me_fft*nd3proc+j3 <= n3) then
5464 : Jp2stb=1; J2stb=1
5465 : Jp2stf=1; J2stf=1
5466 :
5467 : ! transform along x axis
5468 : do j=1,m2ieff,lot1
5469 : ma=j
5470 : mb=min(j+(lot1-1),m2ieff)
5471 : n1dfft=mb-ma+1
5472 :
5473 : ! Zero-pad input.
5474 : ! input: G1,G2,R3,G2,(Rp3)
5475 : ! output: G2,G1,R3,G2,(Rp3)
5476 : if (nproc_fft == 1) then
5477 : call mpiswitch_cent(j3,n1dfft,Jp2stb,J2stb,lot1,max1i,md1,m1i,n1,&
5478 : md2proc,nd3proc,nproc_fft,ioption,zmpi2,zw, unused0, unused0, unused0)
5479 : else
5480 : call mpiswitch_cent(j3,n1dfft,Jp2stb,J2stb,lot1,max1i,md1,m1i,n1,&
5481 : md2proc,nd3proc,nproc_fft,ioption,zmpi1,zw, unused0, unused0, unused0)
5482 : end if
5483 :
5484 : ! Transform along x
5485 : ! input: G2,G1,R3,(Rp3)
5486 : ! output: G2,R1,R3,(Rp3)
5487 : if (n1dfft == lot1) then
5488 : call dfftw_execute_dft(bw_plan1_lot, zw, zt(1,j,1))
5489 : else
5490 : call dfftw_execute_dft(bw_plan1_rest, zw, zt(1,j,1))
5491 : end if
5492 : end do
5493 :
5494 : ! Transform along y axis (take into account c2c or c2r case).
5495 : ! Must loop over the full box.
5496 : !TODO this won't work
5497 : if (cplexwf==1) then
5498 : if(mod(lot2,2).ne.0) lot2=lot2-1 ! needed to introduce jeff
5499 : end if
5500 :
5501 : do j=1,n1eff,lot2
5502 : ma=j
5503 : mb=min(j+(lot2-1),n1eff)
5504 : n1dfft=mb-ma+1
5505 : jeff=j
5506 : includelast=1
5507 :
5508 : if (cplexwf==1) then
5509 : jeff=2*j-1
5510 : includelast=1
5511 : if (mb==n1eff .and. n1eff*2/=n1) includelast=0
5512 : end if
5513 :
5514 : ! Zero-pad the input.
5515 : ! input: G2,R1,R3,(Rp3)
5516 : ! output: R1,G2,R3,(Rp3)
5517 : if (cplexwf==2) then
5518 : call switch_cent(n1dfft,max2i,m2i,n2,lot2,n1,lzt,zt(1,1,jeff),zw)
5519 : else
5520 : call switchreal_cent(includelast,n1dfft,max2i,n2,lot2,m1zt,lzt,zt(1,1,jeff),zw)
5521 : end if
5522 :
5523 : ! input: R1,G2,R3,(Rp3)
5524 : ! output: R1,R2,R3,(Rp3)
5525 : ! Be careful here
5526 : if (n1dfft == lot2) then
5527 : call dfftw_execute_dft(bw_plan2_lot, zw, zw)
5528 : else
5529 : call dfftw_execute_dft(bw_plan2_rest, zw, zw)
5530 : end if
5531 :
5532 : ! Multiply with potential in real space
5533 : jx=cplex*(jeff-1)+1
5534 : call multpot(cplexwf,cplex,includelast,nd1,nd2,n2,lot2,n1dfft,pot(jx,1,j3glob),zw)
5535 :
5536 : ! TRANSFORM BACK IN FOURIER SPACE
5537 : ! transform along y axis
5538 : ! input: R1,R2,R3,(Rp3)
5539 : if (n1dfft == lot2) then
5540 : call dfftw_execute_dft(fw_plan2_lot, zw, zw)
5541 : else
5542 : call dfftw_execute_dft(fw_plan2_rest, zw, zw)
5543 : end if
5544 :
5545 : ! input: R1,G2,R3,(Rp3)
5546 : ! output: G2,R1,R3,(Rp3)
5547 : if (cplexwf==2) then
5548 : call unswitch_cent(n1dfft,max2o,m2o,n2,lot2,n1,lzt,zw,zt(1,1,jeff))
5549 : else
5550 : call unswitchreal_cent(n1dfft,max2o,n2,lot2,n1,lzt,zw,zt(1,1,jeff))
5551 : end if
5552 : end do ! j
5553 :
5554 : ! transform along x axis
5555 : ! input: R2,R1,R3,(Rp3)
5556 : ! output: R2,G1,R3,(Rp3)
5557 : do j=1,m2oeff,lot1
5558 : ma=j
5559 : mb=min(j+(lot1-1),m2oeff)
5560 : n1dfft=mb-ma+1
5561 :
5562 : if (n1dfft == lot1) then
5563 : call dfftw_execute_dft(fw_plan1_lot, zt(1,j,1), zw)
5564 : else
5565 : call dfftw_execute_dft(fw_plan1_rest, zt(1,j,1), zw)
5566 : end if
5567 :
5568 : ! input: G2,G1,R3,Gp2,(Rp3)
5569 : ! output: G1,G2,R3,Gp2,(Rp3)
5570 : if (nproc_fft == 1) then
5571 : call unmpiswitch_cent(j3,n1dfft,Jp2stf,J2stf,lot1,max1o,md1,m1o,n1,&
5572 : md2proc,nd3proc,nproc_fft,ioption,zw,zmpi2)
5573 : else
5574 : call unmpiswitch_cent(j3,n1dfft,Jp2stf,J2stf,lot1,max1o,md1,m1o,n1,&
5575 : md2proc,nd3proc,nproc_fft,ioption,zw,zmpi1)
5576 : end if
5577 : end do ! j
5578 : end if
5579 : end do
5580 :
5581 : ! Interprocessor data transposition
5582 : ! input: G1,G2,R3,Gp2,(Rp3)
5583 : ! output: G1,G2,R3,Rp3,(Gp2)
5584 : if (nproc_fft > 1) then
5585 : call timab(544,1,tsec)
5586 : call xmpi_alltoall(zmpi1,2*md1*md2proc*nd3proc, &
5587 : zmpi2,2*md1*md2proc*nd3proc,comm_fft,ierr)
5588 : call timab(544,2,tsec)
5589 : end if
5590 :
5591 : ! transform along z axis
5592 : ! input: G1,G2,R3,(Gp2)
5593 : !lot=ncache/(4*n3)
5594 : do j2=1,md2proc
5595 : if (me_fft*md2proc+j2 <= m2oeff) then
5596 : do i1=1,m1o,lot3
5597 : ma=i1
5598 : mb=min(i1+(lot3-1),m1o)
5599 : n1dfft=mb-ma+1
5600 :
5601 : ! input: G1,G2,R3,(Gp2)
5602 : ! output: G1,R3,G2,(Gp2)
5603 : call unscramble(i1,j2,lot3,n1dfft,md1,n3,md2proc,nnd3,zmpi2,zw)
5604 :
5605 : if (n1dfft == lot3) then
5606 : call dfftw_execute_dft(fw_plan3_lot, zw, zw)
5607 : else
5608 : call dfftw_execute_dft(fw_plan3_rest, zw, zw)
5609 : end if
5610 :
5611 : call unfill_cent(md1,md3,lot3,n1dfft,max3o,m3o,n3,zw,zf(1,i1,1,j2,idat))
5612 : ! output: G1,G3,G2,(Gp2)
5613 : end do
5614 : end if
5615 : end do
5616 :
5617 : ! Complete missing values with complex conjugate
5618 : ! Inverse of ix is located at nx+2-ix , except for ix=1, for which it is 1.
5619 : if (cplexwf==1) then
5620 : do i3=1,m3o
5621 : i3inv=m3o+2-i3
5622 : if (i3==1) i3inv=1
5623 : if (m2oeff>1)then
5624 : do i2=2,m2oeff
5625 : i2inv=m2o+2-i2
5626 : zf(1,1,i3inv,i2inv,idat)= zf(1,1,i3,i2,idat)
5627 : zf(2,1,i3inv,i2inv,idat)=-zf(2,1,i3,i2,idat)
5628 : do i1=2,m1o
5629 : i1inv=m1o+2-i1
5630 : zf(1,i1inv,i3inv,i2inv,idat)= zf(1,i1,i3,i2,idat)
5631 : zf(2,i1inv,i3inv,i2inv,idat)=-zf(2,i1,i3,i2,idat)
5632 : end do
5633 : end do
5634 : end if
5635 : end do
5636 : end if
5637 :
5638 : end do ! idat
5639 :
5640 : call dfftw_destroy_plan(bw_plan3_lot)
5641 : if (mod(m1i, lot3) /= 0) call dfftw_destroy_plan(bw_plan3_rest)
5642 :
5643 : call dfftw_destroy_plan(bw_plan1_lot)
5644 : if (mod(m2ieff, lot1) /= 0) call dfftw_destroy_plan(bw_plan1_rest)
5645 :
5646 : call dfftw_destroy_plan(bw_plan2_lot)
5647 : if (mod(n1eff, lot2) /= 0) call dfftw_destroy_plan(bw_plan2_rest)
5648 :
5649 : call dfftw_destroy_plan(fw_plan3_lot)
5650 : if (mod(m1o, lot3) /= 0) call dfftw_destroy_plan(fw_plan3_rest)
5651 :
5652 : call dfftw_destroy_plan(fw_plan1_lot)
5653 : if (mod(m2oeff, lot1) /= 0) call dfftw_destroy_plan(fw_plan1_rest)
5654 :
5655 : call dfftw_destroy_plan(fw_plan2_lot)
5656 : if (mod(n1eff, lot2) /= 0) call dfftw_destroy_plan(fw_plan2_rest)
5657 :
5658 : ABI_FREE(zmpi2)
5659 : ABI_FREE(zw)
5660 : ABI_FREE(zt)
5661 : if (nproc_fft > 1) then
5662 : ABI_FREE(zmpi1)
5663 : end if
5664 :
5665 : #else
5666 0 : ABI_ERROR("FFTW3 support not activated")
5667 : ABI_UNUSED((/cplexwf,cplex,ndat,n1,n2,n3,nd1,nd2,nd3,nd3proc/))
5668 : ABI_UNUSED((/max1i,max2i,max3i,m1i,m2i,m3i,md1,md2proc,md3/))
5669 : ABI_UNUSED((/max1o,max2o,max3o,m1o,m2o,m3o,comm_fft,nproc_fft,me_fft/))
5670 : ABI_UNUSED((/pot(1,1,1),zf(1,1,1,1,1)/))
5671 : #endif
5672 :
5673 0 : end subroutine fftw3_applypot
5674 : !!***
5675 :
5676 : !----------------------------------------------------------------------
5677 :
5678 : !!****f* m_fftw3/fftw3_accrho
5679 : !! NAME
5680 : !! fftw3_accrho
5681 : !!
5682 : !! FUNCTION
5683 : !! Accumulates the real space density rho from the ndat wavefunctions zf
5684 : !! by transforming zf into real space and adding all the amplitudes squared
5685 : !!
5686 : !! INPUTS:
5687 : !! ZF: input array (note the switch of i2 and i3)
5688 : !! real(F(i1,i3,i2,idat))=ZF(1,i1,i3,i2,idat)
5689 : !! imag(F(i1,i3,i2,idat))=ZF(2,i1,i3,i2,idat)
5690 : !! max1 is positive or zero ; m1 >=max1+1
5691 : !! i1= 1... max1+1 corresponds to positive and zero wavevectors 0 ... max1
5692 : !! then, if m1 > max1+1, one has min1=max1-m1+1 and
5693 : !! i1= max1+2 ... m1 corresponds to negative wavevectors min1 ... -1
5694 : !! i2 and i3 have a similar definition of range
5695 : !! idat=1,ndat
5696 : !! md1,md2,md3: Dimension of ZF
5697 : !! md2proc=((md2-1)/nproc_fft)+1 ! maximal number of small box 2nd dim slices for one proc
5698 : !! weight(ndat)= weight for the density accumulation
5699 : !!
5700 : !! OUTPUTS:
5701 : !! RHOoutput(i1,i2,i3) = RHOinput(i1,i2,i3) + sum on idat of (FFT(ZF))**2 *weight
5702 : !! i1=1,n1 , i2=1,n2 , i3=1,n3
5703 : !! comm_fft: MPI communicator
5704 : !! nproc_fft: number of processors used as returned by MPI_COMM_SIZE
5705 : !! me_fft: [0:nproc_fft-1] number of processor as returned by MPI_COMM_RANK
5706 : !! n1,n2,n3: logical dimension of the transform. As transform lengths
5707 : !! most products of the prime factors 2,3,5 are allowed.
5708 : !! The detailed table with allowed transform lengths can
5709 : !! be found in subroutine CTRIG
5710 : !! nd1,nd2,nd3: Dimension of RHO
5711 : !! nd3proc=((nd3-1)/nproc_fft)+1 ! maximal number of big box 3rd dim slices for one proc
5712 : !!
5713 : !! NOTES:
5714 : !! PERFORMANCE CONSIDERATIONS:
5715 : !! The maximum number of processors that can reasonably be used is max(n2/2,n3/2)
5716 : !!
5717 : !! It is very important to find the optimal
5718 : !! value of NCACHE. NCACHE determines the size of the work array ZW, that
5719 : !! has to fit into cache. It has therefore to be chosen to equal roughly
5720 : !! half the size of the physical cache in units of real*8 numbers.
5721 : !! The optimal value of ncache can easily be determined by numerical
5722 : !! experimentation. A too large value of ncache leads to a dramatic
5723 : !! and sudden decrease of performance, a too small value to a to a
5724 : !! slow and less dramatic decrease of performance. If NCACHE is set
5725 : !! to a value so small, that not even a single one dimensional transform
5726 : !! can be done in the workarray zw, the program stops with an error message.
5727 : !!
5728 : !! SOURCE
5729 :
5730 0 : subroutine fftw3_accrho(cplexwf,ndat,n1,n2,n3,nd1,nd2,nd3,nd3proc,&
5731 0 : & max1,max2,max3,m1,m2,m3,md1,md2proc,md3,comm_fft,nproc_fft,me_fft,zf,rho,weight_r,weight_i)
5732 :
5733 : !Arguments ------------------------------------
5734 : integer,intent(in) :: cplexwf,ndat,n1,n2,n3,nd1,nd2,nd3,nd3proc
5735 : integer,intent(in) :: max1,max2,max3,m1,m2,m3,md1,md2proc,md3,comm_fft,nproc_fft,me_fft
5736 : real(dp),intent(in) :: zf(2,md1,md3,md2proc,ndat)
5737 : real(dp),intent(in) :: weight_r(ndat) , weight_i(ndat)
5738 : real(dp),intent(inout) :: rho(nd1,nd2,nd3)
5739 :
5740 : !Local variables-------------------------------
5741 : !scalars
5742 : #ifdef HAVE_FFTW3
5743 : integer,parameter :: unused0=0
5744 : integer :: j,i1,idat,ierr,j3glob
5745 : integer :: ioption,j2,j3,j2st,jp2st,lzt,m1zt,ma,mb,n1dfft,nnd3
5746 : integer :: m2eff,ncache,n1eff,jeff,includelast,lot1,lot2,lot3,nthreads
5747 : integer(KIND_FFTW_PLAN) :: bw_plan1_lot,bw_plan1_rest
5748 : integer(KIND_FFTW_PLAN) :: bw_plan2_lot,bw_plan2_rest
5749 : integer(KIND_FFTW_PLAN) :: bw_plan3_lot,bw_plan3_rest
5750 : character(len=500) :: msg
5751 : !arrays
5752 : real(dp), allocatable :: zmpi1(:,:,:,:),zmpi2(:,:,:,:) ! work arrays for MPI
5753 : real(dp),allocatable :: zw(:,:),zt(:,:,:) ! cache work array and array for transpositions
5754 : real(dp) :: tsec(2)
5755 : ! *************************************************************************
5756 :
5757 : !ioption=0 ! This was in the old version.
5758 : ioption=1 ! This one is needed to be compatible with paral_kgb
5759 :
5760 : !nproc_fft = xmpi_comm_size(comm_fft); me_fft = xmpi_comm_rank(comm_fft)
5761 :
5762 : ! find cache size that gives optimal performance on machine
5763 : ncache=2*max(n1,n2,n3,1024)
5764 : if (ncache/(2*max(n1,n2,n3)) < 1) then
5765 : write(msg,"(5a)") &
5766 : 'ncache has to be enlarged to be able to hold at',ch10,&
5767 : 'least one 1-d FFT of each size even though this will',ch10,&
5768 : 'reduce the performance for shorter transform lengths'
5769 : ABI_ERROR(msg)
5770 : end if
5771 :
5772 : !Effective m1 and m2 (complex-to-complex or real-to-complex)
5773 : n1eff=n1; m2eff=m2 ; m1zt=n1
5774 : if (cplexwf==1) then
5775 : n1eff=(n1+1)/2; m2eff=m2/2+1; m1zt=2*(n1/2+1)
5776 : end if
5777 :
5778 : lzt=m2eff
5779 : if (mod(m2eff,2) == 0) lzt=lzt+1
5780 : if (mod(m2eff,4) == 0) lzt=lzt+1
5781 :
5782 : ! maximal number of big box 3rd dim slices for all procs
5783 : nnd3=nd3proc*nproc_fft
5784 :
5785 : ABI_MALLOC(zw,(2,ncache/2))
5786 : ABI_MALLOC(zt,(2,lzt,m1zt))
5787 : ABI_MALLOC(zmpi2,(2,md1,md2proc,nnd3))
5788 : if (nproc_fft > 1) then
5789 : ABI_MALLOC(zmpi1,(2,md1,md2proc,nnd3))
5790 : end if
5791 :
5792 : ! Create plans.
5793 : ! The prototype for sfftw_plan_many_dft is:
5794 : ! sfftw_plan_many_dft(rank, n, howmany,
5795 : ! fin, iembed, istride, idist,
5796 : ! fout, oembed, ostride, odist, isign, my_flags)
5797 :
5798 : lot3=ncache/(2*n3)
5799 : lot1=ncache/(2*n1)
5800 : lot2=ncache/(2*n2)
5801 :
5802 : nthreads = xomp_get_num_threads(open_parallel=.TRUE.)
5803 : !nthreads = 1
5804 :
5805 : bw_plan3_lot = dplan_many_dft_2D(1, [n3], lot3, &
5806 : zw, [ncache/2], lot3, 1, &
5807 : zw, [ncache/2], lot3, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
5808 :
5809 : if (mod(m1, lot3) /= 0) then
5810 : bw_plan3_rest = dplan_many_dft_2D(1, [n3], mod(m1, lot3), &
5811 : zw, [ncache/2], lot3, 1, &
5812 : zw, [ncache/2], lot3, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
5813 : end if
5814 :
5815 : bw_plan1_lot = dplan_many_dft_2D(1, [n1], lot1, &
5816 : zw, [ncache/2], lot1, 1, &
5817 : zt, [lzt, m1zt], lzt, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
5818 :
5819 : if (mod(m2eff, lot1) /= 0) then
5820 : bw_plan1_rest = dplan_many_dft_2D(1, [n1], mod(m2eff, lot1), &
5821 : zw, [ncache/2], lot1, 1, &
5822 : zt, [lzt, m1zt], lzt, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
5823 : end if
5824 :
5825 : ! FIXME THis won't work if ixplexwf == 1
5826 : bw_plan2_lot = dplan_many_dft_2D(1, [n2], lot2, &
5827 : zw, [ncache/2], lot2, 1, &
5828 : zw, [ncache/2], lot2, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
5829 :
5830 : if (mod(n1eff, lot2) /= 0) then
5831 : bw_plan2_rest = dplan_many_dft_2D(1, [n2], mod(n1eff,lot2), &
5832 : zw, [ncache/2], lot2, 1, &
5833 : zw, [ncache/2], lot2, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
5834 : end if
5835 :
5836 : do idat=1,ndat
5837 : ! transform along z axis
5838 : ! input: I1,I3,J2,(Jp2)
5839 : !lot=ncache/(4*n3)
5840 :
5841 : ! Loop over the y planes treated by this node and transform n1ddft G_z lines.
5842 : do j2=1,md2proc
5843 : if (me_fft*md2proc+j2 <= m2eff) then ! MG REMOVED TO BE CONSISTENT WITH BACK_WF
5844 : do i1=1,m1,lot3
5845 : ma=i1
5846 : mb=min(i1+(lot3-1),m1)
5847 : n1dfft=mb-ma+1
5848 :
5849 : ! zero-pad n1dfft G_z lines
5850 : ! input: G1,G3,G2,(Gp2)
5851 : ! output: G1,R3,G2,(Gp2)
5852 : call fill_cent(md1,md3,lot3,n1dfft,max3,m3,n3,zf(1,i1,1,j2,idat),zw)
5853 :
5854 : ! Transform along z.
5855 : if (n1dfft == lot3) then
5856 : call dfftw_execute_dft(bw_plan3_lot, zw, zw)
5857 : else
5858 : call dfftw_execute_dft(bw_plan3_rest, zw, zw)
5859 : end if
5860 :
5861 : ! Local rotation.
5862 : ! input: G1,R3,G2,(Gp2)
5863 : ! output: G1,G2,R3,(Gp2)
5864 : call scramble(i1,j2,lot3,n1dfft,md1,n3,md2proc,nnd3,zw,zmpi2)
5865 : end do
5866 : end if
5867 : end do
5868 :
5869 : ! Interprocessor data transposition
5870 : ! input: G1,G2,R3,Rp3,(Gp2)
5871 : ! output: G1,G2,R3,Gp2,(Rp3)
5872 : if (nproc_fft > 1) then
5873 : call timab(543,1,tsec)
5874 : call xmpi_alltoall(zmpi2,2*md1*md2proc*nd3proc, &
5875 : zmpi1,2*md1*md2proc*nd3proc,comm_fft,ierr)
5876 : call timab(543,2,tsec)
5877 : end if
5878 :
5879 : ! Loop over the z treated by this node.
5880 : do j3=1,nd3proc
5881 : j3glob = j3 + me_fft*nd3proc
5882 :
5883 : if (me_fft*nd3proc+j3 <= n3) then
5884 : Jp2st=1; J2st=1
5885 :
5886 : ! Loop over G_y in the small box.
5887 : do j=1,m2eff,lot1
5888 : ma=j
5889 : mb=min(j+(lot1-1),m2eff)
5890 : n1dfft=mb-ma+1
5891 :
5892 : ! Zero-pad input.
5893 : ! input: G1,G2,R3,JG2,(Rp3)
5894 : ! output: G2,G1,R3,JG2,(Rp3)
5895 : if (nproc_fft == 1) then
5896 : call mpiswitch_cent(j3,n1dfft,Jp2st,J2st,lot1,max1,md1,m1,n1,&
5897 : md2proc,nd3proc,nproc_fft,ioption,zmpi2,zw,unused0, unused0,unused0)
5898 : else
5899 : call mpiswitch_cent(j3,n1dfft,Jp2st,J2st,lot1,max1,md1,m1,n1,&
5900 : md2proc,nd3proc,nproc_fft,ioption,zmpi1,zw, unused0,unused0,unused0)
5901 : end if
5902 :
5903 : ! Transform along x
5904 : ! input: G2,G1,R3,(Rp3)
5905 : ! output: G2,R1,R3,(Rp3)
5906 : if (n1dfft == lot1) then
5907 : call dfftw_execute_dft(bw_plan1_lot, zw, zt(1,j,1))
5908 : else
5909 : call dfftw_execute_dft(bw_plan1_rest, zw, zt(1,j,1))
5910 : end if
5911 :
5912 : end do
5913 :
5914 : ! Transform along y axis (take into account c2c or c2r case).
5915 : ! Must loop over the full box.
5916 : !lot=ncache/(4*n2)
5917 : ! FIXME THis won't work
5918 : if (cplexwf==1) then
5919 : if (mod(lot2,2) /=0) lot2=lot2-1 ! needed to introduce jeff
5920 : end if
5921 :
5922 : do j=1,n1eff,lot2
5923 : ma=j
5924 : mb=min(j+(lot2-1),n1eff)
5925 : n1dfft=mb-ma+1
5926 : jeff=j
5927 : includelast=1
5928 :
5929 : if (cplexwf==1) then
5930 : jeff=2*j-1
5931 : includelast=1
5932 : if (mb==n1eff .and. n1eff*2/=n1) includelast=0
5933 : end if
5934 :
5935 : ! Zero-pad the input.
5936 : ! input: G2,R1,R3,(Rp3)
5937 : ! output: R1,G2,R3,(Rp3)
5938 : if (cplexwf==2) then
5939 : call switch_cent(n1dfft,max2,m2,n2,lot2,n1,lzt,zt(1,1,j),zw)
5940 : else
5941 : call switchreal_cent(includelast,n1dfft,max2,n2,lot2,m1zt,lzt,zt(1,1,jeff),zw)
5942 : end if
5943 :
5944 : if (n1dfft == lot2) then
5945 : call dfftw_execute_dft(bw_plan2_lot, zw, zw)
5946 : else
5947 : call dfftw_execute_dft(bw_plan2_rest, zw, zw)
5948 : end if
5949 :
5950 : ! Accumulate
5951 : call addrho(cplexwf,includelast,nd1,nd2,n2,lot2,n1dfft,&
5952 : & zw,rho(jeff,1,j3glob),weight_r(idat),weight_i(idat))
5953 : end do
5954 : ! output: i1,i2,j3,(jp3)
5955 :
5956 : end if
5957 : end do ! j3
5958 : end do ! idat
5959 :
5960 : call dfftw_destroy_plan(bw_plan3_lot)
5961 : if (mod(m1, lot3) /= 0) call dfftw_destroy_plan(bw_plan3_rest)
5962 :
5963 : call dfftw_destroy_plan(bw_plan1_lot)
5964 : if (mod(m2eff, lot1) /= 0) call dfftw_destroy_plan(bw_plan1_rest)
5965 :
5966 : call dfftw_destroy_plan(bw_plan2_lot)
5967 : if (mod(n1eff, lot2) /= 0) call dfftw_destroy_plan(bw_plan2_rest)
5968 :
5969 : ABI_FREE(zmpi2)
5970 : ABI_FREE(zw)
5971 : ABI_FREE(zt)
5972 : if (nproc_fft > 1) then
5973 : ABI_FREE(zmpi1)
5974 : end if
5975 :
5976 : #else
5977 0 : ABI_ERROR("FFTW3 support not activated")
5978 : ABI_UNUSED((/cplexwf,ndat,n1,n2,n3,nd1,nd2,nd3proc/))
5979 : ABI_UNUSED((/ max1,max2,max3,m1,m2,m3,md1,md2proc,md3,comm_fft,nproc_fft,me_fft/))
5980 : ABI_UNUSED((/zf(1,1,1,1,1),rho(1,1,1),weight_r(1),weight_i(1)/))
5981 : #endif
5982 :
5983 0 : end subroutine fftw3_accrho
5984 : !!***
5985 :
5986 : !----------------------------------------------------------------------
5987 :
5988 : !!****f* m_fftw3/fftw3_mpiback_manywf
5989 : !! NAME
5990 : !! fftw3_mpiback_manywf
5991 : !!
5992 : !! FUNCTION
5993 : !! Does multiple 3-dim backward FFTs from Fourier into real space
5994 : !! Adopt standard convention that isign=1 for backward transform
5995 : !!
5996 : !! CALCULATES THE DISCRETE FOURIER TRANSFORM ZF(I1,I2,I3)=
5997 : !!
5998 : !! S_(j1,j2,j3) EXP(isign*i*2*pi*(j1*i1/n1+j2*i2/n2+j3*i3/n3)) ZF(j1,j3,j2)
5999 : !!
6000 : !! in parallel using MPI/OpenMP.
6001 : !!
6002 : !! INPUTS:
6003 : !! cplexwf=1 if wavefunction is real, 2 if complex
6004 : !! ndat=Number of wavefunctions to transform.
6005 : !! n1,n2,n3: logical dimension of the transform. As transform lengths
6006 : !! most products of the prime factors 2,3,5 are allowed.
6007 : !! The detailed table with allowed transform lengths can be found in subroutine CTRIG
6008 : !! nd1,nd2,nd3: Leading Dimension of ZR
6009 : !! nd3proc=((nd3-1)/nproc_fft)+1 maximal number of big box 3rd dim slices for one proc
6010 : !! max1 is positive or zero; m1 >=max1+1
6011 : !! i1= 1... max1+1 corresponds to positive and zero wavevectors 0 ... max1
6012 : !! then, if m1 > max1+1, one has min1=max1-m1+1 and
6013 : !! i1= max1+2 ... m1 corresponds to negative wavevectors min1 ... -1
6014 : !! max2 and max3 have a similar definition of range
6015 : !! m1,m2,m3=Size of the box enclosing the G-sphere.
6016 : !! md1,md2,md3: Dimension of ZF given on the **small** FFT box.
6017 : !! md2proc=((md2-1)/nproc_fft)+1 maximal number of small box 2nd dim slices for one proc
6018 : !! nproc_fft: number of processors used as returned by MPI_COMM_SIZE
6019 : !! comm_fft=MPI communicator for the FFT.
6020 : !! ZF: input array (note the switch of i2 and i3)
6021 : !! real(F(i1,i3,i2,idat))=ZF(1,i1,i3,i2,idat)
6022 : !! imag(F(i1,i3,i2,idat))=ZF(2,i1,i3,i2,idat)
6023 : !!
6024 : !! OUTPUTS
6025 : !! ZR: output array
6026 : !! ZR(1,i1,i2,i3,idat)=real(R(i1,i2,i3,idat))
6027 : !! ZR(2,i1,i2,i3,idat)=imag(R(i1,i2,i3,idat))
6028 : !! i1=1,n1 , i2=1,n2 , i3=1,n3 , idat=1,ndat
6029 : !!
6030 : !! NOTES
6031 : !! The maximum number of processors that can reasonably be used is max(n2/2,n3/2)
6032 : !!
6033 : !! It is very important to find the optimal
6034 : !! value of NCACHE. NCACHE determines the size of the work array ZW, that
6035 : !! has to fit into cache. It has therefore to be chosen to equal roughly
6036 : !! half the size of the physical cache in units of real*8 numbers.
6037 : !! The optimal value of ncache can easily be determined by numerical
6038 : !! experimentation. A too large value of ncache leads to a dramatic
6039 : !! and sudden decrease of performance, a too small value to a to a
6040 : !! slow and less dramatic decrease of performance. If NCACHE is set
6041 : !! to a value so small, that not even a single one dimensional transform
6042 : !! can be done in the workarray zw, the program stops with an error message.
6043 : !!
6044 : !! SOURCE
6045 :
6046 0 : subroutine fftw3_mpiback_manywf(cplexwf,ndat,n1,n2,n3,nd1,nd2,nd3proc,&
6047 0 : & max1,max2,max3,m1,m2,m3,md1,md2proc,md3,zf,zr,comm_fft)
6048 :
6049 : !Arguments ------------------------------------
6050 : integer,intent(in) :: cplexwf,ndat,n1,n2,n3,nd1,nd2,nd3proc
6051 : integer,intent(in) :: max1,max2,max3,m1,m2,m3,md1,md2proc,md3,comm_fft
6052 : real(dp),intent(in) :: zf(2,md1,md3,md2proc,ndat)
6053 : real(dp),intent(out) :: zr(2,nd1,nd2,nd3proc,ndat)
6054 :
6055 : #ifdef HAVE_FFTW3
6056 : !Local variables-------------------------------
6057 : integer,parameter :: nt1=1
6058 : integer :: j,i1,i2,idat,ierr,includelast,nthreads
6059 : integer :: ioption,j2,j3,j2st,jp2st,jeff,lzt,m1zt,ma,mb,n1dfft,nnd3
6060 : integer :: lot1,lot2,lot3
6061 : integer :: m2eff,ncache,n1eff,n1half,nproc_fft,me_fft
6062 : integer(KIND_FFTW_PLAN) :: bw_plan1_lot,bw_plan1_rest
6063 : integer(KIND_FFTW_PLAN) :: bw_plan2_lot,bw_plan2_rest
6064 : integer(KIND_FFTW_PLAN) :: bw_plan3_lot,bw_plan3_rest
6065 : !type(C_PTR) :: zw_cptr,zt_cptr
6066 : character(len=500) :: msg
6067 : !arrays
6068 : integer :: requests(ndat)
6069 : real(dp) ABI_ASYNC, allocatable :: zmpi1(:,:,:,:,:),zmpi2(:,:,:,:,:) ! work arrays for MPI
6070 : real(dp),allocatable :: zw(:,:),zt(:,:,:) ! cache work array and array for transpositions
6071 : !real(dp),contiguous, pointer :: zw(:,:),zt(:,:,:)
6072 : ! FFT work arrays
6073 : real(dp) :: tsec(2)
6074 : ! *************************************************************************
6075 :
6076 : !call wrtout(std_out,"mpiback with non-blocking IALLTOALL + FFTW3")
6077 : ! FIXME must provide a default value but which one?
6078 : ! ioption = 0
6079 : ioption = 1
6080 : !if (paral_kgb==1) ioption=1
6081 :
6082 : nproc_fft = xmpi_comm_size(comm_fft); me_fft = xmpi_comm_rank(comm_fft)
6083 :
6084 : ! Find cache size that gives optimal performance on machine
6085 : ncache=2*max(n1,n2,n3,1024)
6086 : if (ncache/(2*max(n1,n2,n3))<1) then
6087 : write(msg,"(5a)") &
6088 : 'ncache has to be enlarged to be able to hold at',ch10, &
6089 : 'least one 1-d FFT of each size even though this will',ch10,&
6090 : 'reduce the performance for shorter transform lengths'
6091 : ABI_ERROR(msg)
6092 : end if
6093 :
6094 : ! Effective m1 and m2 (complex-to-complex or real-to-complex)
6095 : n1eff=n1; m2eff=m2; m1zt=n1
6096 : if (cplexwf==1) then
6097 : n1eff=(n1+1)/2; m2eff=m2/2+1; m1zt=2*(n1/2+1)
6098 : end if
6099 :
6100 : lzt=m2eff
6101 : if (mod(m2eff,2)==0) lzt=lzt+1
6102 : if (mod(m2eff,4)==0) lzt=lzt+1
6103 :
6104 : ! maximal number of big box 3rd dim slices for all procs
6105 : nnd3=nd3proc*nproc_fft
6106 :
6107 : ! Allocate cache work array and work arrays for MPI transpositions.
6108 : ABI_MALLOC(zw,(2,ncache/2))
6109 : ABI_MALLOC(zt,(2,lzt,m1zt))
6110 :
6111 : !call fftw3_alloc_real([2,ncache/2],zw_cptr,zw)
6112 : !call fftw3_alloc_real([2,lzt,m1zt],zt_cptr,zt)
6113 :
6114 : ABI_MALLOC(zmpi2,(2,md1,md2proc,nnd3,ndat))
6115 : if (nproc_fft>1) then
6116 : ABI_MALLOC(zmpi1,(2,md1,md2proc,nnd3,ndat))
6117 : end if
6118 :
6119 : ! Create plans.
6120 : ! The prototype for sfftw_plan_many_dft is:
6121 : ! sfftw_plan_many_dft(rank, n, howmany,
6122 : ! fin, iembed, istride, idist,
6123 : ! fout, oembed, ostride, odist, isign, my_flags)
6124 :
6125 : lot3=ncache/(2*n3)
6126 : lot1=ncache/(2*n1)
6127 : lot2=ncache/(2*n2)
6128 :
6129 : nthreads = xomp_get_num_threads(open_parallel=.TRUE.)
6130 : !nthreads = 1
6131 :
6132 : bw_plan3_lot = dplan_many_dft_2D(1, [n3], lot3, &
6133 : zw, [ncache/2], lot3, 1, &
6134 : zw, [ncache/2], lot3, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
6135 :
6136 : if (mod(m1, lot3) /= 0) then
6137 : bw_plan3_rest = dplan_many_dft_2D(1, [n3], mod(m1, lot3), &
6138 : zw, [ncache/2], lot3, 1, &
6139 : zw, [ncache/2], lot3, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
6140 : end if
6141 :
6142 : bw_plan1_lot = dplan_many_dft_2D(1, [n1], lot1, &
6143 : zw, [ncache/2], lot1, 1, &
6144 : zt, [lzt, m1zt], lzt, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
6145 :
6146 : if (mod(m2eff, lot1) /= 0) then
6147 : bw_plan1_rest = dplan_many_dft_2D(1, [n1], mod(m2eff, lot1), &
6148 : zw, [ncache/2], lot1, 1, &
6149 : zt, [lzt, m1zt], lzt, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
6150 : end if
6151 :
6152 : bw_plan2_lot = dplan_many_dft_2D(1, [n2], lot2, &
6153 : zw, [ncache/2], lot2, 1, &
6154 : zr, [nd1,nd2,nd3proc,ndat], nd1, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
6155 :
6156 : if (mod(n1eff, lot2) /= 0) then
6157 : bw_plan2_rest = dplan_many_dft_2D(1, [n2], mod(n1eff,lot2), &
6158 : zw, [ncache/2], lot2, 1, &
6159 : zr, [nd1,nd2,nd3proc,ndat], nd1, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
6160 : end if
6161 :
6162 : do idat=1,ndat
6163 : ! transform along z axis
6164 : ! input: G1,G3,G2,(Gp2)
6165 :
6166 : ! Loop over the y planes treated by this node and transform n1ddft G_z lines.
6167 : do j2=1,md2proc
6168 : ! if (me_fft*md2proc+j2<=m2eff) then !a faire plus tard
6169 : do i1=1,m1,lot3
6170 : ma=i1
6171 : mb=min(i1+(lot3-1),m1)
6172 : n1dfft=mb-ma+1
6173 :
6174 : ! zero-pad n1dfft G_z lines
6175 : ! input: G1,G3,G2,(Gp2)
6176 : ! output: G1,R3,G2,(Gp2)
6177 : call fill_cent(md1,md3,lot3,n1dfft,max3,m3,n3,zf(1,i1,1,j2,idat),zw)
6178 :
6179 : ! Transform along z.
6180 : if (n1dfft == lot3) then
6181 : call dfftw_execute_dft(bw_plan3_lot, zw, zw)
6182 : else
6183 : call dfftw_execute_dft(bw_plan3_rest, zw, zw)
6184 : end if
6185 :
6186 : ! Local rotation.
6187 : ! input: G1,R3,G2,(Gp2)
6188 : ! output: G1,G2,R3,(Gp2)
6189 : call scramble(i1,j2,lot3,n1dfft,md1,n3,md2proc,nnd3,zw,zmpi2(:,:,:,:,idat))
6190 : end do
6191 : end do ! j2
6192 :
6193 : ! Interprocessor data transposition
6194 : ! input: G1,G2,R3,Rp3,(Gp2)
6195 : ! output: G1,G2,R3,Gp2,(Rp3)
6196 : if (nproc_fft>1) then
6197 : call timab(543,1,tsec)
6198 : call xmpi_ialltoall(zmpi2(:,:,:,:,idat),2*md1*md2proc*nd3proc, &
6199 : zmpi1(:,:,:,:,idat),2*md1*md2proc*nd3proc,comm_fft,requests(idat))
6200 : call timab(543,2,tsec)
6201 : end if
6202 : end do
6203 :
6204 : do idat=1,ndat
6205 : if (nproc_fft>1) call xmpi_wait(requests(idat),ierr)
6206 : ! Loop over the z treated by this node.
6207 : do j3=1,nd3proc
6208 : if (me_fft*nd3proc+j3 <= n3) then
6209 : Jp2st=1; J2st=1
6210 :
6211 : ! Loop over G_y in the small box.
6212 : do j=1,m2eff,lot1
6213 : ma=j
6214 : mb=min(j+(lot1-1),m2eff)
6215 : n1dfft=mb-ma+1
6216 :
6217 : ! Zero-pad input.
6218 : ! input: G1,G2,R3,JG2,(Rp3)
6219 : ! output: G2,G1,R3,JG2,(Rp3)
6220 : if (nproc_fft==1) then
6221 : call mpiswitch_cent(j3,n1dfft,Jp2st,J2st,lot1,max1,md1,m1,n1,&
6222 : md2proc,nd3proc,nproc_fft,ioption,zmpi2(:,:,:,:,idat),zw,max2,m2,n2)
6223 : else
6224 : call mpiswitch_cent(j3,n1dfft,Jp2st,J2st,lot1,max1,md1,m1,n1,&
6225 : md2proc,nd3proc,nproc_fft,ioption,zmpi1(:,:,:,:,idat),zw,max2,m2,n2)
6226 : end if
6227 :
6228 : ! Transform along x
6229 : ! input: G2,G1,R3,(Rp3)
6230 : ! output: G2,R1,R3,(Rp3)
6231 : if (n1dfft == lot1) then
6232 : call dfftw_execute_dft(bw_plan1_lot, zw, zt(1,j,1))
6233 : else
6234 : call dfftw_execute_dft(bw_plan1_rest, zw, zt(1,j,1))
6235 : end if
6236 :
6237 : end do ! j
6238 :
6239 : ! Transform along y axis (take into account c2c or c2r case).
6240 : ! Must loop over the full box.
6241 : do j=1,n1eff,lot2
6242 : ma=j
6243 : mb=min(j+(lot2-1),n1eff)
6244 : n1dfft=mb-ma+1
6245 : includelast=1
6246 :
6247 : if (cplexwf==1) then
6248 : jeff=2*j-1
6249 : if (mb==n1eff .and. n1eff*2/=n1) includelast=0
6250 : end if
6251 :
6252 : ! Zero-pad the input.
6253 : ! input: G2,R1,R3,(Rp3)
6254 : ! output: R1,G2,R3,(Rp3)
6255 : if (cplexwf==2) then
6256 : call switch_cent(n1dfft,max2,m2,n2,lot2,n1,lzt,zt(1,1,j),zw)
6257 : else
6258 : call switchreal_cent(includelast,n1dfft,max2,n2,lot2,m1zt,lzt,zt(1,1,jeff),zw)
6259 : end if
6260 :
6261 : ! input: R1,G2,R3,(Rp3)
6262 : ! output: R1,R2,R3,(Rp3)
6263 : if (n1dfft == lot2) then
6264 : call dfftw_execute_dft(bw_plan2_lot, zw, zr(1,j,1,j3,idat))
6265 : else
6266 : call dfftw_execute_dft(bw_plan2_rest, zw, zr(1,j,1,j3,idat))
6267 : end if
6268 :
6269 : end do
6270 :
6271 : ! Treat real wavefunctions.
6272 : if (cplexwf==1) then
6273 : n1half=n1/2
6274 : ! If odd
6275 : if (n1half*2/=n1) then
6276 : do i2=1,n2
6277 : zr(1,n1,i2,j3,idat)=zr(1,n1eff,i2,j3,idat)
6278 : zr(2,n1,i2,j3,idat)=zero
6279 : end do
6280 : end if
6281 : do i2=1,n2
6282 : do i1=n1half,1,-1
6283 : zr(1,2*i1-1,i2,j3,idat)=zr(1,i1,i2,j3,idat)
6284 : zr(1,2*i1 ,i2,j3,idat)=zr(2,i1,i2,j3,idat)
6285 : zr(2,2*i1-1,i2,j3,idat)=zero
6286 : zr(2,2*i1 ,i2,j3,idat)=zero
6287 : end do
6288 : end do
6289 : end if
6290 :
6291 : end if
6292 :
6293 : end do ! j3
6294 : end do ! idat
6295 :
6296 : call dfftw_destroy_plan(bw_plan3_lot)
6297 : if (mod(m1, lot3) /= 0) call dfftw_destroy_plan(bw_plan3_rest)
6298 :
6299 : call dfftw_destroy_plan(bw_plan1_lot)
6300 : if (mod(m2eff, lot1) /= 0) call dfftw_destroy_plan(bw_plan1_rest)
6301 :
6302 : call dfftw_destroy_plan(bw_plan2_lot)
6303 : if (mod(n1eff, lot2) /= 0) call dfftw_destroy_plan(bw_plan2_rest)
6304 :
6305 : ABI_FREE(zmpi2)
6306 : ABI_FREE(zw)
6307 : ABI_FREE(zt)
6308 : if (nproc_fft>1) then
6309 : ABI_FREE(zmpi1)
6310 : end if
6311 :
6312 : #else
6313 0 : ABI_ERROR("FFTW3 support not activated")
6314 : ABI_UNUSED((/cplexwf,ndat,n1,n2,n3,nd1,nd2,nd3proc/))
6315 : ABI_UNUSED((/ max1,max2,max3,m1,m2,m3,md1,md2proc,md3,comm_fft/))
6316 : ABI_UNUSED((/zf(1,1,1,1,1),zr(1,1,1,1,1)/))
6317 : #endif
6318 :
6319 0 : end subroutine fftw3_mpiback_manywf
6320 : !!***
6321 :
6322 : !----------------------------------------------------------------------
6323 :
6324 : !!****f* m_fftw3/fftw3_mpiforw_manywf
6325 : !! NAME
6326 : !! fftw3_mpiforw_manywf
6327 : !!
6328 : !! FUNCTION
6329 : !! Does multiple 3-dim backward FFTs from real into Fourier space
6330 : !! Adopt standard convention that isign=-1 for forward transform
6331 : !! CALCULATES THE DISCRETE FOURIERTRANSFORM
6332 : !!
6333 : !! ZF(I1,I3,I2)=S_(j1,j2,j3) EXP(isign*i*2*pi*(j1*i1/n1+j2*i2/n2+j3*i3/n3)) ZR(j1,j2,j3)
6334 : !!
6335 : !! in parallel using MPI/OpenMP.
6336 : !!
6337 : !! INPUT:
6338 : !! ZR: input array
6339 : !! ZR(1,i1,i2,i3,idat)=real(R(i1,i2,i3,idat))
6340 : !! ZR(2,i1,i2,i3,idat)=imag(R(i1,i2,i3,idat))
6341 : !! i1=1,n1 , i2=1,n2 , i3=1,n3 , idat=1,ndat
6342 : !! NOTE that ZR is changed by the routine
6343 : !!
6344 : !! n1,n2,n3: logical dimension of the transform. As transform lengths
6345 : !! most products of the prime factors 2,3,5 are allowed.
6346 : !! The detailed table with allowed transform lengths can
6347 : !! be found in subroutine CTRIG
6348 : !! nd1,nd2,nd3: Dimension of ZR
6349 : !! nd3proc=((nd3-1)/nproc_fft)+1 maximal number of big box 3rd dim slices for one proc
6350 : !!
6351 : !! OUTPUT:
6352 : !! ZF: output array (note the switch of i2 and i3)
6353 : !! real(F(i1,i3,i2,idat))=ZF(1,i1,i3,i2,idat)
6354 : !! imag(F(i1,i3,i2,idat))=ZF(2,i1,i3,i2,idat)
6355 : !! max1 is positive or zero ; m1 >=max1+1
6356 : !! i1= 1... max1+1 corresponds to positive and zero wavevectors 0 ... max1
6357 : !! then, if m1 > max1+1, one has min1=max1-m1+1 and
6358 : !! i1= max1+2 ... m1 corresponds to negative wavevectors min1 ... -1
6359 : !! i2 and i3 have a similar definition of range
6360 : !! idat=1,ndat
6361 : !! md1,md2,md3: Dimension of ZF
6362 : !! md2proc=((md2-1)/nproc_fft)+1 maximal number of small box 2nd dim slices for one proc
6363 : !! nproc_fft: number of processors used as returned by MPI_COMM_SIZE
6364 : !! me_fft: [0:nproc-1] rank of the processor in the FFT communicator.
6365 : !! comm_fft=MPI communicator for parallel FFT.
6366 : !!
6367 : !! NOTES
6368 : !! The maximum number of processors that can reasonably be used is max(n2/2,n3/2)
6369 : !!
6370 : !! It is very important to find the optimal
6371 : !! value of NCACHE. NCACHE determines the size of the work array ZW, that
6372 : !! has to fit into cache. It has therefore to be chosen to equal roughly
6373 : !! half the size of the physical cache in units of real*8 numbers.
6374 : !! The optimal value of ncache can easily be determined by numerical
6375 : !! experimentation. A too large value of ncache leads to a dramatic
6376 : !! and sudden decrease of performance, a too small value to a to a
6377 : !! slow and less dramatic decrease of performance. If NCACHE is set
6378 : !! to a value so small, that not even a single one dimensional transform
6379 : !! can be done in the workarray zw, the program stops with an error message.
6380 : !!
6381 : !! SOURCE
6382 :
6383 0 : subroutine fftw3_mpiforw_manywf(cplexwf,ndat,n1,n2,n3,nd1,nd2,nd3proc,&
6384 0 : & max1,max2,max3,m1,m2,m3,md1,md2proc,md3,zr,zf,comm_fft)
6385 :
6386 : !Arguments ------------------------------------
6387 : !scalars
6388 : integer,intent(in) :: cplexwf,ndat,n1,n2,n3,nd1,nd2,nd3proc
6389 : integer,intent(in) :: max1,max2,max3,m1,m2,m3,md1,md2proc,md3,comm_fft
6390 : !arrays
6391 : real(dp),intent(inout) :: zr(2,nd1,nd2,nd3proc,ndat)
6392 : real(dp),intent(out) :: zf(2,md1,md3,md2proc,ndat)
6393 :
6394 : !Local variables-------------------------------
6395 : !scalars
6396 : #ifdef HAVE_FFTW3
6397 : integer :: j,i1,i2,i3,idat,ierr,nproc_fft,me_fft
6398 : integer :: ioption,j2,j3,j2st,jp2st,lot1,lot2,lot3,lzt,m1zt,ma,mb,n1dfft,nnd3
6399 : integer :: m2eff,ncache,n1eff,n1half,i1inv,i2inv,i3inv,nthreads
6400 : integer(KIND_FFTW_PLAN) :: fw_plan1_lot,fw_plan1_rest
6401 : integer(KIND_FFTW_PLAN) :: fw_plan2_lot,fw_plan2_rest
6402 : integer(KIND_FFTW_PLAN) :: fw_plan3_lot,fw_plan3_rest
6403 : character(len=500) :: msg
6404 : !arrays
6405 : integer :: requests(ndat)
6406 : real(dp) ABI_ASYNC, allocatable :: zmpi1(:,:,:,:,:),zmpi2(:,:,:,:,:) ! work arrays for MPI
6407 : real(dp),allocatable :: zw(:,:),zt(:,:,:) ! cache work array and array for transpositions
6408 : ! FFT work arrays
6409 : real(dp) :: tsec(2)
6410 : ! *************************************************************************
6411 :
6412 : ! FIXME must provide a default value but which one?
6413 : !ioption = 0
6414 : ioption = 1
6415 : !if (paral_kgb==1) ioption=1
6416 :
6417 : nproc_fft = xmpi_comm_size(comm_fft); me_fft = xmpi_comm_rank(comm_fft)
6418 :
6419 : ! find cache size that gives optimal performance on machine
6420 : ncache=2*max(n1,n2,n3,1024)
6421 : !ncache=2*max(n1,n2,n3,16*1024)
6422 :
6423 : if (ncache/(2*max(n1,n2,n3))<1) then
6424 : write(msg,'(5a)') &
6425 : 'ncache has to be enlarged to be able to hold at',ch10, &
6426 : 'least one 1-d FFT of each size even though this will',ch10,&
6427 : 'reduce the performance for shorter transform lengths'
6428 : ABI_ERROR(msg)
6429 : end if
6430 :
6431 : ! Effective m1 and m2 (complex-to-complex or real-to-complex)
6432 : n1eff=n1; m2eff=m2; m1zt=n1
6433 : if (cplexwf==1) then
6434 : n1eff=(n1+1)/2; m2eff=m2/2+1; m1zt=2*(n1/2+1)
6435 : end if
6436 :
6437 : lzt=m2eff
6438 : if (mod(m2eff,2)==0) lzt=lzt+1
6439 : if (mod(m2eff,4)==0) lzt=lzt+1
6440 :
6441 : ! maximal number of big box 3rd dim slices for all procs
6442 : nnd3=nd3proc*nproc_fft
6443 :
6444 : ABI_MALLOC(zw,(2,ncache/2))
6445 : ABI_MALLOC(zt,(2,lzt,m1zt))
6446 : ABI_MALLOC(zmpi2,(2,md1,md2proc,nnd3,ndat))
6447 : if (nproc_fft>1) then
6448 : ABI_MALLOC(zmpi1,(2,md1,md2proc,nnd3,ndat))
6449 : end if
6450 :
6451 : ! Create plans.
6452 : ! The prototype for sfftw_plan_many_dft is:
6453 : ! sfftw_plan_many_dft(rank, n, howmany,
6454 : ! fin, iembed, istride, idist,
6455 : ! fout, oembed, ostride, odist, isign, my_flags)
6456 :
6457 : lot2=ncache/(2*n2)
6458 : lot1=ncache/(2*n1)
6459 : lot3=ncache/(2*n3)
6460 :
6461 : nthreads = xomp_get_num_threads(open_parallel=.TRUE.)
6462 : !nthreads = 1
6463 :
6464 : fw_plan3_lot = dplan_many_dft_2D(1, [n3], lot3, &
6465 : zw, [ncache/2], lot3, 1, &
6466 : zw, [ncache/2], lot3, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
6467 :
6468 : if (mod(m1, lot3) /= 0) then
6469 : fw_plan3_rest = dplan_many_dft_2D(1, [n3], mod(m1, lot3), &
6470 : zw, [ncache/2], lot3, 1, &
6471 : zw, [ncache/2], lot3, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
6472 : end if
6473 :
6474 : fw_plan1_lot = dplan_many_dft_2D(1, [n1], lot1, &
6475 : zt, [lzt, m1zt], lzt, 1, &
6476 : zw, [ncache/2], lot1, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
6477 :
6478 : if (mod(m2eff, lot1) /= 0) then
6479 : fw_plan1_rest = dplan_many_dft_2D(1, [n1], mod(m2eff, lot1), &
6480 : zt, [lzt, m1zt], lzt, 1, &
6481 : zw, [ncache/2], lot1, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
6482 : end if
6483 :
6484 : fw_plan2_lot = dplan_many_dft_2D(1, [n2], lot2, &
6485 : zr, [nd1,nd2,nd3proc,ndat], nd1, 1, &
6486 : zw, [ncache/2], lot2, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
6487 :
6488 : if (mod(n1eff, lot2) /= 0) then
6489 : fw_plan2_rest = dplan_many_dft_2D(1, [n2], mod(n1eff,lot2), &
6490 : zr, [nd1,nd2,nd3proc,ndat], nd1, 1, &
6491 : zw, [ncache/2], lot2, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
6492 : end if
6493 :
6494 : do idat=1,ndat
6495 : ! Loop over the z-planes treated by this node
6496 : do j3=1,nd3proc
6497 :
6498 : if (me_fft*nd3proc+j3 <= n3) then
6499 : Jp2st=1
6500 : J2st=1
6501 :
6502 : ! Treat real wavefunctions.
6503 : if (cplexwf==1) then
6504 : n1half=n1/2
6505 : do i2=1,n2
6506 : do i1=1,n1half
6507 : zr(1,i1,i2,j3,idat)=zr(1,2*i1-1,i2,j3,idat)
6508 : zr(2,i1,i2,j3,idat)=zr(1,2*i1 ,i2,j3,idat)
6509 : end do
6510 : end do
6511 : ! If odd
6512 : if(n1half*2/=n1)then
6513 : do i2=1,n2
6514 : zr(1,n1eff,i2,j3,idat)=zr(1,n1,i2,j3,idat)
6515 : zr(2,n1eff,i2,j3,idat)=zero
6516 : end do
6517 : end if
6518 : end if
6519 :
6520 : ! transform along y axis
6521 : ! input: R1,R2,R3,(Rp3)
6522 : ! input: R1,G2,R3,(Rp3)
6523 : do j=1,n1eff,lot2
6524 : ma=j
6525 : mb=min(j+(lot2-1),n1eff)
6526 : n1dfft=mb-ma+1
6527 :
6528 : if (n1dfft == lot2) then
6529 : call dfftw_execute_dft(fw_plan2_lot, zr(1,j,1,j3,idat), zw)
6530 : else
6531 : call dfftw_execute_dft(fw_plan2_rest, zr(1,j,1,j3,idat), zw)
6532 : end if
6533 :
6534 : ! input: R1,G2,R3,(Rp3)
6535 : ! output: G2,R1,R3,(Rp3)
6536 : if (cplexwf==2) then
6537 : call unswitch_cent(n1dfft,max2,m2,n2,lot2,n1,lzt,zw,zt(1,1,j))
6538 : else
6539 : call unswitchreal_cent(n1dfft,max2,n2,lot2,n1,lzt,zw,zt(1,1,2*j-1))
6540 : end if
6541 : end do
6542 :
6543 : ! transform along x axis
6544 : ! input: G2,R1,R3,(Rp3)
6545 : do j=1,m2eff,lot1
6546 : ma=j
6547 : mb=min(j+(lot1-1),m2eff)
6548 : n1dfft=mb-ma+1
6549 :
6550 : if (n1dfft == lot1) then
6551 : call dfftw_execute_dft(fw_plan1_lot, zt(1,j,1), zw)
6552 : else
6553 : call dfftw_execute_dft(fw_plan1_rest, zt(1,j,1), zw)
6554 : end if
6555 : ! output: G2,G1,R3,(Rp3)
6556 :
6557 : ! input: G2,G1,R3,Gp2,(Rp3)
6558 : ! output: G1,G2,R3,Gp2,(Rp3)
6559 : if (nproc_fft==1) then
6560 : call unmpiswitch_cent(j3,n1dfft,Jp2st,J2st,lot1,max1,md1,m1,n1,&
6561 : & md2proc,nd3proc,nproc_fft,ioption,zw,zmpi2(:,:,:,:,idat))
6562 : else
6563 : call unmpiswitch_cent(j3,n1dfft,Jp2st,J2st,lot1,max1,md1,m1,n1,&
6564 : & md2proc,nd3proc,nproc_fft,ioption,zw,zmpi1(:,:,:,:,idat))
6565 : end if
6566 : end do
6567 : end if
6568 : end do ! j3
6569 :
6570 : ! Interprocessor data transposition
6571 : ! input: G1,G2,R3,Gp2,(Rp3)
6572 : ! output: G1,G2,R3,Rp3,(Gp2)
6573 : if (nproc_fft>1) then
6574 : call timab(544,1,tsec)
6575 : call xmpi_ialltoall(zmpi1(:,:,:,:,idat),2*md1*md2proc*nd3proc, &
6576 : zmpi2(:,:,:,:,idat),2*md1*md2proc*nd3proc,comm_fft,requests(idat))
6577 : call timab(544,2,tsec)
6578 : end if
6579 : end do
6580 :
6581 : do idat=1,ndat
6582 : if (nproc_fft>1) call xmpi_wait(requests(idat),ierr)
6583 : ! transform along z axis
6584 : ! input: G1,G2,R3,(Gp2)
6585 :
6586 : do j2=1,md2proc
6587 : if (me_fft*md2proc+j2 <= m2eff) then
6588 : ! write(std_out,*)' forwf_wf : before unscramble, j2,md2proc,me_fft,m2=',j2,md2proc,me_fft,m2
6589 : do i1=1,m1,lot3
6590 : ma=i1
6591 : mb=min(i1+(lot3-1),m1)
6592 : n1dfft=mb-ma+1
6593 :
6594 : ! input: G1,G2,R3,(Gp2)
6595 : ! output: G1,R3,G2,(Gp2)
6596 : call unscramble(i1,j2,lot3,n1dfft,md1,n3,md2proc,nnd3,zmpi2(:,:,:,:,idat),zw)
6597 :
6598 : if (n1dfft == lot3) then
6599 : call dfftw_execute_dft(fw_plan3_lot, zw, zw)
6600 : else
6601 : call dfftw_execute_dft(fw_plan3_rest, zw, zw)
6602 : end if
6603 :
6604 : call unfill_cent(md1,md3,lot3,n1dfft,max3,m3,n3,zw,zf(1,i1,1,j2,idat))
6605 : ! output: G1,G3,G2,(Gp2)
6606 : end do
6607 : end if
6608 : end do
6609 :
6610 : if (cplexwf==1) then
6611 : ! Complete missing values with complex conjugate
6612 : ! Inverse of ix is located at nx+2-ix , except for ix=1, for which it is 1.
6613 : do i3=1,m3
6614 : i3inv=m3+2-i3
6615 : if(i3==1)i3inv=1
6616 :
6617 : if (m2eff>1) then
6618 : do i2=2,m2eff
6619 : i2inv=m2+2-i2
6620 : zf(1,1,i3inv,i2inv,idat)= zf(1,1,i3,i2,idat)
6621 : zf(2,1,i3inv,i2inv,idat)=-zf(2,1,i3,i2,idat)
6622 : do i1=2,m1
6623 : i1inv=m1+2-i1
6624 : zf(1,i1inv,i3inv,i2inv,idat)= zf(1,i1,i3,i2,idat)
6625 : zf(2,i1inv,i3inv,i2inv,idat)=-zf(2,i1,i3,i2,idat)
6626 : end do
6627 : end do
6628 : end if
6629 : end do
6630 : end if
6631 :
6632 : end do ! idat
6633 :
6634 : call dfftw_destroy_plan(fw_plan3_lot)
6635 : if (mod(m1, lot3) /= 0) call dfftw_destroy_plan(fw_plan3_rest)
6636 :
6637 : call dfftw_destroy_plan(fw_plan1_lot)
6638 : if (mod(m2eff, lot1) /= 0) call dfftw_destroy_plan(fw_plan1_rest)
6639 :
6640 : call dfftw_destroy_plan(fw_plan2_lot)
6641 : if (mod(n1eff, lot2) /= 0) call dfftw_destroy_plan(fw_plan2_rest)
6642 :
6643 : ABI_FREE(zmpi2)
6644 : ABI_FREE(zw)
6645 : ABI_FREE(zt)
6646 : if (nproc_fft>1) then
6647 : ABI_FREE(zmpi1)
6648 : end if
6649 :
6650 : #else
6651 0 : ABI_ERROR("FFTW3 support not activated")
6652 : ABI_UNUSED((/cplexwf,ndat,n1,n2,n3,nd1,nd2,nd3proc/))
6653 : ABI_UNUSED((/max1,max2,max3,m1,m2,m3,md1,md2proc,md3,comm_fft/))
6654 : ABI_UNUSED((/zf(1,1,1,1,1),zr(1,1,1,1,1)/))
6655 : #endif
6656 :
6657 0 : end subroutine fftw3_mpiforw_manywf
6658 : !!***
6659 :
6660 : !----------------------------------------------------------------------
6661 :
6662 : !!****f* m_fftw3/fftw3_applypot_many
6663 : !! NAME
6664 : !! fftw3_applypot_many
6665 : !!
6666 : !! FUNCTION
6667 : !! Applies the local real space potential to multiple wavefunctions in Fourier space
6668 : !!
6669 : !! INPUTS
6670 : !! ZF: Wavefunction (input/output) (note the switch of i2 and i3)
6671 : !! real(F(i1,i3,i2,idat))=ZF(1,i1,i3,i2,idat)
6672 : !! imag(F(i1,i3,i2,idat))=ZF(2,i1,i3,i2,idat)
6673 : !! max1 is positive or zero ; m1 >=max1+1
6674 : !! i1= 1... max1+1 corresponds to positive and zero wavevectors 0 ... max1
6675 : !! then, if m1 > max1+1, one has min1=max1-m1+1 and
6676 : !! i1= max1+2 ... m1 corresponds to negative wavevectors min1 ... -1
6677 : !! i2 and i3 have a similar definition of range
6678 : !! idat=1,ndat
6679 : !! md1,md2,md3: Dimension of ZF (input as well as output), distributed on different procs
6680 : !! md2proc=((md2-1)/nproc_fft)+1 maximal number of small box 2nd dim slices for one proc
6681 : !!
6682 : !! POT: Potential
6683 : !! POT(cplex*i1,i2,i3)
6684 : !! cplex=1 or 2 , i1=1,n1 , i2=1,n2 , i3=1,n3
6685 : !! nd1,nd2,nd3: dimension of pot
6686 : !! comm_fft: MPI communicator
6687 : !! nproc_fft: number of processors used as returned by MPI_COMM_SIZE
6688 : !! me_fft: [0:nproc_fft-1] number of processor as returned by MPI_COMM_RANK
6689 : !! n1,n2,n3: logical dimension of the transform. As transform lengths
6690 : !! most products of the prime factors 2,3,5 are allowed.
6691 : !! The detailed table with allowed transform lengths can
6692 : !! be found in subroutine CTRIG
6693 : !!
6694 : !! NOTES:
6695 : !! PERFORMANCE CONSIDERATIONS:
6696 : !! The maximum number of processors that can reasonably be used is max(n2/2,n3/2)
6697 : !!
6698 : !! It is very important to find the optimal
6699 : !! value of NCACHE. NCACHE determines the size of the work array ZW, that
6700 : !! has to fit into cache. It has therefore to be chosen to equal roughly
6701 : !! half the size of the physical cache in units of real*8 numbers.
6702 : !! The optimal value of ncache can easily be determined by numerical
6703 : !! experimentation. A too large value of ncache leads to a dramatic
6704 : !! and sudden decrease of performance, a too small value to a to a
6705 : !! slow and less dramatic decrease of performance. If NCACHE is set
6706 : !! to a value so small, that not even a single one dimensional transform
6707 : !! can be done in the workarray zw, the program stops with an error message.
6708 : !!
6709 : !! SOURCE
6710 :
6711 :
6712 0 : subroutine fftw3_applypot_many(cplexwf,cplex,ndat,n1,n2,n3,nd1,nd2,nd3,nd3proc,&
6713 : max1i,max2i,max3i,m1i,m2i,m3i,md1,md2proc,md3,&
6714 0 : max1o,max2o,max3o,m1o,m2o,m3o,comm_fft,nproc_fft,me_fft,pot,zf)
6715 :
6716 : !Arguments ------------------------------------
6717 : integer,intent(in) :: cplexwf,cplex,ndat,n1,n2,n3,nd1,nd2,nd3,nd3proc
6718 : integer,intent(in) :: max1i,max2i,max3i,m1i,m2i,m3i,md1,md2proc,md3
6719 : integer,intent(in) :: max1o,max2o,max3o,m1o,m2o,m3o,comm_fft,nproc_fft,me_fft
6720 : real(dp),intent(in) :: pot(cplex*nd1,nd2,nd3)
6721 : real(dp),intent(inout) :: zf(2,md1,md3,md2proc,ndat)
6722 :
6723 : !Local variables-------------------------------
6724 : !scalars
6725 : #ifdef HAVE_FFTW3
6726 : integer,parameter :: unused0=0
6727 : integer :: j,i1,i2,i3,idat,ierr,j3glob,nthreads
6728 : integer :: ioption,j2,j3,lzt,m1zt,ma,mb,n1dfft,nnd3,lot1,lot2,lot3
6729 : integer :: m2eff,ncache,n1eff,i1inv,i2inv,i3inv,jeff,includelast,j2stb
6730 : integer :: jx,j2stf,Jp2stb,Jp2stf,m2ieff,m2oeff
6731 : integer(KIND_FFTW_PLAN) :: bw_plan1_lot,bw_plan1_rest
6732 : integer(KIND_FFTW_PLAN) :: bw_plan2_lot,bw_plan2_rest
6733 : integer(KIND_FFTW_PLAN) :: bw_plan3_lot,bw_plan3_rest
6734 : integer(KIND_FFTW_PLAN) :: fw_plan1_lot,fw_plan1_rest
6735 : integer(KIND_FFTW_PLAN) :: fw_plan2_lot,fw_plan2_rest
6736 : integer(KIND_FFTW_PLAN) :: fw_plan3_lot,fw_plan3_rest
6737 : character(len=500) :: msg
6738 : !arrays
6739 : integer :: requests(ndat)
6740 : real(dp) :: tsec(2)
6741 : real(dp) ABI_ASYNC, allocatable :: zmpi1(:,:,:,:,:),zmpi2(:,:,:,:,:) ! work arrays for MPI
6742 : real(dp),allocatable :: zw(:,:),zt(:,:,:) ! cache work array and array for transpositions
6743 : ! FFT work arrays
6744 : ! *************************************************************************
6745 :
6746 : !ioption=0 ! This was in the old version.
6747 : ioption=1 ! This one is needed to be compatible with paral_kgb
6748 :
6749 : ncache=2*max(n1,n2,n3,1024)
6750 : if (ncache/(2*max(n1,n2,n3)) < 1) then
6751 : write(msg,"(5a)") &
6752 : 'ncache has to be enlarged to be able to hold at',ch10,&
6753 : 'least one 1-d FFT of each size even though this will',ch10,&
6754 : 'reduce the performance for shorter transform lengths'
6755 : ABI_ERROR(msg)
6756 : end if
6757 :
6758 : !call wrtout(std_out,"applypot with non-blocking IALLTOALL + FFTW3")
6759 : !write(std_out,"(a,i0)")"in applypot_many with ndat: ",ndat
6760 :
6761 : ! Effective m1 and m2 (complex-to-complex or real-to-complex)
6762 : n1eff=n1; m2ieff=m2i; m2oeff=m2o; m1zt=n1
6763 : if (cplexwf==1) then
6764 : n1eff=(n1+1)/2; m2ieff=m2i/2+1; m2oeff=m2o/2+1; m1zt=2*(n1/2+1)
6765 : end if
6766 :
6767 : m2eff=max(m2ieff,m2oeff)
6768 : lzt=m2eff
6769 : if (mod(m2eff,2) == 0) lzt=lzt+1
6770 : if (mod(m2eff,4) == 0) lzt=lzt+1
6771 :
6772 : ! maximal number of big box 3rd dim slices for all procs
6773 : nnd3=nd3proc*nproc_fft
6774 :
6775 : ABI_MALLOC(zw,(2,ncache/2))
6776 : ABI_MALLOC(zt,(2,lzt,m1zt))
6777 : ABI_MALLOC(zmpi2,(2,md1,md2proc,nnd3,ndat))
6778 : if (nproc_fft > 1) then
6779 : ABI_MALLOC(zmpi1,(2,md1,md2proc,nnd3,ndat))
6780 : end if
6781 :
6782 : lot3=ncache/(2*n3)
6783 : lot1=ncache/(2*n1)
6784 : lot2=ncache/(2*n2)
6785 :
6786 : nthreads = xomp_get_num_threads(open_parallel=.TRUE.)
6787 : !nthreads = 1
6788 :
6789 : ! The prototype for sfftw_plan_many_dft is:
6790 : ! sfftw_plan_many_dft(rank, n, howmany,
6791 : ! fin, iembed, istride, idist,
6792 : ! fout, oembed, ostride, odist, isign, my_flags)
6793 :
6794 : ! Create plans for G --> R (see back_wf)
6795 : bw_plan3_lot = dplan_many_dft_2D(1, [n3], lot3, &
6796 : zw, [ncache/2], lot3, 1, &
6797 : zw, [ncache/2], lot3, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
6798 :
6799 : if (mod(m1i, lot3) /= 0) then
6800 : bw_plan3_rest = dplan_many_dft_2D(1, [n3], mod(m1i, lot3),&
6801 : zw, [ncache/2], lot3, 1, &
6802 : zw, [ncache/2], lot3, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
6803 : end if
6804 :
6805 : bw_plan1_lot = dplan_many_dft_2D(1, [n1], lot1, &
6806 : zw, [ncache/2], lot1, 1, &
6807 : zt, [lzt, m1zt], lzt, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
6808 :
6809 : if (mod(m2ieff, lot1) /= 0) then
6810 : bw_plan1_rest = dplan_many_dft_2D(1, [n1], mod(m2ieff, lot1), &
6811 : zw, [ncache/2], lot1, 1, &
6812 : zt, [lzt, m1zt], lzt, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
6813 : end if
6814 :
6815 : !TODO this won't work if iclexwf==1
6816 : ! Recheck this
6817 : bw_plan2_lot = dplan_many_dft_2D(1, [n2], lot2, &
6818 : zw, [ncache/2], lot2, 1, &
6819 : zw, [ncache/2], lot2, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
6820 :
6821 : if (mod(n1eff, lot2) /= 0) then
6822 : bw_plan2_rest = dplan_many_dft_2D(1, [n2], mod(n1eff,lot2), &
6823 : zw, [ncache/2], lot2, 1, &
6824 : zw, [ncache/2], lot2, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
6825 : end if
6826 :
6827 : ! Create plans for G --> R (see forw_wf)
6828 : fw_plan3_lot = dplan_many_dft_2D(1, [n3], lot3, &
6829 : zw, [ncache/2], lot3, 1, &
6830 : zw, [ncache/2], lot3, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
6831 :
6832 : if (mod(m1o, lot3) /= 0) then
6833 : fw_plan3_rest = dplan_many_dft_2D(1, [n3], mod(m1o, lot3),&
6834 : zw, [ncache/2], lot3, 1, &
6835 : zw, [ncache/2], lot3, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
6836 : end if
6837 :
6838 : fw_plan1_lot = dplan_many_dft_2D(1, [n1], lot1,&
6839 : zt, [lzt, m1zt], lzt, 1, &
6840 : zw, [ncache/2], lot1, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
6841 :
6842 : if (mod(m2oeff, lot1) /= 0) then
6843 : fw_plan1_rest = dplan_many_dft_2D(1, [n1], mod(m2oeff, lot1),&
6844 : zt, [lzt, m1zt], lzt, 1, &
6845 : zw, [ncache/2], lot1, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
6846 : end if
6847 :
6848 : fw_plan2_lot = dplan_many_dft_2D(1, [n2], lot2,&
6849 : zw, [ncache/2], lot2, 1, &
6850 : zw, [ncache/2], lot2, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
6851 :
6852 : if (mod(n1eff, lot2) /= 0) then
6853 : fw_plan2_rest = dplan_many_dft_2D(1, [n2], mod(n1eff,lot2),&
6854 : zw, [ncache/2], lot2, 1, &
6855 : zw, [ncache/2], lot2, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
6856 : end if
6857 :
6858 : ! Here we take advantage of non-blocking IALLTOALL:
6859 : ! Perform the first step of MPI-FFT for ndat wavefunctions.
6860 : do idat=1,ndat
6861 : !
6862 : ! transform along z axis
6863 : ! input: G1,G3,G2,(Gp2)
6864 : do j2=1,md2proc
6865 : if (me_fft*md2proc+j2 <= m2ieff) then
6866 : do i1=1,m1i,lot3
6867 : ma=i1
6868 : mb=min(i1+(lot3-1),m1i)
6869 : n1dfft=mb-ma+1
6870 :
6871 : ! zero-pad n1dfft G_z lines
6872 : ! input: G1,G3,G2,(Gp2)
6873 : call fill_cent(md1,md3,lot3,n1dfft,max3i,m3i,n3,zf(1,i1,1,j2,idat),zw)
6874 :
6875 : if (n1dfft == lot3) then
6876 : call dfftw_execute_dft(bw_plan3_lot, zw, zw)
6877 : else
6878 : call dfftw_execute_dft(bw_plan3_rest, zw, zw)
6879 : end if
6880 :
6881 : ! Local rotation.
6882 : ! input: G1,R3,G2,(Gp2)
6883 : ! output: G1,G2,R3,(Gp2)
6884 : call scramble(i1,j2,lot3,n1dfft,md1,n3,md2proc,nnd3,zw,zmpi2(:,:,:,:,idat))
6885 : end do
6886 : end if
6887 : end do
6888 :
6889 : ! Interprocessor data transposition
6890 : ! input: G1,G2,R3,Rp3,(Gp2)
6891 : ! output: G1,G2,R3,Gp2,(Rp3)
6892 : if (nproc_fft > 1) then
6893 : call timab(543,1,tsec)
6894 : call xmpi_ialltoall(zmpi2(:,:,:,:,idat),2*md1*md2proc*nd3proc,&
6895 : zmpi1(:,:,:,:,idat),2*md1*md2proc*nd3proc,comm_fft,requests(idat))
6896 : call timab(543,2,tsec)
6897 : end if
6898 : end do ! idat
6899 :
6900 : ! The second step of MPI-FFT
6901 : do idat=1,ndat
6902 : ! Make sure communication is completed.
6903 : if (nproc_fft>1) call xmpi_wait(requests(idat),ierr)
6904 :
6905 : do j3=1,nd3proc
6906 : j3glob = j3 + me_fft*nd3proc
6907 : if (me_fft*nd3proc+j3 <= n3) then
6908 : Jp2stb=1; J2stb=1
6909 : Jp2stf=1; J2stf=1
6910 :
6911 : ! transform along x axis
6912 : do j=1,m2ieff,lot1
6913 : ma=j
6914 : mb=min(j+(lot1-1),m2ieff)
6915 : n1dfft=mb-ma+1
6916 :
6917 : ! Zero-pad input.
6918 : ! input: G1,G2,R3,G2,(Rp3)
6919 : ! output: G2,G1,R3,G2,(Rp3)
6920 : if (nproc_fft == 1) then
6921 : call mpiswitch_cent(j3,n1dfft,Jp2stb,J2stb,lot1,max1i,md1,m1i,n1,&
6922 : md2proc,nd3proc,nproc_fft,ioption,zmpi2(:,:,:,:,idat),zw, unused0, unused0, unused0)
6923 : else
6924 : call mpiswitch_cent(j3,n1dfft,Jp2stb,J2stb,lot1,max1i,md1,m1i,n1,&
6925 : md2proc,nd3proc,nproc_fft,ioption,zmpi1(:,:,:,:,idat),zw, unused0, unused0, unused0)
6926 : end if
6927 :
6928 : ! Transform along x
6929 : ! input: G2,G1,R3,(Rp3)
6930 : ! output: G2,R1,R3,(Rp3)
6931 : if (n1dfft == lot1) then
6932 : call dfftw_execute_dft(bw_plan1_lot, zw, zt(1,j,1))
6933 : else
6934 : call dfftw_execute_dft(bw_plan1_rest, zw, zt(1,j,1))
6935 : end if
6936 : end do
6937 :
6938 : ! Transform along y axis (take into account c2c or c2r case).
6939 : ! Must loop over the full box.
6940 : !TODO this won't work
6941 : if (cplexwf==1) then
6942 : if(mod(lot2,2).ne.0) lot2=lot2-1 ! needed to introduce jeff
6943 : end if
6944 :
6945 : do j=1,n1eff,lot2
6946 : ma=j
6947 : mb=min(j+(lot2-1),n1eff)
6948 : n1dfft=mb-ma+1
6949 : jeff=j
6950 : includelast=1
6951 :
6952 : if (cplexwf==1) then
6953 : jeff=2*j-1
6954 : includelast=1
6955 : if (mb==n1eff .and. n1eff*2/=n1) includelast=0
6956 : end if
6957 :
6958 : ! Zero-pad the input.
6959 : ! input: G2,R1,R3,(Rp3)
6960 : ! output: R1,G2,R3,(Rp3)
6961 : if (cplexwf==2) then
6962 : call switch_cent(n1dfft,max2i,m2i,n2,lot2,n1,lzt,zt(1,1,jeff),zw)
6963 : else
6964 : call switchreal_cent(includelast,n1dfft,max2i,n2,lot2,m1zt,lzt,zt(1,1,jeff),zw)
6965 : end if
6966 :
6967 : ! input: R1,G2,R3,(Rp3)
6968 : ! output: R1,R2,R3,(Rp3)
6969 : ! Be careful here
6970 : if (n1dfft == lot2) then
6971 : call dfftw_execute_dft(bw_plan2_lot, zw, zw)
6972 : else
6973 : call dfftw_execute_dft(bw_plan2_rest, zw, zw)
6974 : end if
6975 :
6976 : ! Multiply with potential in real space
6977 : jx=cplex*(jeff-1)+1
6978 : call multpot(cplexwf,cplex,includelast,nd1,nd2,n2,lot2,n1dfft,pot(jx,1,j3glob),zw)
6979 :
6980 : ! TRANSFORM BACK IN FOURIER SPACE
6981 : ! transform along y axis
6982 : ! input: R1,R2,R3,(Rp3)
6983 : if (n1dfft == lot2) then
6984 : call dfftw_execute_dft(fw_plan2_lot, zw, zw)
6985 : else
6986 : call dfftw_execute_dft(fw_plan2_rest, zw, zw)
6987 : end if
6988 :
6989 : ! input: R1,G2,R3,(Rp3)
6990 : ! output: G2,R1,R3,(Rp3)
6991 : if (cplexwf==2) then
6992 : call unswitch_cent(n1dfft,max2o,m2o,n2,lot2,n1,lzt,zw,zt(1,1,jeff))
6993 : else
6994 : call unswitchreal_cent(n1dfft,max2o,n2,lot2,n1,lzt,zw,zt(1,1,jeff))
6995 : end if
6996 : end do ! j
6997 :
6998 : ! transform along x axis
6999 : ! input: R2,R1,R3,(Rp3)
7000 : ! output: R2,G1,R3,(Rp3)
7001 : do j=1,m2oeff,lot1
7002 : ma=j
7003 : mb=min(j+(lot1-1),m2oeff)
7004 : n1dfft=mb-ma+1
7005 :
7006 : if (n1dfft == lot1) then
7007 : call dfftw_execute_dft(fw_plan1_lot, zt(1,j,1), zw)
7008 : else
7009 : call dfftw_execute_dft(fw_plan1_rest, zt(1,j,1), zw)
7010 : end if
7011 :
7012 : ! input: G2,G1,R3,Gp2,(Rp3)
7013 : ! output: G1,G2,R3,Gp2,(Rp3)
7014 : if (nproc_fft == 1) then
7015 : call unmpiswitch_cent(j3,n1dfft,Jp2stf,J2stf,lot1,max1o,md1,m1o,n1,&
7016 : md2proc,nd3proc,nproc_fft,ioption,zw,zmpi2(:,:,:,:,idat))
7017 : else
7018 : call unmpiswitch_cent(j3,n1dfft,Jp2stf,J2stf,lot1,max1o,md1,m1o,n1,&
7019 : md2proc,nd3proc,nproc_fft,ioption,zw,zmpi1(:,:,:,:,idat))
7020 : end if
7021 : end do ! j
7022 : end if
7023 : end do
7024 :
7025 : ! Interprocessor data transposition
7026 : ! input: G1,G2,R3,Gp2,(Rp3)
7027 : ! output: G1,G2,R3,Rp3,(Gp2)
7028 : if (nproc_fft > 1) then
7029 : call timab(544,1,tsec)
7030 : call xmpi_ialltoall(zmpi1(:,:,:,:,idat),2*md1*md2proc*nd3proc, &
7031 : zmpi2(:,:,:,:,idat),2*md1*md2proc*nd3proc,comm_fft,requests(idat))
7032 : call timab(544,2,tsec)
7033 : end if
7034 : end do
7035 :
7036 : do idat=1,ndat
7037 : if (nproc_fft>1) call xmpi_wait(requests(idat),ierr)
7038 : ! transform along z axis
7039 : ! input: G1,G2,R3,(Gp2)
7040 : !lot=ncache/(4*n3)
7041 : do j2=1,md2proc
7042 : if (me_fft*md2proc+j2 <= m2oeff) then
7043 : do i1=1,m1o,lot3
7044 : ma=i1
7045 : mb=min(i1+(lot3-1),m1o)
7046 : n1dfft=mb-ma+1
7047 :
7048 : ! input: G1,G2,R3,(Gp2)
7049 : ! output: G1,R3,G2,(Gp2)
7050 : call unscramble(i1,j2,lot3,n1dfft,md1,n3,md2proc,nnd3,zmpi2(:,:,:,:,idat),zw)
7051 :
7052 : if (n1dfft == lot3) then
7053 : call dfftw_execute_dft(fw_plan3_lot, zw, zw)
7054 : else
7055 : call dfftw_execute_dft(fw_plan3_rest, zw, zw)
7056 : end if
7057 :
7058 : call unfill_cent(md1,md3,lot3,n1dfft,max3o,m3o,n3,zw,zf(1,i1,1,j2,idat))
7059 : ! output: G1,G3,G2,(Gp2)
7060 : end do
7061 : end if
7062 : end do
7063 :
7064 : ! Complete missing values with complex conjugate
7065 : ! Inverse of ix is located at nx+2-ix , except for ix=1, for which it is 1.
7066 : if (cplexwf==1) then
7067 : do i3=1,m3o
7068 : i3inv=m3o+2-i3
7069 : if (i3==1) i3inv=1
7070 : if (m2oeff>1)then
7071 : do i2=2,m2oeff
7072 : i2inv=m2o+2-i2
7073 : zf(1,1,i3inv,i2inv,idat)= zf(1,1,i3,i2,idat)
7074 : zf(2,1,i3inv,i2inv,idat)=-zf(2,1,i3,i2,idat)
7075 : do i1=2,m1o
7076 : i1inv=m1o+2-i1
7077 : zf(1,i1inv,i3inv,i2inv,idat)= zf(1,i1,i3,i2,idat)
7078 : zf(2,i1inv,i3inv,i2inv,idat)=-zf(2,i1,i3,i2,idat)
7079 : end do
7080 : end do
7081 : end if
7082 : end do
7083 : end if
7084 :
7085 : end do ! idat
7086 :
7087 : call dfftw_destroy_plan(bw_plan3_lot)
7088 : if (mod(m1i, lot3) /= 0) call dfftw_destroy_plan(bw_plan3_rest)
7089 :
7090 : call dfftw_destroy_plan(bw_plan1_lot)
7091 : if (mod(m2ieff, lot1) /= 0) call dfftw_destroy_plan(bw_plan1_rest)
7092 :
7093 : call dfftw_destroy_plan(bw_plan2_lot)
7094 : if (mod(n1eff, lot2) /= 0) call dfftw_destroy_plan(bw_plan2_rest)
7095 :
7096 : call dfftw_destroy_plan(fw_plan3_lot)
7097 : if (mod(m1o, lot3) /= 0) call dfftw_destroy_plan(fw_plan3_rest)
7098 :
7099 : call dfftw_destroy_plan(fw_plan1_lot)
7100 : if (mod(m2oeff, lot1) /= 0) call dfftw_destroy_plan(fw_plan1_rest)
7101 :
7102 : call dfftw_destroy_plan(fw_plan2_lot)
7103 : if (mod(n1eff, lot2) /= 0) call dfftw_destroy_plan(fw_plan2_rest)
7104 :
7105 : ABI_FREE(zmpi2)
7106 : ABI_FREE(zw)
7107 : ABI_FREE(zt)
7108 : if (nproc_fft > 1) then
7109 : ABI_FREE(zmpi1)
7110 : end if
7111 :
7112 : #else
7113 0 : ABI_ERROR("FFTW3 support not activated")
7114 : ABI_UNUSED((/cplexwf,cplex,ndat,n1,n2,n3,nd1,nd2,nd3,nd3proc/))
7115 : ABI_UNUSED((/max1i,max2i,max3i,m1i,m2i,m3i,md1,md2proc,md3/))
7116 : ABI_UNUSED((/max1o,max2o,max3o,m1o,m2o,m3o,comm_fft,nproc_fft,me_fft/))
7117 : ABI_UNUSED((/pot(1,1,1),zf(1,1,1,1,1)/))
7118 : #endif
7119 :
7120 0 : end subroutine fftw3_applypot_many
7121 : !!***
7122 :
7123 : !----------------------------------------------------------------------
7124 :
7125 : !!****f* m_fftw3/fftw3_poisson
7126 : !! NAME
7127 : !! fftw3_poisson
7128 : !!
7129 : !! FUNCTION
7130 : !! Solve the Poisson equation in G-space given the density, n(r),
7131 : !! in real space of the FFT box.
7132 : !!
7133 : !! INPUTS
7134 : !! cplex=1 if fofr is real, 2 if fofr is complex
7135 : !! nx,ny,nz=Number of FFT points along the three directions.
7136 : !! ldx,ldy,ldz=Leading dimension of the array nr and vg.
7137 : !! ndat = Number of densities
7138 : !! vg(nx*ny*nz)=Potential in reciprocal space.
7139 : !!
7140 : !! SIDE EFFECTS
7141 : !! nr(cplex*ldx*ldy*ldz*ndat)
7142 : !! input: n(r) (real or complex)
7143 : !! output: the hartree potential in real space
7144 : !!
7145 : !! NOTES
7146 : !! vg is given on the FFT mesh instead of the augmented mesh [ldx,ldy,ldz]
7147 : !! in order to simplify the interface with the other routines operating of vg
7148 : !!
7149 : !! SOURCE
7150 :
7151 0 : subroutine fftw3_poisson(cplex,nx,ny,nz,ldx,ldy,ldz,ndat,vg,nr)
7152 :
7153 : !Arguments ------------------------------------
7154 : !scalars
7155 : integer,intent(in) :: cplex,nx,ny,nz,ldx,ldy,ldz,ndat
7156 : !arrays
7157 : real(dp),intent(inout) :: nr(cplex*ldx*ldy*ldz*ndat)
7158 : real(dp),intent(in) :: vg(nx*ny*nz)
7159 :
7160 : #ifdef HAVE_FFTW3
7161 : !Local variables-------------------------------
7162 : !scalars
7163 : integer,parameter :: rank1=1,rank2=2
7164 : integer :: ii,jj,kk,sidx,ig,ir,vgbase,ypad
7165 : integer, parameter :: nthreads=1
7166 : integer(KIND_FFTW_PLAN) :: bw_plan_xy,bw_plan3
7167 : integer(KIND_FFTW_PLAN) :: fw_plan_xy,fw_plan3
7168 : real(dp) :: fft_fact,vg_fftfact
7169 : ! *************************************************************************
7170 :
7171 : !write(std_out,*)"in poisson"
7172 : ABI_CHECK(cplex==2,"cplex!=2 not coded")
7173 : ABI_CHECK(ndat==1,"ndat!=1 not coded")
7174 :
7175 : fft_fact = one/(nx*ny*nz)
7176 :
7177 : ! The prototype for sfftw_plan_many_dft is:
7178 : ! sfftw_plan_many_dft(n, howmany,
7179 : ! fin, iembed, istride, idist,
7180 : ! fout, oembed, ostride, odist, isign, my_flags)
7181 :
7182 : ! 1) ldx*ldy transforms along Rz.
7183 : fw_plan3 = fftw3_plan_many_dft(rank1, (/nz/), ldx*ldy, & ! We have to visit the entire augmented x-y plane!
7184 : nr, (/ldx, ldy, ldz/), ldx*ldy, 1, &
7185 : nr, (/ldx, ldy, ldz/), ldx*ldy, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
7186 :
7187 : call fftw3_execute_dft(fw_plan3, nr, nr) ! Now we have nr(x,y,Gz)
7188 : call fftw3_destroy_plan(fw_plan3)
7189 :
7190 : ! R --> G Transforms in x-y plane
7191 : fw_plan_xy = fftw3_plan_many_dft(rank2, [nx,ny], 1, &
7192 : nr, (/ldx, ldy, ldz/), 1, 1, &
7193 : nr, (/ldx, ldy, ldz/), 1, 1, ABI_FFTW_FORWARD, ABI_FFTW_ESTIMATE, nthreads)
7194 :
7195 : ! G --> R Transforms in x-y plane
7196 : bw_plan_xy = fftw3_plan_many_dft(rank2, [nx, ny], 1, &
7197 : nr, (/ldx, ldy, ldz/), 1, 1, &
7198 : nr, (/ldx, ldy, ldz/), 1, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
7199 :
7200 : ! Loop on z-planes.
7201 : do kk=1,nz
7202 : sidx = 1 + cplex*(kk-1)*ldx*ldy !+ cplex*(dat-1) * ldx*ldy*ldz
7203 :
7204 : call fftw3_execute_dft(fw_plan_xy, nr(sidx:), nr(sidx:))
7205 :
7206 : ! At this point we have nr(Gx,Gy,Gz) on the current plane.
7207 : ! Multiply by vc(Gx,Gy,Gz) and then back transform immediately to get vc(x,y,Gz)
7208 : ! Note that nr is complex whereas vg is real.
7209 : ! Besides, FFTW returns not normalized FTs if sign=-1 so we have to scale by fft_fact
7210 : vgbase = (kk-1)*nx*ny !;vgbase = (kk-1)*ldx*ldy
7211 :
7212 : ig = 0
7213 : do jj=1,ny
7214 : ypad = cplex*(jj-1)*ldx + sidx
7215 : do ii=1,nx
7216 : ig = ig + 1
7217 : vg_fftfact = vg(vgbase+ig) * fft_fact
7218 :
7219 : ir = cplex*(ii-1) + ypad
7220 : nr(ir:ir+1) = nr(ir:ir+1) * vg_fftfact
7221 : end do
7222 : end do
7223 :
7224 : call fftw3_execute_dft(bw_plan_xy, nr(sidx:), nr(sidx:))
7225 : end do
7226 :
7227 : ! Free plans
7228 : call fftw3_destroy_plan(fw_plan_xy)
7229 : call fftw3_destroy_plan(bw_plan_xy)
7230 :
7231 : ! Final transforms of vc(x,y,Gz) along Gz to get vc(x,y,z)
7232 : bw_plan3 = fftw3_plan_many_dft(rank1, (/nz/), ldx*ldy, & ! We have to visit the entire augmented x-y plane!
7233 : nr, (/ldx, ldy, ldz/), ldx*ldy, 1, &
7234 : nr, (/ldx, ldy, ldz/), ldx*ldy, 1, ABI_FFTW_BACKWARD, ABI_FFTW_ESTIMATE, nthreads)
7235 :
7236 : call fftw3_execute_dft(bw_plan3, nr, nr)
7237 : call fftw3_destroy_plan(bw_plan3)
7238 :
7239 : #else
7240 : ABI_UNUSED((/cplex,nx,ny,nz,ldx,ldy,ldz,ndat/))
7241 : ABI_UNUSED((/nr(1),vg(1)/))
7242 : #endif
7243 :
7244 0 : end subroutine fftw3_poisson
7245 : !!**
7246 :
7247 : !----------------------------------------------------------------------
7248 :
7249 : END MODULE m_fftw3
7250 : !!***
|