简体   繁体   English

ODE,多根和事件,R

[英]ODE, multiple roots and events, R

I like to solve a system of coupled differential equations which involve multiple thresholds.我喜欢求解涉及多个阈值的耦合微分方程组。 Going through the R information this leads me to using ODE in combination with the root function and the event function.浏览 R 信息,这使我将 ODE 与根函数和事件函数结合使用。

Going through various examples, ie temperature model, page 14 http://cran.r-project.org/web/packages/diffEq/vignettes/ODEinR.pdf -- code pasted below --, I am able to let my model act on one threshold, ie finding the root/ reaching the threshold for one variable triggers an event.通过各种示例,即温度模型,第 14 页http://cran.r-project.org/web/packages/diffEq/vignettes/ODEinR.pdf -- 下面粘贴的代码 --,我可以让我的模型起作用在一个阈值上,即找到根/达到某个变量的阈值会触发一个事件。

library(deSolve)
yini <- c(temp = 18, heating_on=1)

temp <- function(t,y, parms) {
  dy1 <- ifelse(y[2] == 1, 1.0, -0.5)
  dy2 <- 0
 list(c(dy1, dy2))
}

rootfunc <- function(t,y,parms) c(y[1]-18, y[1]-20)

eventfunc <- function(t,y,parms) {
  y[1] <- y[1]
  y[2] <- ! y[2]  
 return(y)
}

times <- seq(from=0, to=20, by=0.1)
out <- lsode(times=times, y=yini, func = temp, parms = NULL, 
         rootfun = rootfunc, events = list(func=eventfunc, root = TRUE))
plot(out, lwd=2)
attributes(out)$troot

The example shows also that different roots can trigger the same event function (y[1] – 18 and y[1]-20 both trigger eventfunc).该示例还显示不同的根可以触发相同的事件函数(y[1] – 18 和 y[1]-20 都触发 eventfunc)。 My question is, however, is it also possible to have different roots trigger different event functions?然而,我的问题是,是否也有可能让不同的根触发不同的事件函数? Said differently, depending on which root is found, a different eventfunc is triggered?换种说法,根据找到哪个root,触发不同的eventfunc? Or alternatively, within the same eventfunct, can it do different actions depending on which root is found.或者,在同一个 eventfunct 中,它是否可以根据找到的根执行不同的操作。

To keep it simple I first wanted to see if this can work using the same example, for instance by naming the roots and by working with an if statement?为了简单起见,我首先想看看这是否可以使用相同的示例工作,例如通过命名根和使用 if 语句? At the moment that doesn't work.目前这不起作用。 Does anyone have experience with this?有任何人对此有经验吗? If you look at attributes(out) it seems like ODE does keep a record of which root is encountered $indroot (but that's after evaluation.) Thank you in advance.如果您查看 attributes(out),似乎 ODE 确实会记录遇到 $indroot 的根目录(但这是在评估之后。)在此先感谢您。

# library(deSolve)
yini <- c(temp = 18, heating_on=1)

temp <- function(t,y, parms) {
  dy1 <- ifelse(y[2] == 1, 1.0, -0.5)
  dy2 <- 0
 list(c(dy1, dy2))
}

rootfunc <- function(t,y,parms) {
  yroot <- vector(len = 2)
  yroot[1] <- y[1]-18 
  yroot[2] <- y[1]-20
 return(yroot)
}

eventfunc <- function(t,y, parms) {
  y[1] <- y[1]
  ifelse(yroot[2]==2, y[2] <- y[2], y[2] <- !y[2])
 return(y)
}

times <- seq(from=0, to=20,by=0.1)
out <- lsode(times=times, y=yini, func = temp, parms = NULL, 
         rootfun = rootfunc, events = list(func=eventfunc, root = TRUE))
plot(out, lwd=2)
attributes(out)$troot 

The state y of the system is available in both, the root function and the event function, so it can be used as a condition which event to trigger.系统的状态y在根函数和事件函数中都可用,因此可以作为触发事件的条件。

For more complex cases it is of course also possible to dispatch the events from a main event function to different functions for the details, the same is also possible for checking the root condition.对于更复杂的情况,当然也可以将事件从一个主事件函数分派到不同的函数中,以了解细节,同样也可以检查根条件。

Thanks to @Bakaburg for spotting this interesting unanswered question.感谢@Bakaburg 发现了这个有趣的悬而未决的问题。

Here a solution that also simplifies some programming construcs:这是一个也简化了一些编程结构的解决方案:

library(deSolve)
yini <- c(temp = 18, heating_on = 1)

temp <- function(t,y, parms) {
  dy1 <- ifelse(y[2] == 1, 1.0, -0.5)
  dy2 <- 0
  list(c(dy1, dy2))
}

rootfunc <- function(t, y, parms) {
  yroot <- c(y[1] - 18, y[1] - 20)
  return(yroot)
}

eventfunc <- function(t, y, parms) {
  yroot <- c(y[1] - 18, y[1] - 20)
  whichroot <- which(abs(yroot) < 1e-6) # specify tolerance
  y[2] <- if(whichroot == 2) 0 else 1
  return(y)
}

times <- seq(from=0, to=20,by=0.1)
out <- lsode(times=times, y=yini, func = temp, parms = NULL, 
             rootfun = rootfunc, events = list(func=eventfunc, root = TRUE))
plot(out, lwd=2)

寻根和交替事件

I approached a similar problem by using a global variable set in the root or directly in the main function (useful if you trigger it based on overcoming a threshold in a particular direction.我通过在根中或直接在主函数中使用全局变量集来解决类似的问题(如果您基于克服特定方向的阈值来触发它,则很有用。

The global flag then changes the behaviour of the event function.全局标志然后改变事件函数的行为。

Not very elegant but it works.不是很优雅,但它的工作原理。

In your case the code would become:在您的情况下,代码将变为:

trigger <- FALSE

rootfunc <- function(t,y,parms) {
  yroot <- vector(len = 2)
  yroot[1] <- y[1]-18 
  yroot[2] <- y[1]-20

  if (yroot[2] == 0) trigger <- TRUE

  return(yroot)
}

eventfunc <- function(t,y, parms) {
  y[1] <- y[1]
  if (trigger) y[2] <- y[2] else y[2] <- !y[2]
  return(y)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM