c++ 类中的 gsl_odeiv2:int(...) ode 的模板包装器 [英] gsl_odeiv2 in c++ class: Template wrapper for int(...) ode
问题描述
我目前在我的类中使用 gsl_odeiv2 方法来求解微分方程.但是由于众所周知的成员函数问题,我无法在类中定义我的 ode-system.我目前正在使用一种解决方法:我在全局命名空间中定义我的 ode:
I am currently using gsl_odeiv2 methods inside my classes to solve differential equations. But because of the well known memberfunction problem I can not define my ode-system inside the class. I am currently using a workaround: I define my ode in a global namespace:
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 类)对象的指针作为参数.在解决我使用的 ode 的类中:
and use a pointer to an object of a coustom type (class EoS) as parameter. Inside the class that solves the ode I use:
...
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};
...
初始化我的系统.这工作正常,但有点混乱,因为我需要在全局命名空间中声明我的微分方程.
to initalise my system. This works fine but is a bit messy because I need to declare my differential equations in a global namespace.
我知道可以为 gsl_functions 使用模板包装器 stackoverflow.com/questions/.../how-to-avoid-static-member-function-when-using-gsl-with-c/... 使用它们在 C++ 类中.我实际上使用那里描述的包装器为我的类中的 gsl_integration 方法定义函数,它工作得很好,而且更简洁,编写的代码更少.例如:我可以在函数内部直接使用上面的 star_eos 对象:
I know that it is possible to use template wrappers for gsl_functions stackoverflow.com/questions/.../how-to-avoid-static-member-function-when-using-gsl-with-c/... to use them in C++ Classes. I actually use the wrapper described there to define functions for gsl_integration Methods within my classes and it works perfectly and is much cleaner and less code to write. For example: I can use my star_eos Object from above direcly inside the function:
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 机制.
I tried to write such a template wrapper for the int(double r, const double *PM, double *dPdM, void *p) functions that gsl_odeiv2_system needs but I failed because I am new to C++ and did not fully understand its template/static_cast mechanisms.
是否有人使用带有模板包装器的 gsl_odeiv 方法及其 ode 系统?或者有人可以想出一个类似于上述 gsl_functions 模板但用于 int(...) ode 的模板.
Is there someone who uses gsl_odeiv methods and its ode systems with a template wrapper? Or can someone come up with a template similar to the one described above for gsl_functions but for the int(...) ode.
推荐答案
思考我是如何让它与全局命名空间中的微分方程组一起工作的,我找到了解决我的问题的方法.我现在有一个有效的包装器.在全局命名空间中,我有以下内容:
Thinking about how I got it working with the differential equations set in a global namespace I found a solution for my problem. I now have a working wrapper. In a global namespace I have the following:
//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 微分方程组.
So I bassically have all my specific information stored in my new class ode_System, which has an int dim to specify the systems dimensions and a pointer so a std::function object. This object represents the mathematica differential equation system.
在我的课堂中,我想使用 gsl_odeiv2 求解微分方程,我使用 lambda 函数定义该系统:
Inside my class, where I want to solve a differential equation using gsl_odeiv2, I define that system using a lambda function:
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 :
The above system represents a coupled system of 3 differential equations. I then declare a ode_System object with the right dimension and set its function pointer df to my defined system. Then I only need a structure with a reference to that system and done: I can use my differential equation defined inside my class with 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};
...
据我所知,这与我在问题中提出的实现一样好(或不好).它可以使用一些清理,但原则上这对我来说很好用.
As far as I can tell this works just as well (or bad) as the implementation I presented in my question. It can use some clean up but in principle this works fine for me.
但如果有人知道更好的方法,请随时分享!
But if someone knows a better way to do this please feel free to share it!
这篇关于c++ 类中的 gsl_odeiv2:int(...) ode 的模板包装器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!