void operator()( void ) { Stepper stepper; const int o = stepper.order()+1; //order of the error is order of approximation + 1 const state_type x0 = {{ 0.0 , 1.0 }}; state_type x1; const double t = 0.0; /* do a first step with dt=0.1 to get an estimate on the prefactor of the error dx = f * dt^(order+1) */ double dt = 0.5; stepper.do_step( osc() , x0 , t , x1 , dt ); const double f = 2.0 * std::abs( sin(dt) - x1[0] ) / std::pow( dt , o ); // upper bound std::cout << o << " , " << f << std::endl; /* as long as we have errors above machine precision */ while( f*std::pow( dt , o ) > 1E-16 ) { // reset stepper which require resetting (fsal steppers) resetter< typename Stepper::stepper_category >::reset( stepper ); stepper.do_step( osc() , x0 , t , x1 , dt ); std::cout << "Testing dt=" << dt << std::endl; BOOST_CHECK_LT( std::abs( sin(dt) - x1[0] ) , f*std::pow( dt , o ) ); dt *= 0.5; } }
void operator()( void ) { Stepper stepper; const int o = stepper.order()+1; //order of the error is order of approximation + 1 const state_type q0 = {{ 0.0 }}; const state_type p0 = {{ 1.0 }}; state_type q1,p1; std::pair< state_type , state_type >x1( q1 , p1 ); const double t = 0.0; /* do a first step with dt=0.1 to get an estimate on the prefactor of the error dx = f * dt^(order+1) */ double dt = 0.5; stepper.do_step( osc() , std::make_pair( q0 , p0 ) , t , x1 , dt ); const double f = 2.0 * std::abs( sin(dt) - x1.first[0] ) / std::pow( dt , o ); std::cout << o << " , " << f << std::endl; /* as long as we have errors above machine precision */ while( f*std::pow( dt , o ) > 1E-16 ) { stepper.do_step( osc() , std::make_pair( q0 , p0 ) , t , x1 , dt ); std::cout << "Testing dt=" << dt << std::endl; BOOST_CHECK_SMALL( std::abs( sin(dt) - x1.first[0] ) , f*std::pow( dt , o ) ); dt *= 0.5; } }
void check_stepper( Stepper &stepper ) { typedef Stepper stepper_type; 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::order_type order_type; typedef typename stepper_type::algebra_type algebra_type; typedef typename stepper_type::operations_type operations_type; const time_type t( 0.0 * si::second ); time_type dt( 0.1 * si::second ); state_type x( 1.0 * si::meter , 0.0 * si::meter_per_second ); // test call method one stepper.do_step( oscillator , x , t , dt ); // test call method two stepper.do_step( oscillator , x , t , x , dt ); // test call method three deriv_type dxdt; oscillator( x , dxdt , t ); stepper.do_step( oscillator , x , dxdt , t , dt ); // test call method four oscillator( x , dxdt , t ); stepper.do_step( oscillator , x , dxdt , t , x , dt ); }
void check_error_stepper_concept( Stepper &stepper , System system , typename Stepper::state_type &x , typename Stepper::state_type &xerr ) { typedef Stepper stepper_type; typedef typename stepper_type::deriv_type container_type; typedef typename stepper_type::order_type order_type; typedef typename stepper_type::time_type time_type; stepper.do_step( system , x , static_cast<time_type>(0.0) , static_cast<time_type>(0.1) ); stepper.do_step( system , x , static_cast<time_type>(0.0) , static_cast<time_type>(0.1) , xerr ); }
void check_error_stepper_concept( Stepper &stepper , System system , typename Stepper::state_type &x , typename Stepper::state_type &xerr ) { typedef Stepper stepper_type; typedef typename stepper_type::deriv_type container_type; typedef typename stepper_type::order_type order_type; typedef typename stepper_type::time_type time_type; stepper.do_step( system , typename boost::add_reference< container_type>::type( x ), 0.0 , 0.1 ); stepper.do_step( system , typename boost::add_reference< container_type>::type( x ), 0.0 , 0.1 , typename boost::add_reference< container_type>::type( xerr ) ); }
Time integrate_n_steps( Stepper stepper , System system , State &start_state , Time start_time , Time dt , size_t num_of_steps , Observer observer , dense_output_stepper_tag ) { typename odeint::unwrap_reference< Observer >::type &obs = observer; Time time = start_time; const Time end_time = start_time + static_cast< typename unit_value_type<Time>::type >(num_of_steps) * dt; stepper.initialize( start_state , time , dt ); size_t step = 0; while( step < num_of_steps ) { while( less_with_sign( time , stepper.current_time() , stepper.current_time_step() ) ) { stepper.calc_state( time , start_state ); obs( start_state , time ); ++step; // direct computation of the time avoids error propagation happening when using time += dt // we need clumsy type analysis to get boost units working here time = start_time + static_cast< typename unit_value_type<Time>::type >(step) * dt; } // we have not reached the end, do another real step if( less_with_sign( stepper.current_time()+stepper.current_time_step() , end_time , stepper.current_time_step() ) ) { stepper.do_step( system ); } else if( less_with_sign( stepper.current_time() , end_time , stepper.current_time_step() ) ) { // do the last step ending exactly on the end point stepper.initialize( stepper.current_state() , stepper.current_time() , end_time - stepper.current_time() ); stepper.do_step( system ); } } while( stepper.current_time() < end_time ) { if( less_with_sign( end_time , stepper.current_time()+stepper.current_time_step() , stepper.current_time_step() ) ) stepper.initialize( stepper.current_state() , stepper.current_time() , end_time - stepper.current_time() ); stepper.do_step( system ); } // observation at end point, only if we ended exactly on the end-point (or above due to finite precision) obs( stepper.current_state() , end_time ); return time; }
void run( Stepper &stepper , const size_t num_of_steps = 20000000 , const double dt = 1E-10 ) { const size_t loops = 20; accumulator_type acc; timer_type timer; srand( 12312354 ); // transient //stepper.reset_init_cond( ); //for( size_t i = 0 ; i < num_of_steps ; ++i ) // stepper.do_step( dt ); for( size_t n=0 ; n<loops+1 ; ++n ) { stepper.reset_init_cond( ); timer.restart(); for( size_t i = 0 ; i < num_of_steps ; ++i ) stepper.do_step( dt ); if( n>0 ) { // take first run as transient acc(timer.elapsed()); clog.precision(8); clog.width(10); clog << acc << " " << stepper.state(0) << endl; } } cout << acc << endl; }
size_t integrate_adaptive( Stepper stepper , System system , State &start_state , Time start_time , Time end_time , Time dt , Observer observer , dense_output_stepper_tag ) { typename omplext_odeint::unwrap_reference< Observer >::type &obs = observer; size_t count = 0; stepper.initialize( start_state , start_time , dt ); while( less_with_sign( stepper.current_time() , end_time , stepper.current_time_step() ) ) { while( less_eq_with_sign( stepper.current_time() + stepper.current_time_step() , end_time , stepper.current_time_step() ) ) { //make sure we don't go beyond the end_time obs( stepper.current_state() , stepper.current_time() ); stepper.do_step( system ); ++count; } stepper.initialize( stepper.current_state() , stepper.current_time() , end_time - stepper.current_time() ); } obs( stepper.current_state() , stepper.current_time() ); // overwrite start_state with the final point boost::numeric::omplext_odeint::copy( stepper.current_state() , start_state ); return count; }
void check_stepper_concept( Stepper &stepper , System system , typename Stepper::deriv_type &x ) { typedef Stepper stepper_type; typedef typename stepper_type::deriv_type container_type; typedef typename stepper_type::order_type order_type; typedef typename stepper_type::time_type time_type; stepper.do_step( system , x , 0.0 , 0.1 ); }
void operator()( void ) { Stepper stepper; initializing_stepper init_stepper; const int o = stepper.order()+1; //order of the error is order of approximation + 1 const state_type x0 = {{ 0.0 , 1.0 }}; state_type x1 = x0; double t = 0.0; double dt = 0.2; // initialization, does a number of steps already to fill internal buffer, t is increased // we use the rk78 as initializing stepper stepper.initialize( boost::ref(init_stepper) , osc() , x1 , t , dt ); double A = std::sqrt( x1[0]*x1[0] + x1[1]*x1[1] ); double phi = std::asin(x1[0]/A) - t; // do a number of steps to fill the buffer with results from adams bashforth for( size_t n=0 ; n < stepper.steps ; ++n ) { stepper.do_step( osc() , x1 , t , dt ); t += dt; } // now we do the actual step stepper.do_step( osc() , x1 , t , dt ); // only examine the error of the adams-bashforth step, not the initialization const double f = 2.0 * std::abs( A*sin(t+dt+phi) - x1[0] ) / std::pow( dt , o ); // upper bound std::cout << o << " , " << f << std::endl; /* as long as we have errors above machine precision */ while( f*std::pow( dt , o ) > 1E-16 ) { x1 = x0; t = 0.0; stepper.initialize( boost::ref(init_stepper) , osc() , x1 , t , dt ); A = std::sqrt( x1[0]*x1[0] + x1[1]*x1[1] ); phi = std::asin(x1[0]/A) - t; // now we do the actual step stepper.do_step( osc() , x1 , t , dt ); // only examine the error of the adams-bashforth step, not the initialization std::cout << "Testing dt=" << dt << " , " << std::abs( A*sin(t+dt+phi) - x1[0] ) << std::endl; BOOST_CHECK_LT( std::abs( A*sin(t+dt+phi) - x1[0] ) , f*std::pow( dt , o ) ); dt *= 0.5; } }
/*! Returns propagated state and max relative errors in kinetic energy and magnetic moment of particle. */ template<class Stepper> std::tuple<state_t, double, double> trace_trajectory( state_t state, const double time_step ) { using std::fabs; using std::max; constexpr double propagation_time = 424.1; // seconds, 1/100 of doi above Particle_Propagator propagator(proton_charge_mass_ratio); const double initial_energy = 0.5 * proton_mass * state[1].squaredNorm(), initial_magnetic_moment = proton_mass * std::pow(state[1][1], 2) / (2 * get_earth_dipole(state[0]).norm()); Stepper stepper; double nrj_error = 0, mom_error = 0; for (double time = 0; time < propagation_time; time += time_step) { stepper.do_step(propagator, state, time, time_step); const Eigen::Vector3d v(state[1]), b(get_earth_dipole(state[0])), v_perp_b(v - (v.dot(b) / b.squaredNorm()) * b); const double current_energy = 0.5 * proton_mass * state[1].squaredNorm(), current_magnetic_moment = proton_mass * v_perp_b.squaredNorm() / (2 * b.norm()); nrj_error = max( nrj_error, fabs(current_energy - initial_energy) / initial_energy ); mom_error = max( mom_error, fabs(current_magnetic_moment - initial_magnetic_moment) / initial_magnetic_moment ); } return std::make_tuple(state, nrj_error, mom_error); }
void check_dense_output_stepper( Stepper &stepper ) { typedef Stepper stepper_type; 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::order_type order_type; time_type t( 0.0 * si::second ); time_type dt( 0.1 * si::second ); state_type x( 1.0 * si::meter , 0.0 * si::meter_per_second ) , x2; stepper.initialize( x , t , dt ); stepper.do_step( oscillator ); stepper.calc_state( dt / 2.0 , x2 ); }
size_t integrate_adaptive( Stepper stepper , System system , State &start_state , Time start_time , Time end_time , Time dt , Observer observer , stepper_tag ) { size_t steps = boost::numeric::odeint::detail::integrate_const( stepper , system , start_state , start_time , end_time , dt , observer , stepper_tag() ); if( steps*dt < end_time ) { //make a last step to end exactly at end_time stepper.do_step( system , start_state , steps*dt , end_time-steps*dt ); steps++; typename boost::unwrap_reference< Observer >::type &obs = observer; obs( start_state , end_time ); } return steps; }
size_t integrate_adaptive( Stepper stepper , System system , State &start_state , Time start_time , Time end_time , Time dt , Observer observer , stepper_tag ) { size_t steps = static_cast< size_t >( (end_time-start_time)/dt ); Time end = detail::integrate_n_steps( stepper , system , start_state , start_time , dt , steps , observer , stepper_tag() ); if( less_with_sign( end , end_time , dt ) ) { //make a last step to end exactly at end_time stepper.do_step( system , start_state , end , end_time - end ); steps++; typename omplext_odeint::unwrap_reference< Observer >::type &obs = observer; obs( start_state , end_time ); } return steps; }
void operator()( void ) { /* We have to specify the desired precision in advance! */ mpf_set_default_prec( precision ); mpf_t eps_ , unity; mpf_init( eps_ ); mpf_init( unity ); mpf_set_d( unity , 1.0 ); mpf_div_2exp( eps_ , unity , precision-1 ); // 2^(-precision+1) : smallest number that can be represented with used precision value_type eps( eps_ ); Stepper stepper; state_type x; x = 0.0; stepper.do_step( constant_system , x , 0.0 , 0.1 ); BOOST_MESSAGE( eps ); BOOST_CHECK_MESSAGE( abs( x - value_type( 0.1 , precision ) ) < eps , x - 0.1 ); }
Time integrate_n_steps( Stepper stepper , System system , State &start_state , Time start_time , Time dt , size_t num_of_steps , Observer observer , stepper_tag ) { typename odeint::unwrap_reference< Observer >::type &obs = observer; Time time = start_time; for( size_t step = 0; step < num_of_steps ; ++step ) { obs( start_state , time ); stepper.do_step( system , start_state , time , dt ); // direct computation of the time avoids error propagation happening when using time += dt // we need clumsy type analysis to get boost units working here time = start_time + static_cast< typename unit_value_type<Time>::type >( step+1 ) * dt; } obs( start_state , time ); return time; }
typename Stepper::time_type integrate_const_steps( Stepper &stepper , DynamicalSystem &system , typename Stepper::container_type &state , typename Stepper::time_type start_time , typename Stepper::time_type dt , size_t num_of_steps , Observer &observer ) { stepper.adjust_size( state ); size_t iteration = 0; while( iteration < num_of_steps ) { observer( start_time , state , system ); stepper.do_step( system , state , start_time , dt ); start_time += dt; ++iteration; } observer( start_time , state , system ); return start_time; }
size_t integrate_adaptive( Stepper stepper , System system , State &start_state , Time start_time , Time end_time , Time dt , Observer observer , dense_output_stepper_tag ) { typename boost::unwrap_reference< Observer >::type &obs = observer; size_t count = 0; stepper.initialize( start_state , start_time , dt ); while( stepper.current_time() < end_time ) { while( stepper.current_time() + stepper.current_time_step() <= end_time ) { //make sure we don't go beyond the end_time obs( stepper.current_state() , stepper.current_time() ); stepper.do_step( system ); ++count; } stepper.initialize( stepper.current_state() , stepper.current_time() , end_time - stepper.current_time() ); } obs( stepper.current_state() , stepper.current_time() ); return count; }