controlled_adams_bashforth_moulton.hpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. boost/numeric/odeint/stepper/detail/controlled_adams_bashforth_moulton.hpp
  3. [begin_description]
  4. Implemetation of an controlled adams bashforth moulton stepper.
  5. [end_description]
  6. Copyright 2017 Valentin Noah Hartmann
  7. Distributed under the Boost Software License, Version 1.0.
  8. (See accompanying file LICENSE_1_0.txt or
  9. copy at http://www.boost.org/LICENSE_1_0.txt)
  10. */
  11. #ifndef BOOST_NUMERIC_ODEINT_STEPPER_CONTROLLED_ADAMS_BASHFORTH_MOULTON_HPP_INCLUDED
  12. #define BOOST_NUMERIC_ODEINT_STEPPER_CONTROLLED_ADAMS_BASHFORTH_MOULTON_HPP_INCLUDED
  13. #include <boost/numeric/odeint/stepper/stepper_categories.hpp>
  14. #include <boost/numeric/odeint/stepper/controlled_step_result.hpp>
  15. #include <boost/numeric/odeint/stepper/adaptive_adams_bashforth_moulton.hpp>
  16. #include <boost/numeric/odeint/stepper/detail/pid_step_adjuster.hpp>
  17. #include <boost/numeric/odeint/util/unwrap_reference.hpp>
  18. #include <boost/numeric/odeint/util/is_resizeable.hpp>
  19. #include <boost/numeric/odeint/util/resizer.hpp>
  20. #include <boost/numeric/odeint/util/copy.hpp>
  21. #include <boost/numeric/odeint/util/bind.hpp>
  22. #include <iostream>
  23. namespace boost {
  24. namespace numeric {
  25. namespace odeint {
  26. template<
  27. size_t MaxOrder,
  28. class State,
  29. class Value = double,
  30. class Algebra = typename algebra_dispatcher< State >::algebra_type
  31. >
  32. class default_order_adjuster
  33. {
  34. public:
  35. typedef State state_type;
  36. typedef Value value_type;
  37. typedef state_wrapper< state_type > wrapped_state_type;
  38. typedef Algebra algebra_type;
  39. default_order_adjuster( const algebra_type &algebra = algebra_type() )
  40. : m_algebra( algebra )
  41. {};
  42. size_t adjust_order(size_t order, size_t init, boost::array<wrapped_state_type, 4> &xerr)
  43. {
  44. using std::abs;
  45. value_type errc = abs(m_algebra.norm_inf(xerr[2].m_v));
  46. value_type errm1 = 3*errc;
  47. value_type errm2 = 3*errc;
  48. if(order > 2)
  49. {
  50. errm2 = abs(m_algebra.norm_inf(xerr[0].m_v));
  51. }
  52. if(order >= 2)
  53. {
  54. errm1 = abs(m_algebra.norm_inf(xerr[1].m_v));
  55. }
  56. size_t o_new = order;
  57. if(order == 2 && errm1 <= 0.5*errc)
  58. {
  59. o_new = order - 1;
  60. }
  61. else if(order > 2 && errm2 < errc && errm1 < errc)
  62. {
  63. o_new = order - 1;
  64. }
  65. if(init < order)
  66. {
  67. return order+1;
  68. }
  69. else if(o_new == order - 1)
  70. {
  71. return order-1;
  72. }
  73. else if(order <= MaxOrder)
  74. {
  75. value_type errp = abs(m_algebra.norm_inf(xerr[3].m_v));
  76. if(order > 1 && errm1 < errc && errp)
  77. {
  78. return order-1;
  79. }
  80. else if(order < MaxOrder && errp < (0.5-0.25*order/MaxOrder) * errc)
  81. {
  82. return order+1;
  83. }
  84. }
  85. return order;
  86. };
  87. private:
  88. algebra_type m_algebra;
  89. };
  90. template<
  91. class ErrorStepper,
  92. class StepAdjuster = detail::pid_step_adjuster< typename ErrorStepper::state_type,
  93. typename ErrorStepper::value_type,
  94. typename ErrorStepper::deriv_type,
  95. typename ErrorStepper::time_type,
  96. typename ErrorStepper::algebra_type,
  97. typename ErrorStepper::operations_type,
  98. detail::H211PI
  99. >,
  100. class OrderAdjuster = default_order_adjuster< ErrorStepper::order_value,
  101. typename ErrorStepper::state_type,
  102. typename ErrorStepper::value_type,
  103. typename ErrorStepper::algebra_type
  104. >,
  105. class Resizer = initially_resizer
  106. >
  107. class controlled_adams_bashforth_moulton
  108. {
  109. public:
  110. typedef ErrorStepper stepper_type;
  111. static const typename stepper_type::order_type order_value = stepper_type::order_value;
  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 StepAdjuster step_adjuster_type;
  120. typedef OrderAdjuster order_adjuster_type;
  121. typedef controlled_stepper_tag stepper_category;
  122. typedef typename stepper_type::wrapped_state_type wrapped_state_type;
  123. typedef typename stepper_type::wrapped_deriv_type wrapped_deriv_type;
  124. typedef boost::array< wrapped_state_type , 4 > error_storage_type;
  125. typedef typename stepper_type::coeff_type coeff_type;
  126. typedef controlled_adams_bashforth_moulton< ErrorStepper , StepAdjuster , OrderAdjuster , Resizer > controlled_stepper_type;
  127. controlled_adams_bashforth_moulton(step_adjuster_type step_adjuster = step_adjuster_type())
  128. :m_stepper(),
  129. m_dxdt_resizer(), m_xerr_resizer(), m_xnew_resizer(),
  130. m_step_adjuster( step_adjuster ), m_order_adjuster()
  131. {};
  132. template< class ExplicitStepper, class System >
  133. void initialize(ExplicitStepper stepper, System system, state_type &inOut, time_type &t, time_type dt)
  134. {
  135. m_stepper.initialize(stepper, system, inOut, t, dt);
  136. };
  137. template< class System >
  138. void initialize(System system, state_type &inOut, time_type &t, time_type dt)
  139. {
  140. m_stepper.initialize(system, inOut, t, dt);
  141. };
  142. template< class ExplicitStepper, class System >
  143. void initialize_controlled(ExplicitStepper stepper, System system, state_type &inOut, time_type &t, time_type &dt)
  144. {
  145. reset();
  146. coeff_type &coeff = m_stepper.coeff();
  147. m_dxdt_resizer.adjust_size( inOut , detail::bind( &controlled_stepper_type::template resize_dxdt_impl< state_type > , detail::ref( *this ) , detail::_1 ) );
  148. controlled_step_result res = fail;
  149. for( size_t i=0 ; i<order_value; ++i )
  150. {
  151. do
  152. {
  153. res = stepper.try_step( system, inOut, t, dt );
  154. }
  155. while(res != success);
  156. system( inOut , m_dxdt.m_v , t );
  157. coeff.predict(t-dt, dt);
  158. coeff.do_step(m_dxdt.m_v);
  159. coeff.confirm();
  160. if(coeff.m_eo < order_value)
  161. {
  162. ++coeff.m_eo;
  163. }
  164. }
  165. }
  166. template< class System >
  167. controlled_step_result try_step(System system, state_type & inOut, time_type &t, time_type &dt)
  168. {
  169. m_xnew_resizer.adjust_size( inOut , detail::bind( &controlled_stepper_type::template resize_xnew_impl< state_type > , detail::ref( *this ) , detail::_1 ) );
  170. controlled_step_result res = try_step(system, inOut, t, m_xnew.m_v, dt);
  171. if(res == success)
  172. {
  173. boost::numeric::odeint::copy( m_xnew.m_v , inOut);
  174. }
  175. return res;
  176. };
  177. template< class System >
  178. controlled_step_result try_step(System system, const state_type & in, time_type &t, state_type & out, time_type &dt)
  179. {
  180. m_xerr_resizer.adjust_size( in , detail::bind( &controlled_stepper_type::template resize_xerr_impl< state_type > , detail::ref( *this ) , detail::_1 ) );
  181. m_dxdt_resizer.adjust_size( in , detail::bind( &controlled_stepper_type::template resize_dxdt_impl< state_type > , detail::ref( *this ) , detail::_1 ) );
  182. m_stepper.do_step_impl(system, in, t, out, dt, m_xerr[2].m_v);
  183. coeff_type &coeff = m_stepper.coeff();
  184. time_type dtPrev = dt;
  185. dt = m_step_adjuster.adjust_stepsize(coeff.m_eo, dt, m_xerr[2].m_v, out, m_stepper.dxdt() );
  186. if(dt / dtPrev >= step_adjuster_type::threshold())
  187. {
  188. system(out, m_dxdt.m_v, t+dtPrev);
  189. coeff.do_step(m_dxdt.m_v);
  190. coeff.confirm();
  191. t += dtPrev;
  192. size_t eo = coeff.m_eo;
  193. // estimate errors for next step
  194. double factor = 1;
  195. algebra_type m_algebra;
  196. m_algebra.for_each2(m_xerr[2].m_v, coeff.phi[1][eo].m_v,
  197. typename operations_type::template scale_sum1<double>(factor*dt*(coeff.gs[eo])));
  198. if(eo > 1)
  199. {
  200. m_algebra.for_each2(m_xerr[1].m_v, coeff.phi[1][eo-1].m_v,
  201. typename operations_type::template scale_sum1<double>(factor*dt*(coeff.gs[eo-1])));
  202. }
  203. if(eo > 2)
  204. {
  205. m_algebra.for_each2(m_xerr[0].m_v, coeff.phi[1][eo-2].m_v,
  206. typename operations_type::template scale_sum1<double>(factor*dt*(coeff.gs[eo-2])));
  207. }
  208. if(eo < order_value && coeff.m_eo < coeff.m_steps_init-1)
  209. {
  210. m_algebra.for_each2(m_xerr[3].m_v, coeff.phi[1][eo+1].m_v,
  211. typename operations_type::template scale_sum1<double>(factor*dt*(coeff.gs[eo+1])));
  212. }
  213. // adjust order
  214. coeff.m_eo = m_order_adjuster.adjust_order(coeff.m_eo, coeff.m_steps_init-1, m_xerr);
  215. return success;
  216. }
  217. else
  218. {
  219. return fail;
  220. }
  221. };
  222. void reset() { m_stepper.reset(); };
  223. private:
  224. template< class StateType >
  225. bool resize_dxdt_impl( const StateType &x )
  226. {
  227. return adjust_size_by_resizeability( m_dxdt, x, typename is_resizeable<deriv_type>::type() );
  228. };
  229. template< class StateType >
  230. bool resize_xerr_impl( const StateType &x )
  231. {
  232. bool resized( false );
  233. for(size_t i=0; i<m_xerr.size(); ++i)
  234. {
  235. resized |= adjust_size_by_resizeability( m_xerr[i], x, typename is_resizeable<state_type>::type() );
  236. }
  237. return resized;
  238. };
  239. template< class StateType >
  240. bool resize_xnew_impl( const StateType &x )
  241. {
  242. return adjust_size_by_resizeability( m_xnew, x, typename is_resizeable<state_type>::type() );
  243. };
  244. stepper_type m_stepper;
  245. wrapped_deriv_type m_dxdt;
  246. error_storage_type m_xerr;
  247. wrapped_state_type m_xnew;
  248. resizer_type m_dxdt_resizer;
  249. resizer_type m_xerr_resizer;
  250. resizer_type m_xnew_resizer;
  251. step_adjuster_type m_step_adjuster;
  252. order_adjuster_type m_order_adjuster;
  253. };
  254. } // odeint
  255. } // numeric
  256. } // boost
  257. #endif