controlled_runge_kutta.hpp 34 KB

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