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