1 /*
2  [auto_generated]
3   boost/numeric/odeint/iterator/detail/times_iterator_impl.hpp
4 
5   [begin_description]
6   tba.
7   [end_description]
8 
9   Copyright 2009-2013 Karsten Ahnert
10   Copyright 2009-2013 Mario Mulansky
11 
12   Distributed under the Boost Software License, Version 1.0.
13   (See accompanying file LICENSE_1_0.txt or
14   copy at http://www.boost.org/LICENSE_1_0.txt)
15 */
16 
17 
18 #ifndef BOOST_NUMERIC_ODEINT_ITERATOR_DETAIL_TIMES_ITERATOR_IMPL_HPP_DEFINED
19 #define BOOST_NUMERIC_ODEINT_ITERATOR_DETAIL_TIMES_ITERATOR_IMPL_HPP_DEFINED
20 
21 #include <boost/utility/enable_if.hpp>
22 #include <boost/type_traits/is_same.hpp>
23 #include <boost/throw_exception.hpp>
24 
25 #include <boost/numeric/odeint/util/unit_helper.hpp>
26 #include <boost/numeric/odeint/util/copy.hpp>
27 #include <boost/numeric/odeint/stepper/controlled_step_result.hpp>
28 #include <boost/numeric/odeint/iterator/detail/ode_iterator_base.hpp>
29 
30 
31 namespace boost {
32 namespace numeric {
33 namespace odeint {
34 
35 
36     template< class Iterator , class Stepper , class System , class State , class TimeIterator ,
37               typename Tag , typename StepperTag >
38     class times_iterator_impl;
39 
40     /*
41      * Specilization for basic steppers
42      */
43     /**
44      * \brief ODE Iterator with constant step size.
45      *
46      * Implements an ODE iterator with observer calls at predefined times.
47      * Uses controlled steppers. times_iterator is a model of single-pass iterator.
48      *
49      * The value type of this iterator is the state type of the stepper. Hence one can only access the state and not the current time.
50      *
51      * \tparam Stepper The stepper type which should be used during the iteration.
52      * \tparam System The type of the system function (ODE) which should be solved.
53      */
54     template< class Iterator , class Stepper , class System , class State , class TimeIterator , typename Tag >
55     class times_iterator_impl< Iterator , Stepper , System , State , TimeIterator , Tag , stepper_tag >
56         : public detail::ode_iterator_base< Iterator , Stepper , System , State , Tag >
57     {
58     private:
59 
60 
61         typedef Stepper stepper_type;
62         typedef System system_type;
63         typedef typename boost::numeric::odeint::unwrap_reference< stepper_type >::type unwrapped_stepper_type;
64         typedef State state_type;
65         typedef TimeIterator time_iterator_type;
66         typedef typename traits::time_type< stepper_type >::type time_type;
67         typedef typename traits::value_type< stepper_type >::type ode_value_type;
68         #ifndef DOXYGEN_SKIP
69         typedef detail::ode_iterator_base< Iterator , Stepper , System , State , Tag > base_type;
70         #endif
71 
72     public:
73 
74         /**
75          * \brief Constructs a times_iterator. This constructor should be used to construct the begin iterator.
76          *
77          * \param stepper The stepper to use during the iteration.
78          * \param sys The system function (ODE) to solve.
79          * \param s The initial state. adaptive_iterator stores a reference of s and changes its value during the iteration.
80          * \param t_start Iterator to the begin of a sequence of time values.
81          * \param t_end Iterator to the begin of a sequence of time values.
82          * \param dt The (initial) time step.
83          */
times_iterator_impl(stepper_type stepper,system_type sys,state_type & s,time_iterator_type t_start,time_iterator_type t_end,time_type dt)84         times_iterator_impl( stepper_type stepper , system_type sys , state_type &s ,
85                              time_iterator_type t_start , time_iterator_type t_end , time_type dt )
86             : base_type( stepper , sys , *t_start , dt ) ,
87               m_t_start( t_start ) , m_t_end( t_end ) , m_state( &s )
88         {
89             if( t_start == t_end )
90                 this->m_at_end = true;
91         }
92 
93         /**
94          * \brief Constructs an adaptive_iterator. This constructor should be used to construct the end iterator.
95          *
96          * \param stepper The stepper to use during the iteration.
97          * \param sys The system function (ODE) to solve.
98          * \param s The initial state. adaptive_iterator store a reference of s and changes its value during the iteration.
99          */
times_iterator_impl(stepper_type stepper,system_type sys,state_type & s)100         times_iterator_impl( stepper_type stepper , system_type sys , state_type &s )
101             : base_type( stepper , sys ) , m_state( &s ) { }
102 
103     protected:
104 
105         friend class boost::iterator_core_access;
106 
increment()107         void increment()
108         {
109             unwrapped_stepper_type &stepper = this->m_stepper;
110             if( ++m_t_start != m_t_end )
111             {
112                 while( detail::less_with_sign( this->m_t , static_cast<time_type>(*m_t_start) , this->m_dt ) )
113                 {
114                     const time_type current_dt = detail::min_abs( this->m_dt , static_cast<time_type>(*m_t_start) - this->m_t );
115                     stepper.do_step( this->m_system , *( this->m_state ) , this->m_t , current_dt );
116                     this->m_t += current_dt;
117                 }
118 
119             } else {
120                 this->m_at_end = true;
121             }
122          }
123 
124     public:
get_state() const125         const state_type& get_state() const
126         {
127             return *m_state;
128         }
129 
130     private:
131         time_iterator_type m_t_start;
132         time_iterator_type m_t_end;
133         state_type* m_state;
134     };
135 
136 
137 
138     /*
139      * Specilization for controlled steppers
140      */
141     /**
142      * \brief ODE Iterator with adaptive step size control. The value type of this iterator is the state type of the stepper.
143      *
144      * Implements an ODE iterator with observer calls at predefined times.
145      * Uses controlled steppers. times_iterator is a model of single-pass iterator.
146      *
147      * The value type of this iterator is the state type of the stepper. Hence one can only access the state and not the current time.
148      *
149      * \tparam Stepper The stepper type which should be used during the iteration.
150      * \tparam System The type of the system function (ODE) which should be solved.
151      */
152     template< class Iterator , class Stepper , class System , class State , class TimeIterator , typename Tag >
153     class times_iterator_impl< Iterator , Stepper , System , State , TimeIterator , Tag , controlled_stepper_tag >
154         : public detail::ode_iterator_base< Iterator , Stepper , System , State , Tag >
155     {
156     private:
157 
158 
159         typedef Stepper stepper_type;
160         typedef System system_type;
161         typedef typename boost::numeric::odeint::unwrap_reference< stepper_type >::type unwrapped_stepper_type;
162         typedef State state_type;
163         typedef TimeIterator time_iterator_type;
164         typedef typename traits::time_type< stepper_type >::type time_type;
165         typedef typename traits::value_type< stepper_type >::type ode_value_type;
166         #ifndef DOXYGEN_SKIP
167         typedef detail::ode_iterator_base< Iterator , Stepper , System , State , Tag > base_type;
168         #endif
169 
170     public:
171 
172         /**
173          * \brief Constructs a times_iterator. This constructor should be used to construct the begin iterator.
174          *
175          * \param stepper The stepper to use during the iteration.
176          * \param sys The system function (ODE) to solve.
177          * \param s The initial state. adaptive_iterator stores a reference of s and changes its value during the iteration.
178          * \param t_start Iterator to the begin of a sequence of time values.
179          * \param t_end Iterator to the begin of a sequence of time values.
180          * \param dt The (initial) time step.
181          */
times_iterator_impl(stepper_type stepper,system_type sys,state_type & s,time_iterator_type t_start,time_iterator_type t_end,time_type dt)182         times_iterator_impl( stepper_type stepper , system_type sys , state_type &s ,
183                              time_iterator_type t_start , time_iterator_type t_end , time_type dt )
184             : base_type( stepper , sys , *t_start , dt ) ,
185               m_t_start( t_start ) , m_t_end( t_end ) , m_state( &s )
186         {
187             if( t_start == t_end )
188                 this->m_at_end = true;
189         }
190 
191         /**
192          * \brief Constructs an adaptive_iterator. This constructor should be used to construct the end iterator.
193          *
194          * \param stepper The stepper to use during the iteration.
195          * \param sys The system function (ODE) to solve.
196          * \param s The initial state. adaptive_iterator store a reference of s and changes its value during the iteration.
197          */
times_iterator_impl(stepper_type stepper,system_type sys,state_type & s)198         times_iterator_impl( stepper_type stepper , system_type sys , state_type &s )
199             : base_type( stepper , sys ) , m_state( &s ) { }
200 
201     protected:
202 
203         friend class boost::iterator_core_access;
204 
increment()205         void increment()
206         {
207             if( ++m_t_start != m_t_end )
208             {
209                 while( detail::less_with_sign( this->m_t , static_cast<time_type>(*m_t_start) , this->m_dt ) )
210                 {
211                     if( detail::less_with_sign( static_cast<time_type>(*m_t_start) - this->m_t , this->m_dt , this->m_dt ) )
212                     {
213                         // we want to end exactly at the time point
214                         time_type current_dt = static_cast<time_type>(*m_t_start) - this->m_t;
215                         step_loop( current_dt );
216                     } else {
217                         step_loop( this->m_dt );
218                     }
219                 }
220 
221             } else {
222                 this->m_at_end = true;
223             }
224         }
225 
226     private:
step_loop(time_type & dt)227         void step_loop( time_type &dt )
228         {
229             unwrapped_stepper_type &stepper = this->m_stepper;
230             const size_t max_attempts = 1000;
231             size_t trials = 0;
232             controlled_step_result res = success;
233             do
234             {
235                 res = stepper.try_step( this->m_system , *( this->m_state ) , this->m_t , dt );
236                 ++trials;
237             }
238             while( ( res == fail ) && ( trials < max_attempts ) );
239             if( trials == max_attempts )
240             {
241                 BOOST_THROW_EXCEPTION( std::overflow_error( "Adaptive iterator : Maximal number of iterations reached. A step size could not be found." ) );
242             }
243         }
244 
245     public:
get_state() const246         const state_type& get_state() const
247         {
248             return *m_state;
249         }
250 
251 
252     private:
253         time_iterator_type m_t_start;
254         time_iterator_type m_t_end;
255         state_type* m_state;
256     };
257 
258 
259     /*
260      * Specilization for dense outputer steppers
261      */
262     /**
263      * \brief ODE Iterator with step size control and dense output.
264      * Implements an ODE iterator with adaptive step size control. Uses dense-output steppers.
265      * times_iterator is a model of single-pass iterator.
266      *
267      * \tparam Stepper The stepper type which should be used during the iteration.
268      * \tparam System The type of the system function (ODE) which should be solved.
269      */
270     template< class Iterator , class Stepper , class System , class State , class TimeIterator , typename Tag >
271     class times_iterator_impl< Iterator , Stepper , System , State , TimeIterator , Tag , dense_output_stepper_tag >
272         : public detail::ode_iterator_base< Iterator , Stepper , System , State , Tag >
273     {
274     private:
275 
276 
277         typedef Stepper stepper_type;
278         typedef System system_type;
279         typedef typename boost::numeric::odeint::unwrap_reference< stepper_type >::type unwrapped_stepper_type;
280         typedef State state_type;
281         typedef TimeIterator time_iterator_type;
282         typedef typename traits::time_type< stepper_type >::type time_type;
283         typedef typename traits::value_type< stepper_type >::type ode_value_type;
284         #ifndef DOXYGEN_SKIP
285         typedef detail::ode_iterator_base< Iterator , Stepper , System , State , Tag > base_type;
286         #endif
287 
288 
289    public:
290 
291 
292         /**
293          * \brief Constructs a times_iterator. This constructor should be used to construct the begin iterator.
294          *
295          * \param stepper The stepper to use during the iteration.
296          * \param sys The system function (ODE) to solve.
297          * \param s The initial state.
298          * \param t_start Iterator to the begin of a sequence of time values.
299          * \param t_end Iterator to the begin of a sequence of time values.
300          * \param dt The (initial) time step.
301          */
times_iterator_impl(stepper_type stepper,system_type sys,state_type & s,time_iterator_type t_start,time_iterator_type t_end,time_type dt)302         times_iterator_impl( stepper_type stepper , system_type sys , state_type &s ,
303                              time_iterator_type t_start , time_iterator_type t_end , time_type dt )
304             : base_type( stepper , sys , *t_start , dt ) ,
305               m_t_start( t_start ) , m_t_end( t_end ) , m_final_time( *(t_end-1) ) ,
306               m_state( &s )
307         {
308             if( t_start != t_end )
309             {
310                 unwrapped_stepper_type &st = this->m_stepper;
311                 st.initialize( *( this->m_state ) , this->m_t , this->m_dt );
312             } else {
313                 this->m_at_end = true;
314             }
315         }
316 
317         /**
318          * \brief Constructs a times_iterator. This constructor should be used to construct the end iterator.
319          *
320          * \param stepper The stepper to use during the iteration.
321          * \param sys The system function (ODE) to solve.
322          * \param s The initial state.
323          */
times_iterator_impl(stepper_type stepper,system_type sys,state_type & s)324         times_iterator_impl( stepper_type stepper , system_type sys , state_type &s )
325             : base_type( stepper , sys ) , m_state( &s ) { }
326 
327     protected:
328 
329         friend class boost::iterator_core_access;
330 
increment()331         void increment()
332         {
333             unwrapped_stepper_type &st = this->m_stepper;
334             if( ++m_t_start != m_t_end )
335             {
336                 this->m_t = static_cast<time_type>(*m_t_start);
337                 while( detail::less_with_sign( st.current_time() , this->m_t , this->m_dt ) )
338                 {
339                     // make sure we don't go beyond the last point
340                     if( detail::less_with_sign( m_final_time-st.current_time() , st.current_time_step() , st.current_time_step() ) )
341                     {
342                         st.initialize( st.current_state() , st.current_time() , m_final_time-st.current_time() );
343                     }
344                     st.do_step( this->m_system );
345                 }
346                 st.calc_state( this->m_t , *( this->m_state ) );
347             } else {
348                 this->m_at_end = true;
349             }
350         }
351 
352     public:
get_state() const353         const state_type& get_state() const
354         {
355             return *m_state;
356         }
357 
358 
359     private:
360         time_iterator_type m_t_start;
361         time_iterator_type m_t_end;
362         time_type m_final_time;
363         state_type* m_state;
364     };
365 
366 } // namespace odeint
367 } // namespace numeric
368 } // namespace boost
369 
370 
371 #endif // BOOST_NUMERIC_ODEINT_ITERATOR_DETAIL_TIMES_ITERATOR_IMPL_HPP_DEFINED
372