Cuda cufft fftw复杂到真实转换中的周期性差异问题
在我的论文中,我必须使用CUDA优化一个特殊的MPI Navier-Stokes解算器程序。原始程序使用FFTW求解多个偏微分方程。详细地说,几个上三角矩阵在二维中进行傅里叶变换,但作为一维数组处理。目前,我正在处理部分原始代码:(N始终设置为64) 原件: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
//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
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;
}