Merge branch 'rotation-4-5' into rotation
[gromacs/adressmacs.git] / src / mdlib / gmx_fft_fftw3.c
blob342bba6ceac386795fc58187dfcd12c57b137bc6
1 /*
3 * Gromacs 4.0 Copyright (c) 1991-2003
4 * David van der Spoel, Erik Lindahl, University of Groningen.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * To help us fund GROMACS development, we humbly ask that you cite
12 * the research papers on the package. Check out http://www.gromacs.org
14 * And Hey:
15 * Gnomes, ROck Monsters And Chili Sauce
17 #ifdef HAVE_CONFIG_H
18 #include <config.h>
19 #endif
21 #ifdef GMX_FFT_FFTW3
23 #include <errno.h>
24 #include <stdlib.h>
26 #include <fftw3.h>
28 #include "gmx_fft.h"
29 #include "gmx_fatal.h"
32 #ifdef GMX_DOUBLE
33 #define FFTWPREFIX(name) fftw_ ## name
34 #else
35 #define FFTWPREFIX(name) fftwf_ ## name
36 #endif
40 #ifdef GMX_THREADS
41 /* none of the fftw3 calls, except execute(), are thread-safe, so
42 we need to serialize them with this mutex. */
43 static tMPI_Thread_mutex_t big_fftw_mutex=TMPI_THREAD_MUTEX_INITIALIZER;
44 static gmx_bool gmx_fft_threads_initialized=FALSE;
45 #define FFTW_LOCK tMPI_Thread_mutex_lock(&big_fftw_mutex);
46 #define FFTW_UNLOCK tMPI_Thread_mutex_unlock(&big_fftw_mutex);
47 #else /* GMX_THREADS */
48 #define FFTW_LOCK
49 #define FFTW_UNLOCK
50 #endif /* GMX_THREADS */
52 /* We assume here that aligned memory starts at multiple of 16 bytes and unaligned memory starts at multiple of 8 bytes. The later is guranteed for all malloc implementation.
53 Consequesences:
54 - It is not allowed to use these FFT plans from memory which doesn't have a starting address as a multiple of 8 bytes.
55 This is OK as long as the memory directly comes from malloc and is not some subarray within alloated memory.
56 - This has to be fixed if any future architecute requires memory to be aligned to multiples of 32 bytes.
59 struct gmx_fft
61 /* Three alternatives (unaligned/aligned, out-of-place/in-place, forward/backward)
62 * results in 8 different FFTW plans. Keep track of them with 3 array indices:
63 * first index: 0=unaligned, 1=aligned
64 * second index: 0=out-of-place, 1=in-place
65 * third index: 0=backward, 1=forward
67 FFTWPREFIX(plan) plan[2][2][2];
68 /* Catch user mistakes */
69 int real_transform;
70 int ndim;
75 int
76 gmx_fft_init_1d(gmx_fft_t * pfft,
77 int nx,
78 gmx_fft_flag flags)
80 return gmx_fft_init_many_1d(pfft,nx,1,flags);
84 int
85 gmx_fft_init_many_1d(gmx_fft_t * pfft,
86 int nx,
87 int howmany,
88 gmx_fft_flag flags)
90 gmx_fft_t fft;
91 FFTWPREFIX(complex) *p1,*p2,*up1,*up2;
92 size_t pc;
93 int i,j,k;
94 int fftw_flags;
96 #ifdef GMX_DISABLE_FFTW_MEASURE
97 flags |= GMX_FFT_FLAG_CONSERVATIVE;
98 #endif
100 fftw_flags = (flags & GMX_FFT_FLAG_CONSERVATIVE) ? FFTW_ESTIMATE : FFTW_MEASURE;
102 if(pfft==NULL)
104 gmx_fatal(FARGS,"Invalid opaque FFT datatype pointer.");
105 return EINVAL;
107 *pfft = NULL;
109 FFTW_LOCK;
110 if( (fft = (gmx_fft_t)FFTWPREFIX(malloc)(sizeof(struct gmx_fft))) == NULL)
112 FFTW_UNLOCK;
113 return ENOMEM;
116 /* allocate aligned, and extra memory to make it unaligned */
117 p1 = (FFTWPREFIX(complex) *) FFTWPREFIX(malloc)(sizeof(FFTWPREFIX(complex))*(nx+2)*howmany);
118 if(p1==NULL)
120 FFTWPREFIX(free)(fft);
121 FFTW_UNLOCK;
122 return ENOMEM;
125 p2 = (FFTWPREFIX(complex) *) FFTWPREFIX(malloc)(sizeof(FFTWPREFIX(complex))*(nx+2)*howmany);
126 if(p2==NULL)
128 FFTWPREFIX(free)(p1);
129 FFTWPREFIX(free)(fft);
130 FFTW_UNLOCK;
131 return ENOMEM;
134 /* make unaligned pointers.
135 * In double precision the actual complex datatype will be 16 bytes,
136 * so go to a char pointer and force an offset of 8 bytes instead.
138 pc = (size_t)p1;
139 pc += 8;
140 up1 = (FFTWPREFIX(complex) *)pc;
142 pc = (size_t)p2;
143 pc += 8;
144 up2 = (FFTWPREFIX(complex) *)pc;
146 /* int rank, const int *n, int howmany,
147 fftw_complex *in, const int *inembed,
148 int istride, int idist,
149 fftw_complex *out, const int *onembed,
150 int ostride, int odist,
151 int sign, unsigned flags */
152 fft->plan[0][0][0] = FFTWPREFIX(plan_many_dft)(1,&nx,howmany,up1,&nx,1,nx,up2,&nx,1,nx,FFTW_BACKWARD,fftw_flags);
153 fft->plan[0][0][1] = FFTWPREFIX(plan_many_dft)(1,&nx,howmany,up1,&nx,1,nx,up2,&nx,1,nx,FFTW_FORWARD,fftw_flags);
154 fft->plan[0][1][0] = FFTWPREFIX(plan_many_dft)(1,&nx,howmany,up1,&nx,1,nx,up1,&nx,1,nx,FFTW_BACKWARD,fftw_flags);
155 fft->plan[0][1][1] = FFTWPREFIX(plan_many_dft)(1,&nx,howmany,up1,&nx,1,nx,up1,&nx,1,nx,FFTW_FORWARD,fftw_flags);
156 fft->plan[1][0][0] = FFTWPREFIX(plan_many_dft)(1,&nx,howmany,p1,&nx,1,nx,p2,&nx,1,nx,FFTW_BACKWARD,fftw_flags);
157 fft->plan[1][0][1] = FFTWPREFIX(plan_many_dft)(1,&nx,howmany,p1,&nx,1,nx,p2,&nx,1,nx,FFTW_FORWARD,fftw_flags);
158 fft->plan[1][1][0] = FFTWPREFIX(plan_many_dft)(1,&nx,howmany,p1,&nx,1,nx,p1,&nx,1,nx,FFTW_BACKWARD,fftw_flags);
159 fft->plan[1][1][1] = FFTWPREFIX(plan_many_dft)(1,&nx,howmany,p1,&nx,1,nx,p1,&nx,1,nx,FFTW_FORWARD,fftw_flags);
161 for(i=0;i<2;i++)
163 for(j=0;j<2;j++)
165 for(k=0;k<2;k++)
167 if(fft->plan[i][j][k] == NULL)
169 gmx_fatal(FARGS,"Error initializing FFTW3 plan.");
170 FFTW_UNLOCK;
171 gmx_fft_destroy(fft);
172 FFTW_LOCK;
173 FFTWPREFIX(free)(p1);
174 FFTWPREFIX(free)(p2);
175 FFTW_UNLOCK;
176 return -1;
182 FFTWPREFIX(free)(p1);
183 FFTWPREFIX(free)(p2);
185 fft->real_transform = 0;
186 fft->ndim = 1;
188 *pfft = fft;
189 FFTW_UNLOCK;
190 return 0;
195 gmx_fft_init_1d_real(gmx_fft_t * pfft,
196 int nx,
197 gmx_fft_flag flags)
199 return gmx_fft_init_many_1d_real(pfft, nx, 1, flags);
203 gmx_fft_init_many_1d_real(gmx_fft_t * pfft,
204 int nx,
205 int howmany,
206 gmx_fft_flag flags)
208 gmx_fft_t fft;
209 real *p1,*p2,*up1,*up2;
210 size_t pc;
211 int i,j,k;
212 int fftw_flags;
214 #ifdef GMX_DISABLE_FFTW_MEASURE
215 flags |= GMX_FFT_FLAG_CONSERVATIVE;
216 #endif
218 fftw_flags = (flags & GMX_FFT_FLAG_CONSERVATIVE) ? FFTW_ESTIMATE : FFTW_MEASURE;
220 if(pfft==NULL)
222 gmx_fatal(FARGS,"Invalid opaque FFT datatype pointer.");
223 return EINVAL;
225 *pfft = NULL;
227 FFTW_LOCK;
228 if( (fft = (gmx_fft_t) FFTWPREFIX(malloc)(sizeof(struct gmx_fft))) == NULL)
230 FFTW_UNLOCK;
231 return ENOMEM;
234 /* allocate aligned, and extra memory to make it unaligned */
235 p1 = (real *) FFTWPREFIX(malloc)(sizeof(real)*(nx/2+1)*2*howmany + 8);
236 if(p1==NULL)
238 FFTWPREFIX(free)(fft);
239 FFTW_UNLOCK;
240 return ENOMEM;
243 p2 = (real *) FFTWPREFIX(malloc)(sizeof(real)*(nx/2+1)*2*howmany + 8);
244 if(p2==NULL)
246 FFTWPREFIX(free)(p1);
247 FFTWPREFIX(free)(fft);
248 FFTW_UNLOCK;
249 return ENOMEM;
252 /* make unaligned pointers.
253 * In double precision the actual complex datatype will be 16 bytes,
254 * so go to a char pointer and force an offset of 8 bytes instead.
256 pc = (size_t)p1;
257 pc += 8;
258 up1 = (real *)pc;
260 pc = (size_t)p2;
261 pc += 8;
262 up2 = (real *)pc;
264 /* int rank, const int *n, int howmany,
265 double *in, const int *inembed,
266 int istride, int idist,
267 fftw_complex *out, const int *onembed,
268 int ostride, int odist,
269 unsigned flag */
270 fft->plan[0][0][1] = FFTWPREFIX(plan_many_dft_r2c)(1,&nx,howmany,up1,0,1,(nx/2+1)*2,(FFTWPREFIX(complex) *)up2,0,1,(nx/2+1),fftw_flags);
271 fft->plan[0][1][1] = FFTWPREFIX(plan_many_dft_r2c)(1,&nx,howmany,up1,0,1,(nx/2+1)*2,(FFTWPREFIX(complex) *)up1,0,1,(nx/2+1),fftw_flags);
272 fft->plan[1][0][1] = FFTWPREFIX(plan_many_dft_r2c)(1,&nx,howmany, p1,0,1,(nx/2+1)*2,(FFTWPREFIX(complex) *)p2 ,0,1,(nx/2+1),fftw_flags);
273 fft->plan[1][1][1] = FFTWPREFIX(plan_many_dft_r2c)(1,&nx,howmany, p1,0,1,(nx/2+1)*2,(FFTWPREFIX(complex) *)p1 ,0,1,(nx/2+1),fftw_flags);
275 fft->plan[0][0][0] = FFTWPREFIX(plan_many_dft_c2r)(1,&nx,howmany,(FFTWPREFIX(complex) *)up1,0,1,(nx/2+1),up2,0,1,(nx/2+1)*2,fftw_flags);
276 fft->plan[0][1][0] = FFTWPREFIX(plan_many_dft_c2r)(1,&nx,howmany,(FFTWPREFIX(complex) *)up1,0,1,(nx/2+1),up1,0,1,(nx/2+1)*2,fftw_flags);
277 fft->plan[1][0][0] = FFTWPREFIX(plan_many_dft_c2r)(1,&nx,howmany,(FFTWPREFIX(complex) *) p1,0,1,(nx/2+1), p2,0,1,(nx/2+1)*2,fftw_flags);
278 fft->plan[1][1][0] = FFTWPREFIX(plan_many_dft_c2r)(1,&nx,howmany,(FFTWPREFIX(complex) *) p1,0,1,(nx/2+1), p1,0,1,(nx/2+1)*2,fftw_flags);
280 for(i=0;i<2;i++)
282 for(j=0;j<2;j++)
284 for(k=0;k<2;k++)
286 if(fft->plan[i][j][k] == NULL)
288 gmx_fatal(FARGS,"Error initializing FFTW3 plan.");
289 FFTW_UNLOCK;
290 gmx_fft_destroy(fft);
291 FFTW_LOCK;
292 FFTWPREFIX(free)(p1);
293 FFTWPREFIX(free)(p2);
294 FFTW_UNLOCK;
295 return -1;
301 FFTWPREFIX(free)(p1);
302 FFTWPREFIX(free)(p2);
304 fft->real_transform = 1;
305 fft->ndim = 1;
307 *pfft = fft;
308 FFTW_UNLOCK;
309 return 0;
315 gmx_fft_init_2d(gmx_fft_t * pfft,
316 int nx,
317 int ny,
318 gmx_fft_flag flags)
320 gmx_fft_t fft;
321 FFTWPREFIX(complex) *p1,*p2,*up1,*up2;
322 size_t pc;
323 int i,j,k;
324 int fftw_flags;
326 #ifdef GMX_DISABLE_FFTW_MEASURE
327 flags |= GMX_FFT_FLAG_CONSERVATIVE;
328 #endif
330 fftw_flags = (flags & GMX_FFT_FLAG_CONSERVATIVE) ? FFTW_ESTIMATE : FFTW_MEASURE;
332 if(pfft==NULL)
334 gmx_fatal(FARGS,"Invalid opaque FFT datatype pointer.");
335 return EINVAL;
337 *pfft = NULL;
339 FFTW_LOCK;
340 if( (fft = (gmx_fft_t) FFTWPREFIX(malloc)(sizeof(struct gmx_fft))) == NULL)
342 FFTW_UNLOCK;
343 return ENOMEM;
346 /* allocate aligned, and extra memory to make it unaligned */
347 p1 = (FFTWPREFIX(complex) *) FFTWPREFIX(malloc)(sizeof(FFTWPREFIX(complex))*(nx*ny+2));
348 if(p1==NULL)
350 FFTWPREFIX(free)(fft);
351 FFTW_UNLOCK;
352 return ENOMEM;
355 p2 = (FFTWPREFIX(complex) *) FFTWPREFIX(malloc)(sizeof(FFTWPREFIX(complex))*(nx*ny+2));
356 if(p2==NULL)
358 FFTWPREFIX(free)(p1);
359 FFTWPREFIX(free)(fft);
360 FFTW_UNLOCK;
361 return ENOMEM;
364 /* make unaligned pointers.
365 * In double precision the actual complex datatype will be 16 bytes,
366 * so go to a char pointer and force an offset of 8 bytes instead.
368 pc = (size_t)p1;
369 pc += 8;
370 up1 = (FFTWPREFIX(complex) *)pc;
372 pc = (size_t)p2;
373 pc += 8;
374 up2 = (FFTWPREFIX(complex) *)pc;
377 fft->plan[0][0][0] = FFTWPREFIX(plan_dft_2d)(nx,ny,up1,up2,FFTW_BACKWARD,fftw_flags);
378 fft->plan[0][0][1] = FFTWPREFIX(plan_dft_2d)(nx,ny,up1,up2,FFTW_FORWARD,fftw_flags);
379 fft->plan[0][1][0] = FFTWPREFIX(plan_dft_2d)(nx,ny,up1,up1,FFTW_BACKWARD,fftw_flags);
380 fft->plan[0][1][1] = FFTWPREFIX(plan_dft_2d)(nx,ny,up1,up1,FFTW_FORWARD,fftw_flags);
382 fft->plan[1][0][0] = FFTWPREFIX(plan_dft_2d)(nx,ny,p1,p2,FFTW_BACKWARD,fftw_flags);
383 fft->plan[1][0][1] = FFTWPREFIX(plan_dft_2d)(nx,ny,p1,p2,FFTW_FORWARD,fftw_flags);
384 fft->plan[1][1][0] = FFTWPREFIX(plan_dft_2d)(nx,ny,p1,p1,FFTW_BACKWARD,fftw_flags);
385 fft->plan[1][1][1] = FFTWPREFIX(plan_dft_2d)(nx,ny,p1,p1,FFTW_FORWARD,fftw_flags);
388 for(i=0;i<2;i++)
390 for(j=0;j<2;j++)
392 for(k=0;k<2;k++)
394 if(fft->plan[i][j][k] == NULL)
396 gmx_fatal(FARGS,"Error initializing FFTW3 plan.");
397 FFTW_UNLOCK;
398 gmx_fft_destroy(fft);
399 FFTW_LOCK;
400 FFTWPREFIX(free)(p1);
401 FFTWPREFIX(free)(p2);
402 FFTW_UNLOCK;
403 return -1;
409 FFTWPREFIX(free)(p1);
410 FFTWPREFIX(free)(p2);
412 fft->real_transform = 0;
413 fft->ndim = 2;
415 *pfft = fft;
416 FFTW_UNLOCK;
417 return 0;
423 gmx_fft_init_2d_real(gmx_fft_t * pfft,
424 int nx,
425 int ny,
426 gmx_fft_flag flags)
428 gmx_fft_t fft;
429 real *p1,*p2,*up1,*up2;
430 size_t pc;
431 int i,j,k;
432 int fftw_flags;
434 #ifdef GMX_DISABLE_FFTW_MEASURE
435 flags |= GMX_FFT_FLAG_CONSERVATIVE;
436 #endif
438 fftw_flags = (flags & GMX_FFT_FLAG_CONSERVATIVE) ? FFTW_ESTIMATE : FFTW_MEASURE;
440 if(pfft==NULL)
442 gmx_fatal(FARGS,"Invalid opaque FFT datatype pointer.");
443 return EINVAL;
445 *pfft = NULL;
447 FFTW_LOCK;
448 if( (fft = (gmx_fft_t) FFTWPREFIX(malloc)(sizeof(struct gmx_fft))) == NULL)
450 FFTW_UNLOCK;
451 return ENOMEM;
454 /* allocate aligned, and extra memory to make it unaligned */
455 p1 = (real *) FFTWPREFIX(malloc)(sizeof(real)*( nx*(ny/2+1)*2 + 2) );
456 if(p1==NULL)
458 FFTWPREFIX(free)(fft);
459 FFTW_UNLOCK;
460 return ENOMEM;
463 p2 = (real *) FFTWPREFIX(malloc)(sizeof(real)*( nx*(ny/2+1)*2 + 2) );
464 if(p2==NULL)
466 FFTWPREFIX(free)(p1);
467 FFTWPREFIX(free)(fft);
468 FFTW_UNLOCK;
469 return ENOMEM;
472 /* make unaligned pointers.
473 * In double precision the actual complex datatype will be 16 bytes,
474 * so go to a char pointer and force an offset of 8 bytes instead.
476 pc = (size_t)p1;
477 pc += 8;
478 up1 = (real *)pc;
480 pc = (size_t)p2;
481 pc += 8;
482 up2 = (real *)pc;
485 fft->plan[0][0][0] = FFTWPREFIX(plan_dft_c2r_2d)(nx,ny,(FFTWPREFIX(complex) *)up1,up2,fftw_flags);
486 fft->plan[0][0][1] = FFTWPREFIX(plan_dft_r2c_2d)(nx,ny,up1,(FFTWPREFIX(complex) *)up2,fftw_flags);
487 fft->plan[0][1][0] = FFTWPREFIX(plan_dft_c2r_2d)(nx,ny,(FFTWPREFIX(complex) *)up1,up1,fftw_flags);
488 fft->plan[0][1][1] = FFTWPREFIX(plan_dft_r2c_2d)(nx,ny,up1,(FFTWPREFIX(complex) *)up1,fftw_flags);
490 fft->plan[1][0][0] = FFTWPREFIX(plan_dft_c2r_2d)(nx,ny,(FFTWPREFIX(complex) *)p1,p2,fftw_flags);
491 fft->plan[1][0][1] = FFTWPREFIX(plan_dft_r2c_2d)(nx,ny,p1,(FFTWPREFIX(complex) *)p2,fftw_flags);
492 fft->plan[1][1][0] = FFTWPREFIX(plan_dft_c2r_2d)(nx,ny,(FFTWPREFIX(complex) *)p1,p1,fftw_flags);
493 fft->plan[1][1][1] = FFTWPREFIX(plan_dft_r2c_2d)(nx,ny,p1,(FFTWPREFIX(complex) *)p1,fftw_flags);
496 for(i=0;i<2;i++)
498 for(j=0;j<2;j++)
500 for(k=0;k<2;k++)
502 if(fft->plan[i][j][k] == NULL)
504 gmx_fatal(FARGS,"Error initializing FFTW3 plan.");
505 FFTW_UNLOCK;
506 gmx_fft_destroy(fft);
507 FFTW_LOCK;
508 FFTWPREFIX(free)(p1);
509 FFTWPREFIX(free)(p2);
510 FFTW_UNLOCK;
511 return -1;
517 FFTWPREFIX(free)(p1);
518 FFTWPREFIX(free)(p2);
520 fft->real_transform = 1;
521 fft->ndim = 2;
523 *pfft = fft;
524 FFTW_UNLOCK;
525 return 0;
531 gmx_fft_init_3d(gmx_fft_t * pfft,
532 int nx,
533 int ny,
534 int nz,
535 gmx_fft_flag flags)
537 gmx_fft_t fft;
538 FFTWPREFIX(complex) *p1,*p2,*up1,*up2;
539 size_t pc;
540 int i,j,k;
541 int fftw_flags;
543 #ifdef GMX_DISABLE_FFTW_MEASURE
544 flags |= GMX_FFT_FLAG_CONSERVATIVE;
545 #endif
547 fftw_flags = (flags & GMX_FFT_FLAG_CONSERVATIVE) ? FFTW_ESTIMATE : FFTW_MEASURE;
549 if(pfft==NULL)
551 gmx_fatal(FARGS,"Invalid opaque FFT datatype pointer.");
552 return EINVAL;
554 *pfft = NULL;
556 FFTW_LOCK;
557 if( (fft = (gmx_fft_t) FFTWPREFIX(malloc)(sizeof(struct gmx_fft))) == NULL)
559 FFTW_UNLOCK;
560 return ENOMEM;
563 /* allocate aligned, and extra memory to make it unaligned */
564 p1 = (FFTWPREFIX(complex) *) FFTWPREFIX(malloc)(sizeof(FFTWPREFIX(complex))*(nx*ny*nz+2));
565 if(p1==NULL)
567 FFTWPREFIX(free)(fft);
568 FFTW_UNLOCK;
569 return ENOMEM;
572 p2 = (FFTWPREFIX(complex) *) FFTWPREFIX(malloc)(sizeof(FFTWPREFIX(complex))*(nx*ny*nz+2));
573 if(p2==NULL)
575 FFTWPREFIX(free)(p1);
576 FFTWPREFIX(free)(fft);
577 FFTW_UNLOCK;
578 return ENOMEM;
581 /* make unaligned pointers.
582 * In double precision the actual complex datatype will be 16 bytes,
583 * so go to a char pointer and force an offset of 8 bytes instead.
585 pc = (size_t)p1;
586 pc += 8;
587 up1 = (FFTWPREFIX(complex) *)pc;
589 pc = (size_t)p2;
590 pc += 8;
591 up2 = (FFTWPREFIX(complex) *)pc;
594 fft->plan[0][0][0] = FFTWPREFIX(plan_dft_3d)(nx,ny,nz,up1,up2,FFTW_BACKWARD,fftw_flags);
595 fft->plan[0][0][1] = FFTWPREFIX(plan_dft_3d)(nx,ny,nz,up1,up2,FFTW_FORWARD,fftw_flags);
596 fft->plan[0][1][0] = FFTWPREFIX(plan_dft_3d)(nx,ny,nz,up1,up1,FFTW_BACKWARD,fftw_flags);
597 fft->plan[0][1][1] = FFTWPREFIX(plan_dft_3d)(nx,ny,nz,up1,up1,FFTW_FORWARD,fftw_flags);
599 fft->plan[1][0][0] = FFTWPREFIX(plan_dft_3d)(nx,ny,nz,p1,p2,FFTW_BACKWARD,fftw_flags);
600 fft->plan[1][0][1] = FFTWPREFIX(plan_dft_3d)(nx,ny,nz,p1,p2,FFTW_FORWARD,fftw_flags);
601 fft->plan[1][1][0] = FFTWPREFIX(plan_dft_3d)(nx,ny,nz,p1,p1,FFTW_BACKWARD,fftw_flags);
602 fft->plan[1][1][1] = FFTWPREFIX(plan_dft_3d)(nx,ny,nz,p1,p1,FFTW_FORWARD,fftw_flags);
605 for(i=0;i<2;i++)
607 for(j=0;j<2;j++)
609 for(k=0;k<2;k++)
611 if(fft->plan[i][j][k] == NULL)
613 gmx_fatal(FARGS,"Error initializing FFTW3 plan.");
614 FFTW_UNLOCK;
615 gmx_fft_destroy(fft);
616 FFTW_LOCK;
617 FFTWPREFIX(free)(p1);
618 FFTWPREFIX(free)(p2);
619 FFTW_UNLOCK;
620 return -1;
626 FFTWPREFIX(free)(p1);
627 FFTWPREFIX(free)(p2);
629 fft->real_transform = 0;
630 fft->ndim = 3;
632 *pfft = fft;
633 FFTW_UNLOCK;
634 return 0;
640 gmx_fft_init_3d_real(gmx_fft_t * pfft,
641 int nx,
642 int ny,
643 int nz,
644 gmx_fft_flag flags)
646 gmx_fft_t fft;
647 real *p1,*p2,*up1,*up2;
648 size_t pc;
649 int i,j,k;
650 int fftw_flags;
652 #ifdef GMX_DISABLE_FFTW_MEASURE
653 flags |= GMX_FFT_FLAG_CONSERVATIVE;
654 #endif
656 fftw_flags = (flags & GMX_FFT_FLAG_CONSERVATIVE) ? FFTW_ESTIMATE : FFTW_MEASURE;
658 if(pfft==NULL)
660 gmx_fatal(FARGS,"Invalid opaque FFT datatype pointer.");
661 return EINVAL;
663 *pfft = NULL;
665 FFTW_LOCK;
666 if( (fft = (gmx_fft_t) FFTWPREFIX(malloc)(sizeof(struct gmx_fft))) == NULL)
668 FFTW_UNLOCK;
669 return ENOMEM;
672 /* allocate aligned, and extra memory to make it unaligned */
673 p1 = (real *) FFTWPREFIX(malloc)(sizeof(real)*( nx*ny*(nz/2+1)*2 + 2) );
674 if(p1==NULL)
676 FFTWPREFIX(free)(fft);
677 FFTW_UNLOCK;
678 return ENOMEM;
681 p2 = (real *) FFTWPREFIX(malloc)(sizeof(real)*( nx*ny*(nz/2+1)*2 + 2) );
682 if(p2==NULL)
684 FFTWPREFIX(free)(p1);
685 FFTWPREFIX(free)(fft);
686 FFTW_UNLOCK;
687 return ENOMEM;
690 /* make unaligned pointers.
691 * In double precision the actual complex datatype will be 16 bytes,
692 * so go to a void pointer and force an offset of 8 bytes instead.
694 pc = (size_t)p1;
695 pc += 8;
696 up1 = (real *)pc;
698 pc = (size_t)p2;
699 pc += 8;
700 up2 = (real *)pc;
703 fft->plan[0][0][0] = FFTWPREFIX(plan_dft_c2r_3d)(nx,ny,nz,(FFTWPREFIX(complex) *)up1,up2,fftw_flags);
704 fft->plan[0][0][1] = FFTWPREFIX(plan_dft_r2c_3d)(nx,ny,nz,up1,(FFTWPREFIX(complex) *)up2,fftw_flags);
705 fft->plan[0][1][0] = FFTWPREFIX(plan_dft_c2r_3d)(nx,ny,nz,(FFTWPREFIX(complex) *)up1,up1,fftw_flags);
706 fft->plan[0][1][1] = FFTWPREFIX(plan_dft_r2c_3d)(nx,ny,nz,up1,(FFTWPREFIX(complex) *)up1,fftw_flags);
708 fft->plan[1][0][0] = FFTWPREFIX(plan_dft_c2r_3d)(nx,ny,nz,(FFTWPREFIX(complex) *)p1,p2,fftw_flags);
709 fft->plan[1][0][1] = FFTWPREFIX(plan_dft_r2c_3d)(nx,ny,nz,p1,(FFTWPREFIX(complex) *)p2,fftw_flags);
710 fft->plan[1][1][0] = FFTWPREFIX(plan_dft_c2r_3d)(nx,ny,nz,(FFTWPREFIX(complex) *)p1,p1,fftw_flags);
711 fft->plan[1][1][1] = FFTWPREFIX(plan_dft_r2c_3d)(nx,ny,nz,p1,(FFTWPREFIX(complex) *)p1,fftw_flags);
714 for(i=0;i<2;i++)
716 for(j=0;j<2;j++)
718 for(k=0;k<2;k++)
720 if(fft->plan[i][j][k] == NULL)
722 gmx_fatal(FARGS,"Error initializing FFTW3 plan.");
723 FFTW_UNLOCK;
724 gmx_fft_destroy(fft);
725 FFTW_LOCK;
726 FFTWPREFIX(free)(p1);
727 FFTWPREFIX(free)(p2);
728 FFTW_UNLOCK;
729 return -1;
735 FFTWPREFIX(free)(p1);
736 FFTWPREFIX(free)(p2);
738 fft->real_transform = 1;
739 fft->ndim = 3;
741 *pfft = fft;
742 FFTW_UNLOCK;
743 return 0;
747 int
748 gmx_fft_1d (gmx_fft_t fft,
749 enum gmx_fft_direction dir,
750 void * in_data,
751 void * out_data)
753 int aligned = ((((size_t)in_data | (size_t)out_data) & 0xf)==0);
754 int inplace = (in_data == out_data);
755 int isforward = (dir == GMX_FFT_FORWARD);
757 /* Some checks */
758 if( (fft->real_transform == 1) || (fft->ndim != 1) ||
759 ((dir != GMX_FFT_FORWARD) && (dir != GMX_FFT_BACKWARD)) )
761 gmx_fatal(FARGS,"FFT plan mismatch - bad plan or direction.");
762 return EINVAL;
765 FFTWPREFIX(execute_dft)(fft->plan[aligned][inplace][isforward],
766 (FFTWPREFIX(complex) *)in_data,
767 (FFTWPREFIX(complex) *)out_data);
769 return 0;
773 gmx_fft_many_1d (gmx_fft_t fft,
774 enum gmx_fft_direction dir,
775 void * in_data,
776 void * out_data)
778 return gmx_fft_1d(fft,dir,in_data,out_data);
781 int
782 gmx_fft_1d_real (gmx_fft_t fft,
783 enum gmx_fft_direction dir,
784 void * in_data,
785 void * out_data)
787 int aligned = ((((size_t)in_data | (size_t)out_data) & 0xf)==0);
788 int inplace = (in_data == out_data);
789 int isforward = (dir == GMX_FFT_REAL_TO_COMPLEX);
791 /* Some checks */
792 if( (fft->real_transform != 1) || (fft->ndim != 1) ||
793 ((dir != GMX_FFT_REAL_TO_COMPLEX) && (dir != GMX_FFT_COMPLEX_TO_REAL)) )
795 gmx_fatal(FARGS,"FFT plan mismatch - bad plan or direction.");
796 return EINVAL;
799 if(isforward)
801 FFTWPREFIX(execute_dft_r2c)(fft->plan[aligned][inplace][isforward],
802 (real *)in_data,(FFTWPREFIX(complex) *)out_data);
804 else
806 FFTWPREFIX(execute_dft_c2r)(fft->plan[aligned][inplace][isforward],
807 (FFTWPREFIX(complex) *)in_data,(real *)out_data);
810 return 0;
813 int
814 gmx_fft_many_1d_real (gmx_fft_t fft,
815 enum gmx_fft_direction dir,
816 void * in_data,
817 void * out_data)
819 return gmx_fft_1d_real(fft,dir,in_data,out_data);
822 int
823 gmx_fft_2d (gmx_fft_t fft,
824 enum gmx_fft_direction dir,
825 void * in_data,
826 void * out_data)
828 int aligned = ((((size_t)in_data | (size_t)out_data) & 0xf)==0);
829 int inplace = (in_data == out_data);
830 int isforward = (dir == GMX_FFT_FORWARD);
832 /* Some checks */
833 if( (fft->real_transform == 1) || (fft->ndim != 2) ||
834 ((dir != GMX_FFT_FORWARD) && (dir != GMX_FFT_BACKWARD)) )
836 gmx_fatal(FARGS,"FFT plan mismatch - bad plan or direction.");
837 return EINVAL;
840 FFTWPREFIX(execute_dft)(fft->plan[aligned][inplace][isforward],
841 (FFTWPREFIX(complex) *)in_data,
842 (FFTWPREFIX(complex) *)out_data);
844 return 0;
848 int
849 gmx_fft_2d_real (gmx_fft_t fft,
850 enum gmx_fft_direction dir,
851 void * in_data,
852 void * out_data)
854 int aligned = ((((size_t)in_data | (size_t)out_data) & 0xf)==0);
855 int inplace = (in_data == out_data);
856 int isforward = (dir == GMX_FFT_REAL_TO_COMPLEX);
858 /* Some checks */
859 if( (fft->real_transform != 1) || (fft->ndim != 2) ||
860 ((dir != GMX_FFT_REAL_TO_COMPLEX) && (dir != GMX_FFT_COMPLEX_TO_REAL)) )
862 gmx_fatal(FARGS,"FFT plan mismatch - bad plan or direction.");
863 return EINVAL;
866 if(isforward)
868 FFTWPREFIX(execute_dft_r2c)(fft->plan[aligned][inplace][isforward],
869 (real *)in_data,
870 (FFTWPREFIX(complex) *)out_data);
872 else
874 FFTWPREFIX(execute_dft_c2r)(fft->plan[aligned][inplace][isforward],
875 (FFTWPREFIX(complex) *)in_data,
876 (real *)out_data);
880 return 0;
884 int
885 gmx_fft_3d (gmx_fft_t fft,
886 enum gmx_fft_direction dir,
887 void * in_data,
888 void * out_data)
890 int aligned = ((((size_t)in_data | (size_t)out_data) & 0xf)==0);
891 int inplace = (in_data == out_data);
892 int isforward = (dir == GMX_FFT_FORWARD);
894 /* Some checks */
895 if( (fft->real_transform == 1) || (fft->ndim != 3) ||
896 ((dir != GMX_FFT_FORWARD) && (dir != GMX_FFT_BACKWARD)) )
898 gmx_fatal(FARGS,"FFT plan mismatch - bad plan or direction.");
899 return EINVAL;
902 FFTWPREFIX(execute_dft)(fft->plan[aligned][inplace][isforward],
903 (FFTWPREFIX(complex) *)in_data,
904 (FFTWPREFIX(complex) *)out_data);
906 return 0;
910 int
911 gmx_fft_3d_real (gmx_fft_t fft,
912 enum gmx_fft_direction dir,
913 void * in_data,
914 void * out_data)
916 int aligned = ((((size_t)in_data | (size_t)out_data) & 0xf)==0);
917 int inplace = (in_data == out_data);
918 int isforward = (dir == GMX_FFT_REAL_TO_COMPLEX);
920 /* Some checks */
921 if( (fft->real_transform != 1) || (fft->ndim != 3) ||
922 ((dir != GMX_FFT_REAL_TO_COMPLEX) && (dir != GMX_FFT_COMPLEX_TO_REAL)) )
924 gmx_fatal(FARGS,"FFT plan mismatch - bad plan or direction.");
925 return EINVAL;
928 if(isforward)
930 FFTWPREFIX(execute_dft_r2c)(fft->plan[aligned][inplace][isforward],
931 (real *)in_data,
932 (FFTWPREFIX(complex) *)out_data);
934 else
936 FFTWPREFIX(execute_dft_c2r)(fft->plan[aligned][inplace][isforward],
937 (FFTWPREFIX(complex) *)in_data,
938 (real *)out_data);
942 return 0;
946 void
947 gmx_fft_destroy(gmx_fft_t fft)
949 int i,j,k;
951 if(fft != NULL)
953 for(i=0;i<2;i++)
955 for(j=0;j<2;j++)
957 for(k=0;k<2;k++)
959 if(fft->plan[i][j][k] != NULL)
961 FFTW_LOCK;
962 FFTWPREFIX(destroy_plan)(fft->plan[i][j][k]);
963 FFTW_UNLOCK;
964 fft->plan[i][j][k] = NULL;
969 FFTW_LOCK;
970 FFTWPREFIX(free)(fft);
971 FFTW_UNLOCK;
976 void
977 gmx_many_fft_destroy(gmx_fft_t fft)
979 gmx_fft_destroy(fft);
982 #else
984 gmx_fft_fftw3_empty;
985 #endif /* GMX_FFT_FFTW3 */