Cufft 2d

Hello;

I write the same topic before but I think a problem happened so I decided to write it again. I hava a problem with CuFFT.
My problem is using FFT with 2 dimensional arrays. I read the NVDIA cufft library ant it gives a sample code but I think it isn’t enough (at least for the beginners like me )

#define NX 200
#define NY 100
cufftHandle plan;
cufftComplex *data1, *data2;

cudaMalloc((void**)&data1, sizeof(cufftComplex)NXNY);
cudaMalloc((void**)&data2, sizeof(cufftComplex)NXNY);

/* Create a 2D FFT plan. */
cufftPlan2d(&plan, NX, NY, CUFFT_DATA_C2C);

cufftExecute(plan, data1, data2, CUFFT_FORWARD);

The problem is pointers ? I dont know what they are holding ? They points a 2D array or not ? The sample codes with Jcuda whic I looked the jcuda.org have the same problem. Sample shows only one dimensional array. I tried to change it 2D array but it gives me errors. I dont know what will I do.

    JCUDA sample
   
     float outputJCufft[] = input.clone();
    cufftHandle plan = new cufftHandle();
    JCufft.cufftPlan2d(plan, size, size, cufftType.CUFFT_C2C);
    JCufft.cufftExecC2C(plan, outputJCufft, outputJCufft, JCufft.CUFFT_FORWARD);
    JCufft.cufftDestroy(plan);

it is wrong codes and what do you suggest to me ? Do I have to change the 2D array into the 1D array ? :confused:

Thanks;

Hello

I’ll try to post an example for a 2D fft as soon as I find the time (hopefully this week).

bye

I will looking forward your sample. :stuck_out_tongue:
thanks

After reading your message a second time, I’m not sure if the question is specific for a 2D FFT, or if it refers to the general question about passing “2D arrays” to CUDA.

I wrote a few words about the general issue of “2D array” in this post. Does this already answer your question?

In any case, the data that is passed to CUFFT (and to JCufft) has to be a 1D array, regardless of whether it is for a 1D, 2D or 3D transform. The example that you posted also shows that a 1D array of size NX*NY is allocated:
cudaMalloc((void**)&data1, sizeof(cufftComplex)NXNY);

Basically, the execution of a 2D FFT is rather straightforward, for example, a 2D complex forward transform:

cufftHandle plan = new cufftHandle();
cufftPlan2d(plan, N, N, CUFFT_C2C);
cufftExecC2C(plan, data, data, CUFFT_FORWARD);
cufftDestroy(plan);

Here another example, which prints (parts of) the results of a C2C transform executed with JCufft and with JTransforms:

import static jcuda.jcufft.JCufft.*;
import static jcuda.jcufft.cufftType.CUFFT_C2C;

import java.util.*;

import jcuda.jcufft.cufftHandle;
import edu.emory.mathcs.jtransforms.fft.FloatFFT_2D;

public class SimpleJCufft2D
{
    private static final Random random = new Random(0);
    
    public static void main(String args[])
    {
        int N = (1<<4);
        float data[] = createRandomFloatData(N * N * 2);

        float resultJCufft[] = testJCufft(N, data);
        float resultJTransforms[] = testJTransforms(N, data);
        
        System.out.println("JCufft     : "+
            Arrays.toString(Arrays.copyOfRange(resultJCufft, 0, 10))+"...");
        System.out.println("JTransforms: "+
            Arrays.toString(Arrays.copyOfRange(resultJTransforms, 0, 10))+"...");
    }
    
    private static float[] testJCufft(int N, float input[])
    {
        float data[] = input.clone();
        cufftHandle plan = new cufftHandle();
        cufftPlan2d(plan, N, N, CUFFT_C2C);
        cufftExecC2C(plan, data, data, CUFFT_FORWARD);
        cufftDestroy(plan);
        return data;
    }
    
    private static float[] testJTransforms(int N, float input[])
    {
        float data[][] = make2D(input, N, N*2);
        FloatFFT_2D fft = new FloatFFT_2D(N,N);
        fft.complexForward(data);
        return linearize(data);
    }
    
    public static float[] createRandomFloatData(int x)
    {
        float a[] = new float[x];
        for (int i=0; i<x; i++)
        {
            a** = random.nextFloat();
        }
        return a;
    }
    
    public static float[][] make2D(float input[], int x, int y)
    {
        float result[][] = new float[x][y];
        int index = 0;
        for (int i=0; i<x; i++)
        {
            for (int j=0; j<y; j++)
            {
                result**[j] = input[index++];                    
            }
        }
        return result;
    }
    
    public static float[] linearize(float a[][])
    {
        List<Float> list = new ArrayList<Float>();
        for (int x=0; x<a.length; x++)
        {
            for (int y=0; y<a[x].length; y++)
            {
                list.add(a[x][y]);
            }
        }
        float result[] = new float[list.size()];
        for (int i=0; i<list.size(); i++)
        {
            result** = list.get(i);
        }
        return result;
    }
    
    
}

Note that JTransforms needs “real” Java “2D arrays”, so there are some 1D <-> 2D conversion methods, which might be omitted once the library and the corresponding data layout has been chosen.

bye

Hi;

Thanks for your help. but I confused one point.

I am creating one dimensinal array;

[LEFT]
[ol]
[li]int N=16; // for example[/li][li]float[] data = new data[N*N] ; //initialize the random values …[/li][li][FONT=Courier New]cufftHandle plan = new cufftHandle();[/li][li]cufftPlan2d(plan, N, N, CUFFT_C2C);[/li][li]cufftExecC2C(plan, data, data, CUFFT_FORWARD);[/li][li]cufftDestroy(plan);[/li][/ol]
[/FONT]
[/LEFT]

but your example NN2 This means this isn’t NxN dimensinal matris. you are cretaing Nx(2*N) matris
Then I use the sample plan but it gives me wrong values with JTransforms. (completely different values) Also I changed the codes like that

[ol]
[li] private static float[] testJTransforms(int N, float input[])[/li][li] {[/li][li] float data[][] = make2D(input, N, N);[/li][li] FloatFFT_2D fft = new FloatFFT_2D(N,N);[/li][li] fft.complexForward(data);[/li][li] return linearize(data);[/li][li] }[/li][/ol]
But it gives me wrong values. and gives me error " java.lang.ArrayIndexOutOfBoundsException: " for JTransform
Am I doing something wrong? Can you suggest me somethin ?

Best wishes

Hello

I’m not sure if I got this right. The posted example should compute the results with both libraries, and the results should be equal (besides a rounding error of ~1e-6 or so…).

The important point concerning the “NN2” is that the computation is done on complex numbers: These consist of real and imaginary part. So the array has a “width” of N*2, although the Plan is set up for N numbers.

bye
Marco

Yes you are right but I mean for JCufft plan set for N[FONT=Courier New] cufftPlan2d(plan, N, N, CUFFT_C2C);[/FONT]
But array dimension isn’t NxN. array dimension is Nx(2N) so in my opinion it isnt right.

we create plan like that cufftPlan2d(plan, width, height,[FONT=Courier New]CUFFT_C2C[/FONT] ) am I wrong ?

Thanks for answers

Well, since “CUFFT_C2C” refers to complex numbers, and there are N complex numbers, everything should be fine (The fact that N complex numbers are represented by 2*N float numbers is taken into account by CUFFT…)

I got it now. that is why you create 2*N for column. Complex numbers have two part. one for reel and one for imaginary
like that r+i.

for example when I want to use FFT for NxN matris. (N=4)

| matris(0,0) | matris(0,1) | matris(0,2) | matris(0,3) |
| matris(1,0) | matris(1,1) | matris(1,2) | matris(1,3) |
| matris(2,0) | matris(2,1) | matris(2,2) | matris(2,3) |
| matris(3,0) | matris(3,1) | matris(3,2) | matris(3,3) |

first I want to change it complex number
-----------------------------------------------------------------This part is for imaginary part ---------------------
| matris(0,0) | matris(0,1) | matris(0,2) | matris(0,3) | 0 | 0 | 0 | 0 |
| matris(1,0) | matris(1,1) | matris(1,2) | matris(1,3) | 0 | 0 | 0 | 0 |
| matris(2,0) | matris(2,1) | matris(2,2) | matris(2,3) | 0 | 0 | 0 | 0 |
| matris(3,0) | matris(3,1) | matris(3,2) | matris(3,3) | 0 | 0 | 0 | 0 |

Then I turn it one dimensinal array like that
matris(0,0)
matris(0,1)
matris(0,2)
matris(0,3)

matris(1,0)
matris(1,1)
matris(1,2)
matris(1,3)

matris(2,0)
matris(2,1)
matris(2,2)
matris(2,3)

matris(3,0)
matris(3,1)
matris(3,2)
matris(3,3)

0
0
0
0

0
0
0
0

0
0
0
0

0
0
0
0

Or Am I wrong ?

Thanks

Some FFTs offer different possible layouts for the complex numbers, but CUFFT only offers the “Interleaved” layout. So when you have a matrix of real numbers, and want to interpret them as complex numbers, you actually need a 1D array like


matrix(0,0) // real part of number 0
0 // imaginary part of number 0
matrix(0,1) // real part of number 1
0 // imaginary part of number 1
matrix(0,2) // real part of number 2
0 // imaginary part of number 2
...

But maybe you can simply use a R2C transform? In any case you should carefully read the CUFFT Programming Guide (PDF File), especially the section about “CUFFT Transform Types”, which also explains the memory layouts. (I’m not an FFT expert either, so I can hardly give a profound advice about the best approach).

bye

Thank you very much. It was too helpfull for me