【问题标题】:gsl_odeiv2 in c++ class: Template wrapper for int(...) odec++ 类中的 gsl_odeiv2:int(...) ode 的模板包装器
【发布时间】:2016-07-27 12:23:17
【问题描述】:

我目前在我的课程中使用 gsl_odeiv2 方法来求解微分方程。但是由于众所周知的成员函数问题,我无法在类中定义我的 ode 系统。我目前正在使用一种解决方法: 我在全局命名空间中定义我的 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
    }
}

并使用指向自定义类型(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++ 新手并且没有完全理解它模板/static_cast 机制。

是否有人使用带有模板包装器的 gsl_odeiv 方法及其 ode 系统?或者有人可以想出一个类似于上述 gsl_functions 的模板,但用于 int(...) ode。

【问题讨论】:

    标签: templates wrapper gsl


    【解决方案1】:

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

    //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;
        }
    
    };
    

    所以我基本上将所有特定信息都存储在我的新类 ode_System 中,它有一个 int dim 来指定系统尺寸和一个指针,因此是一个 std::函数对象。此对象表示mathematica 微分方程系统。

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

    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;
    };
    

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

     ode_System tov(3);
     tov.df= &dPMeq;
     struct ode_struct comp_tov_params = {&tov};
     gsl_odeiv2_evolve *comp_tov_evolve = gsl_odeiv2_evolve_alloc(3);
     gsl_odeiv2_system comp_tov_system = {ode, NULL, 3, &comp_tov_params};
     ...
    

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

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

    【讨论】:

      猜你喜欢
      • 2021-12-31
      • 1970-01-01
      • 1970-01-01
      • 2020-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-23
      相关资源
      最近更新 更多