These functions return a modified version of a model specification, such that the state variables are updated each time step according to different numerical methods.
Details
To see the computations that update the state variables under these
modified specifications, one may use the
mp_expand
function (see examples).
The default update method for model specifications produced using
mp_tmb_model_spec
is mp_euler
. This update method
yields a difference-equation model where the state is updated once
per time-step using the absolute flow rate as the difference between
steps.
Functions
mp_euler()
: ODE solver using the Euler method, which is equivalent to treating the model as a set of discrete-time difference equations. This is the default method used bymp_tmb_model_spec
, but this default can be changed using the functions described below.mp_rk4()
: ODE solver using Runge-Kutta 4. Any formulas that appear before model flows in theduring
list will only be updated with RK4 if they do contain functions ingetOption("macpan2_non_iterable_funcs")
and if they do not make any state variable assignments (i.e., the left-hand-side does not contain state variables). Each formula that does not meet these conditions will be evaluated only once at each time-step before the other three RK4 iterations are taken. By default, thetime_var
function and functions that generate random numbers (e.g.,rbinom
) are not iterable. Functions that generate random numbers will only be called once with state update methods that do not repeat expressions more than once per time-step (e.g.,mp_euler
), and so repeating these functions with RK4 could make it difficult to compare methods. If you really do want to regenerate random numbers at each RK4 iteration, you can do so by setting the above option appropriately. Thetime_var
function assumes that it will only be called once per time-step, and so it should never be removed from the list of non-iterable functions. Although in principle it could make sense to update state variables manually, it currently causes us to be confused. We therefore require that all state variable updates are set explicitly (e.g., withmp_per_capita_flow
).mp_rk4_old()
: Old version ofmp_rk4
that doesn't keep track of absolute flows through each time-step. As a result this version is more efficient but makes it more difficult to compute things like incidence over a time scale.mp_euler_multinomial()
: Update state with process error given by the Euler-multinomial distribution.mp_hazard()
: Update state with hazard steps, which is equivalent to taking the step given by the expected value of the Euler-multinomial distribution.
Examples
sir = mp_tmb_library("starter_models", "sir", package = "macpan2")
sir
#> ---------------------
#> Default values:
#> ---------------------
#> quantity value
#> beta 0.2
#> gamma 0.1
#> N 100.0
#> I 1.0
#> R 0.0
#>
#> ---------------------
#> Before the simulation loop (t = 0):
#> ---------------------
#> 1: S ~ N - I - R
#>
#> ---------------------
#> At every iteration of the simulation loop (t = 1 to T):
#> ---------------------
#> 1: mp_per_capita_flow(from = "S", to = "I", rate = "beta * I / N",
#> abs_rate = "infection")
#> 2: mp_per_capita_flow(from = "I", to = "R", rate = "gamma", abs_rate = "recovery")
#>
sir |> mp_euler() |> mp_expand()
#> ---------------------
#> Default values:
#> ---------------------
#> quantity value
#> beta 0.2
#> gamma 0.1
#> N 100.0
#> I 1.0
#> R 0.0
#>
#> ---------------------
#> Before the simulation loop (t = 0):
#> ---------------------
#> 1: S ~ N - I - R
#>
#> ---------------------
#> At every iteration of the simulation loop (t = 1 to T):
#> ---------------------
#> 1: infection ~ S * (beta * I/N)
#> 2: recovery ~ I * (gamma)
#> 3: S ~ S - infection
#> 4: I ~ I + infection - recovery
#> 5: R ~ R + recovery
#>
sir |> mp_rk4() |> mp_expand()
#> ---------------------
#> Default values:
#> ---------------------
#> quantity value
#> beta 0.2
#> gamma 0.1
#> N 100.0
#> I 1.0
#> R 0.0
#>
#> ---------------------
#> Before the simulation loop (t = 0):
#> ---------------------
#> 1: S ~ N - I - R
#>
#> ---------------------
#> At every iteration of the simulation loop (t = 1 to T):
#> ---------------------
#> 1: k1_infection ~ S * (beta * I/N)
#> 2: k1_recovery ~ I * (gamma)
#> 3: k1_S ~ -k1_infection
#> 4: k1_I ~ +k1_infection - k1_recovery
#> 5: k1_R ~ +k1_recovery
#> 6: k2_infection ~ (S + (k1_S/2)) * (beta * (I + (k1_I/2))/N)
#> 7: k2_recovery ~ (I + (k1_I/2)) * (gamma)
#> 8: k2_S ~ -k2_infection
#> 9: k2_I ~ +k2_infection - k2_recovery
#> 10: k2_R ~ +k2_recovery
#> 11: k3_infection ~ (S + (k2_S/2)) * (beta * (I + (k2_I/2))/N)
#> 12: k3_recovery ~ (I + (k2_I/2)) * (gamma)
#> 13: k3_S ~ -k3_infection
#> 14: k3_I ~ +k3_infection - k3_recovery
#> 15: k3_R ~ +k3_recovery
#> 16: k4_infection ~ (S + k3_S) * (beta * (I + k3_I)/N)
#> 17: k4_recovery ~ (I + k3_I) * (gamma)
#> 18: k4_S ~ -k4_infection
#> 19: k4_I ~ +k4_infection - k4_recovery
#> 20: k4_R ~ +k4_recovery
#> 21: infection ~ (k1_infection + 2 * k2_infection + 2 * k3_infection + k4_infection)/6
#> 22: recovery ~ (k1_recovery + 2 * k2_recovery + 2 * k3_recovery + k4_recovery)/6
#> 23: S ~ S - infection
#> 24: I ~ I + infection - recovery
#> 25: R ~ R + recovery
#>
sir |> mp_euler_multinomial() |> mp_expand()
#> ---------------------
#> Default values:
#> ---------------------
#> quantity value
#> beta 0.2
#> gamma 0.1
#> N 100.0
#> I 1.0
#> R 0.0
#>
#> ---------------------
#> Before the simulation loop (t = 0):
#> ---------------------
#> 1: S ~ N - I - R
#>
#> ---------------------
#> At every iteration of the simulation loop (t = 1 to T):
#> ---------------------
#> 1: infection ~ reulermultinom(S, (beta * I/N))
#> 2: recovery ~ reulermultinom(I, gamma)
#> 3: S ~ S - infection
#> 4: I ~ I + infection - recovery
#> 5: R ~ R + recovery
#>