【问题标题】:Losing radial symmetry in solving Poisson equation with FFTW in C在 C 中用 FFTW 求解泊松方程时失去径向对称性
【发布时间】:2018-05-31 10:29:06
【问题描述】:

我有一个关于使用 FFTW 求解泊松方程的问题。我试图解决的方程如下:

问题是我得到了一个不再径向对称的解决方案,特别是从输出图中可以看出,沿轴失去了对称性:

代码如下:

    double dx = 25. / ( N*1. ), dy = 25. / ( N*1. ), dkx = 2*pi/(N*dx), dky = 2*pi/(N*dy);//define steps in real and Fourier space
    double Lx = N*dx, Ly = N*dy, Lkx = N*dkx, Lky = N*dky;//define box sides in real and Fourier space
    int i, j, Nh = N/2 + 1;
    double *inr, *in2r, *in2d;
    fftw_complex *outr;
    fftw_complex *outd;
    fftw_plan rplan_forward;
    fftw_plan dplan_backward;
    fftw_plan rplan_backward;

    for ( i = 0; i < N; i++ ) 
    { 
        x[i] = dx*i - Lx/2.;
        kx[i] = dkx*i - Lkx/2.;
        y[i] = dy*i - Ly/2.;
        ky[i] = dky*i - Lky/2.;
    }

    outd = (fftw_complex*)fftw_malloc ( sizeof ( fftw_complex ) * N * Nh );

    inr = ( double * ) malloc ( sizeof ( double ) * N * N );


    for ( i = 0; i < N; i++ ) //Initialize ine to rho
    {
        for ( j = 0; j < N; j++ )
        {
            inr[i*N+j] = rho[i*N+j] * pow( -1, i + j );                            
        }
    }

    outr = (fftw_complex*)fftw_malloc ( sizeof ( fftw_complex ) * N * Nh );

    rplan_forward = fftw_plan_dft_r2c_2d ( N, N, inr, outr, FFTW_ESTIMATE );

    fftw_execute ( rplan_forward ); //fft rho

    for ( i = 0; i < N; i++ ) //Evaluate d in Fourier Space according to Poisson eq
    {
        for ( j = 0; j < Nh; j++ ) 
        {
            outd[i*Nh+j][0] = g * outr[i*Nh+j][0] / ( kx[i]*kx[i] + ky[j]*ky[j] ); 
            outd[i*Nh+j][1] = g * outr[i*Nh+j][1] / ( kx[i]*kx[i] + ky[j]*ky[j] ); 
        }                      
    }

    outd[Nh*N/2+N/2][0] = 0.; //Avoid singularity at k = 0
    outd[Nh*N/2+N/2][1] = 0.;

    in2d = ( double * ) malloc ( sizeof ( double ) * N * N );

    dplan_backward = fftw_plan_dft_c2r_2d ( N, N, outd, in2d, FFTW_ESTIMATE );

    fftw_execute ( dplan_backward ); //Antitrasform d

    in2r = ( double * ) malloc ( sizeof ( double ) * N * N );

    rplan_backward = fftw_plan_dft_c2r_2d ( N, N, outr, in2r, FFTW_ESTIMATE );

    fftw_execute ( rplan_backward ); //Antitrasform rho

    for( i = 0; i < N; i++ ) 
    {
        for ( j = 0; j < N; j++ ) 
        {
            printf( " %le %le %le \n", x[i], y[j], in2d[i*N+j] * pow( -1, i + j ) / ( N*N*1. ) - in2d[0] / ( N*N*1. ) ); //print d in such a way that it is zero at the boundaries
        }

    }

    fftw_destroy_plan ( rplan_forward );
    fftw_destroy_plan ( dplan_backward );
    fftw_destroy_plan ( rplan_backward );
    fftw_free ( outd );
    fftw_free ( inr );
    fftw_free ( outr ); 
    fftw_free ( in2d ); 
    fftw_free ( in2r); 
    fftw_cleanup();

请注意,我想要一个在边界处归零的解决方案。

你能告诉我问题出在哪里吗?我怀疑这只是一个数字问题,但我不确定。

这是边界的缩放(特别是在 -12.5

【问题讨论】:

  • 在您显示的图像中,数据似乎确实在边界处归零。您能否附上一张图片来说明边界处为零 的含义?
  • 是的,对不起。我添加了放大版。

标签: c fft fftw


【解决方案1】:

径向对称性的丧失与域的形状有关:它是正方形,而不是圆形。此外,由于应用了离散傅里叶变换,研究的问题是使用周期性边界条件的平方域上的泊松方程。因此,边界附近的温度可能不会降至零。

这就是为什么不使用零频率(即源项的平均值)的原因。如果不是这种情况,则无法求解稳态热方程。实际上,由于周期性边界条件,从一侧流出的热通量从另一侧进入。当域完全绝缘时,温度会上升并且永远不会达到稳定的解决方案。

要应用零狄利克雷边界解,必须使用正弦变换之一,而不是傅里叶变换。 例如:

http://www.ds.ewi.tudelft.nl/vakken/in4049TU/sheets/lecture10.pdf

这是一个(我的!)答案,其中包含一段代码,通过 FFTW 的正弦变换求解二维泊松方程,零狄利克雷边界条件。 它是 c++,但将其翻译成 c 很简单。

fftw3 for poisson with dirichlet boundary condition for all side of computational domain

要恢复接近径向对称的东西,源的支撑必须远离域的边缘。如果您知道域、边界条件和源项尊重径向对称性,最好的解决方案可能是切换到一维径向方程。

【讨论】:

    【解决方案2】:

    我认为这里有一个问题:

    outd[Nh*N/2+N/2][0] = 0.; //Avoid singularity at k = 0
    

    k=0 位于 (0,0),而不是 (N/2,N/2)。这就是 DFT 的定义方式。 k 从 0 运行到 N-1您正在空间域中引入相移。我不知道这对您以后的计算有何影响。您正试图通过将输入乘以 pow(-1,i) 来使频谱居中。这个技巧适用于N

    如果正确计算kxky 更好:

    for ( i = 0; i < N; i++ ) {
       kx[i] = ( i > N/2 ? i-N : i ) * 2*pi/N;
    }
    

    这适用于任何N。另请注意,我上面对k 的定义对应于径向频率(ω),而不是DFT 的整数k。我认为它也与您的不同(如果是,那么您的错误!)。

    另一个问题是 DFT 不是 FT。 DFT 是在有界空间域上计算的,该域被假定为周期性的。这个域是一个正方形。在方形网格上很难做旋转对称的事情。与轴相比,沿对角线的奈奎斯特频率(最大可能频率)是sqrt(2) 倍。并且该模式的周期也是沿对角线的sqrt(2) 倍。因此,您会在轴上获得更多锯齿,并且您的图案更有可能沿轴重叠。

    如果上述情况导致了您看到的效果,请尝试增加空间域的大小和/或采样密度。

    【讨论】:

    • 关于 k=0 的事情:我实际上正在研究一个居中的频谱,因为正如 FFTW 手册中所述,我正在这样做:inr[i*N+j] = rho[i*N+j] * pow( -1, i + j ); 这是使频谱居中的技巧。您可能对方形域的事情是正确的,如果有人有其他有趣的答案并考虑一下,我将等待。谢谢!
    • 哦,你在做pow(-1) 的事情。我没有注意到这一点。请注意,这仅适用于 N。对于奇怪的N,您需要使输入变得复杂。在傅立叶域中移动数据或正确计算k 更容易。
    • 无论如何增加采样密度不起作用,而增加框尺寸显然会使边界处的峰值更小,但它不能解决问题,因为它们保持相同的轮廓。我在想outd[i*Nh+j][0] = g * outr[i*Nh+j][0] / ( kx[i]*kx[i] + ky[j]*ky[j] );,当我在边界上并且在轴上时(即分母接近 0),我将一个小量除以另一个非常小的量,因此我可能会失去一些精度。听起来合理吗?
    • @Martino:分母的边缘永远不会小。 kxky 将处于其最大值。
    • @Martino:检查我的编辑,我认为您应该调整 kxky 的定义以使您的代码正确。
    猜你喜欢
    • 1970-01-01
    • 2016-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多