Merge branch release-4-6
[alexxy/gromacs.git] / src / gromacs / gmxana / correl.c
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11  * Copyright (c) 2001-2008, The GROMACS development team,
12  * check out http://www.gromacs.org for more information.
13
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * If you want to redistribute modifications, please consider that
20  * scientific software is very special. Version control is crucial -
21  * bugs must be traceable. We will be happy to consider code for
22  * inclusion in the official distribution, but derived work must not
23  * be called official GROMACS. Details are found in the README & COPYING
24  * files - if they are missing, get the official version at www.gromacs.org.
25  *
26  * To help us fund GROMACS development, we humbly ask that you cite
27  * the papers on the package - you can find them in the top README file.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  *
31  * And Hey:
32  * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
33  */
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <math.h>
42
43 #include "gromacs/fft/fft.h"
44 #include "smalloc.h"
45 #include "correl.h"
46
47 #define SWAP(a, b) tempr = (a); (a) = (b); (b) = tempr
48
49 void four1(real data[], int nn, int isign)
50 {
51     int    n, mmax, m, j, istep, i;
52     double wtemp, wr, wpr, wpi, wi, theta;
53     real   tempr, tempi;
54
55     n = nn << 1;
56     j = 1;
57     for (i = 1; i < n; i += 2)
58     {
59         if (j > i)
60         {
61             SWAP(data[j], data[i]);
62             SWAP(data[j+1], data[i+1]);
63         }
64         m = n >> 1;
65         while (m >= 2 && j > m)
66         {
67             j  -= m;
68             m >>= 1;
69         }
70         j += m;
71     }
72     mmax = 2;
73     while (n > mmax)
74     {
75         istep = 2*mmax;
76         theta = 6.28318530717959/(isign*mmax);
77         wtemp = sin(0.5*theta);
78         wpr   = -2.0*wtemp*wtemp;
79         wpi   = sin(theta);
80         wr    = 1.0;
81         wi    = 0.0;
82         for (m = 1; m < mmax; m += 2)
83         {
84             for (i = m; i <= n; i += istep)
85             {
86                 j          = i+mmax;
87                 tempr      = wr*data[j]-wi*data[j+1];
88                 tempi      = wr*data[j+1]+wi*data[j];
89                 data[j]    = data[i]-tempr;
90                 data[j+1]  = data[i+1]-tempi;
91                 data[i]   += tempr;
92                 data[i+1] += tempi;
93             }
94             wr = (wtemp = wr)*wpr-wi*wpi+wr;
95             wi = wi*wpr+wtemp*wpi+wi;
96         }
97         mmax = istep;
98     }
99 }
100
101 #undef SWAP
102
103 static void realft(real data[], int n, int isign)
104 {
105     int    i, i1, i2, i3, i4, n2p3;
106     real   c1 = 0.5, c2, h1r, h1i, h2r, h2i;
107     double wr, wi, wpr, wpi, wtemp, theta;
108
109     theta = 3.141592653589793/(double) n;
110     if (isign == 1)
111     {
112         c2 = -0.5;
113         four1(data, n, 1);
114     }
115     else
116     {
117         c2    = 0.5;
118         theta = -theta;
119     }
120     wtemp = sin(0.5*theta);
121     wpr   = -2.0*wtemp*wtemp;
122     wpi   = sin(theta);
123     wr    = 1.0+wpr;
124     wi    = wpi;
125     n2p3  = 2*n+3;
126     for (i = 2; i <= n/2; i++)
127     {
128         i4       = 1+(i3 = n2p3-(i2 = 1+(i1 = i+i-1)));
129         h1r      = c1*(data[i1]+data[i3]);
130         h1i      = c1*(data[i2]-data[i4]);
131         h2r      = -c2*(data[i2]+data[i4]);
132         h2i      = c2*(data[i1]-data[i3]);
133         data[i1] = h1r+wr*h2r-wi*h2i;
134         data[i2] = h1i+wr*h2i+wi*h2r;
135         data[i3] = h1r-wr*h2r+wi*h2i;
136         data[i4] = -h1i+wr*h2i+wi*h2r;
137         wr       = (wtemp = wr)*wpr-wi*wpi+wr;
138         wi       = wi*wpr+wtemp*wpi+wi;
139     }
140     if (isign == 1)
141     {
142         data[1] = (h1r = data[1])+data[2];
143         data[2] = h1r-data[2];
144     }
145     else
146     {
147         data[1] = c1*((h1r = data[1])+data[2]);
148         data[2] = c1*(h1r-data[2]);
149         four1(data, n, -1);
150     }
151 }
152
153 static void twofft(real data1[], real data2[], real fft1[], real fft2[], int n)
154 {
155     int  nn3, nn2, jj, j;
156     real rep, rem, aip, aim;
157
158     nn3 = 1+(nn2 = 2+n+n);
159     for (j = 1, jj = 2; j <= n; j++, jj += 2)
160     {
161         fft1[jj-1] = data1[j];
162         fft1[jj]   = data2[j];
163     }
164     four1(fft1, n, 1);
165     fft2[1] = fft1[2];
166     fft1[2] = fft2[2] = 0.0;
167     for (j = 3; j <= n+1; j += 2)
168     {
169         rep         = 0.5*(fft1[j]+fft1[nn2-j]);
170         rem         = 0.5*(fft1[j]-fft1[nn2-j]);
171         aip         = 0.5*(fft1[j+1]+fft1[nn3-j]);
172         aim         = 0.5*(fft1[j+1]-fft1[nn3-j]);
173         fft1[j]     = rep;
174         fft1[j+1]   = aim;
175         fft1[nn2-j] = rep;
176         fft1[nn3-j] = -aim;
177         fft2[j]     = aip;
178         fft2[j+1]   = -rem;
179         fft2[nn2-j] = aip;
180         fft2[nn3-j] = rem;
181     }
182 }
183
184 void correl(real data1[], real data2[], int n, real ans[])
185 {
186     int     no2, i;
187     real    dum, *fft;
188
189     snew(fft, 2*n+1);
190     twofft(data1, data2, fft, ans, n);
191     no2 = n/2;
192     for (i = 2; i <= n+2; i += 2)
193     {
194         dum      = ans[i-1];
195         ans[i-1] = (fft[i-1]*dum+fft[i]*ans[i])/no2;
196         ans[i]   = (fft[i]*dum-fft[i-1]*ans[i])/no2;
197     }
198     ans[2] = ans[n+1];
199     realft(ans, no2, -1);
200     sfree(fft);
201 }