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 );
}
}
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;
}
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.
How would I whip up a custom stepper for the ODE integrator in boost? I know how to do that for an array whose size is known at compile time. A simple implementation is like this
#include <boost/array.hpp>
#include <boost/numeric/odeint.hpp>
using namespace std;
using namespace boost::numeric::odeint;
typedef boost::array<double, 2> state_type;
template <size_t N>
class euler_stepper {
public:
typedef double value_type;
typedef double time_type;
typedef unsigned short order_type;
typedef boost::numeric::odeint::stepper_tag stepper_category;
static order_type order(void) { return(1); }
template<class System>
void do_step(System system, state_type &x, time_type t, time_type dt) const {
state_type der;
system(x , der);
for(size_t i=0 ; i<x.size(); i++) {
x[i] += dt*der[i];
}
}
};
struct rhs {
void operator()(const state_type &x, state_type &dxdt) const {
for(int i=0; i < x.size(); i++) dxdt[i] = -x[i];
}
};
struct observer {
void operator()(const state_type &x , double t) const {
for(int i=0; i < x.size(); i++) cout << x[i] << '\t';
cout << endl;
}
};
int main(int argc , char **argv) {
double dt = 0.01;
state_type x = {{2.0, 1.0}};
integrate_const(euler_stepper<2>(), rhs(), x, 0.0, 0.1, dt, observer());
return 0;
}
But how should I change the implementation, if I wanted to work with a state_type like this
typedef vector<complex<double>> state_type;
Basically, I would like to pass the size of the state vector as an argument to main.
Thanks,
Zoltán
Try this:
template < typename State >
class euler_stepper {
public:
using state_type = State;
using value_type = typename state_type::value_type;
using time_type = value_type;
using order_type = unsigned short;
using stepper_category = boost::numeric::odeint::stepper_tag;
static order_type order(void) { return(1); }
template<class System>
void do_step( System system , state_type &x , time_type t , time_type dt ) const
{
state_type der;
system(x , der);
for(size_t i=0 ; i<x.size(); i++) {
x[i] += dt*der[i];
}
}
};
You can also fix the state type for your solver, for example:
class euler_stepper
{
public:
using state_type = vector< complex< double > >;
using value_type = double;
using time_type = double;
// ...
};
I have an ODE of type:
x'(t) = a(t)x+g(t)
Which I am trying to solve. The only GSL ODE example isn't very helpful because the only coefficient (\mu) is not time dependent.
This question has been answered on the GSL mailing list however the answer is very unclear - g(t) is ignored and it has not been explained how to incorporate a(t) into func ( should it be passed in *params?).
Is there any example I can see where such an ODE is solved using GSL?
UPDATE: As has been pointed out below, this has been answered on the GSL mailing list. Here is a full example program of how this is done:
#include <stdio.h>
#include <math.h>
#include "gsl/gsl_errno.h"
#include "gsl/gsl_matrix.h"
#include "gsl/gsl_odeiv2.h"
int func(double t, const double y[], double f[], void *params) {
f[0] = -t* y[0];
return GSL_SUCCESS;
}
int jac(double t, const double y[], double *dfdy, double dfdt[], void
*params) {
gsl_matrix_view dfdy_mat = gsl_matrix_view_array(dfdy, 1, 1);
gsl_matrix * m = &dfdy_mat.matrix;
gsl_matrix_set(m, 0, 0, -t);
dfdt[0] = -1;
return GSL_SUCCESS;
}
int main(void) {
double mu = 0;
gsl_odeiv2_system sys = { func, jac, 1, &mu };
gsl_odeiv2_driver * d = gsl_odeiv2_driver_alloc_y_new(&sys,
gsl_odeiv2_step_rk1imp, 1e-7, 1e-7, 0.0);
int i;
double t = 0.0, t1 = 2.0;
const double x0 = 1.0;
double y[1] = {x0};
const int N = 100;
printf("time\t \tapprox solution \t exact solution\n");
for (i = 0; i <= N; i++) {
double ti = i * (t1 / N);
int status = gsl_odeiv2_driver_apply(d, &t, ti, y);
if (status != GSL_SUCCESS) {
printf("error, return value=%d\n", status);
break;
}
printf("%.5e\t%.5e\t\t%.5e\n", t, y[0], x0*exp(-0.5*t*t));
}
gsl_odeiv2_driver_free(d);
printf("\n...and done!\n");
return 0;
}
If you are not restricted to the GSL and/or C you can use http://odeint.com - a modern C++ library for ODEs. Odeint is part of boost, so it might be already installed on your system or can easily be installed be most of the package managers for Linux distributions.
You can simply define your coefficients and the ODE and use for example the RK4 method:
double coef_a( double t ) { /* return a(t) */ };
double coef_g( double t ) { /* return b(t) */ };
typedef std::array< double , 1 > state_type;
double ode( state_type const &x , state_type &dxdt , double )
{
dxdt[0] = coef_a( t ) * x[0] + coef_g( t );
}
state_type x;
double t_state , t_end , dt;
// initialize x
integrate_const( runge_kutta< state_type >() , ode , x , t_start , dt , t_end );