1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 package ffx.numerics.fft;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public class Complex3D {
55
56 private final int nX, nY, nZ;
57 private final int nZ2;
58 private final int nextX, nextY, nextZ;
59 private final double[] work;
60 private final Complex fftX, fftY, fftZ;
61 private final double[] recip;
62
63
64
65
66
67
68
69
70 public Complex3D(int nX, int nY, int nZ) {
71 this.nX = nX;
72 this.nY = nY;
73 this.nZ = nZ;
74 nZ2 = 2 * nZ;
75 nextX = 2;
76 nextY = 2 * nX;
77 nextZ = nextY * nY;
78
79 work = new double[nZ2];
80 recip = new double[nX * nY * nZ];
81
82 fftX = new Complex(nX);
83 fftY = new Complex(nY);
84 fftZ = new Complex(nZ);
85 }
86
87
88
89
90
91
92
93
94
95
96
97 public static int iComplex3D(int i, int j, int k, int nX, int nY) {
98 return 2 * (i + nX * (j + nY * k));
99 }
100
101
102
103
104
105
106 public void convolution(final double[] input) {
107 for (int z = 0; z < nZ; z++) {
108 for (int offset = z * nextZ, y = 0; y < nY; y++, offset += nextY) {
109 fftX.fft(input, offset, nextX);
110 }
111 for (int offset = z * nextZ, x = 0; x < nX; x++, offset += nextX) {
112 fftY.fft(input, offset, nextY);
113 }
114 }
115 for (int offset = 0, index = 0, y = 0; y < nY; y++) {
116 for (int x = 0; x < nX; x++, offset += nextX) {
117 for (int i = 0, z = offset; i < nZ2; i += 2, z += nextZ) {
118 work[i] = input[z];
119 work[i + 1] = input[z + 1];
120 }
121 fftZ.fft(work, 0, 2);
122 for (int i = 0; i < nZ2; i += 2) {
123 double r = recip[index++];
124 work[i] *= r;
125 work[i + 1] *= r;
126 }
127 fftZ.ifft(work, 0, 2);
128 for (int i = 0, z = offset; i < nZ2; i += 2, z += nextZ) {
129 input[z] = work[i];
130 input[z + 1] = work[i + 1];
131 }
132 }
133 }
134 for (int z = 0; z < nZ; z++) {
135 for (int offset = z * nextZ, x = 0; x < nX; x++, offset += nextX) {
136 fftY.ifft(input, offset, nextY);
137 }
138 for (int offset = z * nextZ, y = 0; y < nY; y++, offset += nextY) {
139 fftX.ifft(input, offset, nextX);
140 }
141 }
142 }
143
144
145
146
147
148
149 public void fft(final double[] input) {
150 for (int z = 0; z < nZ; z++) {
151 for (int offset = z * nextZ, y = 0; y < nY; y++, offset += nextY) {
152 fftX.fft(input, offset, nextX);
153 }
154 for (int offset = z * nextZ, x = 0; x < nX; x++, offset += nextX) {
155 fftY.fft(input, offset, nextY);
156 }
157 }
158 for (int x = 0, offset = 0; x < nX; x++) {
159 for (int y = 0; y < nY; y++, offset += nextX) {
160 for (int i = 0, z = offset; i < nZ2; i += 2, z += nextZ) {
161 work[i] = input[z];
162 work[i + 1] = input[z + 1];
163 }
164 fftZ.fft(work, 0, 2);
165 for (int i = 0, z = offset; i < nZ2; i += 2, z += nextZ) {
166 input[z] = work[i];
167 input[z + 1] = work[i + 1];
168 }
169 }
170 }
171 }
172
173
174
175
176
177
178 public void ifft(final double[] input) {
179 for (int offset = 0, x = 0; x < nX; x++) {
180 for (int y = 0; y < nY; y++, offset += nextX) {
181 for (int i = 0, z = offset; i < nZ2; i += 2, z += nextZ) {
182 work[i] = input[z];
183 work[i + 1] = input[z + 1];
184 }
185 fftZ.ifft(work, 0, 2);
186 for (int i = 0, z = offset; i < nZ2; i += 2, z += nextZ) {
187 input[z] = work[i];
188 input[z + 1] = work[i + 1];
189 }
190 }
191 }
192 for (int z = 0; z < nZ; z++) {
193 for (int offset = z * nextZ, x = 0; x < nX; x++, offset += nextX) {
194 fftY.ifft(input, offset, nextY);
195 }
196 for (int offset = z * nextZ, y = 0; y < nY; y++, offset += nextY) {
197 fftX.ifft(input, offset, nextX);
198 }
199 }
200 }
201
202
203
204
205
206
207 public void setRecip(double[] recip) {
208
209 for (int offset = 0, index = 0, y = 0; y < nY; y++) {
210 for (int x = 0; x < nX; x++, offset += 1) {
211 for (int i = 0, z = offset; i < nZ2; i += 2, z += nX * nY) {
212 this.recip[index++] = recip[z];
213 }
214 }
215 }
216 }
217 }