I intend to use the Boost odeint library in an MCMC routine to estimate parameters in an ODE model. Since these ODEs may be stiff, I need to be able to pass the jacobian into the solver with the derivative. I would like to make a class which has the parameters and initial values as private members and then the derivative, jacobian, and methods to change the parameters as public methods. I tried to modify the stiff example from the odeint website to use one class containing both, but am receiving the error 'error: no matching function for call to 'Fitzhugh::deriv()' when comiling. I am not an experienced C++ programmer, so this is likely a conceptual mistake. Here is the code.
/* Fitzhugh Nagumo Equation in odeint */
#include <iostream>
#include <fstream>
#include <utility>
#include <cmath>
#include <boost/numeric/odeint.hpp>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
using namespace std;
using namespace boost::numeric::odeint;
namespace phoenix = boost::phoenix;
//[ stiff_system_definition
typedef boost::numeric::ublas::vector< double > vector_type;
typedef boost::numeric::ublas::matrix< double > matrix_type;
class Fitzhugh
{
private:
double a;
double b;
double c;
public:
Fitzhugh( double a_, double b_, double c_ ) : a(a_), b(b_), c(c_) { }
void deriv ( const vector_type &x , vector_type &dxdt , double )
{
dxdt[ 0 ] = c*(x[0] - pow(x[0], 3.0)/3.0 + x[1]);
dxdt[ 1 ] = -(x[0] - a + b*x[1])/c;
}
void jac ( const vector_type &x, matrix_type &J , const double & , vector_type &dfdt )
{
J( 0 , 0 ) = c*(1 - pow(x[0], 2.0));
J( 0 , 1 ) = c;
J( 1 , 0 ) = -1/c;
J( 1 , 1 ) = -b/c;
dfdt[0] = 0.0;
dfdt[1] = 0.0;
}
};
int main( int argc , char **argv )
{
// typedef rosenbrock4< double > stepper_type;
// typedef rosenbrock4_controller< stepper_type > controlled_stepper_type;
// typedef rosenbrock4_dense_output< controlled_stepper_type > dense_output_type;
//[ integrate_stiff_system
vector_type x( 2 , 1.0 );
Fitzhugh fitzhugh(0.2, 0.2, 3.0);
size_t num_of_steps = integrate_const( make_dense_output< rosenbrock4< double > >( 1.0e-6 , 1.0e-6 ) ,
make_pair( fitzhugh.deriv() , fitzhugh.jac() ) ,
x , 0.0 , 50.0 , 0.01 ,
cout << phoenix::arg_names::arg2 << " " << phoenix::arg_names::arg1[0] << "\n" );
//]
clog << num_of_steps << endl;
return 0;
}
Here is the full output
/home/chris/C++/examples/fitzhugh/main.cpp: In function ‘int main(int, char**)’:
/home/chris/C++/examples/fitzhugh/main.cpp:60:39: error: no matching function for call to ‘Fitzhugh::deriv()’
/home/chris/C++/examples/fitzhugh/main.cpp:60:39: note: candidate is:
/home/chris/C++/examples/fitzhugh/main.cpp:30:14: note: void Fitzhugh::deriv(const vector_type&, vector_type&, double)
/home/chris/C++/examples/fitzhugh/main.cpp:30:14: note: candidate expects 3 arguments, 0 provided
/home/chris/C++/examples/fitzhugh/main.cpp:60:56: error: no matching function for call to ‘Fitzhugh::jac()’
/home/chris/C++/examples/fitzhugh/main.cpp:60:56: note: candidate is:
/home/chris/C++/examples/fitzhugh/main.cpp:36:14: note: void Fitzhugh::jac(const vector_type&, matrix_type&, const double&, vector_type&)
/home/chris/C++/examples/fitzhugh/main.cpp:36:14: note: candidate expects 4 arguments, 0 provided
to pass member function you need to use a bind mechanism. if you have a c++11 compiler you can use std::bind; include the std::placeholders namespace: using namespace std::placeholders; then use std::bind from <functional>:
make_pair( bind( &Fitzhugh::deriv , &fitzhugh , _1 , _2 , _3 ) ,
bind( &Fitzhugh::jac , &fitzhugh , _1 , _2 , _3, _4 ) )
Related
I was trying to implement a simple ode to test whether boost.odeint is supporting the usage of boost.units. However my example is failing at compilation. Is it my code, or doesn't boost.odeint support boost.Units for dimensional analysis?
#include<boost/units/systems/si.hpp>
#include<boost/numeric/odeint.hpp>
typedef boost::units::quantity<boost::units::si::length,double> state_type;
typedef boost::units::quantity<velocity,double> dev_type;
typedef boost::units::quantity<boost::units::si::time,double> time_type;
using namespace boost::units::si;
void exponential_decay(const state_type &x, dev_type &dxdt, time_type t){
dxdt = -0.0001*x/second;
}
int main(){
state_type startValue = 10*meter;
using namespace boost::numeric::odeint;
auto steps = integrate(exponential_decay, startValue, 0.0*second,
10.0*second, 0.1*second);
return 0;
}
So, after initially failing to find a working set of state_type, algebra and operations¹ #Arash supplied the missing link.
However, for completeness, you do not need to bring the heavy machinery (fusion_algebra.hpp). These are for the more general cases, e.g. where the state type is not a single value.
In this simple case, all that was really required was to specify the algebra, instead of going with the default. This involves declaring a stepper_type, like:
using stepper_type = runge_kutta4<length_type, double, velocity_type,
time_type, vector_space_algebra>;
Next, we pick an itegration algorithm overload that allows us to supply that stepper:
Live On Coliru
#include <boost/numeric/odeint.hpp>
#include <boost/units/systems/si.hpp>
typedef boost::units::quantity<boost::units::si::length, double> length_type;
typedef boost::units::quantity<boost::units::si::velocity, double> velocity_type;
typedef boost::units::quantity<boost::units::si::time, double> time_type;
namespace si = boost::units::si;
void exponential_decay(const length_type &x, velocity_type &dxdt, time_type /*t*/) { dxdt = -0.0001 * x / si::second; }
int main() {
using stepper_type = boost::numeric::odeint::runge_kutta4<
length_type, double, velocity_type, time_type, boost::numeric::odeint::vector_space_algebra>;
length_type startValue = 10 * si::meter;
auto steps = integrate_const(
stepper_type{}, exponential_decay,
startValue, 0.0 * si::second, 10.0 * si::second,
0.1 * si::second);
std::cout << "Steps: " << steps << "\n";
}
Prints
Steps: 100
¹ from just looking at http://www.boost.org/doc/libs/1_66_0/libs/numeric/odeint/doc/html/boost_numeric_odeint/odeint_in_detail/state_types__algebras_and_operations.html and http://www.boost.org/doc/libs/1_66_0/doc/html/boost_units/Quantities.html
Use boost::fusion to fix the problem.
#include <iostream>
#include <vector>
#include <boost/numeric/odeint.hpp>
#include <boost/numeric/odeint/algebra/fusion_algebra.hpp>
#include <boost/numeric/odeint/algebra/fusion_algebra_dispatcher.hpp>
#include <boost/units/systems/si/length.hpp>
#include <boost/units/systems/si/time.hpp>
#include <boost/units/systems/si/velocity.hpp>
#include <boost/units/systems/si/acceleration.hpp>
#include <boost/units/systems/si/io.hpp>
#include <boost/fusion/container.hpp>
using namespace std;
using namespace boost::numeric::odeint;
namespace fusion = boost::fusion;
namespace units = boost::units;
namespace si = boost::units::si;
typedef units::quantity< si::time , double > time_type;
typedef units::quantity< si::length , double > length_type;
typedef units::quantity< si::velocity , double > velocity_type;
typedef units::quantity< si::acceleration , double > acceleration_type;
typedef units::quantity< si::frequency , double > frequency_type;
typedef fusion::vector< length_type > state_type;
typedef fusion::vector< velocity_type > deriv_type;
void exponential_decay( const state_type &x , deriv_type &dxdt , time_type t )
{
fusion::at_c< 0 >( dxdt ) = (-0.0001/si::second)* fusion::at_c< 0 >( x );
}
void observer(const state_type &x,const time_type &t )
{
}
int main( int argc , char**argv )
{
typedef runge_kutta_dopri5< state_type , double , deriv_type , time_type > stepper_type;
state_type startValue( 1.0 * si::meter );
auto steps=integrate_adaptive(
make_dense_output( 1.0e-6 , 1.0e-6 , stepper_type()),
exponential_decay,
startValue , 0.0 * si::second , 100.0 * si::second , 0.1 * si::second , observer);
std::cout<<"steps: "<<steps<<std::endl;
return 0;
}
As I know function call operator overloading is used to pass arbitrary number of parameter to a function inside a class. Is it also possible to pass a 2-Dimensional array ?
something like this in the following code:Edited
class harm_osc {
vector< vector<double> >& m_gam;
public:
harm_osc( vector< vector<double> > &gam ) : m_gam(gam) { }
void operator() ( const state_type &x , state_type &dxdt , const double /* t */ )
{
dxdt[0] = m_gam[0][0]*x[1];
dxdt[1] = m_gam[1][0]*x[0] - m_gam[1][1]*x[1];
}
};
When we have a large system of equations there are a lot of parameters.
Here an example from odeint library with some modification, with a single parameter:Edited
#include <iostream>
#include <vector>
#include <boost/numeric/odeint.hpp>
using namespace std;
/* The type of container used to hold the state vector */
typedef vector< double > state_type;
/* The rhs of x' = f(x) defined as a class */
class harm_osc {
vector< vector<double> >& m_gam;
public:
harm_osc( vector< vector<double> > &gam ) : m_gam(gam) { }
void operator() ( const state_type &x , state_type &dxdt , const double /* t */ )
{
dxdt[0] = m_gam[0][0]*x[1];
dxdt[1] = m_gam[1][0]*x[0] - m_gam[2][2]*x[1];
}
};
int main(int /* argc */ , char** /* argv */ )
{
using namespace boost::numeric::odeint;
//[ state_initialization
state_type x(2);
x[0] = 1.0; // start at x=1.0, p=0.0
x[1] = 0.0;
//]
//[ integration_class
vector< vector<double> > par {{1.,0.},{-1.,0.15}};
harm_osc ho(par);
size_t steps = integrate( ho ,
x , 0.0 , 10.0 , 0.1);
//]
}
Thanks for any guide or comment.
I have been extending the simple Runge Kutta example (example 2, 1D ODE) from ODEINT .
The code itself works without trouble.
But then I tried to put everything into a class called runge_kutta and now the recursive inegration is not working anymore, the orginal line is
integrate_adaptive( make_controlled( 1E-12 , 1E-12 , stepper_type() ) ,
rhs , x , 1.0 , 10.0 , 0.1 , write_cout );
I thought that just adding "runge_kutta::"
return integrate_adaptive( make_controlled( 1E-12 , 1E-12 , stepper_type() ) , runge_kutta::rhs, x , 1.0 , 10.0 , timestep , runge_kutta::write_cout );
would fix the issue , but
the error message is
error: no matching function for call to 'integrate_adaptive(boost::numeric::odeint::result_of::make_controlled<boost::numeric::odeint::runge_kutta_dopri5<double> >::type, <unresolved overloaded function type>, double&, double, double, double&, <unresolved overloaded function type>)'
The complete class is defined as follows:
rk.h
#ifndef RK_H_
#define RK_H_
#include <iostream>
#include <cmath>
#include <odeint.hpp>
using namespace boost::numeric::odeint;
class runge_kutta{
public:
runge_kutta(double beta1, double gamma1);
void setparameter(double dist1,double grad);
double solve(double x,double t);
int main();
void write_cout( const double &x , const double t );
private:
void rhs( const double x , double &dxdt , const double t );
double smoothen(double x);
double beta, gamma;
double distance, gradient;
typedef runge_kutta_dopri5< double > stepper_type;
};
#endif /* RK_H_ */
rk.cpp:
#include "rk.h"
double beta, gamma;
double dist, gradient;
void runge_kutta::rhs( const double x , double &dxdt , const double t )
{
dxdt = smoothen(x)*dist*abs(gradient);
}
void runge_kutta::write_cout( const double &x , const double t )
{
std::cout << t << '\t' << x << std::endl;
}
// state_type = double
runge_kutta::runge_kutta(double beta1, double gamma1){
beta = beta1;
gamma = gamma1;
}
void runge_kutta::setparameter(double dist1,double grad){
dist = dist1;
gradient = grad;
}
double runge_kutta::solve(double x,double t){
beta = 0.4;
gamma = 0.8;
typedef runge_kutta_dopri5< double > stepper_type;
return integrate_adaptive( make_controlled( 1E-12 , 1E-12 , stepper_type() ) , runge_kutta::rhs, x , 1.0 , 10.0 , timestep , runge_kutta::write_cout );
}
double runge_kutta::smoothen(double phix){
if (abs(phix)<= beta)
return 1;
else if (abs(phix)> gamma)
return 0;
else
return ((abs(phix)-gamma)*(abs(phix)-gamma)*(2*abs(phix)+gamma-3*beta)/((gamma-beta)*(gamma-beta)*(gamma-beta)));
}
You've replaced functions like write_cout with member functions, but they are not the same thing. You can't just use free functions and member functions interchangeably.
Also, to take the address of a member function you must use &runge_kutta::write_cout not just runge_kutta::write_cout (but that probably won't fix the error, for the reason above).
I try to run [odeint complex state type example code in boost_1_55_0 on Mac OS X 10.9.2 g++ 5.1.
The code below is the copy on the website which solves the Stuart-Landau oscillator
#include <iostream>
#include <complex>
#include <boost/array.hpp>
#include <boost/numeric/odeint.hpp>
using namespace std;
using namespace boost::numeric::odeint;
//[ stuart_landau_system_function
typedef complex< double > state_type;
struct stuart_landau
{
double m_eta;
double m_alpha;
stuart_landau( double eta = 1.0 , double alpha = 1.0 )
: m_eta( eta ) , m_alpha( alpha ) { }
void operator()( const state_type &x , state_type &dxdt , double t ) const
{
const complex< double > I( 0.0 , 1.0 );
dxdt = ( 1.0 + m_eta * I ) * x - ( 1.0 + m_alpha * I ) * norm( x ) * x;
}
};
//]
/*
//[ stuart_landau_system_function_alternative
double eta = 1.0;
double alpha = 1.0;
void stuart_landau( const state_type &x , state_type &dxdt , double t )
{
const complex< double > I( 0.0 , 1.0 );
dxdt = ( 1.0 + m_eta * I ) * x - ( 1.0 + m_alpha * I ) * norm( x ) * x;
}
//]
*/
struct streaming_observer
{
std::ostream& m_out;
streaming_observer( std::ostream &out ) : m_out( out ) { }
template< class State >
void operator()( const State &x , double t ) const
{
m_out << t;
m_out << "\t" << x.real() << "\t" << x.imag() ;
m_out << "\n";
}
};
int main( int argc , char **argv )
{
//[ stuart_landau_integration
state_type x = complex< double >( 1.0 , 0.0 );
const double dt = 0.1;
typedef runge_kutta4< state_type > stepper_type;
integrate_const( stepper_type() , stuart_landau( 2.0 , 1.0 ) , x , 0.0 , 10.0 , dt , streaming_observer( cout ) );
//]
return 0;
}
The sample code above doesn't compile. 9 errors generates and ends with:
'boost::numeric::odeint::explicit_stepper_base<boost::numeric::odeint::explicit_generic_rk<4, 4, std::__1::complex<double>, double, std::__1::complex<double>, double,
boost::numeric::odeint::range_algebra, boost::numeric::odeint::default_operations, boost::numeric::odeint::initially_resizer>, 4, std::__1::complex<double>, double, std::__1::complex<double>,
double, boost::numeric::odeint::range_algebra, boost::numeric::odeint::default_operations, boost::numeric::odeint::initially_resizer>::do_step_v1<stuart_landau, std::__1::complex<double> >'
requested here
do_step_v1( system , x , t , dt );
^
/usr/include/boost/numeric/odeint/integrate/detail/integrate_adaptive.hpp:62:17: note: in instantiation of function template specialization
'boost::numeric::odeint::explicit_stepper_base<boost::numeric::odeint::explicit_generic_rk<4, 4, std::__1::complex<double>, double, std::__1::complex<double>, double,
boost::numeric::odeint::range_algebra, boost::numeric::odeint::default_operations, boost::numeric::odeint::initially_resizer>, 4, std::__1::complex<double>, double, std::__1::complex<double>,
double, boost::numeric::odeint::range_algebra, boost::numeric::odeint::default_operations, boost::numeric::odeint::initially_resizer>::do_step<stuart_landau, std::__1::complex<double> >' requested
here
stepper.do_step( system , start_state , end , end_time - end );
^
/usr/include/boost/numeric/odeint/integrate/integrate_const.hpp:50:24: note: in instantiation of function template specialization
'boost::numeric::odeint::detail::integrate_adaptive<boost::numeric::odeint::runge_kutta4<std::__1::complex<double>, double, std::__1::complex<double>, double, boost::numeric::odeint::range_algebra,
boost::numeric::odeint::default_operations, boost::numeric::odeint::initially_resizer>, stuart_landau, std::__1::complex<double>, double, streaming_observer>' requested here
return detail::integrate_adaptive(
^
main.cpp:84:5: note: in instantiation of function template specialization 'boost::numeric::odeint::integrate_const<boost::numeric::odeint::runge_kutta4<std::__1::complex<double>, double,
std::__1::complex<double>, double, boost::numeric::odeint::range_algebra, boost::numeric::odeint::default_operations, boost::numeric::odeint::initially_resizer>, stuart_landau,
std::__1::complex<double>, double, streaming_observer>' requested here
integrate_const( stepper_type() , stuart_landau( 2.0 , 1.0 ) , x , 0.0 , 10.0 , dt , streaming_observer( cout ) );
^
What is the bug?
You use a feature which only exist in the github version of odeint. Replace the typedef for the stepper with
typedef runge_kutta4< state_type , double ,
state_type , double ,
vector_space_algebra > stepper_type;
Automatic algebra detection currently works only in the github version of odeint. We try to get this feature into the next official boost version.
Can you provide me with a simple example of performing a numeric integration with odeint in C++?
I would like to use the convenient integrate function, documented as:
integrate( system , x0 , t0 , t1 , dt )
Also I'm not sure, how to pass it instead of a function or a functor, a class method, if that's possible.
In C++11 you can use a simple lambda function wrapping the call to your member method
Class c;
auto f = [&c]( const state_type & x , state_type &dxdt , double t ) {
c.system_func( x , dxdt , t ); };
integrate( f , x0 , t0 , t1 , dt );
std::bind might also work, but then you have to take care if values are passed by reference of by value.
In C++03 you need to write a simple wrapper around your class method
struct wrapper
{
Class &c;
wrapper( Class &c_ ) : c( c_ ) { }
template< typename State , typename Time >
void operator()( State const &x , State &dxdt , Time t ) const
{
c.system_func( x , dxdt , t );
}
};
// ...
integrate( wrapper( c ) , x0 , t0 , t1 , dt );
(Boost.Bind will not work correctly with more then two arguments).
You mean examples in addition to the ones provided online?
#include <iostream>
#include <boost/array.hpp>
#include <boost/numeric/odeint.hpp>
using namespace std;
using namespace boost::numeric::odeint;
const double sigma = 10.0;
const double R = 28.0;
const double b = 8.0 / 3.0;
typedef boost::array< double , 3 > state_type;
void lorenz( const state_type &x , state_type &dxdt , double t )
{
dxdt[0] = sigma * ( x[1] - x[0] );
dxdt[1] = R * x[0] - x[1] - x[0] * x[2];
dxdt[2] = -b * x[2] + x[0] * x[1];
}
void write_lorenz( const state_type &x , const double t )
{
cout << t << '\t' << x[0] << '\t' << x[1] << '\t' << x[2] << endl;
}
int main(int argc, char **argv)
{
state_type x = { 10.0 , 1.0 , 1.0 }; // initial conditions
integrate( lorenz , x , 0.0 , 25.0 , 0.1 , write_lorenz );
}
And regarding the system, you can provide anything where the following expression is valid:
sys( x , dxdt , t ) // returning void
Check the user's guide (and more examples) online.