rxode2 additional model types
2024-06-25
Source:vignettes/rxode2-model-types.Rmd
rxode2-model-types.Rmd
As suggested in the name, rxode2 is often concerned with solutions to ordinary differential equations. The syntax of the ODE models is covered in the rxode2 syntax vignette
You can create other types of models with rxode2:
- Prediction only models without ODE systems in them
(
$PRED
models in NONMEM). - 1, 2 and 3 solved compartment models (
ADVAN/TRANS
in NONMEM). - Mixing any of these items with ODE systems.
Prediction only models
Prediction only models are simple to create. You use the rxode2 syntax without any ODE systems in them. A very simple example is a one-compartment model.
## rxode2 2.1.3.9000 using 2 threads (see ?getRxThreads)
## no cache: create with `rxCreateCache()`
Solving the rxode2 models are the same as saving the simple ODE system, but faster of course.
## using C compiler: ‘gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0’
cmt1
## -- Solved rxode2 object --
## -- Parameters (x$params): --
## ke
## 0.5
## -- Initial Conditions (x$inits): --
## named numeric(0)
## -- First part of data (object): --
## # A tibble: 50 x 2
## time ipre
## <dbl> <dbl>
## 1 0 10
## 2 0.490 7.83
## 3 0.980 6.13
## 4 1.47 4.80
## 5 1.96 3.75
## 6 2.45 2.94
## # i 44 more rows
Solved compartment models
Solved models are also simple to create. You simply place the
linCmt()
psuedo-function into your code. The
linCmt()
function figures out the type of model to use
based on the parameter names specified.
Most often, pharmacometric models are parameterized in terms of
volume and clearances. Clearances are specified by NONMEM-style names of
CL
, Q
, Q1
, Q2
, etc.
or distributional clearances CLD
, CLD2
.
Volumes are specified by Central (VC
or V
),
Peripheral/Tissue (VP
, VT
). While more
translations are available, some example translations are below:
Another popular parameterization is in terms of micro-constants.
rxode2 assumes compartment 1
is the central compartment.
The elimination constant would be specified by K
,
Ke
or Kel
. Some example translations are
below:
The last parameterization possible is using alpha
and
V
and/or A
/B
/C
. Some
example translations are below:
Once the linCmt()
sleuthing is complete, the
1
, 2
or 3
compartment model
solution is used as the value of linCmt()
.
The compartments where you can dose in a linear solved system are
depot
and central
when there is an linear
absorption constant in the model ka
. Without any additional
ODEs, these compartments are numbered depot=1
and
central=2
.
When the absorption constant ka
is missing, you may only
dose to the central
compartment. Without any additional
ODEs the compartment number is central=1
.
These compartments take the same sort of events that a ODE model can take, and are discussed in the rxode2 events vignette.
This then acts as an ODE model; You specify a dose to the depot compartment and then solve the system:
## using C compiler: ‘gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0’
cmt1
## -- Solved rxode2 object --
## -- Parameters (x$params): --
## kel V
## 0.5 1.0
## -- Initial Conditions (x$inits): --
## named numeric(0)
## -- First part of data (object): --
## # A tibble: 50 x 2
## time ipre
## <dbl> <dbl>
## 1 0 10
## 2 0.490 7.83
## 3 0.980 6.13
## 4 1.47 4.80
## 5 1.96 3.75
## 6 2.45 2.94
## # i 44 more rows
Mixing Solved Systems and ODEs
In addition to pure ODEs, you may mix solved systems and ODEs. The
prior 2-compartment indirect response model can be simplified with a
linCmt()
function:
library(rxode2)
## Setup example model
mod1 <-function() {
model({
C2 = centr/V2
C3 = peri/V3
d/dt(depot) =-KA*depot
d/dt(centr) = KA*depot - CL*C2 - Q*C2 + Q*C3
d/dt(peri) = Q*C2 - Q*C3
d/dt(eff) = Kin - Kout*(1-C2/(EC50+C2))*eff
})
}
## Seup parameters and initial conditions
theta <-
c(KA=2.94E-01, CL=1.86E+01, V2=4.02E+01, # central
Q=1.05E+01, V3=2.97E+02, # peripheral
Kin=1, Kout=1, EC50=200) # effects
inits <- c(eff=1)
## Setup dosing event information
ev <- et(amountUnits="mg", timeUnits="hours") %>%
et(amt=10000, addl=9, ii=12) %>%
et(amt=20000, addl=4, time=120, ii=24) %>%
add.sampling(0:240)
## Setup a mixed solved/ode system:
mod2 <- function() {
model({
## the order of variables do not matter, the type of compartmental
## model is determined by the parameters specified.
C2 = linCmt(KA, CL, V2, Q, V3);
eff(0) = 1 ## This specifies that the effect compartment starts at 1.
d/dt(eff) = Kin - Kout*(1-C2/(EC50+C2))*eff;
})
}
This allows the indirect response model above to assign the
2-compartment model to the C2
variable and the used in the
indirect response model.
When mixing the solved systems and the ODEs, the solved system’s compartment is always the last compartment. This is because the solved system technically isn’t a compartment to be solved. Adding the dosing compartment to the end will not interfere with the actual ODE to be solved.
Therefore,in the two-compartment indirect response model, the effect compartment is compartment #1 while the PK dosing compartment for the depot is compartment #2.
This compartment model requires a new event table since the compartment number changed:
ev <- et(amountUnits='mg', timeUnits='hours') %>%
et(amt=10000, addl=9, ii=12, cmt=2) %>%
et(amt=20000, addl=4, time=120, ii=24, cmt=2) %>%
et(0:240)
This can be solved with the following command:
## using C compiler: ‘gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0’
print(x)
## -- Solved rxode2 object --
## -- Parameters ($params): --
## KA CL V2 Q V3 Kin Kout EC50
## 0.294 18.600 40.200 10.500 297.000 1.000 1.000 200.000
## -- Initial Conditions ($inits): --
## eff
## 1
## -- First part of data (object): --
## # A tibble: 241 x 3
## time C2 eff
## [h] <dbl> <dbl>
## 1 0 249. 1
## 2 1 121. 1.35
## 3 2 60.3 1.38
## 4 3 31.0 1.28
## 5 4 17.0 1.18
## 6 5 10.2 1.11
## # i 235 more rows
Note this solving did not require specifying the effect compartment
initial condition to be 1
. Rather, this is already
pre-specified by eff(0)=1
.
This can be solved for different initial conditions easily:
## -- Solved rxode2 object --
## -- Parameters ($params): --
## KA CL V2 Q V3 Kin Kout EC50
## 0.294 18.600 40.200 10.500 297.000 1.000 1.000 200.000
## -- Initial Conditions ($inits): --
## eff
## 2
## -- First part of data (object): --
## # A tibble: 241 x 3
## time C2 eff
## [h] <dbl> <dbl>
## 1 0 249. 2
## 2 1 121. 1.93
## 3 2 60.3 1.67
## 4 3 31.0 1.41
## 5 4 17.0 1.23
## 6 5 10.2 1.13
## # i 235 more rows
The rxode2 detective also does not require you to specify the
variables in the linCmt()
function if they are already
defined in the block. Therefore, the following function will also work
to solve the same system.
mod3 <- function() {
ini({
KA <- 2.94E-01
CL <- 1.86E+01
V2 <- 4.02E+01
Q <- 1.05E+01
V3 <- 2.97E+02
Kin <- 1
Kout <- 1
EC50 <- 200
})
model({
# Since the parameters are in the ini block, put them in linCmt so
# that the model is detected correctly
C2 <- linCmt(KA, CL, V2, Q, V3)
eff(0) <- 1 ## This specifies that the effect compartment starts at 1.
d/dt(eff) <- Kin - Kout*(1-C2/(EC50+C2))*eff;
})
}
x <- mod3 %>% solve(ev)
print(x)
## -- Solved rxode2 object --
## -- Parameters ($params): --
## KA CL V2 Q V3 Kin Kout EC50
## 0.294 18.600 40.200 10.500 297.000 1.000 1.000 200.000
## -- Initial Conditions ($inits): --
## eff
## 1
## -- First part of data (object): --
## # A tibble: 241 x 3
## time C2 eff
## [h] <dbl> <dbl>
## 1 0 249. 1
## 2 1 121. 1.35
## 3 2 60.3 1.38
## 4 3 31.0 1.28
## 5 4 17.0 1.18
## 6 5 10.2 1.11
## # i 235 more rows
Note that you do not specify the parameters when solving the system since they are built into the model, but you can override the parameters:
## -- Solved rxode2 object --
## -- Parameters ($params): --
## KA CL V2 Q V3 Kin Kout EC50
## 10.0 18.6 40.2 10.5 297.0 1.0 1.0 200.0
## -- Initial Conditions ($inits): --
## eff
## 1
## -- First part of data (object): --
## # A tibble: 241 x 3
## time C2 eff
## [h] <dbl> <dbl>
## 1 0 249. 1
## 2 1 121. 1.35
## 3 2 60.3 1.38
## 4 3 31.0 1.28
## 5 4 17.0 1.18
## 6 5 10.2 1.11
## # i 235 more rows