C++ n维系统的模块化Runge-kutta四阶方法的实现
我想把我的龙格库塔四阶码模块化。我不希望每次使用代码时都要编写和声明代码,但是在.hpp和.cpp文件中声明代码,以便分别使用它。但是我有一些问题。通常我想解一个n维方程组。为此,我使用了两个函数:一个用于方程组,另一个用于龙格-库塔法,如下所示:C++ n维系统的模块化Runge-kutta四阶方法的实现,c++,header-files,numerical-methods,runge-kutta,C++,Header Files,Numerical Methods,Runge Kutta,我想把我的龙格库塔四阶码模块化。我不希望每次使用代码时都要编写和声明代码,但是在.hpp和.cpp文件中声明代码,以便分别使用它。但是我有一些问题。通常我想解一个n维方程组。为此,我使用了两个函数:一个用于方程组,另一个用于龙格-库塔法,如下所示: double F(double t, double x[], int eq) { // System equations if (eq == 0) { return (x[1]); } else if (eq ==
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; }
}
使用向量函数,其中向量算法取自特征值3
#include <eigen3/Eigen/Dense>
using namespace Eigen;
#包括
使用名称空间特征;
与问题中讨论的相同部分的
VectorXd Func(常数双t,常数向量xd&x)
{//求解简谐振子的方程
矢量3d-dxdt;
dxdt[0]=x[1];
dxdt[1]=gama*sin(ω*t)-zeta*x[1]-alpha*x[0]-beta*pow(x[0],3)-chi*x[2];
dxdt[2]=-kappa*x[1]-phi*x[2];
返回dxdt;
}
矩阵XXD RK4(向量xd Func(双t,常量向量xd&y),常量Ref&y0,双t,双h,整数步长)
{
矩阵y(y0.rows(),步数);
矢量xd k1,k2,k3,k4;
y、 col(0)=y0;
对于(It i=1;II高度怀疑代码是RK4方法的代码。您只得到订单1方法,而不是预期的订单4方法。测试它,用不同大小的已知解决方案计算非标量测试问题的错误。您正在使用C++。您是否想过将ODE系统实现为导出维度的类。n和ODE函数(通过某些接口或基类)这个振荡器是一个圆耦合系统。你也验证了方法的顺序吗?正如我所说,这个方法仍然是1阶的,并且在第一步之后,数组将被填充1阶正确的值,所以如果步长足够小,仍然可以得到视觉上正确的结果。对于一些有大量样板的C++代码。看看答案,或者是一个更简单的实现,通过一些巧妙的指针处理,您可以在循环中压缩RK4的各个阶段,使用系数数组c={0,0.5,0.5,1};
和b={1,2,2,1};
来同时计算导数并更新下一个状态向量。
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
#include <eigen3/Eigen/Dense>
using namespace 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();
}