Fortran 通过fftw_mpi_r2c_2d和fftw_mpi_c2r_2d的输出不正确

Fortran 通过fftw_mpi_r2c_2d和fftw_mpi_c2r_2d的输出不正确,fortran,mpi,fftw,Fortran,Mpi,Fftw,我编写了一个简单的测试程序,以便在2d域(使用Fortran)中使用MPI实现FFTW。域的宽度为'Ny x Nx',并在第二个('x')索引中进行分区 在正确(我相信?)声明和分配变量和计划后,我调用fftw_mpi r2c_2d函数,然后用fftw_mpi c2r_2d转换其输出,以检查是否得到原始输入。r2c_2d部件似乎工作正常。但是,在使用c2r_2d函数转换回输出(除了归一化)后,我没有得到原始输入:结果向量在索引(:,j)处显示“零”,j对应于“Ny/2”的倍数。我做错了什么?谢谢

我编写了一个简单的测试程序,以便在2d域(使用Fortran)中使用MPI实现FFTW。域的宽度为'Ny x Nx',并在第二个('x')索引中进行分区

在正确(我相信?)声明和分配变量和计划后,我调用fftw_mpi r2c_2d函数,然后用fftw_mpi c2r_2d转换其输出,以检查是否得到原始输入。r2c_2d部件似乎工作正常。但是,在使用c2r_2d函数转换回输出(除了归一化)后,我没有得到原始输入:结果向量在索引(:,j)处显示“零”,j对应于“Ny/2”的倍数。我做错了什么?谢谢

以下是代码摘录:

Program TEST

use, intrinsic :: iso_c_binding

Implicit none

include 'mpif.h'
include 'fftw3-mpi.f03'

Integer*8,parameter :: nx=16, ny=16

!MPI
integer*8 :: ipe,npe
integer*8 ::mpi_realtype,icomm=mpi_comm_world,istat(mpi_status_size),ierr

! FFTW VARIABLES DECLARATION
type(C_PTR)           :: p1, p2, cdatar, cdatac
integer(C_INTPTR_T)   :: alloc_local, local_L, local_L_offset, local_M, local_M_offset
real(C_DOUBLE), pointer :: faux(:,:)   ! real input 2d function
complex(C_DOUBLE), pointer :: gaux(:,:) ! complex output of 2d FFTW (transposed)


! MPI initialization
call mpi_init(ierr)

call mpi_comm_rank(icomm,ipe,ierr)
call mpi_comm_size(icomm,npe,ierr)


! FFTW ALLOCATIONS AND PLANS

call fftw_mpi_init()


alloc_local = fftw_mpi_local_size_2d(ny/2+1,nx &
    ,MPI_COMM_WORLD, local_L, local_L_offset)


cdatac = fftw_alloc_complex(alloc_local)

call c_f_pointer(cdatac, gaux, [nx,local_L]) !transposed

alloc_local = fftw_mpi_local_size_2d(nx,ny/2+1, MPI_COMM_WORLD, &
    local_M, local_M_offset)


cdatar = fftw_alloc_real(2*alloc_local)

call c_f_pointer(cdatar, faux, [ny,local_M])

! Create plans

p1 = fftw_mpi_plan_dft_r2c_2d(nx,ny,faux,gaux, MPI_COMM_WORLD, &
        ior(FFTW_MEASURE, FFTW_MPI_TRANSPOSED_OUT))


p2 = fftw_mpi_plan_dft_c2r_2d(nx,ny,gaux,faux, MPI_COMM_WORLD, &
        ior(FFTW_MEASURE, FFTW_MPI_TRANSPOSED_IN))

! EXECUTE FFTW

call random_number(faux)


print *, "real input:", real(faux(1,:))

call fftw_mpi_execute_dft_r2c(p1,faux,gaux)

call fftw_mpi_execute_dft_c2r(p2, gaux, faux)

print *, "real output:", real(faux(1,:))/(nx*ny)

call fftw_destroy_plan(p1)
call fftw_destroy_plan(p2)


call  mpi_finalize(ierr)


End Program TEST
该问题是由于fftw需要:

虽然实际数据在概念上是n0×n1×n2×…×nd-1,但它在物理上存储为n0×n1×n2×…×[2(nd-1/2+1)]数组,其中最后一个维度已被填充,使其大小与复杂输出相同。这与就地串行r2c/c2r接口非常相似(请参见真实数据的多维DFT),只是在MPI中,即使是异地数据也需要填充

因此,16x16变换的输入数组因此是16x18数组。每行末尾额外两个数字的值在实空间中没有意义。但是,当c指针被转换到fortran 2D数组时,不能忘记这些额外的数字:

call c_f_pointer(cdatar, faux, [2*(ny/2+1),local_M])
额外的数字仍然打印在每行的末尾。可以对数组进行切片,以避免打印这些毫无价值的值:

print *, "real input:", real(faux(1:ny,:))
...
print *, "real output:", real(faux(1:ny,:))/(nx*ny)
这是基于您的完整代码,其中一个可以由
mpif90 main.f90-o main-I/usr/include-L/usr/lib-lfftw3\u mpi-lfftw3-lm
编译,并由
mpirun-np 2 main
运行

Program TEST

use, intrinsic :: iso_c_binding

Implicit none

include 'mpif.h'
include 'fftw3-mpi.f03'

Integer*8,parameter :: nx=4, ny=8

!MPI
integer*8 :: ipe,npe
integer*8 ::mpi_realtype,icomm=mpi_comm_world,istat(mpi_status_size),ierr

! FFTW VARIABLES DECLARATION
type(C_PTR)           :: p1, p2, cdatar, cdatac
integer(C_INTPTR_T)   :: alloc_local, local_L, local_L_offset, local_M, local_M_offset
real(C_DOUBLE), pointer :: faux(:,:)   ! real input 2d function
complex(C_DOUBLE), pointer :: gaux(:,:) ! complex output of 2d FFTW (transposed)


! MPI initialization
call mpi_init(ierr)

call mpi_comm_rank(icomm,ipe,ierr)
call mpi_comm_size(icomm,npe,ierr)


! FFTW ALLOCATIONS AND PLANS

call fftw_mpi_init()


alloc_local = fftw_mpi_local_size_2d(ny/2+1,nx &
    ,MPI_COMM_WORLD, local_L, local_L_offset)


cdatac = fftw_alloc_complex(alloc_local)

call c_f_pointer(cdatac, gaux, [nx,local_L]) !transposed

alloc_local = fftw_mpi_local_size_2d(nx,ny/2+1, MPI_COMM_WORLD, &
    local_M, local_M_offset)


cdatar = fftw_alloc_real(2*alloc_local)

call c_f_pointer(cdatar, faux, [2*(ny/2+1),local_M])

! Create plans

p1 = fftw_mpi_plan_dft_r2c_2d(nx,ny,faux,gaux, MPI_COMM_WORLD, &
        ior(FFTW_MEASURE, FFTW_MPI_TRANSPOSED_OUT))


p2 = fftw_mpi_plan_dft_c2r_2d(nx,ny,gaux,faux, MPI_COMM_WORLD, &
        ior(FFTW_MEASURE, FFTW_MPI_TRANSPOSED_IN))

! EXECUTE FFTW

call random_number(faux)


print *, "real input:", real(faux(1:ny,:))

call fftw_mpi_execute_dft_r2c(p1,faux,gaux)

call fftw_mpi_execute_dft_c2r(p2, gaux, faux)

print *, "real output:", real(faux(1:ny,:))/(nx*ny)

call fftw_destroy_plan(p1)
call fftw_destroy_plan(p2)


call  mpi_finalize(ierr)


End Program TEST

不要使用真实(8)和复杂(8),它是不可移植的。默认情况下,至少有两个编译器会拒绝它。FFTW过程参数声明为实(c_double)和复(c_double),那么为什么不这样做呢?(我不认为这会导致您的错误,它不会。)您是否阅读了关于c2r格式的手册以及为什么只存储了一半的阵列?请不要显示代码的摘录,请显示a。是的,我阅读了手册,我只是复制了一个现有的示例存储了数组。我更新了代码,代码现在是完整的和可验证的,谢谢您的进一步建议