adaptive_adams_coefficients.hpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. boost/numeric/odeint/stepper/detail/adaptive_adams_coefficients.hpp
  3. [begin_description]
  4. Calculation of the coefficients for the adaptive adams 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_DETAIL_ADAPTIVE_ADAMS_COEFFICIENTS_HPP_INCLUDED
  12. #define BOOST_NUMERIC_ODEINT_STEPPER_DETAIL_ADAPTIVE_ADAMS_COEFFICIENTS_HPP_INCLUDED
  13. #include <boost/numeric/odeint/stepper/detail/rotating_buffer.hpp>
  14. #include <boost/numeric/odeint/util/state_wrapper.hpp>
  15. #include <boost/numeric/odeint/util/is_resizeable.hpp>
  16. #include <boost/numeric/odeint/util/resizer.hpp>
  17. #include <boost/numeric/odeint/util/unwrap_reference.hpp>
  18. #include <boost/numeric/odeint/util/bind.hpp>
  19. #include <boost/numeric/odeint/algebra/algebra_dispatcher.hpp>
  20. #include <boost/numeric/odeint/algebra/operations_dispatcher.hpp>
  21. #include <boost/array.hpp>
  22. namespace boost {
  23. namespace numeric {
  24. namespace odeint {
  25. namespace detail {
  26. template<
  27. size_t Steps,
  28. class Deriv,
  29. class Value = double,
  30. class Time = double,
  31. class Algebra = typename algebra_dispatcher< Deriv >::algebra_type,
  32. class Operations = typename operations_dispatcher< Deriv >::operations_type,
  33. class Resizer = initially_resizer
  34. >
  35. class adaptive_adams_coefficients
  36. {
  37. public:
  38. static const size_t steps = Steps;
  39. typedef unsigned short order_type;
  40. static const order_type order_value = steps;
  41. typedef Value value_type;
  42. typedef Deriv deriv_type;
  43. typedef Time time_type;
  44. typedef state_wrapper< deriv_type > wrapped_deriv_type;
  45. typedef rotating_buffer< time_type , steps+1 > time_storage_type;
  46. typedef Algebra algebra_type;
  47. typedef Operations operations_type;
  48. typedef Resizer resizer_type;
  49. typedef adaptive_adams_coefficients< Steps , Deriv , Value , Time , Algebra , Operations , Resizer > aac_type;
  50. adaptive_adams_coefficients( const algebra_type &algebra = algebra_type())
  51. :m_eo(1), m_steps_init(1), beta(), phi(), m_ns(0), m_time_storage(),
  52. m_algebra(algebra),
  53. m_phi_resizer()
  54. {
  55. for (size_t i=0; i<order_value+2; ++i)
  56. {
  57. c[i] = 1.0/(i+1);
  58. c[c_size+i] = 1.0/((i+1)*(i+2));
  59. }
  60. g[0] = c[0];
  61. g[1] = c[c_size];
  62. beta[0][0] = 1;
  63. beta[1][0] = 1;
  64. gs[0] = 1.0;
  65. gs[1] = -1.0/2;
  66. gs[2] = -1.0/12;
  67. gs[3] = -1.0/24;
  68. gs[4] = -19.0/720;
  69. gs[5] = -3.0/160;
  70. gs[6] = -863.0/60480;
  71. gs[7] = -275.0/24192;
  72. gs[8] = -33953.0/3628800;
  73. gs[9] = 35.0/4436;
  74. gs[10] = 40.0/5891;
  75. gs[11] = 37.0/6250;
  76. gs[12] = 25.0/4771;
  77. gs[13] = 40.0/8547;
  78. };
  79. void predict(time_type t, time_type dt)
  80. {
  81. using std::abs;
  82. m_time_storage[0] = t;
  83. if (abs(m_time_storage[0] - m_time_storage[1] - dt) > 1e-16 || m_eo >= m_ns)
  84. {
  85. m_ns = 0;
  86. }
  87. else if (m_ns < order_value + 2)
  88. {
  89. m_ns++;
  90. }
  91. for(size_t i=1+m_ns; i<m_eo+1 && i<m_steps_init; ++i)
  92. {
  93. time_type diff = m_time_storage[0] - m_time_storage[i];
  94. beta[0][i] = beta[0][i-1]*(m_time_storage[0] + dt - m_time_storage[i-1])/diff;
  95. }
  96. for(size_t i=2+m_ns; i<m_eo+2 && i<m_steps_init+1; ++i)
  97. {
  98. time_type diff = m_time_storage[0] + dt - m_time_storage[i-1];
  99. for(size_t j=0; j<m_eo+1-i+1; ++j)
  100. {
  101. c[c_size*i+j] = c[c_size*(i-1)+j] - c[c_size*(i-1)+j+1]*dt/diff;
  102. }
  103. g[i] = c[c_size*i];
  104. }
  105. };
  106. void do_step(const deriv_type &dxdt, const int o = 0)
  107. {
  108. m_phi_resizer.adjust_size( dxdt , detail::bind( &aac_type::template resize_phi_impl< deriv_type > , detail::ref( *this ) , detail::_1 ) );
  109. phi[o][0].m_v = dxdt;
  110. for(size_t i=1; i<m_eo+3 && i<m_steps_init+2 && i<order_value+2; ++i)
  111. {
  112. if (o == 0)
  113. {
  114. this->m_algebra.for_each3(phi[o][i].m_v, phi[o][i-1].m_v, phi[o+1][i-1].m_v,
  115. typename Operations::template scale_sum2<value_type, value_type>(1.0, -beta[o][i-1]));
  116. }
  117. else
  118. {
  119. this->m_algebra.for_each2(phi[o][i].m_v, phi[o][i-1].m_v,
  120. typename Operations::template scale_sum1<value_type>(1.0));
  121. }
  122. }
  123. };
  124. void confirm()
  125. {
  126. beta.rotate();
  127. phi.rotate();
  128. m_time_storage.rotate();
  129. if(m_steps_init < order_value+1)
  130. {
  131. ++m_steps_init;
  132. }
  133. };
  134. void reset() { m_eo = 1; m_steps_init = 1; };
  135. size_t m_eo;
  136. size_t m_steps_init;
  137. rotating_buffer<boost::array<value_type, order_value+1>, 2> beta; // beta[0] = beta(n)
  138. rotating_buffer<boost::array<wrapped_deriv_type, order_value+2>, 3> phi; // phi[0] = phi(n+1)
  139. boost::array<value_type, order_value + 2> g;
  140. boost::array<value_type, 14> gs;
  141. private:
  142. template< class StateType >
  143. bool resize_phi_impl( const StateType &x )
  144. {
  145. bool resized( false );
  146. for(size_t i=0; i<(order_value + 2); ++i)
  147. {
  148. resized |= adjust_size_by_resizeability( phi[0][i], x, typename is_resizeable<deriv_type>::type() );
  149. resized |= adjust_size_by_resizeability( phi[1][i], x, typename is_resizeable<deriv_type>::type() );
  150. resized |= adjust_size_by_resizeability( phi[2][i], x, typename is_resizeable<deriv_type>::type() );
  151. }
  152. return resized;
  153. };
  154. size_t m_ns;
  155. time_storage_type m_time_storage;
  156. static const size_t c_size = order_value + 2;
  157. boost::array<value_type, c_size*c_size> c;
  158. algebra_type m_algebra;
  159. resizer_type m_phi_resizer;
  160. };
  161. } // detail
  162. } // odeint
  163. } // numeric
  164. } // boost
  165. #endif