Merge branch release-4-6
[alexxy/gromacs.git] / src / gromacs / fft / fft_fftw3.cpp
1 /*
2  *
3  * Gromacs 4.0                         Copyright (c) 1991-2003
4  * David van der Spoel, Erik Lindahl, University of Groningen.
5  *
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.
10  *
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
13  *
14  * And Hey:
15  * Gnomes, ROck Monsters And Chili Sauce
16  */
17 #ifdef HAVE_CONFIG_H
18 #include <config.h>
19 #endif
20
21 #include <errno.h>
22 #include <stdlib.h>
23
24 #include <fftw3.h>
25
26 #include "gromacs/fft/fft.h"
27 #include "gmx_fatal.h"
28
29 #ifdef GMX_DOUBLE
30 #define FFTWPREFIX(name) fftw_ ## name
31 #else
32 #define FFTWPREFIX(name) fftwf_ ## name
33 #endif
34
35 #include "thread_mpi/mutex.h"
36 #include "gromacs/utility/exceptions.h"
37
38 /* none of the fftw3 calls, except execute(), are thread-safe, so
39    we need to serialize them with this mutex. */
40 static tMPI::mutex big_fftw_mutex;
41 #define FFTW_LOCK try { big_fftw_mutex.lock(); } GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
42 #define FFTW_UNLOCK try { big_fftw_mutex.unlock(); } GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
43
44 /* 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.
45    Consequesences:
46    - It is not allowed to use these FFT plans from memory which doesn't have a starting address as a multiple of 8 bytes.
47      This is OK as long as the memory directly comes from malloc and is not some subarray within alloated memory.
48    - This has to be fixed if any future architecute requires memory to be aligned to multiples of 32 bytes.
49  */
50 /*! \internal
51  * \brief
52  * Contents of the FFTW3 fft datatype.
53  *
54  * Note that this is one of several possible implementations of gmx_fft_t.
55  */
56 #ifdef DOXYGEN
57 struct gmx_fft_fftw3
58 #else
59 struct gmx_fft
60 #endif
61 {
62     /*! \brief
63      * FFTW plans.
64      *
65      * Three alternatives (unaligned/aligned, out-of-place/in-place, forward/backward)
66      * results in 8 different FFTW plans. Keep track of them with 3 array indices:
67      * first index:   0=unaligned, 1=aligned
68      * second index:  0=out-of-place, 1=in-place
69      * third index:   0=backward, 1=forward
70      */
71     FFTWPREFIX(plan)         plan[2][2][2];
72     /** Used to catch user mistakes */
73     int                      real_transform;
74     /** Number of dimensions in the FFT */
75     int                      ndim;
76 };
77
78 int
79 gmx_fft_init_1d(gmx_fft_t *        pfft,
80                 int                nx,
81                 gmx_fft_flag       flags)
82 {
83     return gmx_fft_init_many_1d(pfft, nx, 1, flags);
84 }
85
86
87 int
88 gmx_fft_init_many_1d(gmx_fft_t *        pfft,
89                      int                nx,
90                      int                howmany,
91                      gmx_fft_flag       flags)
92 {
93     gmx_fft_t              fft;
94     FFTWPREFIX(complex)   *p1, *p2, *up1, *up2;
95     size_t                 pc;
96     int                    i, j, k;
97     int                    fftw_flags;
98
99 #ifdef GMX_DISABLE_FFTW_MEASURE
100     flags |= GMX_FFT_FLAG_CONSERVATIVE;
101 #endif
102
103     fftw_flags = (flags & GMX_FFT_FLAG_CONSERVATIVE) ? FFTW_ESTIMATE : FFTW_MEASURE;
104
105     if (pfft == NULL)
106     {
107         gmx_fatal(FARGS, "Invalid opaque FFT datatype pointer.");
108         return EINVAL;
109     }
110     *pfft = NULL;
111
112     FFTW_LOCK;
113     if ( (fft = (gmx_fft_t)FFTWPREFIX(malloc)(sizeof(struct gmx_fft))) == NULL)
114     {
115         FFTW_UNLOCK;
116         return ENOMEM;
117     }
118
119     /* allocate aligned, and extra memory to make it unaligned */
120     p1  = (FFTWPREFIX(complex) *) FFTWPREFIX(malloc)(sizeof(FFTWPREFIX(complex))*(nx+2)*howmany);
121     if (p1 == NULL)
122     {
123         FFTWPREFIX(free)(fft);
124         FFTW_UNLOCK;
125         return ENOMEM;
126     }
127
128     p2  = (FFTWPREFIX(complex) *) FFTWPREFIX(malloc)(sizeof(FFTWPREFIX(complex))*(nx+2)*howmany);
129     if (p2 == NULL)
130     {
131         FFTWPREFIX(free)(p1);
132         FFTWPREFIX(free)(fft);
133         FFTW_UNLOCK;
134         return ENOMEM;
135     }
136
137     /* make unaligned pointers.
138      * In double precision the actual complex datatype will be 16 bytes,
139      * so go to a char pointer and force an offset of 8 bytes instead.
140      */
141     pc  = (size_t)p1;
142     pc += 8;
143     up1 = (FFTWPREFIX(complex) *)pc;
144
145     pc  = (size_t)p2;
146     pc += 8;
147     up2 = (FFTWPREFIX(complex) *)pc;
148
149     /*                            int rank, const int *n, int howmany,
150                                   fftw_complex *in, const int *inembed,
151                                   int istride, int idist,
152                                   fftw_complex *out, const int *onembed,
153                                   int ostride, int odist,
154                                   int sign, unsigned flags */
155     fft->plan[0][0][0] = FFTWPREFIX(plan_many_dft)(1, &nx, howmany, up1, &nx, 1, nx, up2, &nx, 1, nx, FFTW_BACKWARD, fftw_flags);
156     fft->plan[0][0][1] = FFTWPREFIX(plan_many_dft)(1, &nx, howmany, up1, &nx, 1, nx, up2, &nx, 1, nx, FFTW_FORWARD, fftw_flags);
157     fft->plan[0][1][0] = FFTWPREFIX(plan_many_dft)(1, &nx, howmany, up1, &nx, 1, nx, up1, &nx, 1, nx, FFTW_BACKWARD, fftw_flags);
158     fft->plan[0][1][1] = FFTWPREFIX(plan_many_dft)(1, &nx, howmany, up1, &nx, 1, nx, up1, &nx, 1, nx, FFTW_FORWARD, fftw_flags);
159     fft->plan[1][0][0] = FFTWPREFIX(plan_many_dft)(1, &nx, howmany, p1, &nx, 1, nx, p2, &nx, 1, nx, FFTW_BACKWARD, fftw_flags);
160     fft->plan[1][0][1] = FFTWPREFIX(plan_many_dft)(1, &nx, howmany, p1, &nx, 1, nx, p2, &nx, 1, nx, FFTW_FORWARD, fftw_flags);
161     fft->plan[1][1][0] = FFTWPREFIX(plan_many_dft)(1, &nx, howmany, p1, &nx, 1, nx, p1, &nx, 1, nx, FFTW_BACKWARD, fftw_flags);
162     fft->plan[1][1][1] = FFTWPREFIX(plan_many_dft)(1, &nx, howmany, p1, &nx, 1, nx, p1, &nx, 1, nx, FFTW_FORWARD, fftw_flags);
163
164     for (i = 0; i < 2; i++)
165     {
166         for (j = 0; j < 2; j++)
167         {
168             for (k = 0; k < 2; k++)
169             {
170                 if (fft->plan[i][j][k] == NULL)
171                 {
172                     gmx_fatal(FARGS, "Error initializing FFTW3 plan.");
173                     FFTW_UNLOCK;
174                     gmx_fft_destroy(fft);
175                     FFTW_LOCK;
176                     FFTWPREFIX(free)(p1);
177                     FFTWPREFIX(free)(p2);
178                     FFTW_UNLOCK;
179                     return -1;
180                 }
181             }
182         }
183     }
184
185     FFTWPREFIX(free)(p1);
186     FFTWPREFIX(free)(p2);
187
188     fft->real_transform = 0;
189     fft->ndim           = 1;
190
191     *pfft = fft;
192     FFTW_UNLOCK;
193     return 0;
194 }
195
196 int
197 gmx_fft_init_1d_real(gmx_fft_t *        pfft,
198                      int                nx,
199                      gmx_fft_flag       flags)
200 {
201     return gmx_fft_init_many_1d_real(pfft, nx, 1, flags);
202 }
203
204 int
205 gmx_fft_init_many_1d_real(gmx_fft_t *        pfft,
206                           int                nx,
207                           int                howmany,
208                           gmx_fft_flag       flags)
209 {
210     gmx_fft_t              fft;
211     real                  *p1, *p2, *up1, *up2;
212     size_t                 pc;
213     int                    i, j, k;
214     int                    fftw_flags;
215
216 #ifdef GMX_DISABLE_FFTW_MEASURE
217     flags |= GMX_FFT_FLAG_CONSERVATIVE;
218 #endif
219
220     fftw_flags = (flags & GMX_FFT_FLAG_CONSERVATIVE) ? FFTW_ESTIMATE : FFTW_MEASURE;
221
222     if (pfft == NULL)
223     {
224         gmx_fatal(FARGS, "Invalid opaque FFT datatype pointer.");
225         return EINVAL;
226     }
227     *pfft = NULL;
228
229     FFTW_LOCK;
230     if ( (fft = (gmx_fft_t) FFTWPREFIX(malloc)(sizeof(struct gmx_fft))) == NULL)
231     {
232         FFTW_UNLOCK;
233         return ENOMEM;
234     }
235
236     /* allocate aligned, and extra memory to make it unaligned */
237     p1  = (real *) FFTWPREFIX(malloc)(sizeof(real)*(nx/2+1)*2*howmany + 8);
238     if (p1 == NULL)
239     {
240         FFTWPREFIX(free)(fft);
241         FFTW_UNLOCK;
242         return ENOMEM;
243     }
244
245     p2  = (real *) FFTWPREFIX(malloc)(sizeof(real)*(nx/2+1)*2*howmany + 8);
246     if (p2 == NULL)
247     {
248         FFTWPREFIX(free)(p1);
249         FFTWPREFIX(free)(fft);
250         FFTW_UNLOCK;
251         return ENOMEM;
252     }
253
254     /* make unaligned pointers.
255      * In double precision the actual complex datatype will be 16 bytes,
256      * so go to a char pointer and force an offset of 8 bytes instead.
257      */
258     pc  = (size_t)p1;
259     pc += 8;
260     up1 = (real *)pc;
261
262     pc  = (size_t)p2;
263     pc += 8;
264     up2 = (real *)pc;
265
266     /*                                int rank, const int *n, int howmany,
267                                       double *in, const int *inembed,
268                                       int istride, int idist,
269                                       fftw_complex *out, const int *onembed,
270                                       int ostride, int odist,
271                                       unsigned flag    */
272     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);
273     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);
274     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);
275     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);
276
277     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);
278     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);
279     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);
280     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);
281
282     for (i = 0; i < 2; i++)
283     {
284         for (j = 0; j < 2; j++)
285         {
286             for (k = 0; k < 2; k++)
287             {
288                 if (fft->plan[i][j][k] == NULL)
289                 {
290                     gmx_fatal(FARGS, "Error initializing FFTW3 plan.");
291                     FFTW_UNLOCK;
292                     gmx_fft_destroy(fft);
293                     FFTW_LOCK;
294                     FFTWPREFIX(free)(p1);
295                     FFTWPREFIX(free)(p2);
296                     FFTW_UNLOCK;
297                     return -1;
298                 }
299             }
300         }
301     }
302
303     FFTWPREFIX(free)(p1);
304     FFTWPREFIX(free)(p2);
305
306     fft->real_transform = 1;
307     fft->ndim           = 1;
308
309     *pfft = fft;
310     FFTW_UNLOCK;
311     return 0;
312 }
313
314
315 int
316 gmx_fft_init_2d_real(gmx_fft_t *        pfft,
317                      int                nx,
318                      int                ny,
319                      gmx_fft_flag       flags)
320 {
321     gmx_fft_t              fft;
322     real                  *p1, *p2, *up1, *up2;
323     size_t                 pc;
324     int                    i, j, k;
325     int                    fftw_flags;
326
327 #ifdef GMX_DISABLE_FFTW_MEASURE
328     flags |= GMX_FFT_FLAG_CONSERVATIVE;
329 #endif
330
331     fftw_flags = (flags & GMX_FFT_FLAG_CONSERVATIVE) ? FFTW_ESTIMATE : FFTW_MEASURE;
332
333     if (pfft == NULL)
334     {
335         gmx_fatal(FARGS, "Invalid opaque FFT datatype pointer.");
336         return EINVAL;
337     }
338     *pfft = NULL;
339
340     FFTW_LOCK;
341     if ( (fft = (gmx_fft_t) FFTWPREFIX(malloc)(sizeof(struct gmx_fft))) == NULL)
342     {
343         FFTW_UNLOCK;
344         return ENOMEM;
345     }
346
347     /* allocate aligned, and extra memory to make it unaligned */
348     p1  = (real *) FFTWPREFIX(malloc)(sizeof(real) *( nx*(ny/2+1)*2 + 2) );
349     if (p1 == NULL)
350     {
351         FFTWPREFIX(free)(fft);
352         FFTW_UNLOCK;
353         return ENOMEM;
354     }
355
356     p2  = (real *) FFTWPREFIX(malloc)(sizeof(real) *( nx*(ny/2+1)*2 + 2) );
357     if (p2 == NULL)
358     {
359         FFTWPREFIX(free)(p1);
360         FFTWPREFIX(free)(fft);
361         FFTW_UNLOCK;
362         return ENOMEM;
363     }
364
365     /* make unaligned pointers.
366      * In double precision the actual complex datatype will be 16 bytes,
367      * so go to a char pointer and force an offset of 8 bytes instead.
368      */
369     pc  = (size_t)p1;
370     pc += 8;
371     up1 = (real *)pc;
372
373     pc  = (size_t)p2;
374     pc += 8;
375     up2 = (real *)pc;
376
377
378     fft->plan[0][0][0] = FFTWPREFIX(plan_dft_c2r_2d)(nx, ny, (FFTWPREFIX(complex) *) up1, up2, fftw_flags);
379     fft->plan[0][0][1] = FFTWPREFIX(plan_dft_r2c_2d)(nx, ny, up1, (FFTWPREFIX(complex) *) up2, fftw_flags);
380     fft->plan[0][1][0] = FFTWPREFIX(plan_dft_c2r_2d)(nx, ny, (FFTWPREFIX(complex) *) up1, up1, fftw_flags);
381     fft->plan[0][1][1] = FFTWPREFIX(plan_dft_r2c_2d)(nx, ny, up1, (FFTWPREFIX(complex) *) up1, fftw_flags);
382
383     fft->plan[1][0][0] = FFTWPREFIX(plan_dft_c2r_2d)(nx, ny, (FFTWPREFIX(complex) *) p1, p2, fftw_flags);
384     fft->plan[1][0][1] = FFTWPREFIX(plan_dft_r2c_2d)(nx, ny, p1, (FFTWPREFIX(complex) *) p2, fftw_flags);
385     fft->plan[1][1][0] = FFTWPREFIX(plan_dft_c2r_2d)(nx, ny, (FFTWPREFIX(complex) *) p1, p1, fftw_flags);
386     fft->plan[1][1][1] = FFTWPREFIX(plan_dft_r2c_2d)(nx, ny, p1, (FFTWPREFIX(complex) *) p1, fftw_flags);
387
388
389     for (i = 0; i < 2; i++)
390     {
391         for (j = 0; j < 2; j++)
392         {
393             for (k = 0; k < 2; k++)
394             {
395                 if (fft->plan[i][j][k] == NULL)
396                 {
397                     gmx_fatal(FARGS, "Error initializing FFTW3 plan.");
398                     FFTW_UNLOCK;
399                     gmx_fft_destroy(fft);
400                     FFTW_LOCK;
401                     FFTWPREFIX(free)(p1);
402                     FFTWPREFIX(free)(p2);
403                     FFTW_UNLOCK;
404                     return -1;
405                 }
406             }
407         }
408     }
409
410     FFTWPREFIX(free)(p1);
411     FFTWPREFIX(free)(p2);
412
413     fft->real_transform = 1;
414     fft->ndim           = 2;
415
416     *pfft = fft;
417     FFTW_UNLOCK;
418     return 0;
419 }
420
421 int
422 gmx_fft_1d               (gmx_fft_t                  fft,
423                           enum gmx_fft_direction     dir,
424                           void *                     in_data,
425                           void *                     out_data)
426 {
427     int           aligned   = ((((size_t)in_data | (size_t)out_data) & 0xf) == 0);
428     int           inplace   = (in_data == out_data);
429     int           isforward = (dir == GMX_FFT_FORWARD);
430
431     /* Some checks */
432     if ( (fft->real_transform == 1) || (fft->ndim != 1) ||
433          ((dir != GMX_FFT_FORWARD) && (dir != GMX_FFT_BACKWARD)) )
434     {
435         gmx_fatal(FARGS, "FFT plan mismatch - bad plan or direction.");
436         return EINVAL;
437     }
438
439     FFTWPREFIX(execute_dft)(fft->plan[aligned][inplace][isforward],
440                             (FFTWPREFIX(complex) *) in_data,
441                             (FFTWPREFIX(complex) *) out_data);
442
443     return 0;
444 }
445
446 int
447 gmx_fft_many_1d               (gmx_fft_t                  fft,
448                                enum gmx_fft_direction     dir,
449                                void *                     in_data,
450                                void *                     out_data)
451 {
452     return gmx_fft_1d(fft, dir, in_data, out_data);
453 }
454
455 int
456 gmx_fft_1d_real          (gmx_fft_t                  fft,
457                           enum gmx_fft_direction     dir,
458                           void *                     in_data,
459                           void *                     out_data)
460 {
461     int           aligned   = ((((size_t)in_data | (size_t)out_data) & 0xf) == 0);
462     int           inplace   = (in_data == out_data);
463     int           isforward = (dir == GMX_FFT_REAL_TO_COMPLEX);
464
465     /* Some checks */
466     if ( (fft->real_transform != 1) || (fft->ndim != 1) ||
467          ((dir != GMX_FFT_REAL_TO_COMPLEX) && (dir != GMX_FFT_COMPLEX_TO_REAL)) )
468     {
469         gmx_fatal(FARGS, "FFT plan mismatch - bad plan or direction.");
470         return EINVAL;
471     }
472
473     if (isforward)
474     {
475         FFTWPREFIX(execute_dft_r2c)(fft->plan[aligned][inplace][isforward],
476                                     (real *)in_data, (FFTWPREFIX(complex) *) out_data);
477     }
478     else
479     {
480         FFTWPREFIX(execute_dft_c2r)(fft->plan[aligned][inplace][isforward],
481                                     (FFTWPREFIX(complex) *) in_data, (real *)out_data);
482     }
483
484     return 0;
485 }
486
487 int
488 gmx_fft_many_1d_real     (gmx_fft_t                  fft,
489                           enum gmx_fft_direction     dir,
490                           void *                     in_data,
491                           void *                     out_data)
492 {
493     return gmx_fft_1d_real(fft, dir, in_data, out_data);
494 }
495
496 int
497 gmx_fft_2d_real          (gmx_fft_t                  fft,
498                           enum gmx_fft_direction     dir,
499                           void *                     in_data,
500                           void *                     out_data)
501 {
502     int           aligned   = ((((size_t)in_data | (size_t)out_data) & 0xf) == 0);
503     int           inplace   = (in_data == out_data);
504     int           isforward = (dir == GMX_FFT_REAL_TO_COMPLEX);
505
506     /* Some checks */
507     if ( (fft->real_transform != 1) || (fft->ndim != 2) ||
508          ((dir != GMX_FFT_REAL_TO_COMPLEX) && (dir != GMX_FFT_COMPLEX_TO_REAL)) )
509     {
510         gmx_fatal(FARGS, "FFT plan mismatch - bad plan or direction.");
511         return EINVAL;
512     }
513
514     if (isforward)
515     {
516         FFTWPREFIX(execute_dft_r2c)(fft->plan[aligned][inplace][isforward],
517                                     (real *)in_data,
518                                     (FFTWPREFIX(complex) *) out_data);
519     }
520     else
521     {
522         FFTWPREFIX(execute_dft_c2r)(fft->plan[aligned][inplace][isforward],
523                                     (FFTWPREFIX(complex) *) in_data,
524                                     (real *)out_data);
525     }
526
527
528     return 0;
529 }
530
531 void
532 gmx_fft_destroy(gmx_fft_t      fft)
533 {
534     int                   i, j, k;
535
536     if (fft != NULL)
537     {
538         for (i = 0; i < 2; i++)
539         {
540             for (j = 0; j < 2; j++)
541             {
542                 for (k = 0; k < 2; k++)
543                 {
544                     if (fft->plan[i][j][k] != NULL)
545                     {
546                         FFTW_LOCK;
547                         FFTWPREFIX(destroy_plan)(fft->plan[i][j][k]);
548                         FFTW_UNLOCK;
549                         fft->plan[i][j][k] = NULL;
550                     }
551                 }
552             }
553         }
554         FFTW_LOCK;
555         FFTWPREFIX(free)(fft);
556         FFTW_UNLOCK;
557     }
558
559 }
560
561 void
562 gmx_many_fft_destroy(gmx_fft_t    fft)
563 {
564     gmx_fft_destroy(fft);
565 }
566
567 void gmx_fft_cleanup()
568 {
569     FFTWPREFIX(cleanup)();
570 }
571
572 const char *gmx_fft_get_version_info()
573 {
574 #ifdef GMX_NATIVE_WINDOWS
575     return "fftw3";
576 #else
577     return FFTWPREFIX(version);
578 #endif
579 }