C++ 将R2R FFT从FFTW移植到CUFT

C++ 将R2R FFT从FFTW移植到CUFT,c++,cuda,fft,fftw,cufft,C++,Cuda,Fft,Fftw,Cufft,我正在尝试将一些代码从CPU移植到GPU,其中包括一些FFT。因此,在CPU代码上,使用fftw\u plan\u many\u r2r分别对其实部和imag部分转换一些复杂数组。函数foo表示R2R转换例程,并为复杂数组的每个部分调用两次 void foo(vector_double &evg) { int nx = Dims[0], ny = Dims[1], nz = Dims[2]; const int nxny[] = {ny, nx};

我正在尝试将一些代码从CPU移植到GPU,其中包括一些FFT。因此,在CPU代码上,使用
fftw\u plan\u many\u r2r
分别对其实部和imag部分转换一些复杂数组。函数foo表示R2R转换例程,并为复杂数组的每个部分调用两次

void foo(vector_double  &evg) {    
    int nx = Dims[0], ny = Dims[1], nz = Dims[2];
    
    const int nxny[] = {ny, nx};
    const int n = nx*ny*nz;

    const fftw_r2r_kind kinds[] = {FFTW_RODFT00, FFTW_RODFT00};
    
    if (evg.size() != n)
        throw std::runtime_error ("*** weird size of evg");
    
    fftw_plan p;
    p =  fftw_plan_many_r2r(2, nxny, nz, 
          &evg[0], nxny, 1, nx*ny,
          &evg[0], nxny, 1, nx*ny,
          kinds, FFTW_ESTIMATE);                         

    // actual FFT
    fftw_execute(p);
}

void bar(vector_complex &evg) {
    vector_double tmp;
    tmp = evg.real();
    foo(tmp);
    evg.real() = tmp;
    tmp = evg.imag();
    foo(tmp);
    evg.imag() = tmp;
}
那么,既然没有从FFTW R2R到CUFT的直接转换,我如何在CUDA上获得相同的结果呢?
P.S.vector_double和vector_complex是特征向量,如果这有帮助的话

我不能提供解决方案,但是评论的大小是有限的,所以我把它放在这里:

  • 使用FFTW时,可以使用就地转换,但不能在原地使用FFTW。我不知道这是否正确,我自己从未使用过就地转换

  • 事实上,cuFFT没有R2R,所以我们必须进行调查。根据fftw文档,fftw_RODFT00表示DST-I。根据维基百科,DST-I是正弦变换,如果你制作一个大小为2*(N+1)的向量,并反向复制值,则具有等价的傅里叶变换,如右图中标记为DST-I:。因此,如果对“扩展向量”进行r2c(或c2c)变换,并从变换向量中删除一些值,则得到的就是R2R变换。参见:“DST-I完全等同于实数序列的DFT,实数序列在第零点和中点附近为奇数,按1/2缩放”

  • 但有两个问题:

  • 你必须自己推断哪些索引需要删除(也就是说,复制到结果向量中),在现场进行处理有点复杂

  • 如果您使用带有额外复制的c2r情况,GPU必须比fftw在r2r情况下进行更多的计算(
    2(N+1)
    -大小转换,而不仅仅是
    N
    ),并且必须进行更多的内存分配,因此它不会像r2c或c2c情况那样快。但根据我的经验,即使是较旧的主流GPU也比使用FFT的CPU快得多(比如一个数量级),所以至少可以获得一些加速