C++ 数值积分器来解决 ode 的系统
C++ numerical integrators to solve systems of ode's
我最近开始使用 C++,我刚刚创建了一个 class 允许集成用户定义的 ode 系统。它使用两个不同的积分器来比较其性能。这是代码的总体布局:
class integrators {
private:
double ti; // initial time
double *xi; // initial solution
double tf; // end time
double dt; // time step
int n; // number of ode's
public:
// Function prototypes
double f(double, double *, double *); // function to integrate
double rk4(int, double, double, double, double *, double *);
double dp8(int, double, double, double, double *, double *);
};
// 4th Order Runge-Kutta function
double integrators::rk4(int n, double ti, double tf, double dt, double *xi, double *xf) {
// Function statements
}
// 8th Order Dormand-Prince function
double integrators::dp8(int n, double ti, double tf, double dt, double *xi, double *xf) {
// Function statements
}
// System of first order differential equations
double integrators::f(double t, double *x, double *dx) {
// Function statements
}
int main() {
// Initial conditions and time related parameters
const int n = 4;
double t0, tmax, dt;
double x0[n], xf[n];
x0[0] = 0.0;
x0[1] = 0.0;
x0[2] = 1.0;
x0[3] = 2.0;
// Calling class integrators
integrators example01;
integrators example02;
// First integrator
example02.dp8(n, t0, tmax, dt, x0, xf);
// Second integrator
example01.rk4(n, t0, tmax, dt, x0, xf);
}
问题是包含 main 中初始条件 x0 的数组在执行第一个积分器后发生变化,我不能对第二个积分器使用相同的初始条件,除非我定义另一个具有相同初始条件的数组 (x0_rk4 和 x0_dp8)。有没有更专业的方法来保持这个数组不变,以便在两个积分器中使用它?
不,不是真的。但是有一个更优雅的解决方案:
std::array<double, n> x0_rk4 = { 0.0, 0.0, 1.0, 2.0 };
auto x0_dp8 = x0_rk4; // copy!
您将必须使用 x0_rk4.data()
来访问底层数组。请注意,如果您使用 std::array
和其他现代 C++ 功能而不是原始指针等会更好。
最简单的方法是在集成函数中创建数组的本地副本。
将传递 'n' 的方式更改为 'const int n',这样您就可以在内部创建类似 double currentSolution[n];
的内容,并将元素从初始数组复制到新数组。这种方法将完整地保存您的初始数组,除非您"accidently"在某处修改它。
为了防止这种意外修改的可能性,我们需要更深入地使用其中一个 stl 容器。我想 std::valarray<T>
你会没事的。
更改您将其传递给 const std::valarray<double>&
的方式并再次制作非常量本地副本。
我最近开始使用 C++,我刚刚创建了一个 class 允许集成用户定义的 ode 系统。它使用两个不同的积分器来比较其性能。这是代码的总体布局:
class integrators {
private:
double ti; // initial time
double *xi; // initial solution
double tf; // end time
double dt; // time step
int n; // number of ode's
public:
// Function prototypes
double f(double, double *, double *); // function to integrate
double rk4(int, double, double, double, double *, double *);
double dp8(int, double, double, double, double *, double *);
};
// 4th Order Runge-Kutta function
double integrators::rk4(int n, double ti, double tf, double dt, double *xi, double *xf) {
// Function statements
}
// 8th Order Dormand-Prince function
double integrators::dp8(int n, double ti, double tf, double dt, double *xi, double *xf) {
// Function statements
}
// System of first order differential equations
double integrators::f(double t, double *x, double *dx) {
// Function statements
}
int main() {
// Initial conditions and time related parameters
const int n = 4;
double t0, tmax, dt;
double x0[n], xf[n];
x0[0] = 0.0;
x0[1] = 0.0;
x0[2] = 1.0;
x0[3] = 2.0;
// Calling class integrators
integrators example01;
integrators example02;
// First integrator
example02.dp8(n, t0, tmax, dt, x0, xf);
// Second integrator
example01.rk4(n, t0, tmax, dt, x0, xf);
}
问题是包含 main 中初始条件 x0 的数组在执行第一个积分器后发生变化,我不能对第二个积分器使用相同的初始条件,除非我定义另一个具有相同初始条件的数组 (x0_rk4 和 x0_dp8)。有没有更专业的方法来保持这个数组不变,以便在两个积分器中使用它?
不,不是真的。但是有一个更优雅的解决方案:
std::array<double, n> x0_rk4 = { 0.0, 0.0, 1.0, 2.0 };
auto x0_dp8 = x0_rk4; // copy!
您将必须使用 x0_rk4.data()
来访问底层数组。请注意,如果您使用 std::array
和其他现代 C++ 功能而不是原始指针等会更好。
最简单的方法是在集成函数中创建数组的本地副本。
将传递 'n' 的方式更改为 'const int n',这样您就可以在内部创建类似 double currentSolution[n];
的内容,并将元素从初始数组复制到新数组。这种方法将完整地保存您的初始数组,除非您"accidently"在某处修改它。
为了防止这种意外修改的可能性,我们需要更深入地使用其中一个 stl 容器。我想 std::valarray<T>
你会没事的。
更改您将其传递给 const std::valarray<double>&
的方式并再次制作非常量本地副本。