Документация Engee

Условное дозирование в фармакометрике

В этом примере мы покажем, как смоделировать условное дозирование с помощью DiscreteCallbacks. Задача заключается в следующем. В организме пациента действует препарат A(t). Концентрация препарата задана как C(t)=A(t)/V для некоторой константы объема V. В момент времени t=4 пациент обращается в клинику и проходит обследование. Если концентрация препарата в организме ниже 4, пациент получает новую дозу.

Для нашей модели мы будем использовать простое уравнение распада. Мы напишем его в форме на месте, что позволит легко распространить его на более сложные примеры:

using DifferentialEquations
function f(du, u, p, t)
    du[1] = -u[1]
end
u0 = [10.0]
const V = 1
prob = ODEProblem(f, u0, (0.0, 10.0))
ODEProblem with uType Vector{Float64} and tType Float64. In-place: true
timespan: (0.0, 10.0)
u0: 1-element Vector{Float64}:
 10.0

Посмотрим, как выглядит решение без событий.

sol = solve(prob, Tsit5())
using Plots;
gr();
plot(sol)

Мы видим, что в момент времени t=4 пациент должен получить дозу. Закодируем это событие. Необходимо проверить в точке t=4, является ли концентрация u[1]/4 равной <4, и если да, добавить 10 к u[1]. Это можно сделать следующим образом.

condition(u, t, integrator) = t == 4 && u[1] / V < 4
affect!(integrator) = integrator.u[1] += 10
cb = DiscreteCallback(condition, affect!)
DiscreteCallback{typeof(Main.condition), typeof(Main.affect!), typeof(SciMLBase.INITIALIZE_DEFAULT), typeof(SciMLBase.FINALIZE_DEFAULT)}(Main.condition, Main.affect!, SciMLBase.INITIALIZE_DEFAULT, SciMLBase.FINALIZE_DEFAULT, Bool[1, 1])

Теперь передадим этот обратный вызов решателю и укажем ему остановиться в момент t=4, чтобы таким образом можно было проверить условие:

sol = solve(prob, Tsit5(), tstops = [4.0], callback = cb)
using Plots;
gr();
plot(sol)

Покажем, что вместо установки значения 10 он действительно добавил 10. Мы могли бы задать значение с помощью affect!(integrator) = integrator.u[1] = 10.

println(sol(4.00000))
println(sol(4.000000000001))
[0.18316389221855156]
[10.183163892208368]

Теперь смоделируем ситуацию с пациентом, у которого скорость распада препарата ниже:

function f(du, u, p, t)
    du[1] = -u[1] / 6
end
u0 = [10.0]
const V = 1
prob = ODEProblem(f, u0, (0.0, 10.0))
ODEProblem with uType Vector{Float64} and tType Float64. In-place: true
timespan: (0.0, 10.0)
u0: 1-element Vector{Float64}:
 10.0
sol = solve(prob, Tsit5())
using Plots;
gr();
plot(sol)

При тех же условиях и при таком же событии этот пациент не получит вторую дозу:

sol = solve(prob, Tsit5(), tstops = [4.0], callback = cb)
using Plots;
gr();
plot(sol)