N维系统的模龙格-库塔四阶方法的实现

我正在尝试使我的龙格库塔4阶码模块化。我不想每次使用代码时都要编写和声明它,但是在.hpp和.cpp文件中声明它,以便分别使用它。但我遇到了一些问题。一般来说,我想要解一个n维方程组。为此,我使用了两个函数:一个用于方程组,另一个用于龙格-库塔法,如下所示:

double F(double t, double x[], int eq)
{
    // System equations
    if      (eq == 0) { return (x[1]); }
    else if (eq == 1) { return (gama * sin(OMEGA*t) - zeta * x[1] - alpha * x[0] - beta * pow(x[0], 3) - chi * x[2]); }
    else if (eq == 2) { return (-kappa * x[1] - phi * x[2]); }
    else { return 0; }
}
void rk4(double &t, double x[], double step)
{
    double x_temp1[sistvar], x_temp2[sistvar], x_temp3[sistvar];        
    double k1[sistvar], k2[sistvar], k3[sistvar], k4[sistvar];      

    int j;                                                      

    for (j = 0; j < sistvar; j++) 
    {
        x_temp1[j] = x[j] + 0.5*(k1[j] = step * F(t, x, j));
    }
    for (j = 0; j < sistvar; j++)
    {
        x_temp2[j] = x[j] + 0.5*(k2[j] = step * F(t + 0.5 * step, x_temp1, j));
    }
    for (j = 0; j < sistvar; j++)
    {
        x_temp3[j] = x[j] + (k3[j] = step * F(t + 0.5 * step, x_temp2, j));
    }
    for (j = 0; j < sistvar; j++)
    {
        k4[j] = step * F(t + step, x_temp3, j);
    }
    for (j = 0; j < sistvar; j++) 
    {
        x[j] += (k1[j] + 2 * k2[j] + 2 * k3[j] + k4[j]) / 6.0;
    }

    t += step;
}

上面的代码可以工作,并且经过了验证。但是,它有一些依赖项,因为它使用一些全局变量来工作:

gamaOMEGAzetaalphabetachikappaphi是我想要从.txt文件中读取的全局变量。我已经成功地做到了这一点,但是只在一个包含所有代码的.cpp文件中完成。

此外,sistvar是系统维度,也是全局变量。我正尝试将其作为F中的参数输入。但它的编写方式似乎给出了错误,因为sistvar是一个常量,不能作为变量更改,我也不能将变量放在数组的大小中。

此外,当需要调用<[2-11],eq内的F号码时,这两个函数具有相互依赖性。

你能给我一些如何做到这一点的提示吗?我已经搜索和阅读了关于这方面的书籍,但找不到答案。这可能是一项容易的任务,但我在c/c++编程语言方面相对较新。

提前谢谢!

*已编辑(尝试使用std::VECTOR实现)*

double F(double t, std::vector<double> x, int eq)
{
    // System Equations
    if (eq == 0) { return (x[1]); }
    else if (eq == 1) { return (gama * sin(OMEGA*t) - zeta * x[1] - alpha * x[0] - beta * pow(x[0], 3) - chi * x[2]); }
    else if (eq == 2) { return (-kappa * x[1] - phi * x[2]); }
    else { return 0; }
}

double rk4(double &t, std::vector<double> &x, double step, const int dim)
{
    std::vector<double> x_temp1(dim), x_temp2(dim), x_temp3(dim);
    std::vector<double> k1(dim), k2(dim), k3(dim), k4(dim);

    int j;

    for (j = 0; j < dim; j++) {
        x_temp1[j] = x[j] + 0.5*(k1[j] = step * F(t, x, j));
    }
    for (j = 0; j < dim; j++) {
        x_temp2[j] = x[j] + 0.5*(k2[j] = step * F(t + 0.5 * step, x_temp1, j));
    }
    for (j = 0; j < dim; j++) {
        x_temp3[j] = x[j] + (k3[j] = step * F(t + 0.5 * step, x_temp2, j));
    }
    for (j = 0; j < dim; j++) {
        k4[j] = step * F(t + step, x_temp3, j);
    }

    for (j = 0; j < dim; j++) {
        x[j] += (k1[j] + 2 * k2[j] + 2 * k3[j] + k4[j]) / 6.0;
    }

    t += step;

    for (j = 0; j < dim; j++) {
        return x[j];
    }
}

vector                 array

2.434 s   |        |   0.859 s
2.443 s   |        |   0.845 s
2.314 s   |        |   0.883 s
2.418 s   |        |   0.884 s
2.505 s   |        |   0.852 s
2.428 s   |        |   0.923 s
2.097 s   |        |   0.814 s
2.266 s   |        |   0.922 s
2.133 s   |        |   0.954 s
2.266 s   |        |   0.868 s
_______                _______
average = 2.330 s      average = 0.880 s

解决方案

使用向量函数,其中向量运算取自特征3

#include <eigen3/Eigen/Dense>
using namespace Eigen;

问题中讨论的相同部分可能如下所示(灵感来自function pointer with Eigen)

VectorXd Func(const double t, const VectorXd& x)
{ // equations for solving simple harmonic oscillator
    Vector3d dxdt;
    dxdt[0] = x[1];
    dxdt[1] = gama * sin(OMEGA*t) - zeta * x[1] - alpha * x[0] - beta * pow(x[0], 3) - chi * x[2]; 
    dxdt[2] = -kappa * x[1] - phi * x[2]; 
    return dxdt;
}

MatrixXd RK4(VectorXd Func(double t, const VectorXd& y), const Ref<const VectorXd>& y0, double t, double h, int step_num)
{
    MatrixXd y(y0.rows(), step_num );
    VectorXd k1, k2, k3, k4;
    y.col(0) = y0;

    for (int i=1; i<step_num; i++){
        k1 = Func(t, y.col(i-1));
        k2 = Func(t+0.5*h, y.col(i-1)+0.5*h*k1);
        k3 = Func(t+0.5*h, y.col(i-1)+0.5*h*k2);
        k4 = Func(t+h, y.col(i-1)+h*k3);
        y.col(i) = y.col(i-1) + (k1 + 2*k2 + 2*k3 + k4)*h/6;
        t = t+h;
    }
    return y.transpose();
}

将向量传递给要填充的函数显然需要在本征中考虑更高的模板。

相关文章