getting_started.qbk 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. [/============================================================================
  2. Boost.odeint
  3. Copyright 2011-2013 Karsten Ahnert
  4. Copyright 2011-2012 Mario Mulansky
  5. Copyright 2012 Sylwester Arabas
  6. Use, modification and distribution is subject to the Boost Software License,
  7. Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  8. http://www.boost.org/LICENSE_1_0.txt)
  9. =============================================================================/]
  10. [section Getting started]
  11. [section Overview]
  12. odeint is a library for solving initial value problems (IVP) of ordinary
  13. differential equations. Mathematically, these problems are formulated as
  14. follows:
  15. ['x'(t) = f(x,t)], ['x(0) = x0].
  16. ['x] and ['f] can be vectors and the solution is some function ['x(t)] fulfilling both equations above. In the following we will refer to ['x'(t)] also `dxdt` which is also our notation for the derivative in the source code.
  17. Ordinary differential equations occur nearly everywhere in natural sciences. For example, the whole Newtonian mechanics are described by second order differential equations. Be sure, you will find them in every discipline. They also occur if partial differential equations (PDEs) are discretized. Then, a system of coupled ordinary differential occurs, sometimes also referred as lattices ODEs.
  18. Numerical approximations for the solution ['x(t)] are calculated iteratively. The easiest algorithm is the Euler scheme, where starting at ['x(0)] one finds ['x(dt) = x(0) + dt f(x(0),0)]. Now one can use ['x(dt)] and obtain ['x(2dt)] in a similar way and so on. The Euler method is of order 1, that means the error at each step is ['~ dt[super 2]]. This is, of course, not very satisfying, which is why the Euler method is rarely used for real life problems and serves just as illustrative example.
  19. The main focus of odeint is to provide numerical methods implemented in a way where the algorithm is completely independent on the data structure used to represent the state /x/.
  20. In doing so, odeint is applicable for a broad variety of situations and it can be used with many other libraries. Besides the usual case where the state is defined as a `std::vector` or a `boost::array`, we provide native support for the following libraries:
  21. * __ublas
  22. * __thrust, making odeint naturally running on CUDA devices
  23. * gsl_vector for compatibility with the many numerical function in the GSL
  24. * __boost_range
  25. * __boost_fusion (the state type can be a fusion vector)
  26. * __boost_units
  27. * __intel_mkl for maximum performance
  28. * __vexcl for OpenCL
  29. * __boost_graph (still experimentally)
  30. In odeint, the following algorithms are implemented:
  31. [include stepper_table.qbk]
  32. [endsect]
  33. [section Usage, Compilation, Headers]
  34. odeint is a header-only library, no linking against pre-compiled code is required. It can be included by
  35. ``
  36. #include <boost/numeric/odeint.hpp>
  37. ``
  38. which includes all headers of the library. All functions and classes from odeint live in the namespace
  39. ``
  40. using namespace boost::numeric::odeint;
  41. ``
  42. It is also possible to include only parts of the library. This is the recommended way since it saves a lot of compilation time.
  43. * `#include <boost/numeric/odeint/stepper/XYZ.hpp>` - the include path for all steppers, XYZ is a placeholder for a stepper.
  44. * `#include <boost/numeric/odeint/algebra/XYZ.hpp>` - all algebras.
  45. * `#include <boost/numeric/odeint/util/XYZ.hpp>` - the utility functions like `is_resizeable`, `same_size`, or `resize`.
  46. * `#include <boost/numeric/odeint/integrate/XYZ.hpp>` - the integrate routines.
  47. * `#include <boost/numeric/odeint/iterator/XYZ.hpp>` - the range and iterator functions.
  48. * `#include <boost/numeric/odeint/external/XYZ.hpp>` - any binders to external libraries.
  49. [endsect]
  50. [section Short Example]
  51. Imaging, you want to numerically integrate a harmonic oscillator with
  52. friction. The equations of motion are given by ['x'' = -x + __gamma x'].
  53. Odeint only deals with first order ODEs that have no higher derivatives than
  54. x' involved. However, any higher order ODE can be transformed to a system of
  55. first order ODEs by introducing the new variables ['q=x] and ['p=x'] such that ['w=(q,p)]. To apply numerical integration one first has to design the right hand side of the equation ['w' = f(w) = (p,-q+__gamma p)]:
  56. [import ../examples/harmonic_oscillator.cpp]
  57. [rhs_function]
  58. Here we chose `vector<double>` as the state type, but others are also
  59. possible, for example `boost::array<double,2>`. odeint is designed in such a
  60. way that you can easily use your own state types. Next, the ODE is defined
  61. which is in this case a simple function calculating ['f(x)]. The parameter
  62. signature of this function is crucial: the integration methods will always
  63. call them in the form `f(x, dxdt, t)` (there are exceptions for some special routines). So, even if there is no explicit time dependence, one has to define `t` as a function parameter.
  64. Now, we have to define the initial state from which the integration should start:
  65. [state_initialization]
  66. For the integration itself we'll use the `integrate` function, which is a convenient way to get quick results. It is based on the error-controlled `runge_kutta54_cash_karp` stepper (5th order) and uses adaptive step-size.
  67. [integration]
  68. The integrate function expects as parameters the rhs of the ode as defined
  69. above, the initial state `x`, the start-and end-time of the integration as
  70. well as the initial time step=size. Note, that `integrate` uses an adaptive step-size during
  71. the integration steps so the time points will not be equally spaced. The
  72. integration returns the number of steps that were applied and updates x which
  73. is set to the approximate solution of the ODE at the end of integration.
  74. It is also possible to represent the ode system as a class. The
  75. rhs must then be implemented as a functor - a class with an overloaded function call operator:
  76. [rhs_class]
  77. which can be used via
  78. [integration_class]
  79. In order to observe the solution
  80. during the integration steps all you have to do is
  81. to provide a reasonable observer. An example is
  82. [integrate_observer]
  83. which stores the intermediate steps in a container.
  84. Note, the argument structure of the ()-operator: odeint calls the observer
  85. exactly in this way, providing the current state and time. Now, you only have
  86. to pass this container to the integration function:
  87. [integrate_observ]
  88. That is all. You can use functional libraries like __boost_lambda or __boost_phoenix to ease the creation of observer functions.
  89. The full cpp file for this example can be found here: [github_link examples/harmonic_oscillator.cpp harmonic_oscillator.cpp]
  90. [endsect]
  91. [endsect]