...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 |
In the Tutorial we have
learned how we can use the generation functions make_controlled
and make_dense_output
to
create controlled and dense output stepper from a simple stepper or an error
stepper. The syntax of these two functions is very simple:
auto stepper1 = make_controlled( 1.0e-6 , 1.0e-6 , stepper_type() ); // or with max step size limit: // auto stepper1 = make_controlled( 1.0e-6 , 1.0e-6 , 0.01, stepper_type() ); auto stepper2 = make_dense_output( 1.0e-6 , 1.0e-6 , stepper_type() );
The first two parameters are the absolute and the relative error tolerances
and the third parameter is the stepper. Additionally, a second version exists
where additionally a maximal step size is supplied which ensures the the
step size is not increased above this value. In C++03 you can infer the type
from the result_of
mechanism:
boost::numeric::odeint::result_of::make_controlled< stepper_type >::type stepper3 = make_controlled( 1.0e-6 , 1.0e-6 , stepper_type() ); (void)stepper3; boost::numeric::odeint::result_of::make_dense_output< stepper_type >::type stepper4 = make_dense_output( 1.0e-6 , 1.0e-6 , stepper_type() ); (void)stepper4;
To use your own steppers with the make_controlled
or make_dense_output
you
need to specialize two class templates. Suppose your steppers are called
custom_stepper
, custom_controller
and custom_dense_output
.
Then, the first class you need to specialize is boost::numeric::get_controller
,
a meta function returning the type of the controller:
namespace boost { namespace numeric { namespace odeint { template<> struct get_controller< custom_stepper > { typedef custom_controller type; }; } } }
The second one is a factory class boost::numeric::odeint::controller_factory
which constructs the controller from the tolerances and the stepper. In our
dummy implementation this class is
namespace boost { namespace numeric { namespace odeint { template<> struct controller_factory< custom_stepper , custom_controller > { custom_controller operator()( double abs_tol , double rel_tol , const custom_stepper & ) const { return custom_controller(); } custom_controller operator()( double abs_tol , double rel_tol , double max_dt , const custom_stepper & ) const { // version with maximal allowed step size max_dt return custom_controller(); } }; } } }
This is all to use the make_controlled
mechanism. Now you can use your controller via
auto stepper5 = make_controlled( 1.0e-6 , 1.0e-6 , custom_stepper() );
For the dense_output_stepper everything works similar. Here you have to specialize
boost::numeric::odeint::get_dense_output
and boost::numeric::odeint::dense_output_factory
.
These two classes have the same syntax as their relatives get_controller
and controller_factory
.
All controllers and dense-output steppers in odeint can be used with these
mechanisms. In the table below you will find, which steppers is constructed
from make_controlled
or
make_dense_output
if applied
on a stepper from odeint:
Table 1.7. Generation functions make_controlled( abs_error , rel_error , stepper )
Stepper |
Result of make_controlled |
Remarks |
---|---|---|
|
|
ax=1, adxdt=1 |
|
|
ax=1, adxdt=1 |
|
|
a x=1, adxdt=1 |
|
|
- |
Table 1.8. Generation functions make_dense_output( abs_error , rel_error , stepper )
Stepper |
Result of make_dense_output |
Remarks |
---|---|---|
|
|
a x=1, adxdt=1 |
|
|
- |