c++fftfftwpyfftw

How to use fftw Guru interface


I used to use fftw_plan_dft for multi-dimensional Fourier transformation.

fftw_plan fftw_plan_dft(int rank, const int *n, fftw_complex *in,
                        fftw_complex *out, int sign, unsigned flags);

Now I want to pass 64 bit integer to fftw, it looks like I need to use fftw guru interface.

 fftw_plan fftw_plan_guru64_dft(
     int rank, const fftw_iodim64 *dims,
     int howmany_rank, const fftw_iodim64 *howmany_dims,
     fftw_complex *in, fftw_complex *out,
     int sign, unsigned flags);

But I do not understand what is howmany_rank and howmany_dims mean. The manual of fftw_plan_guru_dft says:

These two functions plan a complex-data, multi-dimensional DFT for the interleaved and split format, respectively. Transform dimensions are given by (rank, dims) over a multi-dimensional vector (loop) of dimensions (howmany_rank, howmany_dims). dims and howmany_dims should point to fftw_iodim arrays of length rank and howmany_rank, respectively.

I do know know what is "multi-dimensional vector (loop) of dimensions (howmany_rank, howmany_dims)" mean. Can you give me an example or explain how to use this guru interface?


Solution

  • If the sizes and strides of your mulitdimensional arrays are larger than 2^32, the 64 bit guru interface becomes useful.

    The prototype of the function creating complex to complex DTFs is:

    fftw_plan fftw_plan_guru64_dft(
     int rank, const fftw_iodim64 *dims,
     int howmany_rank, const fftw_iodim64 *howmany_dims,
     fftw_complex *in, fftw_complex *out,
     int sign, unsigned flags);
    

    where:

    More detail about these arguments are provided in Confusion about FFTW3 guru interface: 3 simultaneous complex FFTs

    The following code calls fftw_plan_guru64_dft() so that it performs the same thing as fftw_plan_dft_3d(). It can be compiled by gcc main.c -o main -lfftw3 -lm -Wall:

    #include<stdlib.h>
    #include<complex.h>
    #include<math.h>
    #include<fftw3.h>
    
    int main(void){
    
        fftw_plan p;
        unsigned long int N = 10;
        unsigned long int M = 12;
        unsigned long int P = 14;
        fftw_complex *in=fftw_malloc(N*M*P*sizeof(fftw_complex));
        if(in==NULL){fprintf(stderr,"malloc failed\n");exit(1);}
        fftw_complex *out=fftw_malloc(N*M*P*sizeof(fftw_complex));
        if(out==NULL){fprintf(stderr,"malloc failed\n");exit(1);}
        unsigned int i,j,k;
    
        int rank=3;
        fftw_iodim64 *dims=malloc(rank*sizeof(fftw_iodim64));
        if(dims==NULL){fprintf(stderr,"malloc failed\n");exit(1);}
        dims[0].n=N;
        dims[0].is=P*M;
        dims[0].os=P*M;
        dims[1].n=M;
        dims[1].is=P;
        dims[1].os=P;
        dims[2].n=P;
        dims[2].is=1;
        dims[2].os=1;
    
        int howmany_rank=1;
        fftw_iodim64 *howmany_dims=malloc(howmany_rank*sizeof(fftw_iodim64));
        if(howmany_dims==NULL){fprintf(stderr,"malloc failed\n");exit(1);}
        howmany_dims[0].n=1;
        howmany_dims[0].is=1;
        howmany_dims[0].os=1;
    
        printf("sizeof fftw complex %ld\n",sizeof(fftw_complex));
        printf("sizeof fftw_iodim64 %ld\n",sizeof(fftw_iodim64));
        printf("creating the plan\n");
        p=fftw_plan_guru64_dft(rank, dims,howmany_rank, howmany_dims,in, out,FFTW_FORWARD, FFTW_ESTIMATE);
        if (p==NULL){fprintf(stderr,"plan creation failed\n");exit(1);}
        printf("created the plan\n");
    
        for(i=0;i<N;i++){
            for(j=0;j<M;j++){
                for(k=0;k<P;k++){
                    //printf("ijk\n");
                    in[(i*M+j)*P+k]=30.+12.*sin(2*3.1415926535*i/((double)N))*sin(2*3.1415926535*j/((double)M))*sin(2*3.1415926535*k/((double)P))*I;
                }
            }
        }
    
        fftw_execute(p);
    
        for (i = 0; i < N; i++){
            for (j = 0; j < M; j++){
                for (k = 0; k < P; k++){
                    printf("result: %d %d %d %g %gI\n", i,j,k, creal(out[(i*M+j)*P+k]), cimag(out[(i*M+j)*P+k]));
                }
            }
        }
    
    
        fftw_destroy_plan(p);
        fftw_free(in);
        fftw_free(out);
    
        free(dims);
        free(howmany_dims);
    
        return(0);
    }
    

    For instance, the guru interface can be used to compute the DFT of a complex 3D electric field. At each point of the grid, the electric field is a vector of size 3. Hence, I can store the electric field as a 4D array, the last dimension specifying the component of the vector. Finally, the guru interface can be used to perform the three 3D DFTs at once:

    #include<stdlib.h>
    #include<complex.h>
    #include<math.h>
    #include<fftw3.h>
    
    int main(void){
    
        fftw_plan p;
        unsigned long int N = 10;
        unsigned long int M = 12;
        unsigned long int P = 14;
        unsigned long int DOF = 3;
        fftw_complex *in=fftw_malloc(N*M*P*DOF*sizeof(fftw_complex));
        if(in==NULL){fprintf(stderr,"malloc failed\n");exit(1);}
        fftw_complex *out=fftw_malloc(N*M*P*DOF*sizeof(fftw_complex));
        if(out==NULL){fprintf(stderr,"malloc failed\n");exit(1);}
        unsigned int i,j,k;
    
        int rank=3;
        fftw_iodim64 *dims=malloc(rank*sizeof(fftw_iodim64));
        if(dims==NULL){fprintf(stderr,"malloc failed\n");exit(1);}
        dims[0].n=N;
        dims[0].is=P*M*DOF;
        dims[0].os=P*M*DOF;
        dims[1].n=M;
        dims[1].is=P*DOF;
        dims[1].os=P*DOF;
        dims[2].n=P;
        dims[2].is=DOF;
        dims[2].os=DOF;
    
        int howmany_rank=1;
        fftw_iodim64 *howmany_dims=malloc(howmany_rank*sizeof(fftw_iodim64));
        if(howmany_dims==NULL){fprintf(stderr,"malloc failed\n");exit(1);}
        howmany_dims[0].n=DOF;
        howmany_dims[0].is=1;
        howmany_dims[0].os=1;
    
        printf("sizeof fftw complex %ld\n",sizeof(fftw_complex));
        printf("sizeof fftw_iodim64 %ld\n",sizeof(fftw_iodim64));
        printf("creating the plan\n");
        p=fftw_plan_guru64_dft(rank, dims,howmany_rank, howmany_dims,in, out,FFTW_FORWARD, FFTW_ESTIMATE);
        if (p==NULL){fprintf(stderr,"plan creation failed\n");exit(1);}
        printf("created the plan\n");
    
        for(i=0;i<N;i++){
            for(j=0;j<M;j++){
                for(k=0;k<P;k++){
                    //printf("ijk\n");
                    in[((i*M+j)*P+k)*DOF]=30.+12.*sin(2*3.1415926535*i/((double)N))*sin(2*3.1415926535*j/((double)M))*sin(2*3.1415926535*k/((double)P))*I;
                    in[((i*M+j)*P+k)*DOF+1]=42.0;
                    in[((i*M+j)*P+k)*DOF+2]=1.0;
                }
            }
        }
    
        fftw_execute(p);
    
        for (i = 0; i < N; i++){
            for (j = 0; j < M; j++){
                for (k = 0; k < P; k++){
                    printf("result: %d %d %d || %g %gI | %g %gI | %g %gI\n", i,j,k, creal(out[((i*M+j)*P+k)*DOF]), cimag(out[((i*M+j)*P+k)*DOF]),creal(out[((i*M+j)*P+k)*DOF+1]), cimag(out[((i*M+j)*P+k)*DOF+1]),creal(out[((i*M+j)*P+k)*DOF+2]), cimag(out[((i*M+j)*P+k)*DOF+2]));
                }
            }
        }
    
    
        fftw_destroy_plan(p);
        fftw_free(in);
        fftw_free(out);
    
        free(dims);
        free(howmany_dims);
    
        return(0);
    }