在 C++ 中使用 RK-4 求解洛伦兹方程

2024-01-03

我用 C++ 编写了使用 RK-4 方法求解洛伦兹方程的代码。我必须绘制吸引子图,并且在使用 RK-4 方法求解 3 一阶耦合微分方程时遇到一些困难。这是我的代码:

/* Solving 3 coupled first order differential equations using RK4 for the 
Lorentz system
dxdt =  sig*(y - x) {f}
dydt =  x*(rho - z) - y {g}
dzdt =  x*y - bet*z {k} */


#include<iostream>
#include<cmath>
#include<fstream>
#include <iomanip>
using namespace std;
double sig = 10.0;
double rho = 28.0;
double bet = 8.0/3.0;

double func1 (double y[], int N) // function to define the n first order 
differential equations
{
    double dxdt;    
    dxdt =  sig*(y[1] - y[0]);
    return dxdt;
}
double func2 (double y[], int N) // function to define the n first order 
differential equations
{
    double dydt;    
    dydt =  y[0]*(rho - y[2]) - y[1];
    return dydt;
}
double func3 (double y[], int N) // function to define the n first order 
differential equations
{
    double dzdt;   
    dzdt =  y[0]*y[1] - bet*y[2];
    return dzdt;
}
void rk4(int n, double x0,double xf,double Y0[],int N) // Function to 
implement RK4 algorithm
{
    double K1;
    double K2;
    double K3;
    double K4;

    double L1;
    double L2;
    double L3;
    double L4;

    double M1;
    double M2;
    double M3;
    double M4;

    double x[n+1];
    double h = (xf-x0)/n;
    long double y[n+1][N];
    double dydx[N];
    double ytemp[N];
    for(int i=0;i<=n;i++) // loop to store values of time
    {
        x[i] = x0 + i*h;
    }

    for(int j =0;j<N;j++) // loop to store initial conditions of diff eq
    {
        y[0][j] = Y0[j];
    }
    for (int k =0;k<n;k++)
    {
        for(int l=0;l<N;l++)
        {
            ytemp[l] = y[k][l];
        }
            K1 = func1(ytemp,N); // f
            L1 = func2(ytemp,N); // g
            M1 = func3(ytemp,N); // k

            ytemp[0] = y[k][0] + 0.5*h*K1;
            ytemp[1] = y[k][1] + 0.5*h*L1;
            ytemp[2] = y[k][2] + 0.5*h*M1;

            K2 = func1(ytemp,N);
            L2 = func2(ytemp,N);
            M2 = func3(ytemp,N);

            ytemp[0] = y[k][0] + 0.5*h*K2;
            ytemp[1] = y[k][1] + 0.5*h*L2;
            ytemp[2] = y[k][2] + 0.5*h*M2;

            K3 = func1(ytemp,N);
            L3 = func2(ytemp,N);
            M3 = func3(ytemp,N);

            ytemp[0] = y[k][0] + h*K3;
            ytemp[1] = y[k][1] + h*L3;
            ytemp[2] = y[k][2] + h*M3;

            K4 = func1(ytemp,N);
            L4 = func2(ytemp,N);
            M4 = func3(ytemp,N);

            dydx[0] = (1.0/6.0)*(K1+ 2.0*K2 + 2.0*K3+ K4);
            dydx[1] = (1.0/6.0)*(L1+ 2.0*L2 + 2.0*L3+ L4);
            dydx[2] = (1.0/6.0)*(M1+ 2.0*M2 + 2.0*M3+ M4);

        for(int l=0;l<N;l++)
        {
            y[k+1][l] = y[k][l] + h*dydx[l];
        }   

    }
    ofstream fout;
    fout.open("prog12bdata.txt",ios::out);
    for (int m =0;m<=n;m++)
    {
        fout<<setw(15) << setprecision(10) <<x[m];
        for(int o =0;o<N;o++)
        {
            fout<<" "<<setw(15) << setprecision(10) <<y[m][o];
        }
        fout<<endl;
    }
    fout.close();
}
int main()
{
    int N;// Order of ODE to solve
    cout<<"Enter the order of ODE to solve: "<<endl;
    cin>>N;

    double x0=0;
    double xf=50;
    int n = 50000; // number of steps
    double Y0[N];

    for(int i=0;i<N;i++)
    {
        cout<<"Enter the initial conditions: "<<endl;
        cin>>Y0[i];
    }
    rk4(n,x0,xf,Y0,N);
}

当我编译它时,我收到一条错误消息,指出程序停止工作。有人可以帮我吗?


我问过OP他们是否能够使用模板,他们回答说"I can use templates, but I wanted it to be simple."首先在幕后设置模板结构还需要做一些工作;但一旦完成;模板的使用确实大大简化了事情。最终,它通常会使代码更加通用,而不是特定于单个任务。


这是一个未实现的类,用于显示 ODE 积分器的通用模式。

#ifndef ODE_GENERALIZED_DEFINITION
#define ODE_GENERALIZED_DEFINITION

// A generalized structure of what an ODE should represent
// This class is not used; but only serves to show the interface
// of what any ODE type integrator - solver needs to contain
template<class Container, class Time = double, class Traits = container_traits<Container> >
class ode_step {
public:
    typedef unsigned short order_type;
    typedef Time time_type;
    typedef Traits traits_type;
    typedef typename traits_type::container_type container_type;
    typedef typename traits_type::value_type value_type;

    ode_step() = default;

    order_type order_step() const {};

    void adjust_size( const container_type& x ) {}

    // performs one step
    template<class DynamicSystem>
    void do_step( DynamicSystem& system, container_type& x, const container_type& dxdt, time_type t, time_type dt ) {}

    // performs one step
    template<class DynamicSystem>
    void do_step( DynamicSystem& system, container_type& x, time_type t, time_type dt ) {}
};

#endif // !ODE_GENERALIZED_DEFINITION

上面不会做任何事情,而仅用于展示 ODE 如何表现或起作用。在我们按照上述模式对任何类型的 ODE 进行建模之前,我们确实需要定义一些东西。


首先我们需要一个container_traits 类。

container_traits.h

#ifndef CONTAINER_TRAITS
#define CONTAINER_TRAITS

template<class Container>
struct container_traits {
    typedef Container container_type;
    typedef typename container_type::value_type value_type;
    typedef typename container_type::iterator iterator;
    typedef typename container_type::const_iterator const_iterator;

    static void resize( const container_type& x, container_type& dxdt ) {
        dxdt.resize( x.size() );
    }
    static bool same_size( const container_type& x1, const container_type& x2 ) {
        return (x1.size() == x2.size());
    }
    static void adjust_size( const container_type& x1, container_type& x2 ) {
        if( !same_size( x1, x2 ) ) resize( x1, x2 );
    }

    static iterator begin( container_type& x ) {
        return x.begin();
    }
    static const_iterator begin( const container_type& x ) {
        return x.begin();
    }
    static iterator end( container_type& x ) {
        return x.end();
    }
    static const_iterator end( const container_type& x ) {
        return x.end();
    }
};

#endif // !CONTAINER_TRAITS

上面的类相当简单且直接。


然后我们需要一组迭代器类型函数来迭代这些容器。迭代器函数稍微复杂一些,但它们的预期目的又相当简单。我将它们包装在命名空间中,这样它们就不会与可能存在的任何其他迭代器类或函数发生冲突。

iterator_algebra.h

#ifndef ITERATOR_ALGEBRA
#define ITERATOR_ALGEBRA

#include <cmath>
#include <iostream>

namespace it_algebra { // iterator algebra

// computes y += alpha * x1
template<class InOutIter, class InIter, class T>
void increment( InOutIter first1, InOutIter last1,
                InIter first2, T alpha ) {
    while( first1 != last1 )
        (*first1++) += alpha * (*first2++);
}

// computes y = alpha1 * ( x1 + x2 + alpha2*x3 )
template<class OutIter, class InIter1, class InIter2, class InIter3, class T>
void increment_sum_sum( OutIter first1, OutIter last1,
                        InIter1 first2, InIter2 first3,
                        InIter3 first4, T alpha1, T alpha2 ) {
    while( first1 != last1 )
        (*first1++) += alpha1 *
        ((*first2++) + (*first3++) + alpha2 * (*first4++));
}

// computes y = alpha1*x1 + alpha2*x2
template<class OutIter, class InIter1, class InIter2, class T>
inline void scale_sum( OutIter y_begin, OutIter y_end,
                       T alpha1, InIter1 x1_begin,
                       T alpha2, InIter2 x2_begin ) {
    while( y_begin != y_end ) {
        (*y_begin++) = alpha1 * (*x1_begin++) +
            alpha2 * (*x2_begin++);
    }
}

// computes y = x1 + alpha2*x2 + alpha3*x3
template<class OutIter, class InIter1, class InIter2, class InIter3, class T>
inline void scale_sum( OutIter y_begin, OutIter y_end,
                       T alpha1, InIter1 x1_begin,
                       T alpha2, InIter2 x2_begin,
                       T alpha3, InIter3 x3_begin ) {
    while( y_begin != y_end )
        (*y_begin++) =
        alpha1 * (*x1_begin++) +
        alpha2 * (*x2_begin++) +
        alpha3 * (*x3_begin++);
}

// computes y = x1 + alpha2*x2 + alpha3*x3 + alpha4*x4
template<class OutIter, class InIter1, class InIter2, class InIter3, class InIter4, class T>
inline void scale_sum( OutIter y_begin, OutIter y_end,
                       T alpha1, InIter1 x1_begin,
                       T alpha2, InIter2 x2_begin,
                       T alpha3, InIter3 x3_begin,
                       T alpha4, InIter4 x4_begin ) {
    while( y_begin != y_end )
        (*y_begin++) =
        alpha1 * (*x1_begin++) +
        alpha2 * (*x2_begin++) +
        alpha3 * (*x3_begin++) +
        alpha4 * (*x4_begin++);
}

// computes y = x1 + alpha2*x2 + alpha3*x3 + alpha4*x4 + alpha5*x5
template<class OutIter, class InIter1, class InIter2,
    class InIter3, class InIter4, class InIter5, class T>
    inline void scale_sum( OutIter y_begin, OutIter y_end,
                           T alpha1, InIter1 x1_begin,
                           T alpha2, InIter2 x2_begin,
                           T alpha3, InIter3 x3_begin,
                           T alpha4, InIter4 x4_begin,
                           T alpha5, InIter5 x5_begin ) {
    while( y_begin != y_end )
        (*y_begin++) =
        alpha1 * (*x1_begin++) +
        alpha2 * (*x2_begin++) +
        alpha3 * (*x3_begin++) +
        alpha4 * (*x4_begin++) +
        alpha5 * (*x5_begin++);
}

// computes y = x1 + alpha2*x2 + alpha3*x3 + alpha4*x4 + alpha5*x5
// + alpha6*x6
template<class OutIter, class InIter1, class InIter2,
    class InIter3, class InIter4, class InIter5, class InIter6, class T>
    inline void scale_sum( OutIter y_begin, OutIter y_end,
                           T alpha1, InIter1 x1_begin,
                           T alpha2, InIter2 x2_begin,
                           T alpha3, InIter3 x3_begin,
                           T alpha4, InIter4 x4_begin,
                           T alpha5, InIter5 x5_begin,
                           T alpha6, InIter6 x6_begin ) {
    while( y_begin != y_end )
        (*y_begin++) =
        alpha1 * (*x1_begin++) +
        alpha2 * (*x2_begin++) +
        alpha3 * (*x3_begin++) +
        alpha4 * (*x4_begin++) +
        alpha5 * (*x5_begin++) +
        alpha6 * (*x6_begin++);
}    

// computes y = x1 + alpha2*x2 + alpha3*x3 + alpha4*x4 + alpha5*x5
// + alpha6*x6 + alpha7*x7
template<class OutIter, class InIter1, class InIter2, class InIter3,
    class InIter4, class InIter5, class InIter6, class InIter7, class T>
    inline void scale_sum( OutIter y_begin, OutIter y_end,
                           T alpha1, InIter1 x1_begin,
                           T alpha2, InIter2 x2_begin,
                           T alpha3, InIter3 x3_begin,
                           T alpha4, InIter4 x4_begin,
                           T alpha5, InIter5 x5_begin,
                           T alpha6, InIter6 x6_begin,
                           T alpha7, InIter7 x7_begin ) {
    while( y_begin != y_end )
        (*y_begin++) =
        alpha1 * (*x1_begin++) +
        alpha2 * (*x2_begin++) +
        alpha3 * (*x3_begin++) +
        alpha4 * (*x4_begin++) +
        alpha5 * (*x5_begin++) +
        alpha6 * (*x6_begin++) +
        alpha7 * (*x7_begin++);
}

// computes y = x1 + alpha2*x2 + alpha3*x3 + alpha4*x4 + alpha5*x5
// + alpha6*x6 + alpha7*x7 + alpha8*x8
template<class OutIter, class InIter1, class InIter2, class InIter3, class InIter4,
    class InIter5, class InIter6, class InIter7, class InIter8, class T>
    inline void scale_sum( OutIter y_begin, OutIter y_end,
                           T alpha1, InIter1 x1_begin,
                           T alpha2, InIter2 x2_begin,
                           T alpha3, InIter3 x3_begin,
                           T alpha4, InIter4 x4_begin,
                           T alpha5, InIter5 x5_begin,
                           T alpha6, InIter6 x6_begin,
                           T alpha7, InIter7 x7_begin,
                           T alpha8, InIter8 x8_begin ) {
    while( y_begin != y_end )
        (*y_begin++) =
        alpha1 * (*x1_begin++) +
        alpha2 * (*x2_begin++) +
        alpha3 * (*x3_begin++) +
        alpha4 * (*x4_begin++) +
        alpha5 * (*x5_begin++) +
        alpha6 * (*x6_begin++) +
        alpha7 * (*x7_begin++) +
        alpha8 * (*x8_begin++);
}

// computes y = x1 + alpha2*x2 + alpha3*x3 + alpha4*x4 + alpha5*x5
// + alpha6*x6 + alpha7*x7 + alpha8*x8 + alpha9*x9
template<class OutIter, class InIter1, class InIter2, class InIter3, class InIter4,
    class InIter5, class InIter6, class InIter7, class InIter8, class InIter9, class T>
    inline void scale_sum( OutIter y_begin, OutIter y_end,
                           T alpha1, InIter1 x1_begin,
                           T alpha2, InIter2 x2_begin,
                           T alpha3, InIter3 x3_begin,
                           T alpha4, InIter4 x4_begin,
                           T alpha5, InIter5 x5_begin,
                           T alpha6, InIter6 x6_begin,
                           T alpha7, InIter7 x7_begin,
                           T alpha8, InIter8 x8_begin,
                           T alpha9, InIter9 x9_begin ) {
    while( y_begin != y_end )
        (*y_begin++) =
        alpha1 * (*x1_begin++) +
        alpha2 * (*x2_begin++) +
        alpha3 * (*x3_begin++) +
        alpha4 * (*x4_begin++) +
        alpha5 * (*x5_begin++) +
        alpha6 * (*x6_begin++) +
        alpha7 * (*x7_begin++) +
        alpha8 * (*x8_begin++) +
        alpha9 * (*x9_begin++);
}

// computes y = x1 + alpha2*x2 + alpha3*x3 + alpha4*x4 + alpha5*x5
// + alpha6*x6 + alpha7*x7 + alpha8*x8 + alpha9*x9 + alpha10*x10
template<class OutIter, class InIter1, class InIter2, class InIter3, class InIter4, class InIter5,
    class InIter6, class InIter7, class InIter8, class InIter9, class InIter10, class T>
    inline void scale_sum( OutIter y_begin, OutIter y_end,
                           T alpha1, InIter1 x1_begin,
                           T alpha2, InIter2 x2_begin,
                           T alpha3, InIter3 x3_begin,
                           T alpha4, InIter4 x4_begin,
                           T alpha5, InIter5 x5_begin,
                           T alpha6, InIter6 x6_begin,
                           T alpha7, InIter7 x7_begin,
                           T alpha8, InIter8 x8_begin,
                           T alpha9, InIter9 x9_begin,
                           T alpha10, InIter10 x10_begin ) {
    while( y_begin != y_end )
        (*y_begin++) =
        alpha1 * (*x1_begin++) +
        alpha2 * (*x2_begin++) +
        alpha3 * (*x3_begin++) +
        alpha4 * (*x4_begin++) +
        alpha5 * (*x5_begin++) +
        alpha6 * (*x6_begin++) +
        alpha7 * (*x7_begin++) +
        alpha8 * (*x8_begin++) +
        alpha9 * (*x9_begin++) +
        alpha10 * (*x10_begin++);
}

// generic version for n values
template<class OutIter, class InIter, class InIterIter, class FactorIter, class T>
inline void scale_sum_generic( OutIter y_begin, OutIter y_end,
                               FactorIter alpha_begin, FactorIter alpha_end,
                               T beta, InIter x_begin, InIterIter x_iter_begin ) {
    FactorIter alpha_iter;
    InIterIter x_iter_iter;
    while( y_begin != y_end ) {
        x_iter_iter = x_iter_begin;
        alpha_iter = alpha_begin;
        *y_begin = *x_begin++;
        //std::clog<<(*y_begin);
        while( alpha_iter != alpha_end ) {
            //std::clog<< " + " <<beta<<" * "<<*alpha_iter<<"*"<<(*(*(x_iter_iter)));
            (*y_begin) += beta * (*alpha_iter++) * (*(*x_iter_iter++)++);
        }
        //std::clog<<" = "<<*y_begin<<std::endl;
        y_begin++;
    }
    //std::clog<<std::endl;
}

// computes y += alpha1*x1 + alpha2*x2 + alpha3*x3 + alpha4*x4
template<class OutIter, class InIter1, class InIter2,
    class InIter3, class InIter4, class T>
    inline void scale_sum_inplace( OutIter y_begin, OutIter y_end,
                                   T alpha1, InIter1 x1_begin,
                                   T alpha2, InIter2 x2_begin,
                                   T alpha3, InIter3 x3_begin,
                                   T alpha4, InIter4 x4_begin ) {
    while( y_begin != y_end )
        (*y_begin++) +=
        alpha1 * (*x1_begin++) +
        alpha2 * (*x2_begin++) +
        alpha3 * (*x3_begin++) +
        alpha4 * (*x4_begin++);
}

// calculates tmp = y, y = x1 + alpha*x2, x1 = tmp 
template<class OutIter, class InIter, class T>
inline void scale_sum_swap( OutIter y_begin, OutIter y_end,
                            OutIter x1_begin, T alpha, InIter x2_begin ) {
    T swap;
    while( y_begin != y_end ) {
        swap = (*x1_begin) + alpha * (*x2_begin++);
        *x1_begin++ = *y_begin;
        *y_begin++ = swap;
    }
}

// computes y = x1 + alpha2 * x2 ; x2 += x3
template<class OutIter, class InIter1,
    class InOutIter, class InIter2, class T>
    void assign_sum_increment( OutIter first1, OutIter last1, InIter1 first2,
                               InOutIter first3, InIter2 first4, T alpha ) {
    while( first1 != last1 ) {
        (*first1++) = (*first2++) + alpha * (*first3);
        (*first3++) += (*first4++);
    }
}

template<class OutIter, class InIter1, class InIter2, class T >
void weighted_scale( OutIter y_begin, OutIter y_end, InIter1 x1_begin, InIter2 x2_begin,
                     T eps_abs, T eps_rel, T a_x, T a_dxdt ) {
    using std::abs;

    while( y_begin != y_end ) {
        *y_begin++ = eps_abs +
        eps_rel * (a_x * abs( *x1_begin++ ) +
        a_dxdt * abs( *x2_begin++ ));
    }
}    

template<class InIter1, class InIter2, class T >
T max_ratio( InIter1 x1_begin, InIter1 x1_end, InIter2 x2_begin, T initial_max ) {
    using std::abs;
    while( x1_begin != x1_end ) {
        initial_max = std::max( static_cast<T>(abs( *x1_begin++ ) / abs( *x2_begin++ )), initial_max );
    }
    return initial_max;
}

} // namespace it_algebra

#endif // !ITERATOR_ALGEBRA

现在我们已经有了所需的结构和函数,我们可以使用上面的模式来实现不同类型的 ODE 积分器。我将展示两个最常见的:euler 和 rk4。只要遵循模式,就可以轻松实现 midpoint、rk5 或任何其他方法。

euler.h

#ifndef EULER_H
#define EULER_H

#include "iterator_algebra.h"
#include "container_traits.h"

template<class Container, class Time = double, class Traits = container_traits<Container> >
class euler_stepper {
public:
    typedef unsigned short order_type;
    typedef Time time_type;
    typedef Traits traits_type;
    typedef typename traits_type::container_type container_type;
    typedef typename traits_type::value_type value_type;

private:
    container_type m_dxdt;

public:
    euler_stepper() = default;
    euler_stepper( const container_type& x ) {
        adjust_size( x );
    }

    order_type order_step() const {
        return 1;
    }

    void adjust_size( const container_type& x ) {
        traits_type::adjust_size( x, m_dxdt );
    }

    // performs one step with the knowledge of dxdt(t)
    template<class DynamicSystem>
    void do_step( DynamicSystem& system, container_type& x, const container_type& dxdt, time_type t, time_type dt ) {
        it_algebra::increment( traits_type::begin( x ),
                               traits_type::end( x ),
                               traits_type::begin( dxdt ),
                               dt );
    }

    // performs one step
    template<class DynamicSystem>
    void do_step( DynamicSystem& system, container_type& x, time_type t, time_type dt ) {
        system( x, m_dxdt, t );
        do_step( system, x, m_dxdt, t, dt );
    }
};

#endif // EULER_H

rk4.h

#ifndef RK4_H
#define RK4_H

#include "iterator_algebra.h"
#include "container_traits.h"

template<class Container, class Time = double, class Traits = container_traits<Container>>
class rk4_stepper {
public:
    typedef unsigned short order_type;
    typedef Time time_type;
    typedef Traits traits_type;
    typedef typename traits_type::container_type container_type;
    typedef typename traits_type::value_type value_type;
    // typedef typename traits_type::iterator iterator;
    // typedef typename traits_type::const_iterator const_iterator;

private:
    container_type m_dxdt;
    container_type m_dxt;
    container_type m_dxm;
    container_type m_dxh;
    container_type m_xt;

public:
    rk4_stepper() = default;
    rk4_stepper( const container_type& x ) { adjust_size( x ); }

    order_type order_step() const { return 4; }

    void adjust_size( const container_type& x ) {
        traits_type::adjust_size( x, m_dxdt );
        traits_type::adjust_size( x, m_dxt );
        traits_type::adjust_size( x, m_dxm );
        traits_type::adjust_size( x, m_xt );
        traits_type::adjust_size( x, m_dxh );
    }

    template<class DynamicSystem>
    void do_step( DynamicSystem& system, container_type& x, const container_type& dxdt, time_type t, time_type dt ) {
        using namespace it_algebra;

        const time_type val1 = static_cast<time_type>(1.0);

        time_type dh = static_cast<time_type>(0.5) * dt;
        time_type th = t + dh;

        // dt * dxdt = k1
        // m_xt = x + dh*dxdt
        scale_sum( traits_type::begin( m_xt ), traits_type::end( m_xt ),
                   val1, traits_type::begin( x ), dh, traits_type::begin( dxdt ) );

        // dt * m_dxt = k2
        system( m_xt, m_dxt, th );
        // m_xt = x + dh*m_dxt
        scale_sum( traits_type::begin( m_xt ), traits_type::end( m_xt ),
                   val1, traits_type::begin( x ), dh, traits_type::begin( m_dxt ) );

        // dt * m_dxm = k3
        system( m_xt, m_dxm, th );
        // m_xt = x + dt*m_dxm
        scale_sum( traits_type::begin( m_xt ), traits_type::end( m_xt ),
                   val1, traits_type::begin( x ), dt, traits_type::begin( m_dxm ) );

        // dt * m_dxh = k4
        system( m_xt, m_dxh, t + dt );
        // x += dt / 6 * (m_dxdt + m_dxt + val2*m_dxm)
        time_type dt6 = dt / static_cast<time_type>(6.0);
        time_type dt3 = dt / static_cast<time_type>(3.0);
        scale_sum_inplace( traits_type::begin( x ), traits_type::end( x ),
                           dt6, traits_type::begin( dxdt ),
                           dt3, traits_type::begin( m_dxt ),
                           dt3, traits_type::begin( m_dxm ),
                           dt6, traits_type::begin( m_dxh ) );
    }

    template<class DynamicSystem>
    void do_step( DynamicSystem& system, container_type& x, time_type t, time_type dt ) {
        system( x, m_dxdt, t );
        do_step( system, x, m_dxdt, t, dt );
    }
};

#endif // !RK4_H

现在我们已经拥有了我们所需要的一切;剩下要做的就是使用它们。


OP 提到解决洛伦兹问题,所以我将用它来演示如何使用 ODE:

main.cpp

#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>

#include "euler.h"
#include "rk4.h"

#define tab "\t"

typedef std::vector<double> state_type; 

const double sigma = 10.0;
const double R = 28.0;
const double b = 8.0 / 3.0;

void lorenz( state_type& x, state_type& dxdt, double t ) {
    dxdt[0] = sigma * (x[1] - x[0]);
    dxdt[1] = R * x[0] - x[1] - x[0] * x[2];
    dxdt[2] = x[0] * x[1] - b * x[2];
}

int main() {
    const double dt = 0.01;
    state_type x1( 3 );
    x1[0] = 1.0;
    x1[1] = 0.0;
    x1[2] = 0.0;

    state_type x2( 3 );
    x2[0] = 1.0;
    x2[1] = 0.0;
    x2[2] = 0.0;

    euler_stepper<state_type> stepper_euler;
    stepper_euler.adjust_size( x1 );

    rk4_stepper<state_type> stepper_rk4;
    stepper_rk4.adjust_size( x2 );

    std::fstream file( "compare.txt", std::ios::out );

    file << tab << "Euler Stepper to Solve Lorenz" << tab << tab << tab << tab << "RK4 Stepper to Solve Lorenz\n"
         << tab << "========================" << tab << tab << tab << "=======================\n";

    double t1 = 0.0;
    double t2 = 0.0;
    for( size_t oi = 0; oi < 10000; ++oi, t1 += dt, t2 += dt ) {
        stepper_euler.do_step( lorenz, x1, t1, dt );
        stepper_rk4.do_step( lorenz, x2, t2, dt );
        file << " " << std::setw( 15 ) << std::setprecision( 10 ) << x1[0]
             << tab << std::setw( 15 ) << std::setprecision( 10 ) << x1[1]
             << tab << std::setw( 15 ) << std::setprecision( 10 ) << x1[2]
             << tab << "||"
             << " " << std::setw( 15 ) << std::setprecision( 10 ) << x2[0]
             << tab << std::setw( 15 ) << std::setprecision( 10 ) << x2[1]
             << tab << std::setw( 15 ) << std::setprecision( 10 ) << x2[2]
             << '\n';
    }

    file.close();

    std::cout << "\nPress any key and enter to quit.\n";
    std::cin.get();
    return 0;
}

现在,您可以看到定义 Lorenz 函数并将其传递给您想要使用的 ODE 积分器类型是多么简单。


作为一个额外的好处,这里有一个很好的小函数,可以与这些结构一起使用来积分常量。

integrate_const.h

#ifndef INTEGRATE_CONST_H
#define INTEGRATE_CONST_H

// This function will iterate the state of the ODE, 
// with the possibility to observe that state in each step

template<class Stepper, class DynamicSystem, class Observer>
size_t integrate_const( Stepper& stepper, DynamicSystem& system, 
                        typename Stepper::container_type& state,
                        typename Stepper::time_type start_time, 
                        typename Stepper::time_type end_time,
                        typename Stepper::time_type dt, 
                        Observer& observer ) {

    stepper.adjust_size( state );
    size_t iteration = 0;
    while( start_time < end_time ) {
        observer( start_time, state, system );
        stepper.do_step( system, state, start_time, dt );
        start_time += dt;
        ++iteration;
    }
    observer( start_time, state, system );

    return iteration;
}

#endif // !INTEGRATE_CONST_H

Summary- 现在可以使用任何具有开始、结束和调整大小功能的容器,而不是使用基本的数组或指针,从而使代码通用,易于实现和使用。上面的代码是工作代码,因为我没有看到任何编译或链接错误。我只对运行时错误进行了适度的测试。

Note:这项工作的灵感来自于我读过的一个项目code project。我确实对我找到的原始版本进行了一些修改,并且从boost图书馆。你可以找到它here https://www.codeproject.com/Articles/43607/Solving-ordinary-differential-equations-in-C。我也相信odeint库现在正式成为新版本的一部分boost图书馆。

以下是一些可能有用的有关使用常微分方程的其他链接:一些是关于对其进行编程的,另一些是关于其背后的数学符号的。

  • 代码梦想 http://www.dreamincode.net/forums/topic/366744-runge-kutta-fourth-order-numerical-integrator/
  • Github 上的 Odeint http://headmyshoulder.github.io/odeint-v2/
  • 堆栈问答 https://stackoverflow.com/questions/42747227/c-numerical-integrators-to-solve-systems-of-odes
  • You Tube https://www.youtube.com/user/HoustonMathPrep
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 C++ 中使用 RK-4 求解洛伦兹方程 的相关文章

  • 生成多个随机数

    我想生成 25 个唯一的随机数并将它们列在控制台中 数字的长度应至少为 10 个字符 有什么简单的方法可以做到这一点吗 尝试将数字构建为字符串 并使用 HashSet 确保它们是唯一的 Random random new Random Ha
  • ASP.NET Web 应用程序中的身份验证遇到问题

    我正在尝试对从登录页面登录我的 Web 应用程序的用户进行身份验证 我正在使用本教程 http support microsoft com kb 301240作为指南 它几乎准确地解释了我希望做什么 但是当我输入用户名和密码时 验证不起作用
  • STL之类的容器typedef快捷方式?

    STL 容器的常见模式是这样的 map
  • 将公历日期转换为儒略日期,然后再转换回来(随着时间)

    我正在编写一个程序 必须将当前的公历日期和时间转换为儒略日期 然后再转换回公历门 最终我需要添加能够添加年 月 日 小时 分钟和秒的功能 但我需要先解决这部分问题 现在我已经从公历日期转换为儒略日期 所以从逻辑上讲 我觉得我应该能够以某种方
  • 如何从 Qt 应用程序通过 ODBC 连接到 MySQL 数据库?

    我有一个新安装的 MySQL 服务器 它监听 localhost 3306 从 Qt 应用程序连接到它的正确方法是什么 原来我需要将MySQL添加到ODBC数据源 我在遵循这个视频教程后做到了这一点 https youtu be K3GZi
  • ContentDialog 未与 UWP 中心对齐

    据我所知 ContentDialog的默认行为应该是使其在 PC 上居中并在移动设备上与顶部对齐 但就我而言 即使在 PC 上我也将其与顶部对齐 但我不明白发生了什么 我正在使用代码隐藏来创建它 这是我正在使用的代码片段 Creates t
  • Monotouch全局异常处理

    我在野外发现了一只令人讨厌的虫子 但我无法确定它的具体情况 有没有办法拥有全局 Try Catch 块 或者有办法处理 Monotouch 中未处理的任何异常 我可以包起来吗UIApplication Main args 在 try cat
  • 控制台应用程序中使用 Unicode 字符的 _tprintf

    我正在从 Unicode 构建的控制台应用程序 使用 C 和 Visual Studio 2008 执行这个简单的输出 此代码旨在在 Windows 上运行 tprintf L Some sample string n 一切正常 但是如果我
  • 在c#中获取没有时间的日期

    我的表上有一列 缺勤日期时间 日期 当我想要获取包含日期的行时 它返回 0 行 这是我的 C 代码 DateTime ClassDate DateTime Parse lblDate Content ToString var Abs dbs
  • 如何从外语线程调用Python函数(C++)

    我正在开发一个程序 使用 DirectShow 来抓取音频数据 媒体文件 DirectShow 使用线程将音频数据传递给回调 我的程序中的函数 然后我让该回调函数调用另一个函数 Python 中的函数 我使用 Boost Python 来包
  • 更改 Xamarin.Forms 应用中顶部栏和底部栏(ControlsBar、StatusBar)的颜色

    无论如何 即使后面需要特定于平台的代码 也可以更改顶部栏 蓝色的 和底部栏 黑色的 的颜色吗 我希望添加对浅色和深色模式的支持 因此我希望能够在运行时更改它 有可能的 Android Using Window SetStatusBarCol
  • 如何构建一棵与或树?

    我需要一个支持 与 和 或 的树结构 例如 给定一个正则表达式 如ab c d e 我想把它变成一棵树 所以 一开始我们有两个 或 分支 它可以向下ab or c d e 如果你低头ab分支 你得到两个节点 a and b or a其次是b
  • 从 DataRow 单元格解析 int [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 如何从 DataRow 单元格解析 int 值 Int32 Parse item QuestionId ToString 这段代码可以工作 但看
  • valgrind 在 Raspberry Pi 上返回未处理的指令

    我最近一直在尝试在运行 Debian GNU Linux7 0 喘息 的树莓派 型号 b 上使用 valgrind 来调试分段错误 每次我在编译的 C 程序上运行 valgrind 时 都会得到类似以下内容的信息 disInstr arm
  • 选择合适的IDE

    您会推荐使用以下哪种 IDE 语言来在 Windows 下开发涉及识别手势并与操作系统交互的项目 我将使用 OpenCV 库来执行图像处理任务 之后 我将使用 win32 API 或 NET 框架与操作系统交互 具体取决于您建议的工具 性能
  • 连接到没有元数据的网络服务

    我想连接到此网络服务 https training api temando com schema 2009 06 server wsdl https training api temando com schema 2009 06 serve
  • 如何从 Access 数据库中读取“是/否”值作为布尔值?

    帮我找回YES NO来自 MS Access 的布尔格式数据类型 我尝试解析它 但它总是返回 false 更新 实际上不是问题抱歉 它确实接受 YES NO 作为布尔值 OleDbconnection dbConnect new OleDb
  • 为什么在构造函数中设置字段是(或不是)线程安全的?

    假设您有一个像这样的简单类 class MyClass private readonly int a private int b public MyClass int a int b this a a this b b public int
  • 在windows + opengl中选择图形设备

    我知道如何使用 openGL 打开窗口 使用 Win32 或其他工具包 但是当系统有2块显卡时 如何选择要渲染的图形设备 我的编程语言是 C 我专注于 Windows 但任何示例都将受到欢迎 编辑 也许更好地解释我的问题是个好主意 以便添加
  • 如何使用 C# 为 azure devops 变量赋值

    我有 selenium C 测试脚本 可以从浏览器获取令牌 我有两个 azure devops 任务 一个用于执行 selenium 测试 另一个用于执行 API 测试 我想将 selenium 测试获取的令牌传递给 API 测试执行任务

随机推荐

  • 从表单中的所有选择元素中获取所有选定的选项元素

    大家好 感谢您抽出时间回答我的问题 我有一个包含 6 个选择元素的表单 其类别为 skillLevel 我需要使用 jQuery 获取 最好是在数组中 每个选择元素的值 我怎样才能做到这一点 您可以使用map method var arr
  • HTML 钻取表:设计

    我试图找出根据标签构建 HTML 钻取表的最佳方法 它必须简单 但最重要的是它应该符合逻辑 关于如何做到这一点是否有任何首选标准 你会推荐什么 一种可能的解决方案是 colspan tbody tr td td td Summery row
  • 更改 PHP.ini 位置文件?

    我在 OSX 上使用 apache2 默认情况下php ini位置是 private etc php ini 我需要把它改成这样 Library FileMaker Server Web Publishing publishing engi
  • Delphi 2010-IDE 不断停止在 CPU 调试窗口

    我在 D2010 IDE 中不断出现 CPU 调试窗口 我注意到这出现在一些断点上 而其他一些断点则不会导致这种效果 无法解释这种情况到底何时发生或哪些断点导致这种情况 但似乎当调试器无法到达代码上的断点时 它会停止在方法的开始地址上 并且
  • 在 jar 中包含属性/配置文件是一种不好的做法吗?

    例如 MyApp 是一个 Web 应用程序 其中包含一个属性文件 server properties 该文件描述应用程序的配置数据 例如服务器名称 在开发阶段 server properties 位于其自己的 IDE 项目文件夹中 它的逻辑
  • 当终端关闭时终止 sudo python 脚本

    如何判断运行 python 脚本的终端是否已关闭 如果用户关闭终端 我想安全地结束我的 python 脚本 我可以使用处理程序捕获 SIGHUP 但当脚本作为 sudo 运行时则不行 当我使用 sudo 启动脚本并关闭终端时 python
  • 模拟内存不足警告不起作用

    我有一个UIWebView in a UIViewController 我正在尝试将此视图控制器推送到现有的UINavigationController 它有另一个视图控制器 它也有一个UIWebView在里面 推动第一个视图控制器后 我尝
  • 单击时切换 CSS3 动画

    在没有 JavaScript 的情况下 在点击时改变 CSS3 动画方向的最佳方法是什么 我最近一直在探索复选框黑客 并试图找到一种方法 只使用一组关键帧 而不是两组 一个前进 一个返回 这可能吗 或者有没有办法用一套来做到这一点 例如我有
  • 如何删除mysql数据库中的重复记录?

    使用rails或mysql查询删除mysql数据库中重复记录的最佳方法是什么 您可以通过以下方式将不同的记录复制到新表中 select distinct into NewTable from MyTable
  • 如何使用 Gradle 运行多个命名测试?

    我知道怎么说 gradle test tests mypackage MyTest 但如何指定多个呢 gradle test tests mypackage MyTest mypackage model ModelTest BasicTes
  • 了解 Qt 中的表单布局机制

    Qt具有灵活且强大的布局机制来处理桌面应用程序窗口的视图 但它是如此灵活 以至于当出现问题并需要微调时 它几乎无法被理解 而且如此强大 以至于它可以击败任何试图压倒 Qt 关于表单外观的观点的人 那么 谁能解释一下 或者提供一下Qt的定位机
  • PDO 因记录过多、缓冲查询而失败

    这个脚本昨天运行良好 但是今天 由于我最初选择的表中现在有大约 150 000 条记录 所以它失败了 说我正在从 null 获取 据我所知 这是因为我的记录太多了 因此 我最终通过向初始查询 1000 添加限制和这一行来纠正它 MysqlC
  • Bash 中的文件名未正确打印,带有下划线“_”[重复]

    这个问题在这里已经有答案了 我正在用这个 DATE FOLDER date b d a G FILENAME HOME date1 tar gz echo BACKUP DESTINATION DATE FOLDER FOLDERNAME
  • Python 继承:何时以及为何使用 __init__

    我是一个Python新手 试图理解继承方法背后的哲学 逻辑 问题最终涉及为什么以及何时必须使用 init 子类中的方法 例子 看来从超类继承的子类不需要有自己的构造函数 init 方法 下面 狗继承了哺乳动物的属性 名字 年龄 和方法 发出
  • 产品密钥的正则表达式

    我正在尝试做一个正则表达式来显示所有具有该值的产品密钥 这是我创建的正则表达式 A Z0 9 5 A Z0 9 5 A Z0 9 5 A Z0 9 5 A Z0 9 5 由于某种原因它不起作用 您打算使用哪种正则表达式工具 grep egr
  • 无法登录活动管理。有什么办法可以创建管理员用户吗? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 当我尝试使用默认管理员用户登录时 我收到 无效的电子邮件或密码 有没有办法用代码创建用户并尝试以这种方式登录 我可以登录我的实时网站 但不
  • 像 Perl 一样在 JavaScript 正则表达式中嵌入注释

    有没有办法在 JavaScript 正则表达式中嵌入注释 例如你可以用 Perl 做 https stackoverflow com questions 632795 how do you comment a perl regular ex
  • WCF - 序列化继承类型

    我有这些课程 DataContract public class ErrorBase DataContract public class FileMissingError ErrorBase DataContract public clas
  • 如何找到上次访问数据库的时间?

    在 SQL Server 2005 中 您能否轻松确定某人上次查询数据库的时间 扩展詹姆斯 艾伦的答案 SELECT d name last user seek MAX last user seek last user scan MAX l
  • 在 C++ 中使用 RK-4 求解洛伦兹方程

    我用 C 编写了使用 RK 4 方法求解洛伦兹方程的代码 我必须绘制吸引子图 并且在使用 RK 4 方法求解 3 一阶耦合微分方程时遇到一些困难 这是我的代码 Solving 3 coupled first order differenti