ODE, множественные корни и события, R
Мне нравится решать систему связанных дифференциальных уравнений, которые включают в себя несколько порогов. Просматривая информацию R, это приводит меня к использованию ODE в сочетании с корневой функцией и функцией события.
Просматривая различные примеры, например температурную модель, стр. 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
В примере также показано, что разные корни могут запускать одну и ту же функцию события (y[1] - 18 и y[1]-20 оба запускают eventfunc). Мой вопрос, однако, возможно ли, чтобы разные корни запускали разные функции событий? Говорят по-разному, в зависимости от того, какой корень найден, запускается другой eventfunc? Или, в качестве альтернативы, в пределах одной и той же функции события он может выполнять различные действия в зависимости от того, какой корень найден.
Для простоты сначала я хотел посмотреть, может ли это работать, используя тот же пример, например, с помощью именования корней и работы с оператором if? На данный момент это не работает. У кого-нибудь есть опыт с этим? Если вы посмотрите на атрибуты (вне), кажется, что 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
2 ответа
Штат
Для более сложных случаев, конечно, также можно отправлять события из основной функции события в другие функции для получения подробностей, то же самое можно сделать и для проверки корневого условия.
Спасибо @Bakaburg за обнаружение этого интересного вопроса без ответа.
Вот решение, которое также упрощает некоторые конструкции программирования:
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)
Я подошел к аналогичной проблеме, используя глобальную переменную, установленную в корне или непосредственно в основной функции (полезно, если вы запускаете ее на основе преодоления порога в определенном направлении.
Затем глобальный флаг изменяет поведение функции события.
Не очень элегантно, но работает.
В вашем случае код станет таким:
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)
}