...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
Home | Libraries | People | FAQ | More |
Most steppers in odeint also accept the state give as a range. A range is
sequence of values modeled by a range concept. See Boost.Range
for an overview over existing concepts and examples of ranges. This means
that the state_type
of the
stepper need not necessarily be used to call the do_step
method.
One use-case for Boost.Range in odeint has been shown in Chaotic System where the state consists of two parts: one for the original system and one for the perturbations. The ranges are used to initialize (solve) only the system part where the perturbation part is not touched, that is a range consisting only of the system part is used. After that the complete state including the perturbations is solved.
Another use case is a system consisting of coupled units where you want to initialize each unit separately with the ODE of the uncoupled unit. An example is a chain of coupled van-der-Pol-oscillators which are initialized uniformly from the uncoupled van-der-Pol-oscillator. Then you can use Boost.Range to solve only one individual oscillator in the chain.
In short, you can Boost.Range to use one state within two system functions which expect states with different sizes.
An example was given in the Chaotic
System tutorial. Using Boost.Range usually means that your system
function needs to adapt to the iterators of Boost.Range. That is, your function
is called with a range and you need to get the iterators from that range.
This can easily be done. You have to implement your system as a class or
a struct and you have to templatize the operator()
. Then you can use the range_iterator
-meta
function and boost::begin
and boost::end
to
obtain the iterators of your range:
class sys { template< class State , class Deriv > void operator()( const State &x_ , Deriv &dxdt_ , double t ) const { typename boost::range_iterator< const State >::type x = boost::begin( x_ ); typename boost::range_iterator< Deriv >::type dxdt = boost::begin( dxdt_ ); // fill dxdt } };
If your range is a random access-range you can also apply the bracket operator to the iterator to access the elements in the range:
class sys { template< class State , class Deriv > void operator()( const State &x_ , Deriv &dxdt_ , double t ) const { typename boost::range_iterator< const State >::type x = boost::begin( x_ ); typename boost::range_iterator< Deriv >::type dxdt = boost::begin( dxdt_ ); dxdt[0] = f1( x[0] , x[1] ); dxdt[1] = f2( x[0] , x[1] ); } };
The following two tables show which steppers and which algebras are compatible with Boost.Range.
Table 1.9. Steppers supporting Boost.Range
Stepper |
---|
adams_bashforth_moulton |
bulirsch_stoer_dense_out |
bulirsch_stoer |
controlled_runge_kutta |
dense_output_runge_kutta |
euler |
explicit_error_generic_rk |
explicit_generic_rk |
rosenbrock4_controller |
rosenbrock4_dense_output |
rosenbrock4 |
runge_kutta4_classic |
runge_kutta4 |
runge_kutta_cash_karp54_classic |
runge_kutta_cash_karp54 |
runge_kutta_dopri5 |
runge_kutta_fehlberg78 |
symplectic_euler |
symplectic_rkn_sb3a_mclachlan |