用于Lorenz系统的Runge Kutta 4用C ++编写

时间:2016-12-12 13:26:32

标签: c++ numerical-methods differential-equations runge-kutta

有人可以在我的代码中找到错误吗?它在特殊点中工作正常,但公差不适合该方法。我的Errorstepper很简单,所以我不认为它的问题。请帮忙。

#include <math.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <conio.h> 
#include <time.h> 
#include <iostream>
#include <string>
using namespace std;
const int q=10;
const double b=8/3;
double r;
double x,y,z;
struct delta
{
    double dx;
    double dy;
    double dz;
};

 double f1(double x , double y)
{
    return (q*(y-x));
}
double f2(double x,double y, double z)
{
    return ((-x)*z+r*x-y);
}
double f3(double x,double y,double z)
{
    return (x*y- b*z);
}
    delta calc(double x,double y,double z,double dh=0.1)
{
    double k1,k2,k3,k4,m1,m2,m3,m4,p1,p2,p3,p4,dx,dy,dz,a,b,c,h;

    h=dh;
    k1=h*f1(x,y);
    m1=h*f2(x,y,z);
    p1=h*f3(x,y,z);

    //h+=dh/2;
    k2=h*f1((x+k1/2.),(y+m1/2.));
    m2=h*f2((x+k1/2.) ,(y+m1/2.),(z+p1/2.));
    p2=h*f3((x+k1/2.),(y+m1/2.),(z+p1/2.));

//  h+=dh/2;
    k3=h*f1((x+k2/2.),(y+m2/2.));
    m3=h*f2((x+k2/2.),(y+m2/2.),(z+p2/2.));
    p3=h*f3((x+k2/2.),(y+m2/2.),(z+p2/2.));

//  h+=dh;
    k4=h*f1((x+k3),(y+m3));
    m4=h*f2((x+k3),(y+m3),(z+p3));
    p4=h*f3((x+k3),(y+m3),(z+p3));

    dx=(k1+2*k2+2*k3+k4)/6.;
    dy=(m1+2*m2+2*m3+m4)/6.;
    dz=(p1+2*p2+2*p3+p4)/6.;

    a=x+dx;
    b=y+dy;
    c=z+dz;
    delta add;

    add.dx=a;
    add.dy=b;
    add.dz=c;

    return add;

}
double Error(double x,double y ,double z, double h)
{
    double xi,e,a,b,c;
    delta end1=calc(x,y,z,h);
    xi=end1.dx;
    end1=calc(x,y,z,h/2);
    a=end1.dx;
    b=end1.dy;
    c=end1.dz;
    end1=calc(a,b,c,h/2);
    e=fabs((xi-end1.dx)/15);
    return e;

}
int main ()
{


    double dx,dy,dz,h,ei,xi,zi,yi,e,t=0,T=0.08,a,b,c,k=0,E,h1,e1,m,E1;
    int n=0;
    FILE *fff; 
    fff=fopen("data.txt","w"); 
    cout <<"x0=";
    cin>>x;
    cout<<"y0=";
    cin>>y;
    cout<<"z0=";
    cin>>z;
    cout<<"h=";
    cin>>h;
    cout<<"r=";
    cin>>r;
    cout<<"Time=";
    cin>>T;
    cout<<"Toleranse=";
    cin>>E;
    xi=x;
    double hmin=0.00005;
    if (E<=0.0000001) 
    hmin=hmin/100;
    else cout<<"ok"<<endl;

    E1=E/10;
do
    {


     e=Error(x,y,z,h);


while (e<E1 || e>E)
    {   
    if (e<E1)
        h+=hmin;
    else if (e>E)
        h-=hmin;
    else cout<<" ok"<<endl;
     e=Error(x,y,z,h);

    };/*
    while(e>E)
    {
    h=h/2;
     e=Error(x,y,z,h);
    };*/
    xi=x;
    yi=y;
    zi=z;
    ei=e;

    delta konec1=calc(x,y,z,h);

    x=end1.dx;
    y=end1.dy;
    z=end1.dz;

    t+=h;   
    k+=1;
//  cout<<"x="<<x<<" y= "<<y<<" z="<<z<<" Pogreshnost= "<<e<<" Time="<<t<<endl;
    fprintf(fff,"%lf, %lf, %lf, %.10lf  ,%lf ,%lf\n", x, y,z,e,t, h);               

}
while (t<=T);
fprintf(fff,"Step = %lf",T/k); 
fclose(fff);
}

1 个答案:

答案 0 :(得分:1)

您的错误步进器,看起来很简单,正在实施一些错误的想法。

一般假设是,在最低阶中,本地错误为e=C·h^5。以步长的一半执行两个步骤因此会产生错误

e2=2·C·(h/2)^5=C·h^5/16=e/16. 

由于人们只知道计算RK4步骤的值y1=y+ey2=y+e2=y+e/16,因此可以找到

y1-y2=15/16*e   or   e=16/15*(y1-y2)   and   e2=(y1-y2)/15.

假设局部错误统一且附加地转换为全局错误,则会得到e·(T/h)的全局错误。或者解释不同,e/h是局部误差密度,所需的全局误差E转换为平均误差密度E/T。因此,您必须将eE/T·h进行比较,而不是将其与E进行比较。特别是缺失的因素h将导致步长不合适。

整个步长计算在计算上也太昂贵了。由于本地错误被发现为e=C·h^5,并且所需的本地错误为E·h/T,因此可能最佳步长h1(不包括较高的高阶效果)由

C·h1^4=E/T   or   h1 = h*(E/(e*T))^0.25.

这个公式比几千次迭代的循环快得多,每次循环3个RK4。可以围绕该公式构建检查,以便确保新的步长确实具有该局部错误,并且步骤大小的变化不是太激进,在伪概念C代码中

fac = 1.0;
do {
    h *= fac;
    y1 = /* RK4 step with h */;
    y2 = /* 2 RK4 steps with h/2 */;
    e = 16*norm(y1-y2)/15;
    fac = pow(E/(e*T), 0.25);
    fac = min(20, max(0.05, fac) );
} while( fac<0.5 or 2<fac ) 
// advance the integration