C ++类成员函数到GSL ODE求解器

时间:2017-11-01 08:27:56

标签: c++ class pointers ode gsl

我正在努力 - 显然 - 一个众所周知的问题。我有一个由类成员函数定义的ODE系统,我想通过一个GSL求解器来解决/集成它。即,我的模型定义为:

class my_model{
...
public:
    int NEQ = 4;
    double y[4], dydt[4];
    double params[25]; 
    int ode_gsl(double t, const double y[], double dydt[], void * params);
    ...
};

int my_model::int ode_gsl(double t, const double y[], double dydt[], void * params){
    dydt[0] = params[1]*params[0]*y[0] - y[1];
    dydt[1] = ...;
    ...
    return GSL_SUCCESS;    
}

然后在我的集成例程中:

int main(){
    my_model chemosc;

   // Parameters for the Integrator
   double HSTART = 1e-3;
   double ATOL = 1e-8;
   double RTOL = 1e-6;

   // Instantiate GSL solver
   gsl_odeiv2_system sys = {&chemosc.ode_gsl, nullptr, chemosc.NEQ, chemosc.params};
   gsl_odeiv2_driver * d;
   d = gsl_odeiv2_driver_alloc_y_new (&sys, gsl_odeiv2_step_rk8pd, HSTART, ATOL, RTOL);

   double twin[2] = {0.,60.};
   double dt = 1e-3;
   double t = twin[0], t1 = twin[1];
   long int NSTEP = (long int)((t1-t)/dt)+1; // +1 if you start counting from zero...
   int NEQ = 4;
   long int NUMEL = (NEQ+1)*NSTEP; // number of elements for solution

   int i = 0,j;
   do{
      double ti = t + dt; // t is automatically updated by the driver
      printf("\n%.3f\t%.3f\t%.3f t%.3f",astro.y[0],astro.y[1],astro.y[2],astro.y[3]);
      int status = gsl_odeiv2_driver_apply (d, &t, ti, astro.y);
      ...
      }
...
}

编译上面的代码会产生一个众所周知的错误,即GSL需要一个指向函数的指针,而我正在传递一个指向成员的函数,即:

error: cannot convert ‘int (chemosc::*)(double, const double*, double*, void*)’ to ‘int (*)(double, const double*, double*, void*)’

我发现了与此主题相关的几个问题:Q1Q2Q3Q4Q5Q6,但我们认真对待,答案很难遵循。声明为static我的成员函数,有一个缺点,编译器要求我也声明为静态所有成员参数。使用建议herestatic_cast会导致所有分段错误(但我认为我在实现中做错了,因为该帖子中的指示非常神秘)。为这个问题提供一劳永逸的清晰且尽可能简单的工作解决方案(可能不使用boost库)会很高兴。

1 个答案:

答案 0 :(得分:2)

这样的事情:

class my_model
{
    private: int
    ode_gsl_impl(double const t, double const * const y, double * const dydt);

    public: static int
    ode_gsl(double const t, double const * const y, double * const dydt, void * const opaque)
    {
        assert(opaque);
        return(static_cast<my_model *>(opaque)->ode_gsl_impl(t, y, dydt));
    }
};

gsl_odeiv2_system sys
{
    &my_model::ode_gsl
,   nullptr
,   chemosc.NEQ
,   reinterpret_cast<void *>(::std::addressof(chemosc))
};

我想提一下,您的原始代码会受到回调参数名称和类字段名称之间名称冲突的影响。