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.
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
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
)
73 gmx_fatal(FARGS
, "Invalid opaque FFT datatype pointer.");
78 if ((fft
= static_cast<gmx_many_fft_t
>(malloc(sizeof(struct gmx_many_fft
)))) == nullptr)
83 gmx_fft_init_1d(&fft
->fft
, nx
, flags
);
84 fft
->howmany
= howmany
;
87 *pfft
= reinterpret_cast<gmx_fft_t
>(fft
);
91 int gmx_fft_init_many_1d_real(gmx_fft_t
* pfft
, int nx
, int howmany
, gmx_fft_flag flags
)
96 gmx_fatal(FARGS
, "Invalid opaque FFT datatype pointer.");
101 if ((fft
= static_cast<gmx_many_fft_t
>(malloc(sizeof(struct gmx_many_fft
)))) == nullptr)
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
);
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
);
118 for (i
= 0; i
< mfft
->howmany
; i
++)
120 ret
= gmx_fft_1d(mfft
->fft
, dir
, in_data
, out_data
);
125 in_data
= static_cast<real
*>(in_data
) + mfft
->dist
;
126 out_data
= static_cast<real
*>(out_data
) + mfft
->dist
;
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
);
135 for (i
= 0; i
< mfft
->howmany
; i
++)
137 ret
= gmx_fft_1d_real(mfft
->fft
, dir
, in_data
, out_data
);
142 in_data
= static_cast<real
*>(in_data
) + mfft
->dist
;
143 out_data
= static_cast<real
*>(out_data
) + mfft
->dist
;
149 void gmx_many_fft_destroy(gmx_fft_t fft
)
151 gmx_many_fft_t mfft
= reinterpret_cast<gmx_many_fft_t
>(fft
);
154 if (mfft
->fft
!= nullptr)
156 gmx_fft_destroy(mfft
->fft
);
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
;
168 int i1
, i1c
, i2
, i2c
, kmi
, max
;
170 t_complex tmp1
, tmp2
, tmp3
;
173 /* Use 500 bytes on stack to indicate moves.
174 * This is just for optimization, it does not limit any dimensions.
179 if (nx
< 2 || ny
< 2)
181 if (in_data
!= out_data
)
183 memcpy(out_data
, in_data
, sizeof(t_complex
) * nx
* ny
);
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
;
202 /* In-place transform. in_data=out_data=data */
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
;
223 for (i
= 0; i
< nmove
; i
++)
230 if (nx
> 2 && ny
> 2)
253 tmp1
.re
= data
[i1
].re
;
254 tmp1
.im
= data
[i1
].im
;
256 tmp2
.re
= data
[i1c
].re
;
257 tmp2
.im
= data
[i1c
].im
;
262 i2
= ny
* i1
- k
* (i1
/ nx
);
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
;
298 data
[i1
].re
= tmp1
.re
;
299 data
[i1
].im
= tmp1
.im
;
300 data
[i1c
].re
= tmp2
.re
;
301 data
[i1c
].im
= tmp2
.im
;
324 while (i2
> i
&& i2
< max
)
327 i2
= ny
* i1
- k
* (i1
/ nx
);