我正在构建一个使用CVODE C例程(SUNDIALS C库的一部分)解决常微分方程(ODE)的包。
如果用户提供计算衍生工具并具有以下形式的函数
,则该包可用#include <Rcpp.h>
using namespace Rcpp;
#include <cvode/cvode.h> /* prototypes for CVODE fcts., consts. */
#include <nvector/nvector_serial.h> /* serial N_Vector types, fcts., macros */
int test (realtype t, N_Vector y, N_Vector ydot, void *user_data){
// test function
NV_Ith_S(ydot,0) = 1*NV_Ith_S(y,0);
NV_Ith_S(ydot,1) = 2*NV_Ith_S(y,1);
NV_Ith_S(ydot,2) = 3*NV_Ith_S(y,2);
return(0);
}
typedef int (*funcPtr)(realtype t, N_Vector y, N_Vector ydot, void *user_data);
// [[Rcpp::export]]
XPtr<funcPtr> putFunPtrInXPtr() {
// return(XPtr<funcPtr> (new funcPtr(&test)));
XPtr<funcPtr> testptr(new funcPtr(&test), false);
return testptr;
在my_fun <- putFunPtrInXPtr()
中形成一个函数指针,即R
,my_fun
从包cvode
输入cvode
提供my_fun
函数} SEXP
,请参阅代码here)。 此作品,即提供正确的结果(请参阅详细说明here)。但是,这需要用户在其系统上安装SUNDIALS
(以访问cvode.h
和nvector_serial.h
)。
我正在尝试制作包,因此用户无需安装SUNDIALS
。因此,获得导数(和生成函数指针)的函数将如下所示
#include <Rcpp.h>
using namespace Rcpp;
//---------------------------------------------------------------------------------
typedef NumericVector (*funcPtr1) (double t, NumericVector y, NumericVector ydot);
//---------------------------------------------------------------------------------
// [[Rcpp::export]]
NumericVector test1 (double t, NumericVector y, NumericVector ydot){
ydot[0] = 1 * y[0];
ydot[1] = 2 * y[1];
ydot[2] = 3 * y[2];
return ydot;
}
// [[Rcpp::export]]
XPtr<funcPtr1> putFunPtrInXPtr1() {
XPtr<funcPtr1> testptr1(new funcPtr1(&test1), false);
return testptr1;
}
在R方面,my_fun1 <- putFunPtrInXPtr1()
将被运行,my_fun1
将被提供给cvode_test
(包中定义的测试函数,以便能够处理使用{{1}定义的派生函数只有。
在我的包中将函数指针类型从NumericVector
转换为XPtr<funcPtr1>
,我执行以下操作
1)全局XPtr<funcPtr>
(SEXP
)在任何函数之外定义
2)在sexp_g
中,输入cvode_test
已分配给SEXP
3)最后,函数sexp_g
定义如下,将fun_test1
转换为N_Vector
,使用NumericVector
中的函数获取导数,然后将它们重新放入{ {1}},即
sexp_g
最后,在N_Vector
中,此typedef int (*funcPtr_test)(double time, NumericVector y, NumericVector ydot);
SEXP sexp_g; // declare a global SEXP
int fun_test1(realtype t, N_Vector y, N_Vector ydot, void* user_data){
// convert y to NumericVector y1
int y_len = NV_LENGTH_S(y);
NumericVector y1(y_len); // filled with zeros
for (int i = 0; i < y_len; i++){
y1[i] = NV_Ith_S(y,i);
}
// use function pointer to get the derivatives
XPtr<funcPtr_test> xpfun(sexp_g);
funcPtr_test fun_test = *xpfun;
NumericVector ydot1(y1.length());
ydot1 = fun_test(t, y1, ydot1);
// convert ydot1 to N_Vector ydot
// N_Vector ydot; ydot = NULL;
ydot = N_VNew_Serial(ydot1.length());
for (int i = 0; i<ydot1.length(); i++){
NV_Ith_S(ydot, i) = ydot1[i];
}
return (0);
}
的使用方法如下
cvode_test
这也可以编译,但问题是当我向fun_test1
提供flag = CVodeInit(cvode_mem, fun_test1, T0, y0);
(即指向my_fun1
)以进行集成时,我得到了垃圾值。我不确定这里出了什么问题,我已经阅读了一些关于保护test1
的文章(即一个here),但我不知道如何在这里实现它。
有关此处出现问题的任何帮助,以及是否有比全局cvode_test
变量更好的方法会有所帮助。由于SEXP
的rhs函数必须具有以下签名
SEXP
我发现不可能使用不同的签名(使用CVOdeInit
)从包外定义的函数中插入上面定义的函数中的信息,除了使用全局变量并且一直在努力问题很长一段时间。任何帮助将不胜感激!
我没有尝试过的另一种方法是1)在任何函数之外声明int RHS_function (N_Vector, N_Vector, void*);
,2)在SEXP
内展开XPtr<funPtr_test>
到SEXP
并将其分配给在函数外声明的指针。但我正在努力使用语法来声明类型为XPtr<funcPtr_test>
的函数指针。
可以找到cvode_test
和XPtr<funcPtr_test>
的完整代码here
由于