Update instructions in containers.rst
[gromacs.git] / src / gromacs / fft / fft.cpp
blob75b30408b2048d35cbcdae235395d4795460a08d
1 /*
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 by the GROMACS development team.
6 * Copyright (c) 2019,2020, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
37 #include "gmxpre.h"
39 #include "fft.h"
41 #include "config.h"
43 #include <cerrno>
44 #include <cstdio>
45 #include <cstdlib>
46 #include <cstring>
48 #include "gromacs/math/gmxcomplex.h"
49 #include "gromacs/utility/fatalerror.h"
50 #include "gromacs/utility/real.h"
52 /* This file contains common fft utility functions, but not
53 * the actual transform implementations. Check the
54 * files like fft_fftw3.c or fft_mkl.c for that.
57 #if !GMX_FFT_FFTW3 && !GMX_FFT_ARMPL_FFTW3
59 struct gmx_many_fft
61 int howmany;
62 int dist;
63 gmx_fft_t fft;
66 typedef struct gmx_many_fft* gmx_many_fft_t;
68 int gmx_fft_init_many_1d(gmx_fft_t* pfft, int nx, int howmany, gmx_fft_flag flags)
70 gmx_many_fft_t fft;
71 if (pfft == nullptr)
73 gmx_fatal(FARGS, "Invalid opaque FFT datatype pointer.");
74 return EINVAL;
76 *pfft = nullptr;
78 if ((fft = static_cast<gmx_many_fft_t>(malloc(sizeof(struct gmx_many_fft)))) == nullptr)
80 return ENOMEM;
83 gmx_fft_init_1d(&fft->fft, nx, flags);
84 fft->howmany = howmany;
85 fft->dist = 2 * nx;
87 *pfft = reinterpret_cast<gmx_fft_t>(fft);
88 return 0;
91 int gmx_fft_init_many_1d_real(gmx_fft_t* pfft, int nx, int howmany, gmx_fft_flag flags)
93 gmx_many_fft_t fft;
94 if (pfft == nullptr)
96 gmx_fatal(FARGS, "Invalid opaque FFT datatype pointer.");
97 return EINVAL;
99 *pfft = nullptr;
101 if ((fft = static_cast<gmx_many_fft_t>(malloc(sizeof(struct gmx_many_fft)))) == nullptr)
103 return ENOMEM;
106 gmx_fft_init_1d_real(&fft->fft, nx, flags);
107 fft->howmany = howmany;
108 fft->dist = 2 * (nx / 2 + 1);
110 *pfft = reinterpret_cast<gmx_fft_t>(fft);
111 return 0;
114 int gmx_fft_many_1d(gmx_fft_t fft, enum gmx_fft_direction dir, void* in_data, void* out_data)
116 gmx_many_fft_t mfft = reinterpret_cast<gmx_many_fft_t>(fft);
117 int i, ret;
118 for (i = 0; i < mfft->howmany; i++)
120 ret = gmx_fft_1d(mfft->fft, dir, in_data, out_data);
121 if (ret != 0)
123 return ret;
125 in_data = static_cast<real*>(in_data) + mfft->dist;
126 out_data = static_cast<real*>(out_data) + mfft->dist;
128 return 0;
131 int gmx_fft_many_1d_real(gmx_fft_t fft, enum gmx_fft_direction dir, void* in_data, void* out_data)
133 gmx_many_fft_t mfft = reinterpret_cast<gmx_many_fft_t>(fft);
134 int i, ret;
135 for (i = 0; i < mfft->howmany; i++)
137 ret = gmx_fft_1d_real(mfft->fft, dir, in_data, out_data);
138 if (ret != 0)
140 return ret;
142 in_data = static_cast<real*>(in_data) + mfft->dist;
143 out_data = static_cast<real*>(out_data) + mfft->dist;
145 return 0;
149 void gmx_many_fft_destroy(gmx_fft_t fft)
151 gmx_many_fft_t mfft = reinterpret_cast<gmx_many_fft_t>(fft);
152 if (mfft != nullptr)
154 if (mfft->fft != nullptr)
156 gmx_fft_destroy(mfft->fft);
158 free(mfft);
162 #endif // not GMX_FFT_FFTW3
164 int gmx_fft_transpose_2d(t_complex* in_data, t_complex* out_data, int nx, int ny)
166 int i, j, k, im, n, ncount;
167 bool done1, done2;
168 int i1, i1c, i2, i2c, kmi, max;
170 t_complex tmp1, tmp2, tmp3;
171 t_complex* data;
173 /* Use 500 bytes on stack to indicate moves.
174 * This is just for optimization, it does not limit any dimensions.
176 char move[500];
177 int nmove = 500;
179 if (nx < 2 || ny < 2)
181 if (in_data != out_data)
183 memcpy(out_data, in_data, sizeof(t_complex) * nx * ny);
185 return 0;
188 /* Out-of-place transposes are easy */
189 if (in_data != out_data)
191 for (i = 0; i < nx; i++)
193 for (j = 0; j < ny; j++)
195 out_data[j * nx + i].re = in_data[i * ny + j].re;
196 out_data[j * nx + i].im = in_data[i * ny + j].im;
199 return 0;
202 /* In-place transform. in_data=out_data=data */
203 data = in_data;
205 if (nx == ny)
207 /* trivial case, just swap elements */
208 for (i = 0; i < nx; i++)
210 for (j = i + 1; j < nx; j++)
212 tmp1.re = data[i * nx + j].re;
213 tmp1.im = data[i * nx + j].im;
214 data[i * nx + j].re = data[j * nx + i].re;
215 data[i * nx + j].im = data[j * nx + i].im;
216 data[j * nx + i].re = tmp1.re;
217 data[j * nx + i].im = tmp1.im;
220 return 0;
223 for (i = 0; i < nmove; i++)
225 move[i] = 0;
228 ncount = 2;
230 if (nx > 2 && ny > 2)
232 i = nx - 1;
233 j = ny - 1;
236 k = i % j;
237 i = j;
238 j = k;
239 } while (k != 0);
240 ncount += i - 1;
243 n = nx * ny;
244 k = n - 1;
245 i = 1;
246 im = ny;
248 done1 = false;
251 i1 = i;
252 kmi = k - i;
253 tmp1.re = data[i1].re;
254 tmp1.im = data[i1].im;
255 i1c = kmi;
256 tmp2.re = data[i1c].re;
257 tmp2.im = data[i1c].im;
259 done2 = false;
262 i2 = ny * i1 - k * (i1 / nx);
263 i2c = k - i2;
264 if (i1 < nmove)
266 move[i1] = 1;
268 if (i1c < nmove)
270 move[i1c] = 1;
272 ncount += 2;
273 if (i2 == i)
275 done2 = true;
277 else if (i2 == kmi)
279 tmp3.re = tmp1.re;
280 tmp3.im = tmp1.im;
281 tmp1.re = tmp2.re;
282 tmp1.im = tmp2.im;
283 tmp2.re = tmp3.re;
284 tmp2.im = tmp3.im;
285 done2 = true;
287 else
289 data[i1].re = data[i2].re;
290 data[i1].im = data[i2].im;
291 data[i1c].re = data[i2c].re;
292 data[i1c].im = data[i2c].im;
293 i1 = i2;
294 i1c = i2c;
296 } while (!done2);
298 data[i1].re = tmp1.re;
299 data[i1].im = tmp1.im;
300 data[i1c].re = tmp2.re;
301 data[i1c].im = tmp2.im;
303 if (ncount >= n)
305 done1 = true;
307 else
309 done2 = false;
312 max = k - i;
313 i++;
314 im += ny;
315 if (im > k)
317 im -= k;
319 i2 = im;
320 if (i != i2)
322 if (i >= nmove)
324 while (i2 > i && i2 < max)
326 i1 = i2;
327 i2 = ny * i1 - k * (i1 / nx);
329 if (i2 == i)
331 done2 = true;
334 else if (!move[i])
336 done2 = true;
339 } while (!done2);
341 } while (!done1);
343 return 0;