C++ 用龙格库塔积分波动方程(二阶)

C++ 用龙格库塔积分波动方程(二阶),c++,numerical-integration,runge-kutta,C++,Numerical Integration,Runge Kutta,我尝试求解数值上简单的方程——无震源的线性波动方程:utt=v2 uxx 式中v——波的速度 我使用初始条件: u(x,0)=sin(x) ux(x,0)=-v*sin(x) 对应于沿x轴以v速度传播的初始波sin(x)(sin(x-vt)是该波动方程的解) 所以,问题是,在2-3次迭代期间,数值解与解析解(sin(x-vt))一致,但在第3次迭代之后,出现了一些错误,解增长得非常快(取值约为128) 我使用Runge-Kutta二阶oreder方法(Euler方法)和二阶导数的四阶近似 下面是

我尝试求解数值上简单的方程——无震源的线性波动方程:utt=v2 uxx

式中v——波的速度

我使用初始条件:

u(x,0)=sin(x)
ux(x,0)=-v*sin(x)

对应于沿x轴以v速度传播的初始波sin(x)(sin(x-vt)是该波动方程的解)

所以,问题是,在2-3次迭代期间,数值解与解析解(sin(x-vt))一致,但在第3次迭代之后,出现了一些错误,解增长得非常快(取值约为128)

我使用Runge-Kutta二阶oreder方法(Euler方法)和二阶导数的四阶近似

下面是C++上的一段代码:

//2nd derivative function

float z2der(int n, int i, int j, float* x, float** zx)
{
    float h = x[2] - x[1];
    float zr, zl, zm, zrr, zll;

    zm = -30.0 * zx[i][j];
    if (i < n - 1)
        zr = 16.0 * zx[i + 1][j];
    else
        zr = 16.0;
    if (i > 0)
        zl = 16.0 * zx[i - 1][j];
    else
        zl = 16.0;
    if (i < n - 2)
        zrr = -zx[i + 2][j];
    else
        zrr = 1.0; //CHECK
    if (i > 1)
        zll = -zx[i - 2][j];

    if (i > 1 && i < n - 2)
        return (zll + zrr + zl + zr + zm) / (12.0 * h * h);
    if (i == 1)
        return (15 / 4 * zx[i][j] - 77 / 6 * zx[i + 1][j] - 107 / 6 * zx[i + 2][j] - 13 * zx[i + 3][j] - 61 / 12 * zx[i + 4][j]) / (h*h);
    if (i == n - 2)
        return (15 / 4 * zx[i][j] - 77 / 6 * zx[i - 1][j] - 107 / 6 * zx[i - 2][j] - 13 * zx[i - 3][j] - 61 / 12 * zx[i - 4][j]) / (h*h);
    if (i == 0 || i == n - 1)
        return 0;
}


//PARAMETERS

float tmin = 0.0;
float tmax = 12.0;
int nt = 37000;
float dt = (tmax - tmin) / float(nt);
float *time = new float[nt];
for (int j = 0; j < nt; j++)
    time[j] = tmin + dt * float(j);

float xmin = -30.0;
float xmax = 30.0;
int nx = 901;
float *x = new float[nx];
for (int i = 0; i < nx; i++)
    x[i] = xmin + (xmax - xmin) * float(i) / float(nx);

float v = -0.1; // velocity

float** wave = new float*[nx];
for (int i = 0; i < nx; i++)
    wave[i] = new float[nt];

float** waved = new float*[nx];
for (int i = 0; i < nx; i++)
    waved[i] = new float[nt];

for (int i = 0; i < nx; i++)
{
    xx = x[i];
    wave[i][0] = sin(xx);
    waved[i][0] = -v * v * sin(xx);
}

float* wavedd = new float[nx];
float* waveddot = new float[nx];

for (int i = 0; i < nx; i++) //j=0;
{
    wavedd[i] = z2der(nx, i, 0, x, wave);
    waveddot[i] = v * v * wavedd[i];
}

for (int j = 0; j < nt - 1; j++)
{
    for (int i = 0; i < nx; i++)
    {
        waved[i][j + 1] = waved[i][j] + dt * waveddot[i];
        wave[i][j + 1] = wave[i][j] + dt * waved[i][j];

        wavedd[i] = z2der(nx, i, j + 1, x, wave);
        waveddot[i] = v * v * wavedd[i];
    }
}
//二阶导数函数
浮点z2der(整数n,整数i,整数j,浮点*x,浮点**zx)
{
浮点数h=x[2]-x[1];
浮动zr,zl,zm,zrr,zll;
zm=-30.0*zx[i][j];
如果(i0)
zl=16.0*zx[i-1][j];
其他的
zl=16.0;
如果(i1)
zll=-zx[i-2][j];
如果(i>1&&i

所以,我不知道为什么会出错,原因是什么。

所有RK表的值都会有问题,因为您正在进行整数除法

return (15 / 4 * ...
由于运算符优先级,这将计算为

return (3 * ...
您需要完全在
double

return (15.0 / 4.0 * ...

数字代码的调试与普通代码非常相似。它适用于更简单的输入吗?如果f(x)=0已经失败,不要尝试正弦。另外,如果你能在一个函数中定位错误,就不要发布两个函数。你的
z2der
函数真的给了你二阶导数吗?好的,我忽略了这个,谢谢。现在我修复了它,但它仍然工作错误(几乎和以前一样)。