1 | ///
|
---|
2 | /// This file is part of ILNumerics Community Edition.
|
---|
3 | ///
|
---|
4 | /// ILNumerics Community Edition - high performance computing for applications.
|
---|
5 | /// Copyright (C) 2006 - 2012 Haymo Kutschbach, http://ilnumerics.net
|
---|
6 | ///
|
---|
7 | /// ILNumerics Community Edition is free software: you can redistribute it and/or modify
|
---|
8 | /// it under the terms of the GNU General Public License version 3 as published by
|
---|
9 | /// the Free Software Foundation.
|
---|
10 | ///
|
---|
11 | /// ILNumerics Community Edition is distributed in the hope that it will be useful,
|
---|
12 | /// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
13 | /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
14 | /// GNU General Public License for more details.
|
---|
15 | ///
|
---|
16 | /// You should have received a copy of the GNU General Public License
|
---|
17 | /// along with ILNumerics Community Edition. See the file License.txt in the root
|
---|
18 | /// of your distribution package. If not, see <http://www.gnu.org/licenses/>.
|
---|
19 | ///
|
---|
20 | /// In addition this software uses the following components and/or licenses:
|
---|
21 | ///
|
---|
22 | /// =================================================================================
|
---|
23 | /// The Open Toolkit Library License
|
---|
24 | ///
|
---|
25 | /// Copyright (c) 2006 - 2009 the Open Toolkit library.
|
---|
26 | ///
|
---|
27 | /// Permission is hereby granted, free of charge, to any person obtaining a copy
|
---|
28 | /// of this software and associated documentation files (the "Software"), to deal
|
---|
29 | /// in the Software without restriction, including without limitation the rights to
|
---|
30 | /// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
---|
31 | /// the Software, and to permit persons to whom the Software is furnished to do
|
---|
32 | /// so, subject to the following conditions:
|
---|
33 | ///
|
---|
34 | /// The above copyright notice and this permission notice shall be included in all
|
---|
35 | /// copies or substantial portions of the Software.
|
---|
36 | ///
|
---|
37 | /// =================================================================================
|
---|
38 | ///
|
---|
39 |
|
---|
40 | #pragma warning disable 1591
|
---|
41 |
|
---|
42 | using System;
|
---|
43 | using System.Collections.Generic;
|
---|
44 | using System.Text;
|
---|
45 | using System.Security;
|
---|
46 | using System.Runtime.InteropServices;
|
---|
47 | using ILNumerics.Exceptions;
|
---|
48 | using ILNumerics.Misc;
|
---|
49 |
|
---|
50 | namespace ILNumerics.Native {
|
---|
51 |
|
---|
52 | /// <summary>
|
---|
53 | /// Wrapper for FFT interface using ACML ver. 3.6
|
---|
54 | /// </summary>
|
---|
55 | public unsafe class ILACMLFFT : IILFFT, IDisposable {
|
---|
56 |
|
---|
57 | #region pinvoke definitions
|
---|
58 |
|
---|
59 | [DllImport("libacml_dll"),SuppressUnmanagedCodeSecurity]
|
---|
60 | private static extern void zfft1mx(int MODE, double SCALE, int INPL, int NSEQ, int N, IntPtr X, int INCX1, int INCX2, IntPtr Y, int INCY1, int INCY2, IntPtr COMM, ref int INFO);
|
---|
61 | [DllImport("libacml_dll"),SuppressUnmanagedCodeSecurity]
|
---|
62 | private static extern void cfft1mx(int MODE, float SCALE, int INPL, int NSEQ, int N, IntPtr X, int INCX1, int INCX2, IntPtr Y, int INCY1, int INCY2, IntPtr COMM, ref int INFO);
|
---|
63 | [DllImport("libacml_dll"),SuppressUnmanagedCodeSecurity]
|
---|
64 | private static extern void zfft2dx(int MODE, double SCALE, int LTRANS, int INPL, int M, int N, IntPtr X, int INCX1, int INCX2, IntPtr Y, int INCY1, int INCY2, IntPtr COMM, ref int INFO);
|
---|
65 | [DllImport("libacml_dll"),SuppressUnmanagedCodeSecurity]
|
---|
66 | private static extern void cfft2dx(int MODE, float SCALE, int LTRANS, int INPL, int M, int N, IntPtr X, int INCX1, int INCX2, IntPtr Y, int INCY1, int INCY2, IntPtr COMM, ref int INFO);
|
---|
67 |
|
---|
68 | #endregion
|
---|
69 |
|
---|
70 | #region value constants
|
---|
71 | private class ACMLValues {
|
---|
72 | public static readonly int Double = 8;
|
---|
73 | public static readonly int Single = 4;
|
---|
74 | public static readonly int Real = 1;
|
---|
75 | public static readonly int Complex = 2;
|
---|
76 | public static readonly int Backwards = 1;
|
---|
77 | public static readonly int Forward = -1;
|
---|
78 | }
|
---|
79 | #endregion
|
---|
80 |
|
---|
81 | #region attributes
|
---|
82 | Dictionary<string,IntPtr> m_descriptors;
|
---|
83 | object _lockobject = new object();
|
---|
84 | #endregion
|
---|
85 |
|
---|
86 | #region constructor
|
---|
87 | public ILACMLFFT () {
|
---|
88 | m_descriptors = new Dictionary<string,IntPtr>(10);
|
---|
89 | }
|
---|
90 | #endregion
|
---|
91 |
|
---|
92 | #region IILFFT Member - 1-D
|
---|
93 |
|
---|
94 | |
---|
95 |
|
---|
96 | public ILRetArray< complex> FFTForward1D(ILInArray< double> A, int dim) {
|
---|
97 | using (ILScope.Enter(A)) {
|
---|
98 | if (object.Equals(A, null) || dim < 0)
|
---|
99 | throw new ILArgumentException("FFTForward1D: invalid parameter!");
|
---|
100 | if (A.IsEmpty) return ILMath.array< complex>(A.Size);
|
---|
101 | if (A.IsScalar || A.Size[dim] == 1)
|
---|
102 | return ILMath.tocomplex(A);
|
---|
103 | // prepare output array
|
---|
104 | ILArray< complex> ret = ILMath.tocomplex(A);
|
---|
105 | fft1dInplace(dim, ret, ACMLValues.Forward);
|
---|
106 | return ret;
|
---|
107 | }
|
---|
108 | }
|
---|
109 | |
---|
110 | #region HYCALPER AUTO GENERATED CODE
|
---|
111 | |
---|
112 |
|
---|
113 | public ILRetArray< fcomplex> FFTBackward1D(ILInArray< fcomplex> A, int dim) {
|
---|
114 | using (ILScope.Enter(A)) {
|
---|
115 | if (object.Equals(A, null) || dim < 0)
|
---|
116 | throw new ILArgumentException("FFTForward1D: invalid parameter!");
|
---|
117 | if (A.IsEmpty) return ILMath.array< fcomplex>(A.Size);
|
---|
118 | if (A.IsScalar || A.Size[dim] == 1)
|
---|
119 | return A.C;
|
---|
120 | // prepare output array
|
---|
121 | ILArray< fcomplex> ret = A.C;
|
---|
122 | fft1dInplace(dim, ret, ACMLValues.Backwards);
|
---|
123 | return ret;
|
---|
124 | }
|
---|
125 | }
|
---|
126 |
|
---|
127 | public ILRetArray< complex> FFTBackward1D(ILInArray< complex> A, int dim) {
|
---|
128 | using (ILScope.Enter(A)) {
|
---|
129 | if (object.Equals(A, null) || dim < 0)
|
---|
130 | throw new ILArgumentException("FFTForward1D: invalid parameter!");
|
---|
131 | if (A.IsEmpty) return ILMath.array< complex>(A.Size);
|
---|
132 | if (A.IsScalar || A.Size[dim] == 1)
|
---|
133 | return A.C;
|
---|
134 | // prepare output array
|
---|
135 | ILArray< complex> ret = A.C;
|
---|
136 | fft1dInplace(dim, ret, ACMLValues.Backwards);
|
---|
137 | return ret;
|
---|
138 | }
|
---|
139 | }
|
---|
140 |
|
---|
141 | public ILRetArray< fcomplex> FFTForward1D(ILInArray< fcomplex> A, int dim) {
|
---|
142 | using (ILScope.Enter(A)) {
|
---|
143 | if (object.Equals(A, null) || dim < 0)
|
---|
144 | throw new ILArgumentException("FFTForward1D: invalid parameter!");
|
---|
145 | if (A.IsEmpty) return ILMath.array< fcomplex>(A.Size);
|
---|
146 | if (A.IsScalar || A.Size[dim] == 1)
|
---|
147 | return A.C;
|
---|
148 | // prepare output array
|
---|
149 | ILArray< fcomplex> ret = A.C;
|
---|
150 | fft1dInplace(dim, ret, ACMLValues.Forward);
|
---|
151 | return ret;
|
---|
152 | }
|
---|
153 | }
|
---|
154 |
|
---|
155 | public ILRetArray< fcomplex> FFTForward1D(ILInArray< float> A, int dim) {
|
---|
156 | using (ILScope.Enter(A)) {
|
---|
157 | if (object.Equals(A, null) || dim < 0)
|
---|
158 | throw new ILArgumentException("FFTForward1D: invalid parameter!");
|
---|
159 | if (A.IsEmpty) return ILMath.array< fcomplex>(A.Size);
|
---|
160 | if (A.IsScalar || A.Size[dim] == 1)
|
---|
161 | return ILMath.tofcomplex(A);
|
---|
162 | // prepare output array
|
---|
163 | ILArray< fcomplex> ret = ILMath.tofcomplex(A);
|
---|
164 | fft1dInplace(dim, ret, ACMLValues.Forward);
|
---|
165 | return ret;
|
---|
166 | }
|
---|
167 | }
|
---|
168 |
|
---|
169 | public ILRetArray< complex> FFTForward1D(ILInArray< complex> A, int dim) {
|
---|
170 | using (ILScope.Enter(A)) {
|
---|
171 | if (object.Equals(A, null) || dim < 0)
|
---|
172 | throw new ILArgumentException("FFTForward1D: invalid parameter!");
|
---|
173 | if (A.IsEmpty) return ILMath.array< complex>(A.Size);
|
---|
174 | if (A.IsScalar || A.Size[dim] == 1)
|
---|
175 | return A.C;
|
---|
176 | // prepare output array
|
---|
177 | ILArray< complex> ret = A.C;
|
---|
178 | fft1dInplace(dim, ret, ACMLValues.Forward);
|
---|
179 | return ret;
|
---|
180 | }
|
---|
181 | }
|
---|
182 |
|
---|
183 | #endregion HYCALPER AUTO GENERATED CODE
|
---|
184 |
|
---|
185 | public ILRetArray<double> FFTBackwSym1D(ILInArray<complex> A, int dim) {
|
---|
186 | return ILMath.real(FFTBackward1D(A,dim));
|
---|
187 | }
|
---|
188 |
|
---|
189 | public ILRetArray<float> FFTBackwSym1D(ILInArray<fcomplex> A, int dim) {
|
---|
190 | return ILMath.real(FFTBackward1D(A,dim));
|
---|
191 | }
|
---|
192 |
|
---|
193 | #endregion
|
---|
194 |
|
---|
195 | #region IILFFT Member n-D
|
---|
196 |
|
---|
197 | |
---|
198 |
|
---|
199 | public ILRetArray< complex> FFTForward(ILInArray< double> A, int nDims) {
|
---|
200 | using (ILScope.Enter(A)) {
|
---|
201 | if (object.Equals(A, null) || nDims <= 0)
|
---|
202 | throw new ILArgumentException("invalid parameter!");
|
---|
203 | if (A.IsEmpty) return ILMath.array< complex>(A.Size);
|
---|
204 | if (A.IsScalar || (A.Size[0] == 1 && nDims == 1))
|
---|
205 | return ILMath.tocomplex(A);
|
---|
206 | if (nDims > A.Size.NumberOfDimensions)
|
---|
207 | return FFTForward(A, A.Size.NumberOfDimensions);
|
---|
208 |
|
---|
209 | // prepare output array + transform each dimension inplace
|
---|
210 | ILArray< complex> ret = ILMath.tocomplex(A);
|
---|
211 | switch (nDims) {
|
---|
212 | case 2:
|
---|
213 | fft2dInplace(ret, ACMLValues.Forward);
|
---|
214 | break;
|
---|
215 | default:
|
---|
216 | for (int i = 0; i < nDims; i++) {
|
---|
217 | fft1dInplace(i, ret, ACMLValues.Forward);
|
---|
218 | }
|
---|
219 | break;
|
---|
220 | }
|
---|
221 | return ret;
|
---|
222 | }
|
---|
223 | }
|
---|
224 | |
---|
225 | #region HYCALPER AUTO GENERATED CODE
|
---|
226 | |
---|
227 |
|
---|
228 | public ILRetArray< fcomplex> FFTBackward(ILInArray< fcomplex> A, int nDims) {
|
---|
229 | using (ILScope.Enter(A)) {
|
---|
230 | if (object.Equals(A, null) || nDims <= 0)
|
---|
231 | throw new ILArgumentException("invalid parameter!");
|
---|
232 | if (A.IsEmpty) return ILMath.array< fcomplex>(A.Size);
|
---|
233 | if (A.IsScalar || (A.Size[0] == 1 && nDims == 1))
|
---|
234 | return A.C;
|
---|
235 | if (nDims > A.Size.NumberOfDimensions)
|
---|
236 | return FFTBackward(A, A.Size.NumberOfDimensions);
|
---|
237 |
|
---|
238 | // prepare output array + transform each dimension inplace
|
---|
239 | ILArray< fcomplex> ret = A.C;
|
---|
240 | switch (nDims) {
|
---|
241 | case 2:
|
---|
242 | fft2dInplace(ret, ACMLValues.Backwards);
|
---|
243 | break;
|
---|
244 | default:
|
---|
245 | for (int i = 0; i < nDims; i++) {
|
---|
246 | fft1dInplace(i, ret, ACMLValues.Backwards);
|
---|
247 | }
|
---|
248 | break;
|
---|
249 | }
|
---|
250 | return ret;
|
---|
251 | }
|
---|
252 | }
|
---|
253 |
|
---|
254 | public ILRetArray< complex> FFTBackward(ILInArray< complex> A, int nDims) {
|
---|
255 | using (ILScope.Enter(A)) {
|
---|
256 | if (object.Equals(A, null) || nDims <= 0)
|
---|
257 | throw new ILArgumentException("invalid parameter!");
|
---|
258 | if (A.IsEmpty) return ILMath.array< complex>(A.Size);
|
---|
259 | if (A.IsScalar || (A.Size[0] == 1 && nDims == 1))
|
---|
260 | return A.C;
|
---|
261 | if (nDims > A.Size.NumberOfDimensions)
|
---|
262 | return FFTBackward(A, A.Size.NumberOfDimensions);
|
---|
263 |
|
---|
264 | // prepare output array + transform each dimension inplace
|
---|
265 | ILArray< complex> ret = A.C;
|
---|
266 | switch (nDims) {
|
---|
267 | case 2:
|
---|
268 | fft2dInplace(ret, ACMLValues.Backwards);
|
---|
269 | break;
|
---|
270 | default:
|
---|
271 | for (int i = 0; i < nDims; i++) {
|
---|
272 | fft1dInplace(i, ret, ACMLValues.Backwards);
|
---|
273 | }
|
---|
274 | break;
|
---|
275 | }
|
---|
276 | return ret;
|
---|
277 | }
|
---|
278 | }
|
---|
279 |
|
---|
280 | public ILRetArray< fcomplex> FFTForward(ILInArray< fcomplex> A, int nDims) {
|
---|
281 | using (ILScope.Enter(A)) {
|
---|
282 | if (object.Equals(A, null) || nDims <= 0)
|
---|
283 | throw new ILArgumentException("invalid parameter!");
|
---|
284 | if (A.IsEmpty) return ILMath.array< fcomplex>(A.Size);
|
---|
285 | if (A.IsScalar || (A.Size[0] == 1 && nDims == 1))
|
---|
286 | return A.C;
|
---|
287 | if (nDims > A.Size.NumberOfDimensions)
|
---|
288 | return FFTForward(A, A.Size.NumberOfDimensions);
|
---|
289 |
|
---|
290 | // prepare output array + transform each dimension inplace
|
---|
291 | ILArray< fcomplex> ret = A.C;
|
---|
292 | switch (nDims) {
|
---|
293 | case 2:
|
---|
294 | fft2dInplace(ret, ACMLValues.Forward);
|
---|
295 | break;
|
---|
296 | default:
|
---|
297 | for (int i = 0; i < nDims; i++) {
|
---|
298 | fft1dInplace(i, ret, ACMLValues.Forward);
|
---|
299 | }
|
---|
300 | break;
|
---|
301 | }
|
---|
302 | return ret;
|
---|
303 | }
|
---|
304 | }
|
---|
305 |
|
---|
306 | public ILRetArray< fcomplex> FFTForward(ILInArray< float> A, int nDims) {
|
---|
307 | using (ILScope.Enter(A)) {
|
---|
308 | if (object.Equals(A, null) || nDims <= 0)
|
---|
309 | throw new ILArgumentException("invalid parameter!");
|
---|
310 | if (A.IsEmpty) return ILMath.array< fcomplex>(A.Size);
|
---|
311 | if (A.IsScalar || (A.Size[0] == 1 && nDims == 1))
|
---|
312 | return ILMath.tofcomplex(A);
|
---|
313 | if (nDims > A.Size.NumberOfDimensions)
|
---|
314 | return FFTForward(A, A.Size.NumberOfDimensions);
|
---|
315 |
|
---|
316 | // prepare output array + transform each dimension inplace
|
---|
317 | ILArray< fcomplex> ret = ILMath.tofcomplex(A);
|
---|
318 | switch (nDims) {
|
---|
319 | case 2:
|
---|
320 | fft2dInplace(ret, ACMLValues.Forward);
|
---|
321 | break;
|
---|
322 | default:
|
---|
323 | for (int i = 0; i < nDims; i++) {
|
---|
324 | fft1dInplace(i, ret, ACMLValues.Forward);
|
---|
325 | }
|
---|
326 | break;
|
---|
327 | }
|
---|
328 | return ret;
|
---|
329 | }
|
---|
330 | }
|
---|
331 |
|
---|
332 | public ILRetArray< complex> FFTForward(ILInArray< complex> A, int nDims) {
|
---|
333 | using (ILScope.Enter(A)) {
|
---|
334 | if (object.Equals(A, null) || nDims <= 0)
|
---|
335 | throw new ILArgumentException("invalid parameter!");
|
---|
336 | if (A.IsEmpty) return ILMath.array< complex>(A.Size);
|
---|
337 | if (A.IsScalar || (A.Size[0] == 1 && nDims == 1))
|
---|
338 | return A.C;
|
---|
339 | if (nDims > A.Size.NumberOfDimensions)
|
---|
340 | return FFTForward(A, A.Size.NumberOfDimensions);
|
---|
341 |
|
---|
342 | // prepare output array + transform each dimension inplace
|
---|
343 | ILArray< complex> ret = A.C;
|
---|
344 | switch (nDims) {
|
---|
345 | case 2:
|
---|
346 | fft2dInplace(ret, ACMLValues.Forward);
|
---|
347 | break;
|
---|
348 | default:
|
---|
349 | for (int i = 0; i < nDims; i++) {
|
---|
350 | fft1dInplace(i, ret, ACMLValues.Forward);
|
---|
351 | }
|
---|
352 | break;
|
---|
353 | }
|
---|
354 | return ret;
|
---|
355 | }
|
---|
356 | }
|
---|
357 |
|
---|
358 | #endregion HYCALPER AUTO GENERATED CODE
|
---|
359 |
|
---|
360 | public ILRetArray<float> FFTBackwSym(ILInArray<fcomplex> A, int nDims) {
|
---|
361 | return ILMath.real(FFTBackward(A,nDims));
|
---|
362 | }
|
---|
363 |
|
---|
364 | public ILRetArray<double> FFTBackwSym(ILInArray<complex> A, int nDims) {
|
---|
365 | return ILMath.real(FFTBackward(A,nDims));
|
---|
366 | }
|
---|
367 |
|
---|
368 | public bool CachePlans {
|
---|
369 | get { return true; }
|
---|
370 | }
|
---|
371 |
|
---|
372 | public void FreePlans() {
|
---|
373 | FreeAllDescriptors();
|
---|
374 | }
|
---|
375 |
|
---|
376 | public bool SpeedyHermitian {
|
---|
377 | get { return false; }
|
---|
378 | }
|
---|
379 |
|
---|
380 | #endregion
|
---|
381 |
|
---|
382 | #region private helper
|
---|
383 |
|
---|
384 | private void fft1dInplace(int dim, ILInArray<complex> ret, int mode) {
|
---|
385 | using (ILScope.Enter(ret)) {
|
---|
386 | int N = ret.Size[dim], info = 0;
|
---|
387 | // spacing between elements
|
---|
388 | int incx1 = ret.Size.SequentialIndexDistance(dim);
|
---|
389 | // storage of subsequent transformations
|
---|
390 | int incx2 = incx1 * N;
|
---|
391 | // number of transformations
|
---|
392 | int nseq = ret.Size.NumberOfElements / incx2;
|
---|
393 | double scale = (mode == ACMLValues.Backwards) ? 1.0 / N : 1.0;
|
---|
394 | string hash = hashPlan(ACMLValues.Double, ACMLValues.Complex, N, "zfft1mx");
|
---|
395 | IntPtr descriptor;
|
---|
396 | lock (_lockobject) {
|
---|
397 | if (!m_descriptors.TryGetValue(hash, out descriptor)) {
|
---|
398 | int commLength = (3 * N + 100) * ACMLValues.Double * 2;
|
---|
399 | try {
|
---|
400 | descriptor = Marshal.AllocCoTaskMem(commLength);
|
---|
401 | zfft1mx(0, scale, 1, nseq, N, IntPtr.Zero, incx1, incx2, IntPtr.Zero, 0, 0, descriptor, ref info);
|
---|
402 | if (info != 0)
|
---|
403 | throw new ILInvalidOperationException("error creating fft-plan");
|
---|
404 | m_descriptors[hash] = descriptor;
|
---|
405 | } catch (OutOfMemoryException exc) {
|
---|
406 | if (m_descriptors.Count > 0) {
|
---|
407 | FreeAllDescriptors();
|
---|
408 | descriptor = Marshal.AllocCoTaskMem(commLength);
|
---|
409 | zfft1mx(0, scale, 1, nseq, N, IntPtr.Zero, incx1, incx2, IntPtr.Zero, 0, 0, descriptor, ref info);
|
---|
410 | if (info != 0)
|
---|
411 | throw new ILInvalidOperationException("error creating fft-plan");
|
---|
412 | m_descriptors[hash] = descriptor;
|
---|
413 | }
|
---|
414 | throw exc;
|
---|
415 | }
|
---|
416 | }
|
---|
417 | // do the transform(s)
|
---|
418 | fixed (complex* start = ret.GetArrayForWrite()) {
|
---|
419 | for (int i = 0; i < incx1 && info == 0; i++)
|
---|
420 | zfft1mx(mode, scale, 1, nseq, N, (IntPtr)(start + i), incx1, incx2, IntPtr.Zero, 0, 0, descriptor, ref info);
|
---|
421 | }
|
---|
422 | }
|
---|
423 | if (info != 0) {
|
---|
424 | throw new ILInvalidOperationException(String.Format("error: {0}th parameter was invalid", -info));
|
---|
425 | }
|
---|
426 | }
|
---|
427 | }
|
---|
428 | private void fft2dInplace(ILInArray<complex> ret, int mode) {
|
---|
429 | using (ILScope.Enter(ret)) {
|
---|
430 | System.Diagnostics.Debug.Assert(ret.Size.NumberOfDimensions >= 2);
|
---|
431 | int N = ret.Size[1], M = ret.Size[0], info = 0;
|
---|
432 | int MN = M * N;
|
---|
433 | // number of transformations
|
---|
434 | int nseq = ret.Size.NumberOfElements / (MN);
|
---|
435 | double scale = (mode == ACMLValues.Backwards) ? 1.0 / MN : 1.0;
|
---|
436 | string hash = hashPlan(ACMLValues.Double, ACMLValues.Complex, M, N, "zfft2dx");
|
---|
437 | IntPtr descriptor;
|
---|
438 | lock (_lockobject) {
|
---|
439 | if (!m_descriptors.TryGetValue(hash, out descriptor)) {
|
---|
440 | int commLength = (3 * (N + M) + MN + 200) * ACMLValues.Double * 2;
|
---|
441 | try {
|
---|
442 | descriptor = Marshal.AllocCoTaskMem(commLength);
|
---|
443 | zfft2dx(0, scale, 1, 1, M, N, IntPtr.Zero, 1, M, IntPtr.Zero, 0, 0, descriptor, ref info);
|
---|
444 | if (info != 0)
|
---|
445 | throw new ILInvalidOperationException("error creating fft-plan");
|
---|
446 | m_descriptors[hash] = descriptor;
|
---|
447 | } catch (OutOfMemoryException exc) {
|
---|
448 | if (m_descriptors.Count > 0) {
|
---|
449 | FreeAllDescriptors();
|
---|
450 | descriptor = Marshal.AllocCoTaskMem(commLength);
|
---|
451 | zfft2dx(0, scale, 1, 1, M, N, IntPtr.Zero, 1, M, IntPtr.Zero, 0, 0, descriptor, ref info);
|
---|
452 | if (info != 0)
|
---|
453 | throw new ILInvalidOperationException("error creating fft-plan");
|
---|
454 | m_descriptors[hash] = descriptor;
|
---|
455 | }
|
---|
456 | throw exc;
|
---|
457 | }
|
---|
458 | }
|
---|
459 | // do the transform(s)
|
---|
460 | fixed (complex* start = ret.GetArrayForWrite()) {
|
---|
461 | for (int i = 0; i < nseq && info == 0; i++)
|
---|
462 | zfft2dx(mode, scale, 1, 1, M, N, (IntPtr)(start + i * MN), 1, M, IntPtr.Zero, 0, 0, descriptor, ref info);
|
---|
463 | }
|
---|
464 | }
|
---|
465 | if (info != 0) {
|
---|
466 | throw new ILInvalidOperationException(String.Format("error: {0}th parameter was invalid", -info));
|
---|
467 | }
|
---|
468 | }
|
---|
469 | }
|
---|
470 |
|
---|
471 | private void fft1dInplace(int dim, ILInArray<fcomplex> ret, int mode) {
|
---|
472 | using (ILScope.Enter(ret)) {
|
---|
473 | int N = ret.Size[dim], info = 0;
|
---|
474 | // spacing between elements
|
---|
475 | int incx1 = ret.Size.SequentialIndexDistance(dim);
|
---|
476 | // storage of subsequent transformations
|
---|
477 | int incx2 = incx1 * N;
|
---|
478 | // number of transformations
|
---|
479 | int nseq = ret.Size.NumberOfElements / incx2;
|
---|
480 | float scale = (mode == ACMLValues.Backwards) ? 1.0f / N : 1.0f;
|
---|
481 | string hash = hashPlan(ACMLValues.Single, ACMLValues.Complex, N, "cfft1mx");
|
---|
482 | IntPtr descriptor;
|
---|
483 | lock (_lockobject) {
|
---|
484 | if (!m_descriptors.TryGetValue(hash, out descriptor)) {
|
---|
485 | int commLength = (3 * N + 100) * ACMLValues.Single * 2;
|
---|
486 | try {
|
---|
487 | descriptor = Marshal.AllocCoTaskMem(commLength);
|
---|
488 | cfft1mx(0, 1.0f, 1, 1, N, IntPtr.Zero, 1, 1, IntPtr.Zero, 0, 0, descriptor, ref info);
|
---|
489 | if (info != 0)
|
---|
490 | throw new ILInvalidOperationException("error creating fft-plan");
|
---|
491 | m_descriptors[hash] = descriptor;
|
---|
492 | } catch (OutOfMemoryException exc) {
|
---|
493 | if (m_descriptors.Count > 0) {
|
---|
494 | FreeAllDescriptors();
|
---|
495 | descriptor = Marshal.AllocCoTaskMem(commLength);
|
---|
496 | cfft1mx(0, 1.0f, 1, 1, N, IntPtr.Zero, 1, 1, IntPtr.Zero, 0, 0, descriptor, ref info);
|
---|
497 | if (info != 0)
|
---|
498 | throw new ILInvalidOperationException("error creating fft-plan");
|
---|
499 | m_descriptors[hash] = descriptor;
|
---|
500 | }
|
---|
501 | throw exc;
|
---|
502 | }
|
---|
503 | }
|
---|
504 | // do the transform(s)
|
---|
505 | fixed (fcomplex* start = ret.GetArrayForWrite()) {
|
---|
506 | for (int i = 0; i < incx1 && info == 0; i++)
|
---|
507 | cfft1mx(mode, scale, 1, nseq, N, (IntPtr)(start + i), incx1, incx2, IntPtr.Zero, 0, 0, descriptor, ref info);
|
---|
508 | }
|
---|
509 | }
|
---|
510 | if (info != 0) {
|
---|
511 | throw new ILInvalidOperationException(String.Format("error: {0}th parameter was invalid", -info));
|
---|
512 | }
|
---|
513 | }
|
---|
514 | }
|
---|
515 | private void fft2dInplace(ILInArray<fcomplex> ret, int mode) {
|
---|
516 | using (ILScope.Enter(ret)) {
|
---|
517 | System.Diagnostics.Debug.Assert(ret.Size.NumberOfDimensions >= 2);
|
---|
518 | int N = ret.Size[1], M = ret.Size[0], info = 0;
|
---|
519 | int MN = M * N;
|
---|
520 | // number of transformations
|
---|
521 | int nseq = ret.Size.NumberOfElements / (MN);
|
---|
522 | float scale = (mode == ACMLValues.Backwards) ? 1.0f / MN : 1.0f;
|
---|
523 | string hash = hashPlan(ACMLValues.Single, ACMLValues.Complex, M, N, "cfft2dx");
|
---|
524 | IntPtr descriptor;
|
---|
525 | lock (_lockobject) {
|
---|
526 | if (!m_descriptors.TryGetValue(hash, out descriptor)) {
|
---|
527 | int commLength = (3 * (N + M) + MN + 200) * ACMLValues.Single * 2;
|
---|
528 | try {
|
---|
529 | descriptor = Marshal.AllocCoTaskMem(commLength);
|
---|
530 | cfft2dx(0, scale, 1, 1, M, N, IntPtr.Zero, 1, M, IntPtr.Zero, 0, 0, descriptor, ref info);
|
---|
531 | if (info != 0)
|
---|
532 | throw new ILInvalidOperationException("error creating fft-plan");
|
---|
533 | m_descriptors[hash] = descriptor;
|
---|
534 | } catch (OutOfMemoryException exc) {
|
---|
535 | if (m_descriptors.Count > 0) {
|
---|
536 | FreeAllDescriptors();
|
---|
537 | descriptor = Marshal.AllocCoTaskMem(commLength);
|
---|
538 | cfft2dx(0, scale, 1, 1, M, N, IntPtr.Zero, 1, M, IntPtr.Zero, 0, 0, descriptor, ref info);
|
---|
539 | if (info != 0)
|
---|
540 | throw new ILInvalidOperationException("error creating fft-plan");
|
---|
541 | m_descriptors[hash] = descriptor;
|
---|
542 | }
|
---|
543 | throw exc;
|
---|
544 | }
|
---|
545 | }
|
---|
546 | // do the transform(s)
|
---|
547 | fixed (fcomplex* start = ret.GetArrayForWrite()) {
|
---|
548 | for (int i = 0; i < nseq && info == 0; i++)
|
---|
549 | cfft2dx(mode, scale, 1, 1, M, N, (IntPtr)(start + i * MN), 1, M, IntPtr.Zero, 0, 0, descriptor, ref info);
|
---|
550 | }
|
---|
551 | }
|
---|
552 | if (info != 0) {
|
---|
553 | throw new ILInvalidOperationException(String.Format("error: {0}th parameter was invalid", -info));
|
---|
554 | }
|
---|
555 | }
|
---|
556 | }
|
---|
557 |
|
---|
558 | private static string hashPlan(int precision, int realcomplex, int N, string funcname) {
|
---|
559 | return hashPlan(precision,realcomplex,0,N,funcname);
|
---|
560 | }
|
---|
561 | private static string hashPlan(int precision, int realcomplex, int M, int N, string funcname) {
|
---|
562 | return String.Format("{0}|{1}|{2}|{3}|{4}",precision, realcomplex,M,N,funcname);
|
---|
563 | }
|
---|
564 | private void FreeAllDescriptors() {
|
---|
565 | lock (_lockobject) {
|
---|
566 | if (m_descriptors != null) {
|
---|
567 | foreach (IntPtr p in m_descriptors.Values) {
|
---|
568 | if (p != IntPtr.Zero)
|
---|
569 | Marshal.FreeCoTaskMem(p);
|
---|
570 | }
|
---|
571 | m_descriptors.Clear();
|
---|
572 | }
|
---|
573 | }
|
---|
574 | }
|
---|
575 |
|
---|
576 | #endregion
|
---|
577 |
|
---|
578 | #region IDisposable Member
|
---|
579 |
|
---|
580 | public void Dispose() {
|
---|
581 | Dispose(true);
|
---|
582 | /* we cannot supress finalize,since the class will only wipe all
|
---|
583 | * cached cotask memory. Supsequent calls will again allocate those.
|
---|
584 | * Therefore the finalizer must check at the end again.
|
---|
585 | */
|
---|
586 | // GC.SuppressFinalize(this);
|
---|
587 | }
|
---|
588 |
|
---|
589 | public virtual void Dispose (bool manual) {
|
---|
590 | if (m_descriptors != null && m_descriptors.Count > 0) {
|
---|
591 | if (manual) {
|
---|
592 | FreeAllDescriptors();
|
---|
593 | }
|
---|
594 | }
|
---|
595 | }
|
---|
596 |
|
---|
597 | ~ILACMLFFT () {
|
---|
598 | Dispose(true);
|
---|
599 | }
|
---|
600 | #endregion
|
---|
601 |
|
---|
602 | }
|
---|
603 | }
|
---|