2016-07-27 4 views
1

Ich verwende derzeit gsl_odeiv2 Methoden innerhalb meiner Klassen, um Differentialgleichungen zu lösen. Aber wegen des bekannten Memberfunktionsproblems kann ich mein Ode-System nicht innerhalb der Klasse definieren. Ich bin derzeit eine Abhilfe: definiere ich meine Ode in einem globalen Namensraum:gsl_odeiv2 in C++ - Klasse: Template Wrapper für int (...) 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 
    } 
} 

und einen Zeiger auf ein Objekt eines coustom Typs (Klasse EoS) als Parameter verwenden. Innerhalb der Klasse, die die Ode ich löst:

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

initalise mein System. Das funktioniert gut, ist aber ein bisschen unordentlich, weil ich meine Differentialgleichungen in einem globalen Namensraum deklarieren muss.

Ich weiß, dass es möglich ist, Vorlage Wrapper für gsl_functions stackoverflow.com/questions/.../how-to-avoid-static-member-function-when-using-gsl-with-c/... zu verwenden, um sie in C++ - Klassen zu verwenden. Ich benutze den Wrapper, der dort beschrieben wird, um Funktionen für gsl_integration Methoden innerhalb meiner Klassen zu definieren und es funktioniert perfekt und ist viel sauberer und weniger Code zum schreiben. Zum Beispiel: Ich kann meine star_eos innerhalb der Funktion von oben direcly Objekt verwenden:

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

Ich habe versucht, eine solche Vorlage Wrapper für die int (double r, const double * PM, double * DPDM, void * zu schreiben p) Funktionen, die gsl_odeiv2_system benötigt, aber ich scheiterte, weil ich neu in C++ bin und die Mechanismen template/static_cast nicht vollständig verstanden habe.

Gibt es jemanden, der gsl_odeiv-Methoden und seine Ode-Systeme mit einem Template-Wrapper verwendet? Oder kann jemand eine Vorlage ähnlich der oben für gsl_functions beschriebenen aber für die int (...) ode.

Antwort

0

Als ich darüber nachdachte, wie ich mit den Differentialgleichungen in einem globalen Namensraum arbeiten konnte, fand ich eine Lösung für mein Problem. Ich habe jetzt einen Working Wrapper. In einem globalen Namensraum habe ich die folgende:

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

}; 

So bassically meine all spezifische Informationen in meiner neuen Klasse gespeichert Ich habe ode_System, die ein int dim die Systeme Dimensionen zu spezifizieren und einen Zeiger so ein std :: function-Objekt. Dieses Objekt repräsentiert das mathematische Differentialgleichungssystem.

Innerhalb meiner Klasse, wo ich will eine Differentialgleichung unter Verwendung gsl_odeiv2 lösen, definiere ich, dass das System eine Lambda-Funktion:

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

Das obige System stellt ein gekoppeltes System von 3 Differentialgleichungen. Ich deklariere dann ein ode_System Objekt mit der richtigen Dimension und setze seinen Funktionszeiger df auf mein definiertes System. Dann brauche ich nur eine Struktur mit einem Verweis auf dieses System und getan: Ich kann meine Differentialgleichung in meiner Klasse mit gsl_odeiv2_system definiert verwenden:

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

Soweit ich sagen kann, dies funktioniert genauso gut (oder schlecht) als die Umsetzung, die ich in meiner Frage vorgestellt habe. Es kann etwas sauber machen, aber im Prinzip funktioniert das gut für mich.

Aber wenn jemand einen besseren Weg zu tun weiß, bitte zögern Sie nicht, es zu teilen!

Verwandte Themen