Cuda cufft fftw复杂到真实转换中的周期性差异问题

Cuda cufft fftw复杂到真实转换中的周期性差异问题,cuda,fft,c99,fftw,Cuda,Fft,C99,Fftw,在我的论文中,我必须使用CUDA优化一个特殊的MPI Navier-Stokes解算器程序。原始程序使用FFTW求解多个偏微分方程。详细地说,几个上三角矩阵在二维中进行傅里叶变换,但作为一维数组处理。目前,我正在处理部分原始代码:(N始终设置为64) 原件: //Does the complex to real in place fft an normalizes void fftC2R(double complex *arr) { fftw_execute_dft_c2r(plan_c2r

在我的论文中,我必须使用CUDA优化一个特殊的MPI Navier-Stokes解算器程序。原始程序使用FFTW求解多个偏微分方程。详细地说,几个上三角矩阵在二维中进行傅里叶变换,但作为一维数组处理。目前,我正在处理部分原始代码:(N始终设置为64)

原件:

//Does the complex to real in place fft an normalizes
void fftC2R(double complex *arr) {
  fftw_execute_dft_c2r(plan_c2r, (fftw_complex*)arr, (double*)arr);
  //Currently ignored: Normalization
  /*  for(int i=0; i<N*(N/2+1); i++)
arr[i] /= (double complex)sqrt((double complex)(N*N));*/
}

void doTimeStepETDRK2_nonlin_original() {
      //calc velocity
      ux[0] = 0;
      uy[0] = 0;

      for(int i=1; i<N*(N/2+1); i++) {
         ux[i] =  I*kvec[1][i]*qvec[i] / kvec[2][i];
         uy[i] = -I*kvec[0][i]*qvec[i] / kvec[2][i];
      }

      fftC2R(ux);
      fftC2R(uy);

      //do some stuff here...
      //...
      return;
}
fft计划创建为:

plan_c2r = fftw_plan_dft_c2r_2d(N, N,(fftw_complex*) qvec, (double*)qvec, FFTW_ESTIMATE);
其中,qvec的分配方式与ux和uy相同,且数据类型为双复数


以下是CUDA代码的相关部分:

NN2_VecSetZero_and_init<<<block_size,grid_size>>>();
cudaSafeCall(cudaDeviceSynchronize());
cudaSafeCall(cudaGetLastError());

int err = (int)cufftExecZ2D(cu_plan_c2r,(cufftDoubleComplex*)sym_ux,(cufftDoubleReal*)sym_ux);

if (err != CUFFT_SUCCESS ) {
    exit(EXIT_FAILURE);
    return;
}

err = (int)cufftExecZ2D(cu_plan_c2r,(cufftDoubleComplex*)sym_uy,(cufftDoubleReal*)sym_uy);

if (err != CUFFT_SUCCESS ) {
    exit(EXIT_FAILURE);
    return;
}

//do some stuff here...
//...
return;
相关cufft部件的初始化如下所示

if (cufftPlan2d(&cu_plan_c2r,N,N, CUFFT_Z2D) != CUFFT_SUCCESS){
    exit(EXIT_FAILURE);
    return -1;
}

if (cufftPlan2d(&cu_plan_r2c,N,N, CUFFT_D2Z)  != CUFFT_SUCCESS){
    exit(EXIT_FAILURE);
    return -1;
}

if ( cufftSetCompatibilityMode ( cu_plan_c2r , CUFFT_COMPATIBILITY_FFTW_ALL) != CUFFT_SUCCESS ) {
    exit(EXIT_FAILURE);
    return -1;
}

if ( cufftSetCompatibilityMode ( cu_plan_r2c , CUFFT_COMPATIBILITY_FFTW_ALL) != CUFFT_SUCCESS ) {
    exit(EXIT_FAILURE);
    return -1;
}

所以我使用完全的FFTW兼容性,并使用FFTW调用模式调用每个函数。 当我运行这两个版本时,我收到的ux和uy结果几乎相同(sim_ux和sim_uy)。但在阵列的周期性位置,Cufft似乎忽略了这些元素,其中FFTW将这些元素的实部设置为零,并计算复杂部分(阵列太大,此处无法显示它们)。发生这种情况的步数为N/2+1。所以我相信,我并没有完全理解Cufft和FFTW之间的fft填充理论。 在调用Cufft执行之前,我可以排除这些数组之间以前的任何差异。因此,上述代码的任何其他数组在这里都不相关。
我的问题是:我是否过于乐观地使用几乎100%的FFTW通话风格?我必须在FFT之前处理数组吗?Cufft文档说,我必须调整数据输入和输出数组的大小。但是,当我在原地运行转换时,我该怎么做呢?我真的不想离原始代码太远,我也不想在每次fft调用中使用更多的复制指令,因为内存有限,数组应该尽可能长时间地保留在gpu上处理

我感谢每一个暗示、批评的陈述或想法

我的配置:

  • 编译器:gcc 4.6(C99标准)
  • MPI包:mvapich2-1.5.1p1(由于减少了单处理调试模式,因此不应发挥作用)
  • CUDA版本:4.2
  • GPU:CUDA-arch-COMPUTE20(NVIDIA GeForce GTX 570)
  • FFTW 3.3

一旦我不得不使用CUFFT,我唯一能使用的解决方案就是独家使用“cu_plan_c2c”-真实阵列和复杂阵列之间的转换非常简单:

ux = (double complex*)fftw_malloc(N*(N/2+1) * sizeof(double complex));
uy = (double complex*)fftw_malloc(N*(N/2+1) * sizeof(double complex));
-用0填充复杂零件以模拟cu_plan_r2c

-在复杂结果上使用atan2(而不是atan)来模拟cu_plan_c2r


很抱歉没有给你指出更好的解决方案,但我就是这样解决这个问题的。希望您没有陷入任何cpu内存不足的硬磁盘中……

谢谢!我已经试过了。对于这个特殊问题,我发现,这些填充位置对我的进一步最终结果没有影响,因为在计算最终输出之前,每个FFT都会进行反向运算。但在使用cufftPlanMany进行批处理的就地C2R FFT时,我又面临了一个非常类似的问题。在这里,cufft似乎有一些问题需要认识,我想在适当的地方使用它,并由于填充而造成奇怪的内存损坏。我将再次检查你解决这个问题的方法。据我记忆所及,这是我批量计算的解决方法-因此这可能会有所帮助。
if (cufftPlan2d(&cu_plan_c2r,N,N, CUFFT_Z2D) != CUFFT_SUCCESS){
    exit(EXIT_FAILURE);
    return -1;
}

if (cufftPlan2d(&cu_plan_r2c,N,N, CUFFT_D2Z)  != CUFFT_SUCCESS){
    exit(EXIT_FAILURE);
    return -1;
}

if ( cufftSetCompatibilityMode ( cu_plan_c2r , CUFFT_COMPATIBILITY_FFTW_ALL) != CUFFT_SUCCESS ) {
    exit(EXIT_FAILURE);
    return -1;
}

if ( cufftSetCompatibilityMode ( cu_plan_r2c , CUFFT_COMPATIBILITY_FFTW_ALL) != CUFFT_SUCCESS ) {
    exit(EXIT_FAILURE);
    return -1;
}