2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2003 Erik Lindahl, David van der Spoel, University of Groningen.
5 * Copyright (c) 2013,2014,2015,2017,2018,2019, by the GROMACS development team, led by
6 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7 * and including many others, as listed in the AUTHORS file in the
8 * top-level source directory and at http://www.gromacs.org.
10 * GROMACS is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1
13 * of the License, or (at your option) any later version.
15 * GROMACS is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with GROMACS; if not, see
22 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * If you want to redistribute modifications to GROMACS, please
26 * consider that scientific software is very special. Version
27 * control is crucial - bugs must be traceable. We will be happy to
28 * consider code for inclusion in the official distribution, but
29 * derived work must not be called official GROMACS. Details are found
30 * in the README & COPYING files - if they are missing, get the
31 * official version at http://www.gromacs.org.
33 * To help us fund GROMACS development, we humbly ask that you cite
34 * the research papers on the package. Check out http://www.gromacs.org.
47 #include "gromacs/math/gmxcomplex.h"
48 #include "gromacs/utility/fatalerror.h"
49 #include "gromacs/utility/real.h"
51 /* This file contains common fft utility functions, but not
52 * the actual transform implementations. Check the
53 * files like fft_fftw3.c or fft_mkl.c for that.
56 #if !GMX_FFT_FFTW3 && !GMX_FFT_ARMPL_FFTW3
65 typedef struct gmx_many_fft* gmx_many_fft_t;
67 int gmx_fft_init_many_1d(gmx_fft_t* pfft, int nx, int howmany, gmx_fft_flag flags)
72 gmx_fatal(FARGS, "Invalid opaque FFT datatype pointer.");
77 if ((fft = static_cast<gmx_many_fft_t>(malloc(sizeof(struct gmx_many_fft)))) == nullptr)
82 gmx_fft_init_1d(&fft->fft, nx, flags);
83 fft->howmany = howmany;
86 *pfft = reinterpret_cast<gmx_fft_t>(fft);
90 int gmx_fft_init_many_1d_real(gmx_fft_t* pfft, int nx, int howmany, gmx_fft_flag flags)
95 gmx_fatal(FARGS, "Invalid opaque FFT datatype pointer.");
100 if ((fft = static_cast<gmx_many_fft_t>(malloc(sizeof(struct gmx_many_fft)))) == nullptr)
105 gmx_fft_init_1d_real(&fft->fft, nx, flags);
106 fft->howmany = howmany;
107 fft->dist = 2 * (nx / 2 + 1);
109 *pfft = reinterpret_cast<gmx_fft_t>(fft);
113 int gmx_fft_many_1d(gmx_fft_t fft, enum gmx_fft_direction dir, void* in_data, void* out_data)
115 gmx_many_fft_t mfft = reinterpret_cast<gmx_many_fft_t>(fft);
117 for (i = 0; i < mfft->howmany; i++)
119 ret = gmx_fft_1d(mfft->fft, dir, in_data, out_data);
124 in_data = static_cast<real*>(in_data) + mfft->dist;
125 out_data = static_cast<real*>(out_data) + mfft->dist;
130 int gmx_fft_many_1d_real(gmx_fft_t fft, enum gmx_fft_direction dir, void* in_data, void* out_data)
132 gmx_many_fft_t mfft = reinterpret_cast<gmx_many_fft_t>(fft);
134 for (i = 0; i < mfft->howmany; i++)
136 ret = gmx_fft_1d_real(mfft->fft, dir, in_data, out_data);
141 in_data = static_cast<real*>(in_data) + mfft->dist;
142 out_data = static_cast<real*>(out_data) + mfft->dist;
148 void gmx_many_fft_destroy(gmx_fft_t fft)
150 gmx_many_fft_t mfft = reinterpret_cast<gmx_many_fft_t>(fft);
153 if (mfft->fft != nullptr)
155 gmx_fft_destroy(mfft->fft);
161 #endif // not GMX_FFT_FFTW3
163 int gmx_fft_transpose_2d(t_complex* in_data, t_complex* out_data, int nx, int ny)
165 int i, j, k, im, n, ncount;
167 int i1, i1c, i2, i2c, kmi, max;
169 t_complex tmp1, tmp2, tmp3;
172 /* Use 500 bytes on stack to indicate moves.
173 * This is just for optimization, it does not limit any dimensions.
178 if (nx < 2 || ny < 2)
180 if (in_data != out_data)
182 memcpy(out_data, in_data, sizeof(t_complex) * nx * ny);
187 /* Out-of-place transposes are easy */
188 if (in_data != out_data)
190 for (i = 0; i < nx; i++)
192 for (j = 0; j < ny; j++)
194 out_data[j * nx + i].re = in_data[i * ny + j].re;
195 out_data[j * nx + i].im = in_data[i * ny + j].im;
201 /* In-place transform. in_data=out_data=data */
206 /* trivial case, just swap elements */
207 for (i = 0; i < nx; i++)
209 for (j = i + 1; j < nx; j++)
211 tmp1.re = data[i * nx + j].re;
212 tmp1.im = data[i * nx + j].im;
213 data[i * nx + j].re = data[j * nx + i].re;
214 data[i * nx + j].im = data[j * nx + i].im;
215 data[j * nx + i].re = tmp1.re;
216 data[j * nx + i].im = tmp1.im;
222 for (i = 0; i < nmove; i++)
229 if (nx > 2 && ny > 2)
252 tmp1.re = data[i1].re;
253 tmp1.im = data[i1].im;
255 tmp2.re = data[i1c].re;
256 tmp2.im = data[i1c].im;
261 i2 = ny * i1 - k * (i1 / nx);
288 data[i1].re = data[i2].re;
289 data[i1].im = data[i2].im;
290 data[i1c].re = data[i2c].re;
291 data[i1c].im = data[i2c].im;
297 data[i1].re = tmp1.re;
298 data[i1].im = tmp1.im;
299 data[i1c].re = tmp2.re;
300 data[i1c].im = tmp2.im;
323 while (i2 > i && i2 < max)
326 i2 = ny * i1 - k * (i1 / nx);