RxODE Solved Systems and ODEs

Matthew L. Fidler, Melissa Hallow, and Wenping Wang

2018-06-18

RxODE

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(RxODE)
## Setup example model
mod1 <-RxODE({
    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 <- eventTable(amount.units="mg", time.units="hours") %>%
    add.dosing(dose=10000, nbr.doses=10, dosing.interval=12) %>%
    add.dosing(dose=20000, nbr.doses=5, start.time=120,dosing.interval=24) %>%
    add.sampling(0:240);

## Setup a mixed solved/ode system:
mod2 <- RxODE({
    ## 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;
})

Like a Sherlock Holmes on the case of a mystery, 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).

Another popular parameterization is in terms of micro-constants. RxODE assumes compartment 1 is the central compartment. The elimination constant would be specified by K, Ke or Kel.

Once the linCmt() sleuthing is complete, the 1, 2 or 3 compartment model solution is used as the value of linCmt().

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 <- eventTable(amount.units='mg', time.units='hours') %>%
    add.dosing(dose=10000, nbr.doses=10, dosing.interval=12,dosing.to=2) %>%
    add.dosing(dose=20000, nbr.doses=5, start.time=120,dosing.interval=24,dosing.to=2) %>%
    add.sampling(0:240);

This can be solved with the following command:

x <- mod2 %>%  solve(theta, ev)
rxHtml(x)
Solved RxODE object
Parameters ($params):
KA V2 CL Q V3 Kin Kout EC50
0.294 40.2 18.6 10.5 297 1 1 200
Initial Conditions ( $inits):
eff
1
First part of data (object):
time eff C2
0 1.000000 0.00000
1 1.084665 44.37555
2 1.180826 54.88295
3 1.228914 51.90342
4 1.234610 44.49737
5 1.214743 36.48434

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:

x <- mod2 %>%  solve(theta, ev,c(eff=2))
rxHtml(x)
Solved RxODE object
Parameters ($params):
KA V2 CL Q V3 Kin Kout EC50
0.294 40.2 18.6 10.5 297 1 1 200
Initial Conditions ( $inits):
eff
2
First part of data (object):
time eff C2
0 2.000000 0.00000
1 1.496778 44.37555
2 1.366782 54.88295
3 1.313536 51.90342
4 1.272430 44.49737
5 1.231204 36.48434

The RxODE 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 <- RxODE({
    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;
    ## The linCmt() picks up the variables from above
    C2   = linCmt();
    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)
rxHtml(x)
Solved RxODE object
Parameters ($params):
KA CL V2 Q V3 Kin Kout EC50
0.294 18.6 40.2 10.5 297 1 1 200
Initial Conditions ( $inits):
eff
1
First part of data (object):
time eff C2
0 1.000000 0.00000
1 1.084665 44.37555
2 1.180826 54.88295
3 1.228914 51.90342
4 1.234610 44.49737
5 1.214743 36.48434

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:

x <- mod3 %>%  solve(c(KA=10),ev)
rxHtml(x)
Solved RxODE object
Parameters ($params):
KA CL V2 Q V3 Kin Kout EC50
10 18.6 40.2 10.5 297 1 1 200
Initial Conditions ( $inits):
eff
1
First part of data (object):
time eff C2
0 1.000000 0.00000
1 1.340982 130.61937
2 1.392185 64.75317
3 1.298397 33.17930
4 1.191799 18.02218
5 1.115887 10.72199