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;
}
上面的代码可以工作,并且经过了验证。但是,它有一些依赖项,因为它使用一些全局变量来工作:
gama
、OMEGA
、zeta
、alpha
、beta
、chi
、kappa
和phi
是我想要从.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();
}
将向量传递给要填充的函数显然需要在本征中考虑更高的模板。
相关文章