草庐IT

c++ - 数值不稳定性 FFTW <> Matlab

coder 2023-11-15 原文

我正在尝试用数值方法求解 Swift-Hohenberg 方程 http://en.wikipedia.org/wiki/Swift%E2%80%93Hohenberg_equation使用伪谱方案,其中线性项在傅立叶空间中隐式处理,而非线性在实空间中评估。一个简单的欧拉方案用于时间积分。
我的问题是,我提出的 Matlab 代码可以完美运行,而依赖 FFTW 进行傅立叶变换的 C++ 代码在几千个时间步后变得不稳定并发散。我已经追踪到处理非线性项的方式(请参阅 C++ 代码中的注释)。如果我只使用 Phi 的实部,就会发生不稳定。然而,由于数值舍入误差,Phi 应该只有一个可以忽略不计的虚部,而 Matlab 正在做类似的事情,使 Phi 保持纯实数。 Matlab 代码在 Octave 下也运行良好。初始条件可以是这样的
R=0.02*(rand(256,256)-0.5);
在 Matlab 中(小幅度波动)。

长篇小说;

为什么这些代码片段做不同的事情?具体来说,我怎样才能使 C++ 代码以与 Matlab 版本相同的方式工作?

编辑 1:

为了完整起见,我使用 FFTW 提供的 R2C/C2R 函数添加了代码。参见 http://fftw.org/fftw3_doc/Multi_002dDimensional-DFTs-of-Real-Data.html有关详细信息(我希望我的数据布局正确)。此代码始终显示大约 3100 个时间步后的不稳定性。如果我将 dt 减少到例如0.01,10次后出现。

使用复杂 DFT 的 C++ 代码

#include <iostream>
#include <fstream>
#include <cmath>
#include <fftw3.h>

int main() {

const int N=256, nSteps=10000;
const double k=2.0*M_PI/N, dt=0.1, eps=0.25;

double *Buf=(double*)fftw_malloc(N*N*sizeof(double));
double *D0=(double*)fftw_malloc(N*N*sizeof(double));

// complex arrays
fftw_complex *Phi=(fftw_complex*)fftw_malloc(N*N*sizeof(fftw_complex));
fftw_complex *PhiF=(fftw_complex*)fftw_malloc(N*N*sizeof(fftw_complex));
fftw_complex *NPhiF=(fftw_complex*)fftw_malloc(N*N*sizeof(fftw_complex));

// plans for Fourier transforms
fftw_plan phiPlan=fftw_plan_dft_2d(N, N, Phi, PhiF, FFTW_FORWARD, FFTW_ESTIMATE);
fftw_plan nPhiPlan=fftw_plan_dft_2d(N, N, NPhiF, NPhiF, FFTW_FORWARD, FFTW_ESTIMATE);
fftw_plan phiInvPlan=fftw_plan_dft_2d(N, N, Phi, Phi, FFTW_BACKWARD, FFTW_ESTIMATE);

std::ifstream fin("R.dat", std::ios::in | std::ios::binary); // read initial condition
fin.read(reinterpret_cast<char*>(Buf), N*N*sizeof(double));
fin.close();
for(int i=0; i<N*N; i++) {
    Phi[i][0]=Buf[i];   //initial condition
    Phi[i][1]=0.0;  //no imaginary part
}

fftw_execute(phiPlan);  //PhiF contains FT of initial condition

for(int j=0; j<N; j++) {
    for(int i=0; i<N; i++) {

        double kx=(i-(i/(N-N/2)*N))*k;
        double ky=(j-(j/(N-N/2)*N))*k;
        double k2=kx*kx+ky*ky;

        D0[j*N+i]=1.0/((1.0 - dt*(eps-1.0 + 2.0*k2 - k2*k2)));  // array of prefactors
    }
}   

const double norm=1.0/(N*N);

for(int n=0; n<=nSteps; n++) {

    if(n%100==0) {
        std::cout<<"n = "<<n<<'\n';
    }

    for(int j=0; j<N*N; j++) {
        // nonlinear term Phi^3
        //NPhiF[j][0]=Phi[j][0]*Phi[j][0]*Phi[j][0]; // unstable
        //NPhiF[j][1]=0.0;
            NPhiF[j][0]=Phi[j][0]*Phi[j][0]*Phi[j][0] - 3.0*Phi[j][0]*Phi[j][1]*Phi[j][1];
            NPhiF[j][1]=-Phi[j][1]*Phi[j][1]*Phi[j][1] + 3.0*Phi[j][0]*Phi[j][0]*Phi[j][1];
    }

    fftw_execute(nPhiPlan); // NPhiF contains FT of Phi^3

    for(int j=0; j<N*N; j++) {
        PhiF[j][0]=(PhiF[j][0] - dt*NPhiF[j][0])*D0[j]; // update
        PhiF[j][1]=(PhiF[j][1] - dt*NPhiF[j][1])*D0[j];

        Phi[j][0]=PhiF[j][0]*norm; // FFTW does not normalize
        Phi[j][1]=PhiF[j][1]*norm;
    }

    fftw_execute(phiInvPlan); // Phi contains the updated Phi in real space
}

for(int i=0; i<N*N; i++) {
    Buf[i]=Phi[i][0];   // saving the real part of Phi
}
std::ofstream fout("Phi.dat", std::ios::trunc | std::ios::binary);
fout.write(reinterpret_cast<char*>(Buf), N*N*sizeof(double));
fout.close();

for(int i=0; i<N*N; i++) {
    Buf[i]=Phi[i][1];   // saving the imag part of Phi
}
fout.open("PhiImag.dat", std::ios::trunc | std::ios::binary);
fout.write(reinterpret_cast<char*>(Buf), N*N*sizeof(double));
fout.close();


fftw_free(D0);
fftw_free(Buf);

fftw_free(Phi);
fftw_free(PhiF);
fftw_free(NPhiF);

fftw_destroy_plan(phiPlan);
fftw_destroy_plan(phiInvPlan);
fftw_destroy_plan(nPhiPlan);

return EXIT_SUCCESS;
}

使用 R2C/C2R 的 C++ 代码


#include <iostream>
#include <fstream>
#include <cmath>
#include <fftw3.h>

int main() {

const int N=256, nSteps=3100;
const int w=N/2+1;
const double k=2.0*M_PI/N, dt=0.1, eps=0.25;

double *Buf=(double*)fftw_malloc(N*N*sizeof(double));
double *D0=(double*)fftw_malloc(N*w*sizeof(double));

fftw_complex *Phi=(fftw_complex*)fftw_malloc(N*w*sizeof(fftw_complex));
fftw_complex *PhiF=(fftw_complex*)fftw_malloc(N*w*sizeof(fftw_complex));
fftw_complex *NPhi=(fftw_complex*)fftw_malloc(N*w*sizeof(fftw_complex));

fftw_plan phiPlan=fftw_plan_dft_r2c_2d(N, N, (double*)PhiF, PhiF, FFTW_ESTIMATE);
fftw_plan nPhiPlan=fftw_plan_dft_r2c_2d(N, N, (double*)NPhi, NPhi, FFTW_ESTIMATE);
fftw_plan phiInvPlan=fftw_plan_dft_c2r_2d(N, N, Phi, (double*)Phi, FFTW_ESTIMATE);

std::ifstream fin("R.dat", std::ios::in | std::ios::binary);
fin.read(reinterpret_cast<char*>(Buf), N*N*sizeof(double));
fin.close();
for(int j=0; j<N; j++) {
    for(int i=0; i<N; i++) {
        ((double*)PhiF)[j*2*w+i]=Buf[j*N+i];
        ((double*)Phi)[j*2*w+i]=Buf[j*N+i];
    }
}

fftw_execute(phiPlan); //PhiF contains FT of IC

for(int j=0; j<N; j++) {
    for(int i=0; i<w; i++) {

        double kx=(i-(i/(N-N/2)*N))*k;
        double ky=(j-(j/(N-N/2)*N))*k;
        double k2=kx*kx+ky*ky;

        D0[j*w+i]=1.0/(1.0 - dt*(eps-1.0 + 2.0*k2 - k2*k2));
    }
}

const double norm=1.0/(N*N);

//begin first Euler step
for(int n=0; n<=nSteps; n++) {

    if(n%100==0) {
        std::cout<<"n = "<<n<<'\n';
    }

    for(int j=0; j<N; j++) {
        for(int i=0; i<N; i++) {
            ((double*)NPhi)[j*2*w+i]=((double*)Phi)[j*2*w+i]  *((double*)Phi)[j*2*w+i]  * ((double*)Phi)[j*2*w+i];
        }
    }

    fftw_execute(nPhiPlan); // NPhi contains FT of Phi^3

    for(int j=0; j<N*w; j++) {
        PhiF[j][0]=(PhiF[j][0] - dt*NPhi[j][0])*D0[j];
        PhiF[j][1]=(PhiF[j][1] - dt*NPhi[j][1])*D0[j];
    }

    for(int j=0; j<N*w; j++) {
        Phi[j][0]=PhiF[j][0]*norm;
        Phi[j][1]=PhiF[j][1]*norm;
    }

    fftw_execute(phiInvPlan);

}

for(int j=0; j<N; j++) {
    for(int i=0; i<N; i++) {
        Buf[j*N+i]=((double*)Phi)[j*2*w+i];
    }
}

std::ofstream fout("Phi.dat", std::ios::trunc | std::ios::binary);
fout.write(reinterpret_cast<char*>(Buf), N*N*sizeof(double));
fout.close();

fftw_destroy_plan(phiPlan);
fftw_destroy_plan(phiInvPlan);
fftw_destroy_plan(nPhiPlan);

fftw_free(D0);
fftw_free(Buf);
fftw_free(Phi);
fftw_free(PhiF);
fftw_free(NPhi);
}

Matlab代码

function Phi=SwiHoEuler(Phi, nSteps)
epsi=0.25;
dt=0.1;

[nR nC]=size(Phi);
if mod(nR, 2)==0
    kR=[0:nR/2-1 -nR/2:-1]*2*pi/nR;
else
    kR=[0:nR/2 -floor(nR/2):-1]*2*pi/nR;
end
Ky=repmat(kR.', 1, nC);

if mod(nC, 2)==0
    kC=[0:nC/2-1 -nC/2:-1]*2*pi/nC;
else
    kC=[0:nC/2 -floor(nC/2):-1]*2*pi/nC;
end
Kx=repmat(kC, nR, 1); % frequencies
K2=Kx.^2+Ky.^2; % used for Laplacian in Fourier space
D0=1.0./(1.0-dt*(epsi-1.0+2.0*K2-K2.*K2)); % linear factors combined

PhiF=fft2(Phi);

for n=0:nSteps
    NPhiF=fft2(Phi.^3); % nonlinear term, evaluated in real space
    if mod(n, 100)==0
        fprintf('n = %i\n', n);
    end
    PhiF=(PhiF - dt*NPhiF).*D0; % update

    Phi=ifft2(PhiF); % inverse transform
end
return

最佳答案

看看这些行:

for ...
  double kx=(i-(i/(N-N/2)*N))*k;
  double ky=(j-(j/(N-N/2)*N))*k;
  double k2=kx*kx+ky*ky;
...

我不得不承认我没有研究算法,但“i/(N-N/2)”由整数组成,我怀疑你的 kx、ky 和 ​​k2 是按预期计算的。您可以尝试这样的方法来避免潜在的整数舍入错误:

for ...
  double kx=( double(i) -( double(i)/(0.5*double(N*N)))*k; // where in our case: (N-N/2)*N) = 0.5*N*N
  ...
...

关于c++ - 数值不稳定性 FFTW <> Matlab,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6847708/

有关c++ - 数值不稳定性 FFTW <> Matlab的更多相关文章

  1. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  2. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  3. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  4. ruby-on-rails - rspec should have_select ('cars' , :options => ['volvo' , 'saab' ] 不工作 - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request

  5. ruby-on-rails - Nokogiri:使用 XPath 搜索 <div> - 2

    我使用Nokogiri(Rubygem)css搜索寻找某些在我的html里面。看起来Nokogiri的css搜索不喜欢正则表达式。我想切换到Nokogiri的xpath搜索,因为这似乎支持搜索字符串中的正则表达式。如何在xpath搜索中实现下面提到的(伪)css搜索?require'rubygems'require'nokogiri'value=Nokogiri::HTML.parse(ABBlaCD3"HTML_END#my_blockisgivenmy_bl="1"#my_eqcorrespondstothisregexmy_eq="\/[0-9]+\/"#FIXMEThefoll

  6. Matlab imread()读到了什么 (浅显 当复习文档了) - 2

    matlab打开matlab,用最简单的imread方法读取一个图像clcclearimg_h=imread('hua.jpg');返回一个数组(矩阵),往往是a*b*cunit8类型解释一下这个三维数组的意思,行数、数和层数,unit8:指数据类型,无符号八位整形,可理解为0~2^8的数三个层数分别代表RGB三个通道图像rgb最常用的是24-位实现方法,即RGB每个通道有256色阶(2^8)。基于这样的24-位RGB模型的色彩空间可以表现256×256×256≈1670万色当imshow传入了一个二维数组,它将以灰度方式绘制;可以把图像拆分为rgb三层,可以以灰度的方式观察它figure(1

  7. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  8. MIMO-OFDM无线通信技术及MATLAB实现(1)无线信道:传播和衰落 - 2

     MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO

  9. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  10. ruby-on-rails - 没有参数的 `<<`(小于两倍)是什么意思? - 2

    我在一个我想在formtasticGem中覆盖的方法中找到了这个。该方法如下所示:defto_htmlinput_wrappingdohidden_field_html是什么意思?在第三行做什么?我知道它对数组有什么作用,但在这里我不知道。 最佳答案 你可以这样读:hidden_field_htmllabel_with_nested_checkbox是连接到hidden_​​field_html末尾的参数-为了“清晰”,他们将其分成两行 关于ruby-on-rails-没有参数的`

随机推荐