在共享库中的类中调用GSL函数 [英] Calling GSL function inside a class in a shared library

查看:163
本文介绍了在共享库中的类中调用GSL函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在c ++中实现一个共享库,实现Fermi气体的工具。我使用GSL库以数字方式解决一个函数,我的代码运行没有问题,而没有运行作为脚本,但当试图将其转换为共享库和类我遇到问题。

I'm trying make a shared library in c++ implementing tools for Fermi gases. I'm using the GSL library to solve a function numerically and my code runs without a problem without when running as a script, but when trying to convert it to a shared library and classes I encounter problems.

我遇到过类似的问题:
Q1
第2季
Q3

I've seen similar questions: Q1 Q2 Q3

我是c ++的新手 - 编程,似乎不能适应我的问题的不同的答案。可能因为我不太明白答案。

I'm fairly new to c++-programming and cannot seem to adapt the different answers to my problem. Probably since I do not quite understand the answers.

我的代码是:

/* Define structure for the GSL-function: chempot_integrand */
struct chempot_integrand_params { double mu; double T; };

double
ChemicalPotential::chempot_integrand (double x, void * params){
    /* Computes the integrand for the integral used to obtain the chemical potential.
     *
     * This is a GSL-function, which are integrated using gsl_integration_qag.
     */

    // Get input parameters.
    struct chempot_integrand_params * p = (struct chempot_integrand_params *) params;
    double mu = p->mu;
    double T = p->T;

    // Initiate output parameters for GSL-function.
    gsl_sf_result_e10 result;
    int status = gsl_sf_exp_e10_e( ( gsl_pow_2(x) - mu ) / T , &result );

    if (status != GSL_SUCCESS){
        printf ("Fault in calculating exponential function.");
    }

    // Return (double) integrand.
    return (gsl_pow_2(x) / ( 1 + result.val * gsl_sf_pow_int(10,result.e10) ));
}

/* Define structure for the GSL-function: chempot_integration */
struct chempot_integral_params { double T; };

double
ChemicalPotential::chempot_integration (double mu, double T){
    /* Computes the integral used to obtain the chemical potential using the integrand: chempot_integrand.
    */

    // Set input parameters for the integrand: chempot_integrand.
    struct chempot_integrand_params params_integrand = { mu, T };

    // Initiate the numerical integration.
    gsl_integration_workspace * w = gsl_integration_workspace_alloc (1000); // Allocate memory for the numerical integration. Can be made larger if neccessary, REMEMBER to change it in the function call: gsl_integration_qag as well.
    double result, error;
    gsl_function F;
    F.function = &ChemicalPotential::chempot_integrand;
    F.params = &params_integrand;

    // Upper limit for integration
    double TOL = 1e-9;
    double upp_lim = - T * gsl_sf_log(TOL) + 10;

    gsl_integration_qag (&F, 0, upp_lim, 1e-12, 1e-12, 1000, 6, w, &result, &error);

    // Free memory used for the integration.
    gsl_integration_workspace_free (w);

    return result;
}

并且编译时得到错误

error: cannot convert ‘double (Fermi_Gas::ChemicalPotential::*)(double, void*)’ to ‘double (*)(double, void*)’ 

F.function = &ChemicalPotential::chempot_integrand;


推荐答案

再次。一个原因可能是所提出的解决方案不容易理解。我为一个人有理解和实施他们的问题。 (解决方案对我来说没有开箱即用。)

It is indeed interesting that people ask this over and over again. One reason may be that the proposed solutions are not easy to understand. I for one had problems understanding and implementing them. (the solutions did not work out of the box for me, as you might expect.)

tlamadon 我只是想出了一个解决方案,在这里也可以是有帮助的。让我们看看你们的想法。

With the help of tlamadon I just figured out a solution that may be helpful here as well. Let's see what you guys think.

因此,只是重述一下,问题是你有一个类包含一个成员函数,您希望使用来自GSL库的东西。如果GSL接口需要一个

So just to recap, the problem is that you have a class that contains a member function on which you want to operate with something from the GSL library. Our example is useful if the GSL interface requires a

gsl_function F;

查看此处的定义。

这里是示例类:

class MyClass {

    private:
        gsl_f_pars *p;  // not necessary to have as member

    public: 
        double obj(double x, void * pars);  // objective fun
        double GetSolution( void );  
        void setPars( gsl_f_pars * xp ) { p = xp; };
        double getC( void )  ;  // helper fun

};

此练习的目的是能够


  1. 启动 MyClass测试

  2. 提供一个参数结构构造函数)和

  3. 调用 test.GetSolution(),它应该返回任何GSL函数 obj ,根,整数或任何内容)

  1. initiate MyClass test,
  2. supply it with a paramter struct (or write a corresponding constructor), and
  3. call test.GetSolution() on it, which should return whatever the GSL function was used for (the minimum of obj, a root, the integral or whatever)

现在要在参数 struct gsl_f_pars 中有一个元素,其中是指向MyClass的指针。这是结构:

The trick is now to put have an element in the parameter struct gsl_f_pars which is a pointer to MyClass. Here's the struct:

struct gsl_f_pars {
    double a;
    double b;
    double c;
    MyClass * pt_MyClass;
};

最后一个是提供一个包装器,将在 MyClass中调用: :GetSolution()(包装器是成员函数 MyClass :: obj 的替代品,我们不能指向& obj )。这个包装器将使用参数struct,dereference pt_MyClass 并评估 pt_MyClass 的成员 obj

The final piece is to provide a wrapper that will be called inside MyClass::GetSolution() (the wrapper is a stand in for the member function MyClass::obj, which we cannot just point to with &obj inside the class). This wrapper will take the parameter struct, dereference pt_MyClass and evaluate pt_MyClass's member obj:

// Wrapper that points to member function
// Trick: MyClass is an element of the gsl_f_pars struct
// so we can tease the value of the objective function out
// of there.
double gslClassWrapper(double x, void * pp) {
    gsl_f_pars *p = (gsl_f_pars *)pp;
    return p->pt_MyClass->obj(x,p);
}

完整的例子有点太长了,一个精神。这是一个头文件 cpp文件,它应该工作在任何你有GSL。编译并运行

The full example is a bit too long to post here, so I put up a gist. It's a header file and a cpp file, it should be working wherever you have GSL. Compile and run with

g++ MyClass.cpp -lgsl -o test
./test

这篇关于在共享库中的类中调用GSL函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆