我写了一个函数: ODEsystem = function(t,states,parameters),它包含一个ODE系统,并用记录良好的R软件包解决它" deSolve"由Karline Soetaert,Thomas Petzoldt和R. Woodrow Setzer撰写。该软件包的文档是全面的,并有许多示例。它让我对编程和内存优化技能充满信心。
然而,当以每日间隔而不是每月间隔求解ODE系统时,计算指定时刻的状态值所花费的时间增加十倍。可能会有一些额外的计算来达到确切的所需时刻,但对于这两种情况,应该大致采用相同的内部动态时间步长。我没想到运行时会有这么大的下降。
“desolve”中对 ode()的调用如下所示:
out <- as.data.frame(ode(states, t=times, func=ODEsystem), parms=parameters, method="ode45"))
我经常使用两种变体 times = seq(0,100 * 365,by = 365/12)#100年,每月一个时间点 times = seq(0,100 * 365,by = 1)#100年,每天一个时间点
每月调用数据点
user system elapsed
4.59 0.00 4.58
每月调用数据点,并在包含ODEsystem的函数上调用 cmpfun()
user system elapsed
4.39 0.00 4.38
每天使用数据点调用
user system elapsed
44.41 0.00 44.46
每天调用数据点,并在包含ODEsystem的函数上调用 cmpfun()
user system elapsed
43.01 0.00 43.17
使用 system.time()测量的运行时间从每月间隔切换到每日间隔时会增加10倍。在包含ODE系统的函数上使用 cmpfun(),事情并没有太大改善。
(输出&#34; out&#34;仅在完成对 ode()的函数调用时分配。因此预分配&#34; out&#34;不会产生任何性能增益。)
问题1:我正在寻找运行/性能下降的原因。
(我希望它在deSolve包的内部。)
问题2:给出问题1的答案,如何在不诉诸动态链接库的情况下改进运行时?
为“out”可能有所帮助预先分配一些内存(使用“时间”中的时间步骤的知识),但我不知道 ode()中的哪个内部变量影响。
#### Clear currrent lists from memory
rm(list=ls())
### Load libraries
# library(rootSolve);library(ggplot2);
library(base);library(deSolve);library(stringr);library(compiler);library(data.table);
#### constants
dpy=365;durX1 = 40*dpy;rH = 1/durX1;durX4 = 365/12;rX4 = 1/durX4;durX6 = 365/12;rX6 = 1/durX6;durX2 = 80;rX2 = 1/durX2;durX3 = 31;rX3 = 1/durX3;durX7 = 20*365/12;rX7 = 1/durX7;durX5 = 29;rX5 = 1/durX5;durX8 = 200;rX8 = 1/durX8;fS = 0.013;fR = 8/100;fL = .03;fP = .03;fF = .05;X1zero = 1000;UDdur = 365/12*5;rK = rX3*(1/UDdur);fD1 = .05;fD2 = .05;durbt = 4;bt = 1/durbt;LX11 = 14;rF = 1/LX11;durX11 = 5;rX11 = 1/durX11;iniX12 = 0;pH = 1;frac_Im = 0;durX9 = dpy*5;ini_X2 = 1;sp = .90;fpX1 = 5;NF = fpX1*X1zero;rT1 = fD1*rX4;rT2 = fD2*rX6;pX1 = 0*sp;pX2 = 1/80*sp;pX3 = .50*sp;pX4 = .5*sp;pX6 = .5*sp;pX7 = 1/100*sp;pX5 = pX3;pX9 = 0*sp;pX8 = 1*sp;rX9 = 1/durX9;
#### vector with parameters
parameters = c(rH, rX3, rX4, rX6, rX2, rX8, rX7, rX5, rK, rT1, rT2, bt, rF, NF, rX11, pX1, pX2, pX3, pX4, pX6, pX7, pX5, pX9, pX8, rX9, X1zero)
### States contains initial conditions
states = c( X1 =X1zero-1,X2=1,X3=0, X4=0, X5=0,X6=0, X7=0, X8=0, X9=0, X10=NF,X11=0,X12=0, X13 = 0)
### function with ODE system
ODEsystem = function(t,states,parameters){
with(as.list(c(states,parameters)),{
### functions
X1part = (pX2*X2 + pX3*X3 + pX4*X4 + pX6*X6 + pX7*X7 + pX5*X5 + pX9*X9 + pX8*X8); prob1 = bt * X12 / X1zero; lF = bt * X1part/X1zero; AD = rK*(X3+X5+X4+X6)+rT1*X4+rT2*X6;
### fluxes
J1 = prob1*X1; J2 = fS*rX2*X2; J3 = (1-fS)*rX2*X2; J4 = (1-fP)*rX3*X3 ; J5 = fP*rX3*X3; J6 = (1-fF)*rX4*X4; J7 = fF*rX4*X4; J8 = rX6*X6; J9 = fR*rX7*X7; J10 = rX5*X5; J11 = (1-fR)*(1-fL)*rX7*X7; J12 = (1-fR)*fL*rX7*X7; J13 = rX8*X8; J14 = rH*X3; J15 = rH*X1; J16 = rH*X2; J17 = rH*X4; J18 = rH*X6; J19 = rH*X5; J20 = rH*X8; J21 = rH*X7; J22 = rH*X9; J23 = rK*X3; J24 = rK*X4; J25 = rK*X6; J26 = rT2*X6; J27 = rH*X1zero; J28 = rT1*X4; J29 = AD; J30 = rK*X5; J31 = rF*X12; J32 = rF*X11; J33 = rF*X10; J34 = lF*X10; J35 = rX11*X11; J36 = rF*NF; J37 = rX9*X9; J38 = 0; J39 = 0; J40 = 0; J41 = 0; J42 = 0; J43 = 0; flux1=J4/X1zero*1e4*dpy; flux2=J12/X1zero*1e4*dpy;
# rate of change
dX1 = - J1 - J15 + J27 + J29 + J37
dX2 = + J1 - J2 - J3 - J16 - J40
dX3 = + J2 - J4 - J5 - J14 - J23 - J41
dX4 = + J4 - J6 - J7 - J17 - J24 - J28
dX5 = + J9 - J10 - J19 - J30 - J43
dX6 = + J7 - J8 + J10 - J18 - J25 - J26
dX7 = + J5 + J6 + J8 - J9 - J11 - J12 - J21
dX8 = + J12 - J13 - J20 - J42
dX9 = + J3 + J11 + J13 - J22 - J37 + J40 + J41 + J42 + J43
dX10 = - J33 - J34 + J36
dX11 = - J32 + J34 - J35
dX12 = - J31 + J35
dX13 = + J38 - J39
# return the rate of change
list(c(dX1,dX2,dX3,dX4,dX5,dX6,dX7,dX8,dX9,dX10,dX11,dX12,dX13),flux1,flux2,prob1)
})
}
## compiled version of ODE system function
cfODEsystem=cmpfun(ODEsystem)
#### time points to be calculated
times = seq(0, 100*365,by=365/12) # 100 year, time points per month
#times = seq(0, 100*365,by=1) # 100 year, time points per day
### calculations
system.time(out <- as.data.frame(ode(states, t=times, func=ODEsystem, parms=parameters, method="ode45")))
#system.time(out <- as.data.frame(ode(states, t=times, func=cfODEsystem, parms=parameters, method="ode45")))
### longitudinal plots of each variable, flux1 and 2 and prob1
for (i in seq(from=2, to=dim(out)[2], by=1) ) {
tempdata <- out[c("time",names(out)[i])]
tempdata$time= tempdata$time/365
templabel <-names(out)[i]
plot(tempdata,col = "black","l",xlab="time (years)",ylab=templabel,
xlim=c(0, max(tempdata$time)), ylim=c(0, signif(max(tempdata[2]),2)))
}
答案 0 :(得分:0)
所以感谢写这个问题,它促使我调查deSolve内部并学习一点(也可能加快我自己的代码)。
问题1
ODE函数被多次调用以求解函数(可能小于时间点的数量),但是也会在一个时间点调用一次以评估其他代数方程。因此,如果您添加30倍的时间点,由于设置和拆卸等原因,您将始终添加到运行时但不到30倍。
问题2
你可以采取一些措施来加快速度而不诉诸C代码(尽管这是一个很好的选择)
with
,而是使用数组访问(可能是临时命名变量)。