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.
Related
I ran the following code which solves a simple differential equation. The result seems to depend on tsteps. The result I get for tsteps = 100 is 9.688438503116524e-15, but for tsteps = 1000 the answer is 7.124585369895499e-218 much closer to the expected result.
#include <iostream>
#include <iomanip>
#include <boost/numeric/odeint.hpp> // odeint function definitions
using namespace std;
using namespace boost::numeric::odeint;
typedef std::vector< double> state_type;
int tsize = 1;
void my_observer( const state_type &x, const double t );
void initarrays(state_type &x)
{
x[0]=1.0e0;
}
void my_system( const state_type &x , state_type &dxdt , const double t )
{
dxdt[0]=-x[0];
}
void my_observer( const state_type &x, const double t )
{
std::cout<<t<<" ";
for(int i=0;i<tsize;i++)
{
std::cout<<x[i]<<" ";
}
std::cout<<std::endl;
}
int main()
{
std::cout.setf ( std::ios::scientific, std::ios::floatfield );
std::cout.precision(15);
int size=tsize;
state_type x0(size);
double err_abs = 1.0e-12;
double err_rel = 1.0e-12;
double a_x = 1.0;
double a_dxdt = 1.0;
initarrays(x0);
double t0 = 0.0e0;
int tsteps = 1000;
double t1 = 500.0e0;
double dt = (t1-t0)/((double)tsteps);
typedef runge_kutta_fehlberg78< state_type > solver;
typedef controlled_runge_kutta< solver > controller;
my_observer(x0,t0);
for(int ts=0;ts<tsteps;ts++)
{
integrate_adaptive( make_controlled( err_abs , err_rel , solver() ), my_system, x0 , t0+ts*dt , t0+(1+ts)*dt , dt);
my_observer(x0,t0+(1+ts)*dt);
}
}
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;
}
I'm trying to use solve my ode system and use openmp. When I try stepper.do_step with:
typedef runge_kutta_dopri5< state_type , double , state_type , double , openmp_range_algebra > stepper;
I define my state_type as std::vector
And I compile I get:
error: expected unqualified-id before '.' token stepper.do_step(c , Y , t, dt );
Is it a problem of my typedef or I can't use do_step with openmp?
#include <boost/numeric/odeint.hpp>
#include<omp.h>
#include <boost/numeric/odeint/external/openmp/openmp.hpp>
typedef std::vector< double > state_type;
struct T
{
double m_param1;
double m_param2;
};
class sys
{
struct T T1;
public:
sys(struct T G) : T1(G) {}
void operator() ( state_type const& Y , state_type& dY , double t )
{
const size_t N = Y.size();
#pragma omp parallel for schedule(runtime)
for (size_t aux = 0; aux <= N; aux++) {
mdlfnt(Y,dY,t,T1.m_currents,T1.m_stim); //Here is my ode system
}
}
};
struct T T2;
state_type Y(45); // initial conditions
void main()
{
typedef runge_kutta_dopri5< state_type , double , state_type , double , openmp_range_algebra , default_operations , never_resizer > stepper;
int number_threads = 1;
omp_set_num_threads(number_threads);
int chunk_size = omp_get_max_threads();
omp_set_schedule( omp_sched_static , chunk_size );
for(int i=0;i<nd;i++){
sys c(T2);
stepperdo_step(c , Y , t, dt );
}
}
Is there a way to write the outputs of t and x of this example to a txt file instead of the console. Thanks!
This is the example I copied from Odeint website.
#include <iostream>
#include <boost/numeric/odeint.hpp>
using namespace std;
using namespace boost::numeric::odeint;
/* we solve the simple ODE x' = 3/(2t^2) + x/(2t)
* with initial condition x(1) = 0.
* Analytic solution is x(t) = sqrt(t) - 1/t
*/
void rhs( const double x , double &dxdt , const double t )
{
dxdt = 3.0/(2.0*t*t) + x/(2.0*t);
}
void write_cout( const double &x , const double t )
{
cout << t << '\t' << x << endl;
}
// state_type = double
typedef runge_kutta_dopri5< double > stepper_type;
int main()
{
double x = 0.0;
integrate_adaptive( make_controlled( 1E-12 , 1E-12 , stepper_type() ) ,
rhs , x , 1.0 , 10.0 , 0.1 , write_cout );
}
you can simply pipe the output of this example into a text file
$ ./lorenz > data.txt
Otherwise you can use a C++ ofstreams to write the output directly into a file, e.g. described there: http://www.cplusplus.com/doc/tutorial/files/
just replace cout with object of ofstream.
#include <iostream>
#include <fstream>
#include <boost/numeric/odeint.hpp>
using namespace std;
using namespace boost::numeric::odeint;
ofstream data("data.txt");
/* we solve the simple ODE x' = 3/(2t^2) + x/(2t)
* with initial condition x(1) = 0.
* Analytic solution is x(t) = sqrt(t) - 1/t
*/
void rhs(const double x, double &dxdt, const double t)
{
dxdt = 3.0 / (2.0*t*t) + x / (2.0*t);
}
void write_cout(const double &x, const double t)
{
data << t << '\t' << x << endl;
}
// state_type = double
typedef runge_kutta_dopri5< double > stepper_type;
int main()
{
double x = 0.0;
integrate_adaptive(make_controlled(1E-12, 1E-12, stepper_type()),
rhs, x, 1.0, 10.0, 0.1, write_cout);
}
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.