1 /*
2  [auto_generated]
3  boost/numeric/odeint/stepper/base/symplectic_rkn_stepper_base.hpp
4 
5  [begin_description]
6  Base class for symplectic Runge-Kutta-Nystrom steppers.
7  [end_description]
8 
9  Copyright 2011-2013 Karsten Ahnert
10  Copyright 2011-2013 Mario Mulansky
11  Copyright 2012 Christoph Koke
12 
13  Distributed under the Boost Software License, Version 1.0.
14  (See accompanying file LICENSE_1_0.txt or
15  copy at http://www.boost.org/LICENSE_1_0.txt)
16  */
17 
18 
19 #ifndef BOOST_NUMERIC_ODEINT_STEPPER_BASE_SYMPLECTIC_RKN_STEPPER_BASE_HPP_INCLUDED
20 #define BOOST_NUMERIC_ODEINT_STEPPER_BASE_SYMPLECTIC_RKN_STEPPER_BASE_HPP_INCLUDED
21 
22 #include <boost/array.hpp>
23 
24 #include <boost/numeric/odeint/util/bind.hpp>
25 #include <boost/numeric/odeint/util/unwrap_reference.hpp>
26 
27 #include <boost/numeric/odeint/util/copy.hpp>
28 #include <boost/numeric/odeint/util/is_pair.hpp>
29 
30 #include <boost/numeric/odeint/util/state_wrapper.hpp>
31 #include <boost/numeric/odeint/util/resizer.hpp>
32 
33 #include <boost/numeric/odeint/stepper/stepper_categories.hpp>
34 
35 #include <boost/numeric/odeint/stepper/base/algebra_stepper_base.hpp>
36 
37 
38 
39 
40 namespace boost {
41 namespace numeric {
42 namespace odeint {
43 
44 
45 template<
46 size_t NumOfStages ,
47 unsigned short Order ,
48 class Coor ,
49 class Momentum ,
50 class Value ,
51 class CoorDeriv ,
52 class MomentumDeriv ,
53 class Time ,
54 class Algebra ,
55 class Operations ,
56 class Resizer
57 >
58 class symplectic_nystroem_stepper_base : public algebra_stepper_base< Algebra , Operations >
59 {
60 
61 public:
62 
63     typedef algebra_stepper_base< Algebra , Operations > algebra_stepper_base_type;
64     typedef typename algebra_stepper_base_type::algebra_type algebra_type;
65     typedef typename algebra_stepper_base_type::operations_type operations_type;
66 
67     const static size_t num_of_stages = NumOfStages;
68     typedef Coor coor_type;
69     typedef Momentum momentum_type;
70     typedef std::pair< coor_type , momentum_type > state_type;
71     typedef CoorDeriv coor_deriv_type;
72     typedef state_wrapper< coor_deriv_type> wrapped_coor_deriv_type;
73     typedef MomentumDeriv momentum_deriv_type;
74     typedef state_wrapper< momentum_deriv_type > wrapped_momentum_deriv_type;
75     typedef std::pair< coor_deriv_type , momentum_deriv_type > deriv_type;
76     typedef Value value_type;
77     typedef Time time_type;
78     typedef Resizer resizer_type;
79     typedef stepper_tag stepper_category;
80 
81     #ifndef DOXYGEN_SKIP
82     typedef symplectic_nystroem_stepper_base< NumOfStages , Order , Coor , Momentum , Value ,
83             CoorDeriv , MomentumDeriv , Time , Algebra , Operations , Resizer > internal_stepper_base_type;
84     #endif
85     typedef unsigned short order_type;
86 
87     static const order_type order_value = Order;
88 
89     typedef boost::array< value_type , num_of_stages > coef_type;
90 
symplectic_nystroem_stepper_base(const coef_type & coef_a,const coef_type & coef_b,const algebra_type & algebra=algebra_type ())91     symplectic_nystroem_stepper_base( const coef_type &coef_a , const coef_type &coef_b , const algebra_type &algebra = algebra_type() )
92         : algebra_stepper_base_type( algebra ) , m_coef_a( coef_a ) , m_coef_b( coef_b ) ,
93           m_dqdt_resizer() , m_dpdt_resizer() , m_dqdt() , m_dpdt()
94     { }
95 
96 
order(void) const97     order_type order( void ) const
98     {
99         return order_value;
100     }
101 
102     /*
103      * Version 1 : do_step( system , x , t , dt )
104      *
105      * This version does not solve the forwarding problem, boost.range can not be used.
106      */
107     template< class System , class StateInOut >
do_step(System system,const StateInOut & state,time_type t,time_type dt)108     void do_step( System system , const StateInOut &state , time_type t , time_type dt )
109     {
110         typedef typename odeint::unwrap_reference< System >::type system_type;
111         do_step_impl( system , state , t , state , dt , typename is_pair< system_type >::type() );
112     }
113 
114     /**
115      * \brief Same function as above. It differs only in a different const specifier in order
116      * to solve the forwarding problem, can be used with Boost.Range.
117      */
118     template< class System , class StateInOut >
do_step(System system,StateInOut & state,time_type t,time_type dt)119     void do_step( System system , StateInOut &state , time_type t , time_type dt )
120     {
121         typedef typename odeint::unwrap_reference< System >::type system_type;
122         do_step_impl( system , state , t , state , dt , typename is_pair< system_type >::type() );
123     }
124 
125 
126 
127 
128     /*
129      * Version 2 : do_step( system , q , p , t , dt );
130      *
131      * For Convenience
132      *
133      * The two overloads are needed in order to solve the forwarding problem.
134      */
135     template< class System , class CoorInOut , class MomentumInOut >
do_step(System system,CoorInOut & q,MomentumInOut & p,time_type t,time_type dt)136     void do_step( System system , CoorInOut &q , MomentumInOut &p , time_type t , time_type dt )
137     {
138         do_step( system , std::make_pair( detail::ref( q ) , detail::ref( p ) ) , t , dt );
139     }
140 
141     /**
142      * \brief Same function as do_step( system , q , p , t , dt ). It differs only in a different const specifier in order
143      * to solve the forwarding problem, can be called with Boost.Range.
144      */
145     template< class System , class CoorInOut , class MomentumInOut >
do_step(System system,const CoorInOut & q,const MomentumInOut & p,time_type t,time_type dt)146     void do_step( System system , const CoorInOut &q , const MomentumInOut &p , time_type t , time_type dt )
147     {
148         do_step( system , std::make_pair( detail::ref( q ) , detail::ref( p ) ) , t , dt );
149     }
150 
151 
152 
153 
154 
155     /*
156      * Version 3 : do_step( system , in , t , out , dt )
157      *
158      * The forwarding problem is not solved in this version
159      */
160     template< class System , class StateIn , class StateOut >
do_step(System system,const StateIn & in,time_type t,StateOut & out,time_type dt)161     void do_step( System system , const StateIn &in , time_type t , StateOut &out , time_type dt )
162     {
163         typedef typename odeint::unwrap_reference< System >::type system_type;
164         do_step_impl( system , in , t , out , dt , typename is_pair< system_type >::type() );
165     }
166 
167 
168     template< class StateType >
adjust_size(const StateType & x)169     void adjust_size( const StateType &x )
170     {
171         resize_dqdt( x );
172         resize_dpdt( x );
173     }
174 
175     /** \brief Returns the coefficients a. */
coef_a(void) const176     const coef_type& coef_a( void ) const { return m_coef_a; }
177 
178     /** \brief Returns the coefficients b. */
coef_b(void) const179     const coef_type& coef_b( void ) const { return m_coef_b; }
180 
181 private:
182 
183     // stepper for systems with function for dq/dt = f(p) and dp/dt = -f(q)
184     template< class System , class StateIn , class StateOut >
do_step_impl(System system,const StateIn & in,time_type,StateOut & out,time_type dt,boost::mpl::true_)185     void do_step_impl( System system , const StateIn &in , time_type /* t */ , StateOut &out , time_type dt , boost::mpl::true_ )
186     {
187         typedef typename odeint::unwrap_reference< System >::type system_type;
188         typedef typename odeint::unwrap_reference< typename system_type::first_type >::type coor_deriv_func_type;
189         typedef typename odeint::unwrap_reference< typename system_type::second_type >::type momentum_deriv_func_type;
190         system_type &sys = system;
191         coor_deriv_func_type &coor_func = sys.first;
192         momentum_deriv_func_type &momentum_func = sys.second;
193 
194         typedef typename odeint::unwrap_reference< StateIn >::type state_in_type;
195         typedef typename odeint::unwrap_reference< typename state_in_type::first_type >::type coor_in_type;
196         typedef typename odeint::unwrap_reference< typename state_in_type::second_type >::type momentum_in_type;
197         const state_in_type &state_in = in;
198         const coor_in_type &coor_in = state_in.first;
199         const momentum_in_type &momentum_in = state_in.second;
200 
201         typedef typename odeint::unwrap_reference< StateOut >::type state_out_type;
202         typedef typename odeint::unwrap_reference< typename state_out_type::first_type >::type coor_out_type;
203         typedef typename odeint::unwrap_reference< typename state_out_type::second_type >::type momentum_out_type;
204         state_out_type &state_out = out;
205         coor_out_type &coor_out = state_out.first;
206         momentum_out_type &momentum_out = state_out.second;
207 
208         m_dqdt_resizer.adjust_size( coor_in , detail::bind( &internal_stepper_base_type::template resize_dqdt< coor_in_type > , detail::ref( *this ) , detail::_1 ) );
209         m_dpdt_resizer.adjust_size( momentum_in , detail::bind( &internal_stepper_base_type::template resize_dpdt< momentum_in_type > , detail::ref( *this ) , detail::_1 ) );
210 
211         // ToDo: check sizes?
212 
213         for( size_t l=0 ; l<num_of_stages ; ++l )
214         {
215             if( l == 0 )
216             {
217                 coor_func( momentum_in , m_dqdt.m_v );
218                 this->m_algebra.for_each3( coor_out , coor_in , m_dqdt.m_v ,
219                         typename operations_type::template scale_sum2< value_type , time_type >( 1.0 , m_coef_a[l] * dt ) );
220                 momentum_func( coor_out , m_dpdt.m_v );
221                 this->m_algebra.for_each3( momentum_out , momentum_in , m_dpdt.m_v ,
222                         typename operations_type::template scale_sum2< value_type , time_type >( 1.0 , m_coef_b[l] * dt ) );
223             }
224             else
225             {
226                 coor_func( momentum_out , m_dqdt.m_v );
227                 this->m_algebra.for_each3( coor_out , coor_out , m_dqdt.m_v ,
228                         typename operations_type::template scale_sum2< value_type , time_type >( 1.0 , m_coef_a[l] * dt ) );
229                 momentum_func( coor_out , m_dpdt.m_v );
230                 this->m_algebra.for_each3( momentum_out , momentum_out , m_dpdt.m_v ,
231                         typename operations_type::template scale_sum2< value_type , time_type >( 1.0 , m_coef_b[l] * dt ) );
232             }
233         }
234     }
235 
236 
237     // stepper for systems with only function dp /dt = -f(q), dq/dt = p, time not required but still expected for compatibility reasons
238     template< class System , class StateIn , class StateOut >
do_step_impl(System system,const StateIn & in,time_type,StateOut & out,time_type dt,boost::mpl::false_)239     void do_step_impl( System system , const StateIn &in , time_type  /* t */ , StateOut &out , time_type dt , boost::mpl::false_ )
240     {
241         typedef typename odeint::unwrap_reference< System >::type momentum_deriv_func_type;
242         momentum_deriv_func_type &momentum_func = system;
243 
244         typedef typename odeint::unwrap_reference< StateIn >::type state_in_type;
245         typedef typename odeint::unwrap_reference< typename state_in_type::first_type >::type coor_in_type;
246         typedef typename odeint::unwrap_reference< typename state_in_type::second_type >::type momentum_in_type;
247         const state_in_type &state_in = in;
248         const coor_in_type &coor_in = state_in.first;
249         const momentum_in_type &momentum_in = state_in.second;
250 
251         typedef typename odeint::unwrap_reference< StateOut >::type state_out_type;
252         typedef typename odeint::unwrap_reference< typename state_out_type::first_type >::type coor_out_type;
253         typedef typename odeint::unwrap_reference< typename state_out_type::second_type >::type momentum_out_type;
254         state_out_type &state_out = out;
255         coor_out_type &coor_out = state_out.first;
256         momentum_out_type &momentum_out = state_out.second;
257 
258 
259         // m_dqdt not required when called with momentum_func only - don't resize
260         // m_dqdt_resizer.adjust_size( coor_in , detail::bind( &internal_stepper_base_type::template resize_dqdt< coor_in_type > , detail::ref( *this ) , detail::_1 ) );
261         m_dpdt_resizer.adjust_size( momentum_in , detail::bind( &internal_stepper_base_type::template resize_dpdt< momentum_in_type > , detail::ref( *this ) , detail::_1 ) );
262 
263 
264         // ToDo: check sizes?
265 
266         // step 0
267         this->m_algebra.for_each3( coor_out  , coor_in , momentum_in ,
268                         typename operations_type::template scale_sum2< value_type , time_type >( 1.0 , m_coef_a[0] * dt ) );
269         momentum_func( coor_out , m_dpdt.m_v );
270         this->m_algebra.for_each3( momentum_out , momentum_in , m_dpdt.m_v ,
271                                            typename operations_type::template scale_sum2< value_type , time_type >( 1.0 , m_coef_b[0] * dt ) );
272 
273         for( size_t l=1 ; l<num_of_stages ; ++l )
274         {
275             this->m_algebra.for_each3( coor_out , coor_out , momentum_out ,
276                         typename operations_type::template scale_sum2< value_type , time_type >( 1.0 , m_coef_a[l] * dt ) );
277             momentum_func( coor_out , m_dpdt.m_v );
278             this->m_algebra.for_each3( momentum_out , momentum_out , m_dpdt.m_v ,
279                                        typename operations_type::template scale_sum2< value_type , time_type >( 1.0 , m_coef_b[l] * dt ) );
280         }
281     }
282 
283     template< class StateIn >
resize_dqdt(const StateIn & x)284     bool resize_dqdt( const StateIn &x )
285     {
286         return adjust_size_by_resizeability( m_dqdt , x , typename is_resizeable<coor_deriv_type>::type() );
287     }
288 
289     template< class StateIn >
resize_dpdt(const StateIn & x)290     bool resize_dpdt( const StateIn &x )
291     {
292         return adjust_size_by_resizeability( m_dpdt , x , typename is_resizeable<momentum_deriv_type>::type() );
293     }
294 
295 
296     const coef_type m_coef_a;
297     const coef_type m_coef_b;
298 
299     resizer_type m_dqdt_resizer;
300     resizer_type m_dpdt_resizer;
301     wrapped_coor_deriv_type m_dqdt;
302     wrapped_momentum_deriv_type m_dpdt;
303 
304 };
305 
306 /********* DOXYGEN *********/
307 
308 /**
309  * \class symplectic_nystroem_stepper_base
310  * \brief Base class for all symplectic steppers of Nystroem type.
311  *
312  * This class is the base class for the symplectic Runge-Kutta-Nystroem steppers. Symplectic steppers are usually
313  * used to solve Hamiltonian systems and they conserve the phase space volume, see
314  * <a href="http://en.wikipedia.org/wiki/Symplectic_integrator">en.wikipedia.org/wiki/Symplectic_integrator</a>.
315  * Furthermore, the energy is conserved
316  * in average. In detail this class of steppers can be used to solve separable Hamiltonian systems which can be written
317  * in the form H(q,p) = H1(p) + H2(q). q is usually called the coordinate, while p is the momentum. The equations of motion
318  * are dq/dt = dH1/dp, dp/dt = -dH2/dq.
319  *
320  * ToDo : add formula for solver and explanation of the coefficients
321  *
322  * symplectic_nystroem_stepper_base uses odeints algebra and operation system. Step size and error estimation are not
323  * provided for this class of solvers. It derives from algebra_stepper_base. Several `do_step` variants are provided:
324  *
325  * - `do_step( sys , x , t , dt )` - The classical `do_step` method. The sys can be either a pair of function objects
326  *    for the coordinate or the momentum part or one function object for the momentum part. `x` is a pair of coordinate
327  *    and momentum. The state is updated in-place.
328  * - `do_step( sys , q , p , t , dt )` - This method is similar to the method above with the difference that the coordinate
329  *    and the momentum are passed explicitly and not packed into a pair.
330  * - `do_step( sys , x_in , t , x_out , dt )` - This method transforms the state out-of-place. `x_in` and `x_out` are here pairs
331  *    of coordinate and momentum.
332  *
333  * \tparam NumOfStages Number of stages.
334  * \tparam Order The order of the stepper.
335  * \tparam Coor The type representing the coordinates q.
336  * \tparam Momentum The type representing the coordinates p.
337  * \tparam Value The basic value type. Should be something like float, double or a high-precision type.
338  * \tparam CoorDeriv The type representing the time derivative of the coordinate dq/dt.
339  * \tparam MomemtnumDeriv The type representing the time derivative of the momentum dp/dt.
340  * \tparam Time The type representing the time t.
341  * \tparam Algebra The algebra.
342  * \tparam Operations The operations.
343  * \tparam Resizer The resizer policy.
344  */
345 
346     /**
347      * \fn symplectic_nystroem_stepper_base::symplectic_nystroem_stepper_base( const coef_type &coef_a , const coef_type &coef_b , const algebra_type &algebra )
348      * \brief Constructs a symplectic_nystroem_stepper_base class. The parameters of the specific Nystroem method and the
349      * algebra have to be passed.
350      * \param coef_a The coefficients a.
351      * \param coef_b The coefficients b.
352      * \param algebra A copy of algebra is made and stored inside explicit_stepper_base.
353      */
354 
355     /**
356      * \fn symplectic_nystroem_stepper_base::order( void ) const
357      * \return Returns the order of the stepper.
358      */
359 
360     /**
361      * \fn symplectic_nystroem_stepper_base::do_step( System system , const StateInOut &state , time_type t , time_type dt )
362      * \brief This method performs one step. The system can be either a pair of two function object
363      * describing the momentum part and the coordinate part or one function object describing only
364      * the momentum part. In this case the coordinate is assumed to be trivial dq/dt = p. The state
365      * is updated in-place.
366      *
367      * \note boost::ref or std::ref can be used for the system as well as for the state. So, it is correct
368      * to write `stepper.do_step( make_pair( std::ref( fq ) , std::ref( fp ) ) , make_pair( std::ref( q ) , std::ref( p ) ) , t , dt )`.
369      *
370      * \note This method solves the forwarding problem.
371      *
372      * \param system The system, can be represented as a pair of two function object or one function object. See above.
373      * \param state The state of the ODE. It is a pair of Coor and Momentum. The state is updated in-place, therefore, the
374      * new value of the state will be written into this variable.
375      * \param t The time of the ODE. It is not advanced by this method.
376      * \param dt The time step.
377      */
378 
379     /**
380      * \fn symplectic_nystroem_stepper_base::do_step( System system , CoorInOut &q , MomentumInOut &p , time_type t , time_type dt )
381      * \brief This method performs one step. The system can be either a pair of two function object
382      * describing the momentum part and the coordinate part or one function object describing only
383      * the momentum part. In this case the coordinate is assumed to be trivial dq/dt = p. The state
384      * is updated in-place.
385      *
386      * \note boost::ref or std::ref can be used for the system. So, it is correct
387      * to write `stepper.do_step( make_pair( std::ref( fq ) , std::ref( fp ) ) , q , p , t , dt )`.
388      *
389      * \note This method solves the forwarding problem.
390      *
391      * \param system The system, can be represented as a pair of two function object or one function object. See above.
392      * \param q The coordinate of the ODE. It is updated in-place. Therefore, the new value of the coordinate will be written
393      * into this variable.
394      * \param p The momentum of the ODE. It is updated in-place. Therefore, the new value of the momentum will be written info
395      * this variable.
396      * \param t The time of the ODE. It is not advanced by this method.
397      * \param dt The time step.
398      */
399 
400     /**
401      * \fn symplectic_nystroem_stepper_base::do_step( System system , const StateIn &in , time_type t , StateOut &out , time_type dt )
402      * \brief This method performs one step. The system can be either a pair of two function object
403      * describing the momentum part and the coordinate part or one function object describing only
404      * the momentum part. In this case the coordinate is assumed to be trivial dq/dt = p. The state
405      * is updated out-of-place.
406      *
407      * \note boost::ref or std::ref can be used for the system. So, it is correct
408      * to write `stepper.do_step( make_pair( std::ref( fq ) , std::ref( fp ) ) , x_in , t , x_out , dt )`.
409      *
410      * \note This method NOT solve the forwarding problem.
411      *
412      * \param system The system, can be represented as a pair of two function object or one function object. See above.
413      * \param in The state of the ODE, which is a pair of coordinate and momentum. The state is updated out-of-place, therefore the
414      * new value is written into out
415      * \param t The time of the ODE. It is not advanced by this method.
416      * \param out The new state of the ODE.
417      * \param dt The time step.
418      */
419 
420     /**
421      * \fn symplectic_nystroem_stepper_base::adjust_size( const StateType &x )
422      * \brief Adjust the size of all temporaries in the stepper manually.
423      * \param x A state from which the size of the temporaries to be resized is deduced.
424      */
425 
426 } // namespace odeint
427 } // namespace numeric
428 } // namespace boost
429 
430 
431 #endif // BOOST_NUMERIC_ODEINT_STEPPER_BASE_SYMPLECTIC_RKN_STEPPER_BASE_HPP_INCLUDED
432