controlled_runge_kutta.hpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014
  1. /* [auto_generated]
  2. boost/numeric/odeint/stepper/controlled_runge_kutta.hpp
  3. [begin_description]
  4. The default controlled stepper which can be used with all explicit Runge-Kutta error steppers.
  5. [end_description]
  6. Copyright 2010-2013 Karsten Ahnert
  7. Copyright 2010-2015 Mario Mulansky
  8. Copyright 2012 Christoph Koke
  9. Distributed under the Boost Software License, Version 1.0.
  10. (See accompanying file LICENSE_1_0.txt or
  11. copy at http://www.boost.org/LICENSE_1_0.txt)
  12. */
  13. #ifndef BOOST_NUMERIC_ODEINT_STEPPER_CONTROLLED_RUNGE_KUTTA_HPP_INCLUDED
  14. #define BOOST_NUMERIC_ODEINT_STEPPER_CONTROLLED_RUNGE_KUTTA_HPP_INCLUDED
  15. #include <cmath>
  16. #include <boost/config.hpp>
  17. #include <boost/utility/enable_if.hpp>
  18. #include <boost/type_traits/is_same.hpp>
  19. #include <boost/numeric/odeint/util/bind.hpp>
  20. #include <boost/numeric/odeint/util/unwrap_reference.hpp>
  21. #include <boost/numeric/odeint/util/copy.hpp>
  22. #include <boost/numeric/odeint/util/state_wrapper.hpp>
  23. #include <boost/numeric/odeint/util/is_resizeable.hpp>
  24. #include <boost/numeric/odeint/util/resizer.hpp>
  25. #include <boost/numeric/odeint/util/detail/less_with_sign.hpp>
  26. #include <boost/numeric/odeint/algebra/range_algebra.hpp>
  27. #include <boost/numeric/odeint/algebra/default_operations.hpp>
  28. #include <boost/numeric/odeint/algebra/algebra_dispatcher.hpp>
  29. #include <boost/numeric/odeint/stepper/controlled_step_result.hpp>
  30. #include <boost/numeric/odeint/stepper/stepper_categories.hpp>
  31. namespace boost {
  32. namespace numeric {
  33. namespace odeint {
  34. template
  35. <
  36. class Value ,
  37. class Algebra ,
  38. class Operations
  39. >
  40. class default_error_checker
  41. {
  42. public:
  43. typedef Value value_type;
  44. typedef Algebra algebra_type;
  45. typedef Operations operations_type;
  46. default_error_checker(
  47. value_type eps_abs = static_cast< value_type >( 1.0e-6 ) ,
  48. value_type eps_rel = static_cast< value_type >( 1.0e-6 ) ,
  49. value_type a_x = static_cast< value_type >( 1 ) ,
  50. value_type a_dxdt = static_cast< value_type >( 1 ))
  51. : m_eps_abs( eps_abs ) , m_eps_rel( eps_rel ) , m_a_x( a_x ) , m_a_dxdt( a_dxdt )
  52. { }
  53. template< class State , class Deriv , class Err, class Time >
  54. value_type error( const State &x_old , const Deriv &dxdt_old , Err &x_err , Time dt ) const
  55. {
  56. return error( algebra_type() , x_old , dxdt_old , x_err , dt );
  57. }
  58. template< class State , class Deriv , class Err, class Time >
  59. value_type error( algebra_type &algebra , const State &x_old , const Deriv &dxdt_old , Err &x_err , Time dt ) const
  60. {
  61. using std::abs;
  62. // this overwrites x_err !
  63. algebra.for_each3( x_err , x_old , dxdt_old ,
  64. typename operations_type::template rel_error< value_type >( m_eps_abs , m_eps_rel , m_a_x , m_a_dxdt * abs(get_unit_value( dt )) ) );
  65. // value_type res = algebra.reduce( x_err ,
  66. // typename operations_type::template maximum< value_type >() , static_cast< value_type >( 0 ) );
  67. return algebra.norm_inf( x_err );
  68. }
  69. private:
  70. value_type m_eps_abs;
  71. value_type m_eps_rel;
  72. value_type m_a_x;
  73. value_type m_a_dxdt;
  74. };
  75. template< typename Value, typename Time >
  76. class default_step_adjuster
  77. {
  78. public:
  79. typedef Time time_type;
  80. typedef Value value_type;
  81. default_step_adjuster(const time_type max_dt=static_cast<time_type>(0))
  82. : m_max_dt(max_dt)
  83. {}
  84. time_type decrease_step(time_type dt, const value_type error, const int error_order) const
  85. {
  86. // returns the decreased time step
  87. BOOST_USING_STD_MIN();
  88. BOOST_USING_STD_MAX();
  89. using std::pow;
  90. dt *= max
  91. BOOST_PREVENT_MACRO_SUBSTITUTION(
  92. static_cast<value_type>( static_cast<value_type>(9) / static_cast<value_type>(10) *
  93. pow(error, static_cast<value_type>(-1) / (error_order - 1))),
  94. static_cast<value_type>( static_cast<value_type>(1) / static_cast<value_type> (5)));
  95. if(m_max_dt != static_cast<time_type >(0))
  96. // limit to maximal stepsize even when decreasing
  97. dt = detail::min_abs(dt, m_max_dt);
  98. return dt;
  99. }
  100. time_type increase_step(time_type dt, value_type error, const int stepper_order) const
  101. {
  102. // returns the increased time step
  103. BOOST_USING_STD_MIN();
  104. BOOST_USING_STD_MAX();
  105. using std::pow;
  106. // adjust the size if dt is smaller than max_dt (providede max_dt is not zero)
  107. if(error < 0.5)
  108. {
  109. // error should be > 0
  110. error = max BOOST_PREVENT_MACRO_SUBSTITUTION (
  111. static_cast<value_type>( pow( static_cast<value_type>(5.0) , -static_cast<value_type>(stepper_order) ) ) ,
  112. error);
  113. // time_type dt_old = dt; unused variable warning
  114. //error too small - increase dt and keep the evolution and limit scaling factor to 5.0
  115. dt *= static_cast<value_type>(9)/static_cast<value_type>(10) *
  116. pow(error, static_cast<value_type>(-1) / stepper_order);
  117. if(m_max_dt != static_cast<time_type >(0))
  118. // limit to maximal stepsize
  119. dt = detail::min_abs(dt, m_max_dt);
  120. }
  121. return dt;
  122. }
  123. bool check_step_size_limit(const time_type dt)
  124. {
  125. if(m_max_dt != static_cast<time_type >(0))
  126. return detail::less_eq_with_sign(dt, m_max_dt, dt);
  127. return true;
  128. }
  129. time_type get_max_dt() { return m_max_dt; }
  130. private:
  131. time_type m_max_dt;
  132. };
  133. /*
  134. * error stepper category dispatcher
  135. */
  136. template<
  137. class ErrorStepper ,
  138. class ErrorChecker = default_error_checker< typename ErrorStepper::value_type ,
  139. typename ErrorStepper::algebra_type ,
  140. typename ErrorStepper::operations_type > ,
  141. class StepAdjuster = default_step_adjuster< typename ErrorStepper::value_type ,
  142. typename ErrorStepper::time_type > ,
  143. class Resizer = typename ErrorStepper::resizer_type ,
  144. class ErrorStepperCategory = typename ErrorStepper::stepper_category
  145. >
  146. class controlled_runge_kutta ;
  147. /*
  148. * explicit stepper version
  149. *
  150. * this class introduces the following try_step overloads
  151. * try_step( sys , x , t , dt )
  152. * try_step( sys , x , dxdt , t , dt )
  153. * try_step( sys , in , t , out , dt )
  154. * try_step( sys , in , dxdt , t , out , dt )
  155. */
  156. /**
  157. * \brief Implements step size control for Runge-Kutta steppers with error
  158. * estimation.
  159. *
  160. * This class implements the step size control for standard Runge-Kutta
  161. * steppers with error estimation.
  162. *
  163. * \tparam ErrorStepper The stepper type with error estimation, has to fulfill the ErrorStepper concept.
  164. * \tparam ErrorChecker The error checker
  165. * \tparam Resizer The resizer policy type.
  166. */
  167. template<
  168. class ErrorStepper,
  169. class ErrorChecker,
  170. class StepAdjuster,
  171. class Resizer
  172. >
  173. class controlled_runge_kutta< ErrorStepper , ErrorChecker , StepAdjuster, Resizer ,
  174. explicit_error_stepper_tag >
  175. {
  176. public:
  177. typedef ErrorStepper stepper_type;
  178. typedef typename stepper_type::state_type state_type;
  179. typedef typename stepper_type::value_type value_type;
  180. typedef typename stepper_type::deriv_type deriv_type;
  181. typedef typename stepper_type::time_type time_type;
  182. typedef typename stepper_type::algebra_type algebra_type;
  183. typedef typename stepper_type::operations_type operations_type;
  184. typedef Resizer resizer_type;
  185. typedef ErrorChecker error_checker_type;
  186. typedef StepAdjuster step_adjuster_type;
  187. typedef explicit_controlled_stepper_tag stepper_category;
  188. #ifndef DOXYGEN_SKIP
  189. typedef typename stepper_type::wrapped_state_type wrapped_state_type;
  190. typedef typename stepper_type::wrapped_deriv_type wrapped_deriv_type;
  191. typedef controlled_runge_kutta< ErrorStepper , ErrorChecker , StepAdjuster ,
  192. Resizer , explicit_error_stepper_tag > controlled_stepper_type;
  193. #endif //DOXYGEN_SKIP
  194. /**
  195. * \brief Constructs the controlled Runge-Kutta stepper.
  196. * \param error_checker An instance of the error checker.
  197. * \param stepper An instance of the underlying stepper.
  198. */
  199. controlled_runge_kutta(
  200. const error_checker_type &error_checker = error_checker_type( ) ,
  201. const step_adjuster_type &step_adjuster = step_adjuster_type() ,
  202. const stepper_type &stepper = stepper_type( )
  203. )
  204. : m_stepper(stepper), m_error_checker(error_checker) , m_step_adjuster(step_adjuster)
  205. { }
  206. /*
  207. * Version 1 : try_step( sys , x , t , dt )
  208. *
  209. * The overloads are needed to solve the forwarding problem
  210. */
  211. /**
  212. * \brief Tries to perform one step.
  213. *
  214. * This method tries to do one step with step size dt. If the error estimate
  215. * is to large, the step is rejected and the method returns fail and the
  216. * step size dt is reduced. If the error estimate is acceptably small, the
  217. * step is performed, success is returned and dt might be increased to make
  218. * the steps as large as possible. This method also updates t if a step is
  219. * performed.
  220. *
  221. * \param system The system function to solve, hence the r.h.s. of the ODE. It must fulfill the
  222. * Simple System concept.
  223. * \param x The state of the ODE which should be solved. Overwritten if
  224. * the step is successful.
  225. * \param t The value of the time. Updated if the step is successful.
  226. * \param dt The step size. Updated.
  227. * \return success if the step was accepted, fail otherwise.
  228. */
  229. template< class System , class StateInOut >
  230. controlled_step_result try_step( System system , StateInOut &x , time_type &t , time_type &dt )
  231. {
  232. return try_step_v1( system , x , t, dt );
  233. }
  234. /**
  235. * \brief Tries to perform one step. Solves the forwarding problem and
  236. * allows for using boost range as state_type.
  237. *
  238. * This method tries to do one step with step size dt. If the error estimate
  239. * is to large, the step is rejected and the method returns fail and the
  240. * step size dt is reduced. If the error estimate is acceptably small, the
  241. * step is performed, success is returned and dt might be increased to make
  242. * the steps as large as possible. This method also updates t if a step is
  243. * performed.
  244. *
  245. * \param system The system function to solve, hence the r.h.s. of the ODE. It must fulfill the
  246. * Simple System concept.
  247. * \param x The state of the ODE which should be solved. Overwritten if
  248. * the step is successful. Can be a boost range.
  249. * \param t The value of the time. Updated if the step is successful.
  250. * \param dt The step size. Updated.
  251. * \return success if the step was accepted, fail otherwise.
  252. */
  253. template< class System , class StateInOut >
  254. controlled_step_result try_step( System system , const StateInOut &x , time_type &t , time_type &dt )
  255. {
  256. return try_step_v1( system , x , t, dt );
  257. }
  258. /*
  259. * Version 2 : try_step( sys , x , dxdt , t , dt )
  260. *
  261. * this version does not solve the forwarding problem, boost.range can not be used
  262. */
  263. /**
  264. * \brief Tries to perform one step.
  265. *
  266. * This method tries to do one step with step size dt. If the error estimate
  267. * is to large, the step is rejected and the method returns fail and the
  268. * step size dt is reduced. If the error estimate is acceptably small, the
  269. * step is performed, success is returned and dt might be increased to make
  270. * the steps as large as possible. This method also updates t if a step is
  271. * performed.
  272. *
  273. * \param system The system function to solve, hence the r.h.s. of the ODE. It must fulfill the
  274. * Simple System concept.
  275. * \param x The state of the ODE which should be solved. Overwritten if
  276. * the step is successful.
  277. * \param dxdt The derivative of state.
  278. * \param t The value of the time. Updated if the step is successful.
  279. * \param dt The step size. Updated.
  280. * \return success if the step was accepted, fail otherwise.
  281. */
  282. template< class System , class StateInOut , class DerivIn >
  283. controlled_step_result try_step( System system , StateInOut &x , const DerivIn &dxdt , time_type &t , time_type &dt )
  284. {
  285. m_xnew_resizer.adjust_size( x , detail::bind( &controlled_runge_kutta::template resize_m_xnew_impl< StateInOut > , detail::ref( *this ) , detail::_1 ) );
  286. controlled_step_result res = try_step( system , x , dxdt , t , m_xnew.m_v , dt );
  287. if( res == success )
  288. {
  289. boost::numeric::odeint::copy( m_xnew.m_v , x );
  290. }
  291. return res;
  292. }
  293. /*
  294. * Version 3 : try_step( sys , in , t , out , dt )
  295. *
  296. * this version does not solve the forwarding problem, boost.range can not be used
  297. *
  298. * the disable is needed to avoid ambiguous overloads if state_type = time_type
  299. */
  300. /**
  301. * \brief Tries to perform one step.
  302. *
  303. * \note This method is disabled if state_type=time_type to avoid ambiguity.
  304. *
  305. * This method tries to do one step with step size dt. If the error estimate
  306. * is to large, the step is rejected and the method returns fail and the
  307. * step size dt is reduced. If the error estimate is acceptably small, the
  308. * step is performed, success is returned and dt might be increased to make
  309. * the steps as large as possible. This method also updates t if a step is
  310. * performed.
  311. *
  312. * \param system The system function to solve, hence the r.h.s. of the ODE. It must fulfill the
  313. * Simple System concept.
  314. * \param in The state of the ODE which should be solved.
  315. * \param t The value of the time. Updated if the step is successful.
  316. * \param out Used to store the result of the step.
  317. * \param dt The step size. Updated.
  318. * \return success if the step was accepted, fail otherwise.
  319. */
  320. template< class System , class StateIn , class StateOut >
  321. typename boost::disable_if< boost::is_same< StateIn , time_type > , controlled_step_result >::type
  322. try_step( System system , const StateIn &in , time_type &t , StateOut &out , time_type &dt )
  323. {
  324. typename odeint::unwrap_reference< System >::type &sys = system;
  325. m_dxdt_resizer.adjust_size( in , detail::bind( &controlled_runge_kutta::template resize_m_dxdt_impl< StateIn > , detail::ref( *this ) , detail::_1 ) );
  326. sys( in , m_dxdt.m_v , t );
  327. return try_step( system , in , m_dxdt.m_v , t , out , dt );
  328. }
  329. /*
  330. * Version 4 : try_step( sys , in , dxdt , t , out , dt )
  331. *
  332. * this version does not solve the forwarding problem, boost.range can not be used
  333. */
  334. /**
  335. * \brief Tries to perform one step.
  336. *
  337. * This method tries to do one step with step size dt. If the error estimate
  338. * is to large, the step is rejected and the method returns fail and the
  339. * step size dt is reduced. If the error estimate is acceptably small, the
  340. * step is performed, success is returned and dt might be increased to make
  341. * the steps as large as possible. This method also updates t if a step is
  342. * performed.
  343. *
  344. * \param system The system function to solve, hence the r.h.s. of the ODE. It must fulfill the
  345. * Simple System concept.
  346. * \param in The state of the ODE which should be solved.
  347. * \param dxdt The derivative of state.
  348. * \param t The value of the time. Updated if the step is successful.
  349. * \param out Used to store the result of the step.
  350. * \param dt The step size. Updated.
  351. * \return success if the step was accepted, fail otherwise.
  352. */
  353. template< class System , class StateIn , class DerivIn , class StateOut >
  354. controlled_step_result try_step( System system , const StateIn &in , const DerivIn &dxdt , time_type &t , StateOut &out , time_type &dt )
  355. {
  356. if( !m_step_adjuster.check_step_size_limit(dt) )
  357. {
  358. // given dt was above step size limit - adjust and return fail;
  359. dt = m_step_adjuster.get_max_dt();
  360. return fail;
  361. }
  362. m_xerr_resizer.adjust_size( in , detail::bind( &controlled_runge_kutta::template resize_m_xerr_impl< StateIn > , detail::ref( *this ) , detail::_1 ) );
  363. // do one step with error calculation
  364. m_stepper.do_step( system , in , dxdt , t , out , dt , m_xerr.m_v );
  365. value_type max_rel_err = m_error_checker.error( m_stepper.algebra() , in , dxdt , m_xerr.m_v , dt );
  366. if( max_rel_err > 1.0 )
  367. {
  368. // error too big, decrease step size and reject this step
  369. dt = m_step_adjuster.decrease_step(dt, max_rel_err, m_stepper.error_order());
  370. return fail;
  371. } else
  372. {
  373. // otherwise, increase step size and accept
  374. t += dt;
  375. dt = m_step_adjuster.increase_step(dt, max_rel_err, m_stepper.stepper_order());
  376. return success;
  377. }
  378. }
  379. /**
  380. * \brief Adjust the size of all temporaries in the stepper manually.
  381. * \param x A state from which the size of the temporaries to be resized is deduced.
  382. */
  383. template< class StateType >
  384. void adjust_size( const StateType &x )
  385. {
  386. resize_m_xerr_impl( x );
  387. resize_m_dxdt_impl( x );
  388. resize_m_xnew_impl( x );
  389. m_stepper.adjust_size( x );
  390. }
  391. /**
  392. * \brief Returns the instance of the underlying stepper.
  393. * \returns The instance of the underlying stepper.
  394. */
  395. stepper_type& stepper( void )
  396. {
  397. return m_stepper;
  398. }
  399. /**
  400. * \brief Returns the instance of the underlying stepper.
  401. * \returns The instance of the underlying stepper.
  402. */
  403. const stepper_type& stepper( void ) const
  404. {
  405. return m_stepper;
  406. }
  407. private:
  408. template< class System , class StateInOut >
  409. controlled_step_result try_step_v1( System system , StateInOut &x , time_type &t , time_type &dt )
  410. {
  411. typename odeint::unwrap_reference< System >::type &sys = system;
  412. m_dxdt_resizer.adjust_size( x , detail::bind( &controlled_runge_kutta::template resize_m_dxdt_impl< StateInOut > , detail::ref( *this ) , detail::_1 ) );
  413. sys( x , m_dxdt.m_v ,t );
  414. return try_step( system , x , m_dxdt.m_v , t , dt );
  415. }
  416. template< class StateIn >
  417. bool resize_m_xerr_impl( const StateIn &x )
  418. {
  419. return adjust_size_by_resizeability( m_xerr , x , typename is_resizeable<state_type>::type() );
  420. }
  421. template< class StateIn >
  422. bool resize_m_dxdt_impl( const StateIn &x )
  423. {
  424. return adjust_size_by_resizeability( m_dxdt , x , typename is_resizeable<deriv_type>::type() );
  425. }
  426. template< class StateIn >
  427. bool resize_m_xnew_impl( const StateIn &x )
  428. {
  429. return adjust_size_by_resizeability( m_xnew , x , typename is_resizeable<state_type>::type() );
  430. }
  431. stepper_type m_stepper;
  432. error_checker_type m_error_checker;
  433. step_adjuster_type m_step_adjuster;
  434. resizer_type m_dxdt_resizer;
  435. resizer_type m_xerr_resizer;
  436. resizer_type m_xnew_resizer;
  437. wrapped_deriv_type m_dxdt;
  438. wrapped_state_type m_xerr;
  439. wrapped_state_type m_xnew;
  440. };
  441. /*
  442. * explicit stepper fsal version
  443. *
  444. * the class introduces the following try_step overloads
  445. * try_step( sys , x , t , dt )
  446. * try_step( sys , in , t , out , dt )
  447. * try_step( sys , x , dxdt , t , dt )
  448. * try_step( sys , in , dxdt_in , t , out , dxdt_out , dt )
  449. */
  450. /**
  451. * \brief Implements step size control for Runge-Kutta FSAL steppers with
  452. * error estimation.
  453. *
  454. * This class implements the step size control for FSAL Runge-Kutta
  455. * steppers with error estimation.
  456. *
  457. * \tparam ErrorStepper The stepper type with error estimation, has to fulfill the ErrorStepper concept.
  458. * \tparam ErrorChecker The error checker
  459. * \tparam Resizer The resizer policy type.
  460. */
  461. template<
  462. class ErrorStepper ,
  463. class ErrorChecker ,
  464. class StepAdjuster ,
  465. class Resizer
  466. >
  467. class controlled_runge_kutta< ErrorStepper , ErrorChecker , StepAdjuster , Resizer , explicit_error_stepper_fsal_tag >
  468. {
  469. public:
  470. typedef ErrorStepper stepper_type;
  471. typedef typename stepper_type::state_type state_type;
  472. typedef typename stepper_type::value_type value_type;
  473. typedef typename stepper_type::deriv_type deriv_type;
  474. typedef typename stepper_type::time_type time_type;
  475. typedef typename stepper_type::algebra_type algebra_type;
  476. typedef typename stepper_type::operations_type operations_type;
  477. typedef Resizer resizer_type;
  478. typedef ErrorChecker error_checker_type;
  479. typedef StepAdjuster step_adjuster_type;
  480. typedef explicit_controlled_stepper_fsal_tag stepper_category;
  481. #ifndef DOXYGEN_SKIP
  482. typedef typename stepper_type::wrapped_state_type wrapped_state_type;
  483. typedef typename stepper_type::wrapped_deriv_type wrapped_deriv_type;
  484. typedef controlled_runge_kutta< ErrorStepper , ErrorChecker , StepAdjuster , Resizer , explicit_error_stepper_tag > controlled_stepper_type;
  485. #endif // DOXYGEN_SKIP
  486. /**
  487. * \brief Constructs the controlled Runge-Kutta stepper.
  488. * \param error_checker An instance of the error checker.
  489. * \param stepper An instance of the underlying stepper.
  490. */
  491. controlled_runge_kutta(
  492. const error_checker_type &error_checker = error_checker_type() ,
  493. const step_adjuster_type &step_adjuster = step_adjuster_type() ,
  494. const stepper_type &stepper = stepper_type()
  495. )
  496. : m_stepper( stepper ) , m_error_checker( error_checker ) , m_step_adjuster(step_adjuster) ,
  497. m_first_call( true )
  498. { }
  499. /*
  500. * Version 1 : try_step( sys , x , t , dt )
  501. *
  502. * The two overloads are needed in order to solve the forwarding problem
  503. */
  504. /**
  505. * \brief Tries to perform one step.
  506. *
  507. * This method tries to do one step with step size dt. If the error estimate
  508. * is to large, the step is rejected and the method returns fail and the
  509. * step size dt is reduced. If the error estimate is acceptably small, the
  510. * step is performed, success is returned and dt might be increased to make
  511. * the steps as large as possible. This method also updates t if a step is
  512. * performed.
  513. *
  514. * \param system The system function to solve, hence the r.h.s. of the ODE. It must fulfill the
  515. * Simple System concept.
  516. * \param x The state of the ODE which should be solved. Overwritten if
  517. * the step is successful.
  518. * \param t The value of the time. Updated if the step is successful.
  519. * \param dt The step size. Updated.
  520. * \return success if the step was accepted, fail otherwise.
  521. */
  522. template< class System , class StateInOut >
  523. controlled_step_result try_step( System system , StateInOut &x , time_type &t , time_type &dt )
  524. {
  525. return try_step_v1( system , x , t , dt );
  526. }
  527. /**
  528. * \brief Tries to perform one step. Solves the forwarding problem and
  529. * allows for using boost range as state_type.
  530. *
  531. * This method tries to do one step with step size dt. If the error estimate
  532. * is to large, the step is rejected and the method returns fail and the
  533. * step size dt is reduced. If the error estimate is acceptably small, the
  534. * step is performed, success is returned and dt might be increased to make
  535. * the steps as large as possible. This method also updates t if a step is
  536. * performed.
  537. *
  538. * \param system The system function to solve, hence the r.h.s. of the ODE. It must fulfill the
  539. * Simple System concept.
  540. * \param x The state of the ODE which should be solved. Overwritten if
  541. * the step is successful. Can be a boost range.
  542. * \param t The value of the time. Updated if the step is successful.
  543. * \param dt The step size. Updated.
  544. * \return success if the step was accepted, fail otherwise.
  545. */
  546. template< class System , class StateInOut >
  547. controlled_step_result try_step( System system , const StateInOut &x , time_type &t , time_type &dt )
  548. {
  549. return try_step_v1( system , x , t , dt );
  550. }
  551. /*
  552. * Version 2 : try_step( sys , in , t , out , dt );
  553. *
  554. * This version does not solve the forwarding problem, boost::range can not be used.
  555. *
  556. * The disabler is needed to solve ambiguous overloads
  557. */
  558. /**
  559. * \brief Tries to perform one step.
  560. *
  561. * \note This method is disabled if state_type=time_type to avoid ambiguity.
  562. *
  563. * This method tries to do one step with step size dt. If the error estimate
  564. * is to large, the step is rejected and the method returns fail and the
  565. * step size dt is reduced. If the error estimate is acceptably small, the
  566. * step is performed, success is returned and dt might be increased to make
  567. * the steps as large as possible. This method also updates t if a step is
  568. * performed.
  569. *
  570. * \param system The system function to solve, hence the r.h.s. of the ODE. It must fulfill the
  571. * Simple System concept.
  572. * \param in The state of the ODE which should be solved.
  573. * \param t The value of the time. Updated if the step is successful.
  574. * \param out Used to store the result of the step.
  575. * \param dt The step size. Updated.
  576. * \return success if the step was accepted, fail otherwise.
  577. */
  578. template< class System , class StateIn , class StateOut >
  579. typename boost::disable_if< boost::is_same< StateIn , time_type > , controlled_step_result >::type
  580. try_step( System system , const StateIn &in , time_type &t , StateOut &out , time_type &dt )
  581. {
  582. if( m_dxdt_resizer.adjust_size( in , detail::bind( &controlled_runge_kutta::template resize_m_dxdt_impl< StateIn > , detail::ref( *this ) , detail::_1 ) ) || m_first_call )
  583. {
  584. initialize( system , in , t );
  585. }
  586. return try_step( system , in , m_dxdt.m_v , t , out , dt );
  587. }
  588. /*
  589. * Version 3 : try_step( sys , x , dxdt , t , dt )
  590. *
  591. * This version does not solve the forwarding problem, boost::range can not be used.
  592. */
  593. /**
  594. * \brief Tries to perform one step.
  595. *
  596. * This method tries to do one step with step size dt. If the error estimate
  597. * is to large, the step is rejected and the method returns fail and the
  598. * step size dt is reduced. If the error estimate is acceptably small, the
  599. * step is performed, success is returned and dt might be increased to make
  600. * the steps as large as possible. This method also updates t if a step is
  601. * performed.
  602. *
  603. * \param system The system function to solve, hence the r.h.s. of the ODE. It must fulfill the
  604. * Simple System concept.
  605. * \param x The state of the ODE which should be solved. Overwritten if
  606. * the step is successful.
  607. * \param dxdt The derivative of state.
  608. * \param t The value of the time. Updated if the step is successful.
  609. * \param dt The step size. Updated.
  610. * \return success if the step was accepted, fail otherwise.
  611. */
  612. template< class System , class StateInOut , class DerivInOut >
  613. controlled_step_result try_step( System system , StateInOut &x , DerivInOut &dxdt , time_type &t , time_type &dt )
  614. {
  615. m_xnew_resizer.adjust_size( x , detail::bind( &controlled_runge_kutta::template resize_m_xnew_impl< StateInOut > , detail::ref( *this ) , detail::_1 ) );
  616. m_dxdt_new_resizer.adjust_size( x , detail::bind( &controlled_runge_kutta::template resize_m_dxdt_new_impl< StateInOut > , detail::ref( *this ) , detail::_1 ) );
  617. controlled_step_result res = try_step( system , x , dxdt , t , m_xnew.m_v , m_dxdtnew.m_v , dt );
  618. if( res == success )
  619. {
  620. boost::numeric::odeint::copy( m_xnew.m_v , x );
  621. boost::numeric::odeint::copy( m_dxdtnew.m_v , dxdt );
  622. }
  623. return res;
  624. }
  625. /*
  626. * Version 4 : try_step( sys , in , dxdt_in , t , out , dxdt_out , dt )
  627. *
  628. * This version does not solve the forwarding problem, boost::range can not be used.
  629. */
  630. /**
  631. * \brief Tries to perform one step.
  632. *
  633. * This method tries to do one step with step size dt. If the error estimate
  634. * is to large, the step is rejected and the method returns fail and the
  635. * step size dt is reduced. If the error estimate is acceptably small, the
  636. * step is performed, success is returned and dt might be increased to make
  637. * the steps as large as possible. This method also updates t if a step is
  638. * performed.
  639. *
  640. * \param system The system function to solve, hence the r.h.s. of the ODE. It must fulfill the
  641. * Simple System concept.
  642. * \param in The state of the ODE which should be solved.
  643. * \param dxdt The derivative of state.
  644. * \param t The value of the time. Updated if the step is successful.
  645. * \param out Used to store the result of the step.
  646. * \param dt The step size. Updated.
  647. * \return success if the step was accepted, fail otherwise.
  648. */
  649. template< class System , class StateIn , class DerivIn , class StateOut , class DerivOut >
  650. controlled_step_result try_step( System system , const StateIn &in , const DerivIn &dxdt_in , time_type &t ,
  651. StateOut &out , DerivOut &dxdt_out , time_type &dt )
  652. {
  653. if( !m_step_adjuster.check_step_size_limit(dt) )
  654. {
  655. // given dt was above step size limit - adjust and return fail;
  656. dt = m_step_adjuster.get_max_dt();
  657. return fail;
  658. }
  659. m_xerr_resizer.adjust_size( in , detail::bind( &controlled_runge_kutta::template resize_m_xerr_impl< StateIn > , detail::ref( *this ) , detail::_1 ) );
  660. //fsal: m_stepper.get_dxdt( dxdt );
  661. //fsal: m_stepper.do_step( sys , x , dxdt , t , dt , m_x_err );
  662. m_stepper.do_step( system , in , dxdt_in , t , out , dxdt_out , dt , m_xerr.m_v );
  663. // this potentially overwrites m_x_err! (standard_error_checker does, at least)
  664. value_type max_rel_err = m_error_checker.error( m_stepper.algebra() , in , dxdt_in , m_xerr.m_v , dt );
  665. if( max_rel_err > 1.0 )
  666. {
  667. // error too big, decrease step size and reject this step
  668. dt = m_step_adjuster.decrease_step(dt, max_rel_err, m_stepper.error_order());
  669. return fail;
  670. }
  671. // otherwise, increase step size and accept
  672. t += dt;
  673. dt = m_step_adjuster.increase_step(dt, max_rel_err, m_stepper.stepper_order());
  674. return success;
  675. }
  676. /**
  677. * \brief Resets the internal state of the underlying FSAL stepper.
  678. */
  679. void reset( void )
  680. {
  681. m_first_call = true;
  682. }
  683. /**
  684. * \brief Initializes the internal state storing an internal copy of the derivative.
  685. *
  686. * \param deriv The initial derivative of the ODE.
  687. */
  688. template< class DerivIn >
  689. void initialize( const DerivIn &deriv )
  690. {
  691. boost::numeric::odeint::copy( deriv , m_dxdt.m_v );
  692. m_first_call = false;
  693. }
  694. /**
  695. * \brief Initializes the internal state storing an internal copy of the derivative.
  696. *
  697. * \param system The system function to solve, hence the r.h.s. of the ODE. It must fulfill the
  698. * Simple System concept.
  699. * \param x The initial state of the ODE which should be solved.
  700. * \param t The initial time.
  701. */
  702. template< class System , class StateIn >
  703. void initialize( System system , const StateIn &x , time_type t )
  704. {
  705. typename odeint::unwrap_reference< System >::type &sys = system;
  706. sys( x , m_dxdt.m_v , t );
  707. m_first_call = false;
  708. }
  709. /**
  710. * \brief Returns true if the stepper has been initialized, false otherwise.
  711. *
  712. * \return true, if the stepper has been initialized, false otherwise.
  713. */
  714. bool is_initialized( void ) const
  715. {
  716. return ! m_first_call;
  717. }
  718. /**
  719. * \brief Adjust the size of all temporaries in the stepper manually.
  720. * \param x A state from which the size of the temporaries to be resized is deduced.
  721. */
  722. template< class StateType >
  723. void adjust_size( const StateType &x )
  724. {
  725. resize_m_xerr_impl( x );
  726. resize_m_dxdt_impl( x );
  727. resize_m_dxdt_new_impl( x );
  728. resize_m_xnew_impl( x );
  729. }
  730. /**
  731. * \brief Returns the instance of the underlying stepper.
  732. * \returns The instance of the underlying stepper.
  733. */
  734. stepper_type& stepper( void )
  735. {
  736. return m_stepper;
  737. }
  738. /**
  739. * \brief Returns the instance of the underlying stepper.
  740. * \returns The instance of the underlying stepper.
  741. */
  742. const stepper_type& stepper( void ) const
  743. {
  744. return m_stepper;
  745. }
  746. private:
  747. template< class StateIn >
  748. bool resize_m_xerr_impl( const StateIn &x )
  749. {
  750. return adjust_size_by_resizeability( m_xerr , x , typename is_resizeable<state_type>::type() );
  751. }
  752. template< class StateIn >
  753. bool resize_m_dxdt_impl( const StateIn &x )
  754. {
  755. return adjust_size_by_resizeability( m_dxdt , x , typename is_resizeable<deriv_type>::type() );
  756. }
  757. template< class StateIn >
  758. bool resize_m_dxdt_new_impl( const StateIn &x )
  759. {
  760. return adjust_size_by_resizeability( m_dxdtnew , x , typename is_resizeable<deriv_type>::type() );
  761. }
  762. template< class StateIn >
  763. bool resize_m_xnew_impl( const StateIn &x )
  764. {
  765. return adjust_size_by_resizeability( m_xnew , x , typename is_resizeable<state_type>::type() );
  766. }
  767. template< class System , class StateInOut >
  768. controlled_step_result try_step_v1( System system , StateInOut &x , time_type &t , time_type &dt )
  769. {
  770. if( m_dxdt_resizer.adjust_size( x , detail::bind( &controlled_runge_kutta::template resize_m_dxdt_impl< StateInOut > , detail::ref( *this ) , detail::_1 ) ) || m_first_call )
  771. {
  772. initialize( system , x , t );
  773. }
  774. return try_step( system , x , m_dxdt.m_v , t , dt );
  775. }
  776. stepper_type m_stepper;
  777. error_checker_type m_error_checker;
  778. step_adjuster_type m_step_adjuster;
  779. resizer_type m_dxdt_resizer;
  780. resizer_type m_xerr_resizer;
  781. resizer_type m_xnew_resizer;
  782. resizer_type m_dxdt_new_resizer;
  783. wrapped_deriv_type m_dxdt;
  784. wrapped_state_type m_xerr;
  785. wrapped_state_type m_xnew;
  786. wrapped_deriv_type m_dxdtnew;
  787. bool m_first_call;
  788. };
  789. /********** DOXYGEN **********/
  790. /**** DEFAULT ERROR CHECKER ****/
  791. /**
  792. * \class default_error_checker
  793. * \brief The default error checker to be used with Runge-Kutta error steppers
  794. *
  795. * This class provides the default mechanism to compare the error estimates
  796. * reported by Runge-Kutta error steppers with user defined error bounds.
  797. * It is used by the controlled_runge_kutta steppers.
  798. *
  799. * \tparam Value The value type.
  800. * \tparam Time The time type.
  801. * \tparam Algebra The algebra type.
  802. * \tparam Operations The operations type.
  803. */
  804. /**
  805. * \fn default_error_checker( value_type eps_abs , value_type eps_rel , value_type a_x , value_type a_dxdt ,
  806. * time_type max_dt)
  807. * \brief Constructs the error checker.
  808. *
  809. * The error is calculated as follows: ????
  810. *
  811. * \param eps_abs Absolute tolerance level.
  812. * \param eps_rel Relative tolerance level.
  813. * \param a_x Factor for the weight of the state.
  814. * \param a_dxdt Factor for the weight of the derivative.
  815. * \param max_dt Maximum allowed step size.
  816. */
  817. /**
  818. * \fn error( const State &x_old , const Deriv &dxdt_old , Err &x_err , time_type dt ) const
  819. * \brief Calculates the error level.
  820. *
  821. * If the returned error level is greater than 1, the estimated error was
  822. * larger than the permitted error bounds and the step should be repeated
  823. * with a smaller step size.
  824. *
  825. * \param x_old State at the beginning of the step.
  826. * \param dxdt_old Derivative at the beginning of the step.
  827. * \param x_err Error estimate.
  828. * \param dt Time step.
  829. * \return error
  830. */
  831. /**
  832. * \fn error( algebra_type &algebra , const State &x_old , const Deriv &dxdt_old , Err &x_err , time_type dt ) const
  833. * \brief Calculates the error level using a given algebra.
  834. *
  835. * If the returned error level is greater than 1, the estimated error was
  836. * larger than the permitted error bounds and the step should be repeated
  837. * with a smaller step size.
  838. *
  839. * \param algebra The algebra used for calculation of the error.
  840. * \param x_old State at the beginning of the step.
  841. * \param dxdt_old Derivative at the beginning of the step.
  842. * \param x_err Error estimate.
  843. * \param dt Time step.
  844. * \return error
  845. */
  846. /**
  847. * \fn time_type decrease_step(const time_type dt, const value_type error, const int error_order)
  848. * \brief Returns a decreased step size based on the given error and order
  849. *
  850. * Calculates a new smaller step size based on the given error and its order.
  851. *
  852. * \param dt The old step size.
  853. * \param error The computed error estimate.
  854. * \param error_order The error order of the stepper.
  855. * \return dt_new The new, reduced step size.
  856. */
  857. /**
  858. * \fn time_type increase_step(const time_type dt, const value_type error, const int error_order)
  859. * \brief Returns an increased step size based on the given error and order.
  860. *
  861. * Calculates a new bigger step size based on the given error and its order. If max_dt != 0, the
  862. * new step size is limited to max_dt.
  863. *
  864. * \param dt The old step size.
  865. * \param error The computed error estimate.
  866. * \param error_order The order of the stepper.
  867. * \return dt_new The new, increased step size.
  868. */
  869. } // odeint
  870. } // numeric
  871. } // boost
  872. #endif // BOOST_NUMERIC_ODEINT_STEPPER_CONTROLLED_RUNGE_KUTTA_HPP_INCLUDED