DoubleFFT_3D { public void complexForward(final double[] a) { int nthreads = ConcurrencyUtils.getNumberOfThreads(); if (isPowerOfTwo) { int oldn3 = columns; columns = 2 * columns; sliceStride = rows * columns; rowStride = columns; if (nthreads != oldNthreads) { nt = slices; if (nt < rows) { nt = rows; } nt *= 8; if (nthreads > 1) { nt *= nthreads; } if (columns == 4) { nt >>= 1; } else if (columns < 4) { nt >>= 2; } t = new double[nt]; oldNthreads = nthreads; } if ((nthreads > 1) && useThreads) { xdft3da_subth2(0, -1, a, true); cdft3db_subth(-1, a, true); } else { xdft3da_sub2(0, -1, a, true); cdft3db_sub(-1, a, true); } columns = oldn3; sliceStride = rows * columns; rowStride = columns; } else { sliceStride = 2 * rows * columns; rowStride = 2 * columns; if ((nthreads > 1) && useThreads && (slices >= nthreads) && (rows >= nthreads) && (columns >= nthreads)) { Future<?>[] futures = new Future[nthreads]; int p = slices / nthreads; for (int l = 0; l < nthreads; l++) { final int firstSlice = l * p; final int lastSlice = (l == (nthreads - 1)) ? slices : firstSlice + p; futures[l] = ConcurrencyUtils.submit(new Runnable() { @Override public void run() { for (int s = firstSlice; s < lastSlice; s++) { int idx1 = s * sliceStride; for (int r = 0; r < rows; r++) { fftColumns.complexForward(a, idx1 + r * rowStride); } } } }); } ConcurrencyUtils.waitForCompletion(futures); for (int l = 0; l < nthreads; l++) { final int firstSlice = l * p; final int lastSlice = (l == (nthreads - 1)) ? slices : firstSlice + p; futures[l] = ConcurrencyUtils.submit(new Runnable() { @Override public void run() { double[] temp = new double[2 * rows]; for (int s = firstSlice; s < lastSlice; s++) { int idx1 = s * sliceStride; for (int c = 0; c < columns; c++) { int idx2 = 2 * c; for (int r = 0; r < rows; r++) { int idx3 = idx1 + idx2 + r * rowStride; int idx4 = 2 * r; temp[idx4] = a[idx3]; temp[idx4 + 1] = a[idx3 + 1]; } fftRows.complexForward(temp); for (int r = 0; r < rows; r++) { int idx3 = idx1 + idx2 + r * rowStride; int idx4 = 2 * r; a[idx3] = temp[idx4]; a[idx3 + 1] = temp[idx4 + 1]; } } } } }); } ConcurrencyUtils.waitForCompletion(futures); p = rows / nthreads; for (int l = 0; l < nthreads; l++) { final int firstRow = l * p; final int lastRow = (l == (nthreads - 1)) ? rows : firstRow + p; futures[l] = ConcurrencyUtils.submit(new Runnable() { @Override public void run() { double[] temp = new double[2 * slices]; for (int r = firstRow; r < lastRow; r++) { int idx1 = r * rowStride; for (int c = 0; c < columns; c++) { int idx2 = 2 * c; for (int s = 0; s < slices; s++) { int idx3 = s * sliceStride + idx1 + idx2; int idx4 = 2 * s; temp[idx4] = a[idx3]; temp[idx4 + 1] = a[idx3 + 1]; } fftSlices.complexForward(temp); for (int s = 0; s < slices; s++) { int idx3 = s * sliceStride + idx1 + idx2; int idx4 = 2 * s; a[idx3] = temp[idx4]; a[idx3 + 1] = temp[idx4 + 1]; } } } } }); } ConcurrencyUtils.waitForCompletion(futures); } else { for (int s = 0; s < slices; s++) { int idx1 = s * sliceStride; for (int r = 0; r < rows; r++) { fftColumns.complexForward(a, idx1 + r * rowStride); } } double[] temp = new double[2 * rows]; for (int s = 0; s < slices; s++) { int idx1 = s * sliceStride; for (int c = 0; c < columns; c++) { int idx2 = 2 * c; for (int r = 0; r < rows; r++) { int idx3 = idx1 + idx2 + r * rowStride; int idx4 = 2 * r; temp[idx4] = a[idx3]; temp[idx4 + 1] = a[idx3 + 1]; } fftRows.complexForward(temp); for (int r = 0; r < rows; r++) { int idx3 = idx1 + idx2 + r * rowStride; int idx4 = 2 * r; a[idx3] = temp[idx4]; a[idx3 + 1] = temp[idx4 + 1]; } } } temp = new double[2 * slices]; for (int r = 0; r < rows; r++) { int idx1 = r * rowStride; for (int c = 0; c < columns; c++) { int idx2 = 2 * c; for (int s = 0; s < slices; s++) { int idx3 = s * sliceStride + idx1 + idx2; int idx4 = 2 * s; temp[idx4] = a[idx3]; temp[idx4 + 1] = a[idx3 + 1]; } fftSlices.complexForward(temp); for (int s = 0; s < slices; s++) { int idx3 = s * sliceStride + idx1 + idx2; int idx4 = 2 * s; a[idx3] = temp[idx4]; a[idx3 + 1] = temp[idx4 + 1]; } } } } sliceStride = rows * columns; rowStride = columns; } } DoubleFFT_3D(int slices, int rows, int columns); void complexForward(final double[] a); void complexForward(final double[][][] a); void complexInverse(final double[] a, final boolean scale); void complexInverse(final double[][][] a, final boolean scale); void realForward(double[] a); void realForward(double[][][] a); void realForwardFull(double[] a); void realForwardFull(double[][][] a); void realInverse(double[] a, boolean scale); void realInverse(double[][][] a, boolean scale); void realInverseFull(double[] a, boolean scale); void realInverseFull(double[][][] a, boolean scale);  }
@Test public void testComplexForward1dInput() { final FloatingPointEqualityChecker checker = createEqualityChecker( Math.ulp(1d), 0d); final double[] actual = new double[2 * numSlices * numRows * numCols]; final double[][][] expected = new double[numSlices][numRows][2 * numCols]; for (int s = 0; s < numSlices; s++) { for (int r = 0; r < numRows; r++) { for (int c = 0; c < 2 * numCols; c++) { final int index = 2 * numCols * (r + numRows * s) + c; final double rnd = random.nextDouble(); actual[index] = rnd; expected[s][r][c] = rnd; } } } fft.complexForward(actual); complexForward(expected); for (int s = 0; s < numSlices; s++) { for (int r = 0; r < numRows; r++) { for (int c = 0; c < 2 * numCols; c++) { final int index = 2 * numCols * (r + numRows * s) + c; final double exp = expected[s][r][c]; final double act = actual[index]; checker.assertEquals("[" + index + "]", exp, act); } } } }
@Test public void testComplexForward3dInput() { final FloatingPointEqualityChecker checker = createEqualityChecker( Math.ulp(1d), 0d); final double[][][] actual = new double[numSlices][numRows][2 * numCols]; final double[][][] expected = new double[numSlices][numRows][2 * numCols]; for (int s = 0; s < numSlices; s++) { for (int r = 0; r < numRows; r++) { for (int c = 0; c < 2 * numCols; c++) { final double rnd = random.nextDouble(); actual[s][r][c] = rnd; expected[s][r][c] = rnd; } } } fft.complexForward(actual); complexForward(expected); for (int s = 0; s < numSlices; s++) { for (int r = 0; r < numRows; r++) { for (int c = 0; c < 2 * numCols; c++) { final double exp = expected[s][r][c]; final double act = actual[s][r][c]; checker.assertEquals("[" + s + "][" + r + "][" + c + "]", exp, act); } } } }