使用FFTW3库评估FORTRAN中高斯函数的快速傅立叶变换

时间:2018-11-23 02:17:57

标签: fortran fft physics fftw

我正在尝试编写一个FORTRAN代码,以使用f(r)=exp(-(r^2))库来评估高斯函数FFTW3的快速傅立叶变换。众所周知,高斯函数的傅立叶变换是另一个高斯函数。

我考虑在球坐标系中评估高斯函数的傅立叶变换积分。

因此,所得积分可以简化为[r*exp(-(r^2))*sin(kr)]dr的积分。

我编写了以下FORTRAN代码,以使用纯实数输入数组评估离散SINE变换DST,即离散傅里叶变换DFT。考虑到位置空间中的离散值是r = i * delta(i = 1,2,...,1024),且输入是C_FFTW_RODFT00中存在的FFTW3执行DST DST的数组是函数r*exp(-(r^2))而不是高斯函数。 [r*exp(-(r^2))*sin(kr)]dr的积分中的正弦函数是通过在球坐标上的积分而产生的,通常进行解析傅立叶变换时,并不是exp(ik.r)的虚部出现。

但是,结果不是动量空间中的高斯函数。

Module FFTW3
 use, intrinsic :: iso_c_binding
include 'fftw3.f03'
end module  

program sine_FFT_transform
use FFTW3
implicit none
integer, parameter :: dp=selected_real_kind(8)

real(kind=dp), parameter :: pi=acos(-1.0_dp)
integer, parameter :: n=1024 
real(kind=dp) :: delta, k
real(kind=dp) :: numerical_F_transform
integer :: i
type(C_PTR) ::  my_plan
real(C_DOUBLE), dimension(1024) :: y
real(C_DOUBLE), dimension(1024) :: yy, yk
integer(C_FFTW_R2R_KIND) :: C_FFTW_RODFT00

my_plan= fftw_plan_r2r_1d(1024,y,yy,FFTW_FORWARD, FFTW_ESTIMATE)

delta=0.0125_dp
do i=1, n        !inserting the input one-dimension position function
y(i)= 2*(delta)*(i-1)*exp(-((i-1)*delta)**2) 
! I multiplied by 2 due to the definition of C_FFTW_RODFT00 in FFTW3
end do

call fftw_execute_r2r(my_plan, y,yy)   
do i=2, n
k = (i-1)*pi/n/delta 
yk(i) = 4*pi*delta*yy(i)/2  !I divide by 2 due to the definition of 
                            !C_FFTW_RODFT00
numerical_F_transform=yk(i)/k
write(11,*) i,k,numerical_F_transform
end do
call fftw_destroy_plan(my_plan)

end program 

执行前面的代码将给出以下图表,该图表不适用于高斯函数。 enter image description here 谁能帮助我了解问题所在?我想这个问题主要是由于FFTW3造成的。也许我没有正确使用它,尤其是在边界条件方面。

2 个答案:

答案 0 :(得分:5)

查看FFTW站点中的相关页面(Real-to-Real Transformstransform kindsReal-odd DFT (DST))和Fortran的头文件,似乎FFTW希望使用FFTW_RODFT00等比FFTW_FORWARD来指定 真实转换。例如,

! my_plan= fftw_plan_r2r_1d( n, y, yy, FFTW_FORWARD, FFTW_ESTIMATE )
my_plan= fftw_plan_r2r_1d( n, y, yy, FFTW_RODFT00, FFTW_ESTIMATE )

执行上一页中显示的“ I型”离散正弦变换(DST-I)。这种修改似乎可以解决该问题(即使傅立叶变换为具有正值的高斯)。


以下是OP的代码的稍作修改的版本,以尝试上述修改:

! ... only the modified part is shown...
real(dp) :: delta, k, r, fftw, num, ana
integer :: i, j, n
type(C_PTR) ::  my_plan
real(C_DOUBLE), allocatable :: y(:), yy(:)

delta = 0.0125_dp ; n = 1024   ! rmax = 12.8
! delta = 0.1_dp    ; n = 128    ! rmax = 12.8
! delta = 0.2_dp    ; n = 64    ! rmax = 12.8
! delta = 0.4_dp    ; n = 32    ! rmax = 12.8

allocate( y( n ), yy( n ) )

! my_plan= fftw_plan_r2r_1d( n, y, yy, FFTW_FORWARD, FFTW_ESTIMATE )
my_plan= fftw_plan_r2r_1d( n, y, yy, FFTW_RODFT00, FFTW_ESTIMATE )

! Loop over r-grid
do i = 1, n
    r = i * delta              ! (2-a)
    y( i )= r * exp( -r**2 )
end do

call fftw_execute_r2r( my_plan, y, yy )

! Loop over k-grid
do i = 1, n

    ! Result of FFTW
    k = i * pi / ((n + 1) * delta)    ! (2-b)
    fftw = 4 * pi * delta * yy( i ) / k / 2   ! the last 2 due to RODFT00

    ! Numerical result via quadrature
    num = 0
    do j = 1, n
        r = j * delta
        num = num + r * exp( -r**2 ) * sin( k * r )
    enddo
    num = num * 4 * pi * delta / k

    ! Analytical result
    ana = sqrt( pi )**3 * exp( -k**2 / 4 )

    ! Output
    write(10,*) k, fftw
    write(20,*) k, num
    write(30,*) k, ana
end do

编译(使用gfortran-8.2 + FFTW3.3.8 + OSX10.11):

$ gfortran -fcheck=all -Wall sine.f90 -I/usr/local/Cellar/fftw/3.3.8/include -L/usr/local/Cellar/fftw/3.3.8/lib -lfftw3

如果我们在原始代码中使用FFTW_FORWARD,则会得到

orig.png

具有一个负波瓣(其中要塞10,要塞20和要塞30对应于FFTW,正交和分析结果)。修改代码以使用FFTW_RODFT00会更改结果,如下所示,因此修改似乎可行(但请参见下面的网格定义)。

new.png


附加说明

  • 我在我的代码(第(2-a)行和(2-b)行)中略微修改了r和k的网格定义,发现这样做可以提高精度。但是我仍然不确定上述定义是否与FFTW使用的定义匹配,因此请阅读手册以了解详细信息...
  • fftw3.f03头文件提供了fftw_plan_r2r_1d的接口

    type(C_PTR) function fftw_plan_r2r_1d(n,in,out,kind,flags) bind(C, name='fftw_plan_r2r_1d')
      import
      integer(C_INT), value :: n
      real(C_DOUBLE), dimension(*), intent(out) :: in
      real(C_DOUBLE), dimension(*), intent(out) :: out
      integer(C_FFTW_R2R_KIND), value :: kind
      integer(C_INT), value :: flags
    end function fftw_plan_r2r_1d
    
  • (由于不支持Tex,这部分非常难看...)r = 0->无限的4 pi r^2 * exp(-r^2) * sin(kr)/(kr)的积分是pi^(3/2) * exp(-k^2 / 4)(从{{3}获得) }或通过注意到这实际上是exp(-(x ^ 2 + y ^ 2 + z ^ 2))由exp(-i *(k1 x + k2 y + k3 z))进行的3-D傅立叶变换, k =(k1,k2,k3))。因此,尽管有点违反直觉,但结果仍为正高斯。

  • 我猜想r-grid可以选择得更粗糙(例如delta最高为0.4),只要覆盖转换函数的频域(此处为{{1} })。

答案 1 :(得分:2)

当然,有限的高斯频谱的FFT的实数部分为负。您只是在使用转换的真实部分。所以你的情节是绝对正确的。

您似乎误解了幅度的真实部分,这当然不是负面的。为此,您需要fftw_plan_dft_r2c_1d,然后计算复数系数的绝对值。否则您可能会误用有限的DFT进行傅立叶变换。

您可能要在此处进行检查,以使自己确信上述计算的正确性:

http://docs.mantidproject.org/nightly/algorithms/FFT-v1.html

请记住,上一页的图已移动,因此0频率位于频谱的中间。

自言自语,[r*exp(-(r^2))*sin(kr)]dr的数字积分如果将最高频率归一化为0,则会对所有k>1产生负分量。

TLDR:您的绘图是绝对最新的,并且是离散的和有限的功能分析的内联线。