c ++类中的gsl_odeiv2:int(...)ode

时间:2016-07-27 12:23:17

标签: templates wrapper gsl

我目前在我的类中使用gsl_odeiv2方法来解决微分方程。但由于众所周知的成员函数问题,我无法在类中定义我的ode-system。我目前正在使用解决方法: 我在全局命名空间中定义了我的ode:

ODE.hpp:
#include "EoS.hpp"

#include <gsl/gsl_math.h>
#include <gsl/gsl_errno.h>

namespace ODEs
{
    struct tov_eq_params {EoS *eos;};
    int tov_eq(double, const double *, double *, void *);
}

ODE.cpp:
namespace ODEs {
    int tov_eq(double r, const double *PM, double *dPdM, void *p) {
        struct tov_eq_params * params = (struct tov_eq_params *)p;
        EoS *eos = (params->eos);
        ...
    return GSL_SUCCESS
    }
}

并使用指向coustom类型(EoS类)对象的指针作为参数。在解决我使用的颂歌的课程中:

...
struct tov_eq_params comp_tov_params = {(this->star_eos)};
gsl_odeiv2_evolve *comp_tov_evolve = gsl_odeiv2_evolve_alloc(3);
gsl_odeiv2_system comp_tov_system = {tov_eq, NULL, 3,&comp_tov_params};
...

致电我的系统。这很好但有点乱,因为我需要在全局命名空间中声明我的微分方程。

我知道可以使用gsl_functions stackoverflow.com/questions/.../how-to-avoid-static-member-function-when-using-gsl-with-c/...的模板包装器在C ++类中使用它们。我实际上使用那里描述的包装器为我的类中的gsl_integration方法定义函数,它工作得很完美,而且编写的代码更简洁。例如:我可以在函数内部直接使用我的star_eos对象:

  auto dBf = [=](double r)->double{
        return 4 * M_PI * gsl_pow_2(r) * (this->star_eos)->nbar(this->P(r)) * sqrt(this->expLambda(r))* 1e54;
    };
    gsl_function_pp<decltype(dBf)> dBfp(dBf);
    gsl_function *dB = static_cast<gsl_function*>(&dBfp);

我试着为gsl_odeiv2_system需要的int(double r,const double * PM,double * dPdM,void * p)函数编写这样的模板包装器,但是我失败了因为我是C ++的新手并且没有完全理解它template / static_cast机制。

是否有人使用gsl_odeiv方法及其ode系统和模板包装器?或者有人可以提出类似于上面针对gsl_functions描述的模板,但是对于int(...)ode。

1 个答案:

答案 0 :(得分:0)

考虑如何使用全局命名空间中设置的微分方程,我找到了解决问题的方法。我现在有一个工作包装器。在全局命名空间中,我有以下内容:

git submodule foreach git pull

所以我低声地将我的所有特定信息都存储在我的新类 ode_System 中,它有一个 int dim 来指定系统维度和一个指针,所以std ::功能对象。该对象代表mathematica微分方程系统。

在我的课程中,我想使用gsl_odeiv2解决微分方程,我使用lambda函数定义该系统:

//gsl_wrapper.hpp
#include <iostream>
#include <vector>
#include <functional>

#include <gsl/gsl_math.h>
#include <gsl/gsl_errno.h>

namespace gsl_wrapper {

    class ode_System{
    public:
        ode_System(int);
        int dim;
        std::function<double (double, const double *, double *, int)> *df;

    };

    struct ode_struct {ode_System *ode;};
    int ode(double, const double *, double *, void *);
}

//gsl_wrapper.cpp
#include "../../include/gsl_wrapper.hpp"

namespace gsl_wrapper {

    ode_System::ode_System(int dim) {
        this->dim=dim;
    }

    int ode(double r, const double *f, double *df, void *p) {
        struct ode_struct * params = (struct ode_struct *)p;
        ode_System *odeFunc = (params->ode);

        int dim = odeFunc->dim;
        std::function<double (double, const double *, double *, int)> dfeq=*(odeFunc->df);

        for(int i=0;i<dim;i++){
            df[i] = dfeq(r,f,df,i);
        }

        return GSL_SUCCESS;
    }

};

上述系统代表3个微分方程的耦合系统。然后我声明一个具有正确维度的 ode_System 对象,并将其函数指针 df 设置为我定义的系统。然后我只需要一个引用该系统并完成的结构:我可以使用我的类中定义的差分方程 gsl_odeiv2_system

std::function<double (double, const double *, double *, int)> dPMeq = [=](double r , const double * PM, double *dPdM, int i)->double{
    double df;
    switch ( i )
    {
        case 0:
            df = ... // df_1/dr
            break;
        case 1: 
            df = ... // df_2/dr
            break;
        case 2: 
            df = ... // df_3/dr
            break;
        default:
            GSL_ERROR_VAL ("comp_tov_eq:", GSL_FAILURE,GSL_FAILURE);
            df = 0;
    }
    return df;
};

据我所知,这与我在问题中提出的实现一样好(或坏)。它可以使用一些清理,但原则上这对我来说很好。

但如果有人知道更好的方法,请随时分享!