【发布时间】:2021-08-16 16:31:27
【问题描述】:
在调用已编译的 ODE 来解决时,我正在努力解决一个可能很小的问题
通过 R 包'deSolve' 和我寻求更多专家用户的建议。
背景
我有几个 ODE 系统需要用 'deSolve' 解决。我已经在单独的 C++ 函数(每个模型一个)中定义了 ODE,我通过 R 与 'Rcpp' 一起调用。如果函数从另一个模型中获取输入,系统的初始值会发生变化(因此基本上是级联)。
这很好用,但是,对于一个模型,我必须为t < 2 设置初始参数。我尝试在 C++ 函数中执行此操作,但它似乎不起作用。
运行代码示例
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export("set_ODE")]]
SEXP set_ODE(double t, NumericVector state, NumericVector parameters) {
List dn(3);
double tau2 = parameters["tau2"];
double Ae2_4 = parameters["Ae2_4"];
double d2 = parameters["d2"];
double N2 = parameters["N2"];
double n2 = state["n2"];
double m4 = state["m4"];
double ne = state["ne"];
// change starting conditions for t < 2
if(t < 2) {
n2 = (n2 * m4) / N2;
m4 = n2;
ne = 0;
}
dn[0] = n2*d2 - ne*Ae2_4 - ne/tau2;
dn[1] = ne/tau2 - n2*d2;
dn[2] = -ne*Ae2_4;
return(Rcpp::List::create(dn));
}
/*** R
state <- c(ne = 10, n2 = 0, m4 = 0)
parameters <- c(N2 = 5e17, tau2 = 1e-8, Ae2_4 = 5e3, d2 = 0)
results <- deSolve::lsoda(
y = state,
times = 1:10,
func = set_ODE,
parms = parameters
)
print(results)
*/
输出读取(这里只有前两行):
time ne n2 m4
1 1 1.000000e+01 0.000000e+00 0.000000e+00
2 2 1.000000e+01 2.169236e-07 -1.084618e-11
以防万一:如何运行此代码示例?
我的示例使用RStudio进行了测试:
- 将代码复制到以 *.cpp 结尾的文件中
- 点击“来源”按钮(或
<shift>+<cmd>+<s>)
它应该在没有 RStudio 存在的情况下也能工作,但必须安装包 'Rcpp' 和 'deSolve' 并编译它需要在 Windows 上使用 Rtools、在 Linux 上使用 GNU 编译器和在 macOS 上使用 Xcode 的代码。
问题
据我了解,ne 对于time = 1(或t < 2)应该是0。不幸的是,求解器似乎没有考虑我在 C++ 函数中提供的内容,除了 ODE。但是,如果我将 R 中的 state 更改为另一个值,它就可以工作。不知何故,我在 C++ 中定义的 if 条件被忽略了,但我不明白为什么以及如何在 C++ 而不是 R 中计算初始值。
【问题讨论】:
-
嗨@RLumSK:有趣的是,您设法将 deSolve 与 Rcpp 结合起来。 deSolve 的文档仅支持 C 和 Fortran。有一些方法可以在 R 函数中使用 C++ 代码作为外部“C”,但我不知道直接 Rcpp 连接。我们会尝试一下。
-
感谢您回复我。我不得不承认,我不是第一个设法将这一点结合起来的人,但@J_F 在他的 R 包 RLumModel (github.com/R-Lum/RLumModel) 的博士论文中做到了这一点。我是这个包的合著者,但将 deSolve 与 Rcpp 一起使用的功劳归于他。