解决ODEs - 只有积极的解决方案

时间:2017-11-20 21:48:24

标签: r constraints ode

我试图解决限制为正解的ODE,即:

dx/dt=f(x)

x>=0

在MATLAB中,这很容易实现。 R是否有任何变通方法或包来将解决方案空间限制为正值?

这对我来说非常重要,遗憾的是没有其他选择。我现在搜索了一段时间但没有任何成功。 : - (

4 个答案:

答案 0 :(得分:2)

还有不足以继续下去。对于我熟悉的各种问题,修改系统以在对数转换状态变量的范围内操作效果很好(您可以总是对结果进行反向转换,例如将它们与数据进行比较)。例如,我使用了SIR model in epidemiology。我将尝试使用@ MauritsEver的示例来说明将系统转换为以对数比例运行:

library(deSolve)
model <- function (time, y, parms) {
   with(as.list(c(y, parms)), {
       dlogN <-   r * (1 - exp(logN) / K)
       list(dlogN)
   })
}

# Starting conditions
y <- c(logN = log(0.1))
parms <- c(r = 0.1, K = 10)
times <- seq(0, 100, 1)
out <- as.data.frame(ode(y, times, model, parms))
out_backtran <- transform(out,N=exp(logN))
plot(N~time,data=out_backtran)

enter image description here

这种方法有以下缺点:

  • 它不会处理完全在边界上的解决方案,并且会遇到接近边界的解决方案的问题太快&#34; (即状态变量在有限时间内收敛为零)
  • 如需书面说明需要手动翻译。完全有可能编写一个系统,允许用户输入一组方程式和一组转换并自动应用转换,但这将是一些努力。
  • 它可能会略微增加计算量(任何时候我们必须使用状态变量的原始值我们必须取幂)

答案 1 :(得分:1)

如果没有ODE的任何具体示例代码或细节,则难以更具体。 可能非常简单,具体取决于问题。

以下是使用deSolve及其函数deSolve::subset的简单示例。

# Example straight from the deSolve manual
library(deSolve);
model <- function (time, y, parms) {
    with(as.list(c(y, parms)), {
        dN <-   r * N * (1 - N / K);
        list(dN)
    })
}

# Starting conditions
y <- c(N = 0.1);
parms <- c(r = 0.1, K = 10);
times <- seq(0, 100, 1);

# Solve ODE and plot
out <- ode(y, times, model, parms);
plot(out, type = "l", xlim = c(0, 100));

enter image description here

我们现在对timesubset解决方案施加约束。

# Constrain: time > 20 and plot
out.constrained <- subset(out, select = c("time", "N"), subset = time > 20);
plot(out.constrained, type = "l", xlim = c(0, 100));

enter image description here

答案 2 :(得分:0)

我认为我有同样的问题,可能会为您提供一个示例。

考虑溶解过程,其中产物A_solid以溶剂的速率常数k_1溶解到A_bulk中(该反应可以在两个方向上进行)。 A_solid溶解到溶剂中直到A_bulk达到饱和度A_sat。 此外,A_bulk与产物B反应,以速率常数k_2得到C. 这是反应的图片: Dissolution process

这是我为反应写的代码:

library(deSolve)

# inputs 
T = 0  + 273.15 # K (Kelvin ) / tTemperature 
V = 50 # mL / Volume
A_solid = 125/V # mmol/mL = mol/L / initial concentration of product A_solid
B = 100/V # mol/L / initial concentration of product B

# parameters
R = 8.314 # J/(K*mol) / gas constant
expfact_sat = 2
E_a_sat = 10^3

params <- c(k1 = 0.1, # rate constant of dissolution
            k2 = 3*10^(-3), # rate constant of reaction
            A_sat = expfact_sat*exp(-E_a_sat/(R*T))) # saturation of the A_bulk into the solvent

# initial values
state <- c(A_solid = A_solid, A_bulk = 0, B = B, C = 0)

# system of differential equations
derivs <- function(t, y, parms) {
  with(as.list(c(y, parms)), {
    dA_solid = -k1*(A_sat - A_bulk)
    dA_bulk = -k2*A_bulk*B + k1*(A_sat - A_bulk)
    dB = -k2*A_bulk*B
    dC = k2*A_bulk*B
    return(list(c(dA_solid, dA_bulk, dB, dC)))
  })                                                        
}

times = seq(0, 500, by = 0.01)
init <- ode(y = state, func = derivs, time = times, parms = params)

l = dim(init)[1]-1
matplot(init[,1], init[,-1], type = "l", lty = 1:1, lwd = c(2),
        col = 1:l, xlab = "time [min]", ylab = "concn [mol/L]")
legend("topright", colnames(init)[-1], col = 1:l, lwd = c(2))

这里的问题是,如果你制作图表,你会看到A_solid低于0,这意味着A_solid的浓度是负的,这是无意义的。

这是最终情节的样子: Dissolution

如果您有任何建议或解决方案如何处理此问题,这将是不错的。

@BenBolker:日志转换的问题是,正如你在缺点中所说的那样,A_solid的浓度在有限时间内变为0,所以我不确定我们是否仍然可以应用这种技术。

P.S。:我是这个论坛的新手,因此无法直接显示图像。

答案 3 :(得分:0)

@Anto添加if语句将其设置为零

dA_solid = -k1*(A_sat - A_bulk)
if((A_solid+dA_solid)<0 {dA_solid = -1*(A_solid)}
dA_bulk = -k2*A_bulk*B + k1*(A_sat - A_bulk)