常微分方程式(ODEs, O.D.E.: Ordinary Differential Equations)の初期値問題(IVP: Initial Value Problems)を解くためのライブラリ。
オイラー法、ルンゲクッタ法を始めとした様々な手法を適用可能。
オイラー法、ルンゲクッタ法を始めとした様々な手法を適用可能。
- Google: boost::numeric::odeint
- Yamamoto's Laboratory (山本昌志) / 講義ノート / 2004年度 / 計算機応用 (数値計算) / 計算機応用 (数値計算:C言語) / 常微分方程式と連立方程式のまとめ(後期中間試験に向けて) / 2 常微分方程式の数値計算法 # 2.5 高階の常微分方程式
- stackoverflow / 2014-02-03: Second order differential equation using C++ Boost odeint library
- Qiita
- ignis_fatuus / 2014-12-18: C++ Advent Calendar 2014|18日目 Boost.odeintの紹介
- hmito / 2019-11-09: C++で常微分方程式:boost::odeint入門
1階の連立常微分方程式に変換してやることで、問題を簡略化、つまり1階の連立常微分方程式のソルバーで計算が可能になる。
例えば、 について、
と置けば、
のように1階の連立常微分方程式に変換できる。更に高次の場合であっても、同様にして1次の連立常微分方程式に変換できる。
例えば、 について、
と置けば、
のように1階の連立常微分方程式に変換できる。更に高次の場合であっても、同様にして1次の連立常微分方程式に変換できる。
最も単純な例の一つとして、等加速度運動(放物運動)を挙げておく。
この例では UAM::operator() の引数 x[0,1] 及び x[2,3] が時刻 t における位置と速度であり、
これらの値を用いて、dxdt[0,1] 及び dxdt[2,3] に時刻 t における速度と加速度を算出し返してやる。
main() で呼んでいる integrate_const() の末尾に与えている lambda の引数 x[0,1] 及び x[2,3] により時刻 t における位置と速度が得られる。
stepper を変更すると、ソルバーを変更できる。
実行結果
この例では UAM::operator() の引数 x[0,1] 及び x[2,3] が時刻 t における位置と速度であり、
これらの値を用いて、dxdt[0,1] 及び dxdt[2,3] に時刻 t における速度と加速度を算出し返してやる。
main() で呼んでいる integrate_const() の末尾に与えている lambda の引数 x[0,1] 及び x[2,3] により時刻 t における位置と速度が得られる。
stepper を変更すると、ソルバーを変更できる。
/** * UAM - Uniform Accelerated Motion */ #include <cstdio> #include <cstdlib> #include <vector> #include <boost/numeric/odeint.hpp> struct UAM { typedef std::vector<double> State; State a; // a_{x,y} UAM(const State &_a) : a(_a) {} void operator()(const State& x, State& dxdt, const double t) { dxdt[0] = x[2]; // v_x(t) dxdt[1] = x[3]; // v_y(t) dxdt[2] = a[0]; // a_x(t) dxdt[3] = a[1]; // a_y(t) } }; int main(int argc, char *argv[]) { UAM::State x(4); // position_{x,y}(t), v_{x,y}(t) UAM::State a(2); // a_{x,y}(t) UAM::State t(2); // t_{0,1} double dt; if (argc != 10) { fprintf(stderr, "Usage: %s <x(t0)> <y(t0)> <vx(t0)> <vy(t0)> <ax(t)> <ay(t)> <t0> <t1> <dt>\n", argv[0]); return EXIT_FAILURE; } x[0] = atof(argv[1]); // x(t0) x[1] = atof(argv[2]); // y(t0) x[2] = atof(argv[3]); // v_x(t0) x[3] = atof(argv[4]); // v_y(t0) a[0] = atof(argv[5]); // a_x(t) a[1] = atof(argv[6]); // a_y(t) t[0] = atof(argv[7]); // t_0 t[1] = atof(argv[8]); // t_1 dt = atof(argv[9]); boost::numeric::odeint::runge_kutta4<UAM::State> stepper; UAM uam(a); size_t steps = boost::numeric::odeint::integrate_const(stepper, uam, x, t[0], t[1], dt, [&](const UAM::State& x, const double t) { printf("%f %f %f %f %f\n", t, x[0], x[1], x[2], x[3]); } ); return EXIT_SUCCESS; }
$ g++ uam.cpp && ./a.out 0 0 1 1 0 -0.1 0 20 1 | tee uam.txt 0.000000 0.000000 0.000000 1.000000 1.000000 1.000000 1.000000 0.950000 1.000000 0.900000 2.000000 2.000000 1.800000 1.000000 0.800000 3.000000 3.000000 2.550000 1.000000 0.700000 4.000000 4.000000 3.200000 1.000000 0.600000 5.000000 5.000000 3.750000 1.000000 0.500000 6.000000 6.000000 4.200000 1.000000 0.400000 7.000000 7.000000 4.550000 1.000000 0.300000 8.000000 8.000000 4.800000 1.000000 0.200000 9.000000 9.000000 4.950000 1.000000 0.100000 10.000000 10.000000 5.000000 1.000000 -0.000000 11.000000 11.000000 4.950000 1.000000 -0.100000 12.000000 12.000000 4.800000 1.000000 -0.200000 13.000000 13.000000 4.550000 1.000000 -0.300000 14.000000 14.000000 4.200000 1.000000 -0.400000 15.000000 15.000000 3.750000 1.000000 -0.500000 16.000000 16.000000 3.200000 1.000000 -0.600000 17.000000 17.000000 2.550000 1.000000 -0.700000 18.000000 18.000000 1.800000 1.000000 -0.800000 19.000000 19.000000 0.950000 1.000000 -0.900000 20.000000 20.000000 -0.000000 1.000000 -1.000000gnuplot によるプロット
plot [0:20] [0:6] 'uam.txt' using 2:3 w lp
タグ
コメントをかく