/* boost/numeric/odeint/stepper/detail/controlled_adams_bashforth_moulton.hpp [begin_description] Implemetation of an controlled adams bashforth moulton stepper. [end_description] Copyright 2017 Valentin Noah Hartmann Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef BOOST_NUMERIC_ODEINT_STEPPER_CONTROLLED_ADAMS_BASHFORTH_MOULTON_HPP_INCLUDED #define BOOST_NUMERIC_ODEINT_STEPPER_CONTROLLED_ADAMS_BASHFORTH_MOULTON_HPP_INCLUDED #include #include #include #include #include #include #include #include #include #include namespace boost { namespace numeric { namespace odeint { template< size_t MaxOrder, class State, class Value = double, class Algebra = typename algebra_dispatcher< State >::algebra_type > class default_order_adjuster { public: typedef State state_type; typedef Value value_type; typedef state_wrapper< state_type > wrapped_state_type; typedef Algebra algebra_type; default_order_adjuster( const algebra_type &algebra = algebra_type() ) : m_algebra( algebra ) {}; size_t adjust_order(size_t order, size_t init, boost::array &xerr) { using std::abs; value_type errc = abs(m_algebra.norm_inf(xerr[2].m_v)); value_type errm1 = 3*errc; value_type errm2 = 3*errc; if(order > 2) { errm2 = abs(m_algebra.norm_inf(xerr[0].m_v)); } if(order >= 2) { errm1 = abs(m_algebra.norm_inf(xerr[1].m_v)); } size_t o_new = order; if(order == 2 && errm1 <= 0.5*errc) { o_new = order - 1; } else if(order > 2 && errm2 < errc && errm1 < errc) { o_new = order - 1; } if(init < order) { return order+1; } else if(o_new == order - 1) { return order-1; } else if(order <= MaxOrder) { value_type errp = abs(m_algebra.norm_inf(xerr[3].m_v)); if(order > 1 && errm1 < errc && errp) { return order-1; } else if(order < MaxOrder && errp < (0.5-0.25*order/MaxOrder) * errc) { return order+1; } } return order; }; private: algebra_type m_algebra; }; template< class ErrorStepper, class StepAdjuster = detail::pid_step_adjuster< typename ErrorStepper::state_type, typename ErrorStepper::value_type, typename ErrorStepper::deriv_type, typename ErrorStepper::time_type, typename ErrorStepper::algebra_type, typename ErrorStepper::operations_type, detail::H211PI >, class OrderAdjuster = default_order_adjuster< ErrorStepper::order_value, typename ErrorStepper::state_type, typename ErrorStepper::value_type, typename ErrorStepper::algebra_type >, class Resizer = initially_resizer > class controlled_adams_bashforth_moulton { public: typedef ErrorStepper stepper_type; static const typename stepper_type::order_type order_value = stepper_type::order_value; typedef typename stepper_type::state_type state_type; typedef typename stepper_type::value_type value_type; typedef typename stepper_type::deriv_type deriv_type; typedef typename stepper_type::time_type time_type; typedef typename stepper_type::algebra_type algebra_type; typedef typename stepper_type::operations_type operations_type; typedef Resizer resizer_type; typedef StepAdjuster step_adjuster_type; typedef OrderAdjuster order_adjuster_type; typedef controlled_stepper_tag stepper_category; typedef typename stepper_type::wrapped_state_type wrapped_state_type; typedef typename stepper_type::wrapped_deriv_type wrapped_deriv_type; typedef boost::array< wrapped_state_type , 4 > error_storage_type; typedef typename stepper_type::coeff_type coeff_type; typedef controlled_adams_bashforth_moulton< ErrorStepper , StepAdjuster , OrderAdjuster , Resizer > controlled_stepper_type; controlled_adams_bashforth_moulton(step_adjuster_type step_adjuster = step_adjuster_type()) :m_stepper(), m_dxdt_resizer(), m_xerr_resizer(), m_xnew_resizer(), m_step_adjuster( step_adjuster ), m_order_adjuster() {}; template< class ExplicitStepper, class System > void initialize(ExplicitStepper stepper, System system, state_type &inOut, time_type &t, time_type dt) { m_stepper.initialize(stepper, system, inOut, t, dt); }; template< class System > void initialize(System system, state_type &inOut, time_type &t, time_type dt) { m_stepper.initialize(system, inOut, t, dt); }; template< class ExplicitStepper, class System > void initialize_controlled(ExplicitStepper stepper, System system, state_type &inOut, time_type &t, time_type &dt) { reset(); coeff_type &coeff = m_stepper.coeff(); m_dxdt_resizer.adjust_size( inOut , detail::bind( &controlled_stepper_type::template resize_dxdt_impl< state_type > , detail::ref( *this ) , detail::_1 ) ); controlled_step_result res = fail; for( size_t i=0 ; i controlled_step_result try_step(System system, state_type & inOut, time_type &t, time_type &dt) { m_xnew_resizer.adjust_size( inOut , detail::bind( &controlled_stepper_type::template resize_xnew_impl< state_type > , detail::ref( *this ) , detail::_1 ) ); controlled_step_result res = try_step(system, inOut, t, m_xnew.m_v, dt); if(res == success) { boost::numeric::odeint::copy( m_xnew.m_v , inOut); } return res; }; template< class System > controlled_step_result try_step(System system, const state_type & in, time_type &t, state_type & out, time_type &dt) { m_xerr_resizer.adjust_size( in , detail::bind( &controlled_stepper_type::template resize_xerr_impl< state_type > , detail::ref( *this ) , detail::_1 ) ); m_dxdt_resizer.adjust_size( in , detail::bind( &controlled_stepper_type::template resize_dxdt_impl< state_type > , detail::ref( *this ) , detail::_1 ) ); m_stepper.do_step_impl(system, in, t, out, dt, m_xerr[2].m_v); coeff_type &coeff = m_stepper.coeff(); time_type dtPrev = dt; dt = m_step_adjuster.adjust_stepsize(coeff.m_eo, dt, m_xerr[2].m_v, out, m_stepper.dxdt() ); if(dt / dtPrev >= step_adjuster_type::threshold()) { system(out, m_dxdt.m_v, t+dtPrev); coeff.do_step(m_dxdt.m_v); coeff.confirm(); t += dtPrev; size_t eo = coeff.m_eo; // estimate errors for next step double factor = 1; algebra_type m_algebra; m_algebra.for_each2(m_xerr[2].m_v, coeff.phi[1][eo].m_v, typename operations_type::template scale_sum1(factor*dt*(coeff.gs[eo]))); if(eo > 1) { m_algebra.for_each2(m_xerr[1].m_v, coeff.phi[1][eo-1].m_v, typename operations_type::template scale_sum1(factor*dt*(coeff.gs[eo-1]))); } if(eo > 2) { m_algebra.for_each2(m_xerr[0].m_v, coeff.phi[1][eo-2].m_v, typename operations_type::template scale_sum1(factor*dt*(coeff.gs[eo-2]))); } if(eo < order_value && coeff.m_eo < coeff.m_steps_init-1) { m_algebra.for_each2(m_xerr[3].m_v, coeff.phi[1][eo+1].m_v, typename operations_type::template scale_sum1(factor*dt*(coeff.gs[eo+1]))); } // adjust order coeff.m_eo = m_order_adjuster.adjust_order(coeff.m_eo, coeff.m_steps_init-1, m_xerr); return success; } else { return fail; } }; void reset() { m_stepper.reset(); }; private: template< class StateType > bool resize_dxdt_impl( const StateType &x ) { return adjust_size_by_resizeability( m_dxdt, x, typename is_resizeable::type() ); }; template< class StateType > bool resize_xerr_impl( const StateType &x ) { bool resized( false ); for(size_t i=0; i::type() ); } return resized; }; template< class StateType > bool resize_xnew_impl( const StateType &x ) { return adjust_size_by_resizeability( m_xnew, x, typename is_resizeable::type() ); }; stepper_type m_stepper; wrapped_deriv_type m_dxdt; error_storage_type m_xerr; wrapped_state_type m_xnew; resizer_type m_dxdt_resizer; resizer_type m_xerr_resizer; resizer_type m_xnew_resizer; step_adjuster_type m_step_adjuster; order_adjuster_type m_order_adjuster; }; } // odeint } // numeric } // boost #endif