Introduction
In the Simulation vignette several examples are provided using fixed dosing regimens. This works well for compounds that are relatively safe, the PK is consistent over time, and for which the drug concentrations required to achieve efficacy are consistent. In fact these restrictions apply to many different compounds. However, there are many scenarios where it is necessary to adjust dosing based on periodic clinical visits: compounds with a narrow therapeutic index, disease progression which alters the drug PK or requires increases in the dose amount, etc. While it is possible to do this manually with the current simulation tools provided, this section outlines a generalized framework to make this easier for the users. The workshop provides several examples of running titration or rule-based simulations. To make a copy of these scripts and other supporting files in the current working directory run the following:
library(ubiquity)
fr = workshop_fetch(section="Titration", overwrite=TRUE)
This should provide you with the following scripts:
-
analysis_repeat_dosing.r
- Implement fixed bolus dosing using the titration framework -
analysis_repeat_infusion.r
- Implement fixed infusion rates using the titration framework -
analysis_visit_dosing_titration.r
- Alter dosing based on predictions at specified time points (individual) -
analysis_visit_dosing_titration_stochastic.r
- Alter dosing based on predictions at specified time points (population) -
analysis_state_reset.r
- Combine multiple rules to dose the drug and perform a state reset
Titration or rule-based simulations are run using the following functions:
-
system_new_tt_rule()
- Defines a new rule and the times when it is evaluated -
system_set_tt_cond()
- Adds a condition to a rule and an associated action to perform when that condition is true -
run_simulation_titrate()
- Runs an individual simulation using titration rules
Repeated Bolus Dosing (analysis_repeat_dosing.r
)
This example shows how to implement a dosing regimen using both the fixed-dosing methodologies and the titration functions above. This is meant as a means to bridge these two concepts. First we use the same model from the Simulation vignette (Davda etal. mAbs, 6(4), 1094-1102), and simulate five doses of 500 mg IV given every two weeks:
cfg = build_system()
cfg = system_select_set(cfg, "default")
parameters = system_fetch_parameters(cfg)
cfg=system_set_option(cfg,group = "simulation", option = "solver", value = "lsoda")
cfg=system_set_option(cfg, group = "simulation", option = "output_times", seq(0,10*7,1))
cfg = system_zero_inputs(cfg)
cfg = system_set_bolus(cfg, state = "Cc",
times = c(0, 14, 28, 42, 56),
values = c(500, 500, 500, 500, 500))
som_fix = run_simulation_ubiquity(parameters, cfg)
To use rule-based control of the simulation we have to enable the titration option:
cfg=system_set_option(cfg,
group = "titration",
option = "titrate",
value = TRUE)
Next we need to define a rule using
system_new_tt_rule()
. A rule contains a set of times (and
the timescale) where we want to evaluate that rule. Here we create a
rule called "ivdose"
and we evaluate this rule at weeks 0,
2, 4, 6 and 8. Any timescale defined using <TS:?>
in
the system file can be used:
cfg=system_new_tt_rule(cfg,
name = "ivdose",
times = c(0, 2, 4, 6, 8),
timescale = "weeks")
Once a rule has been created you can attach conditions to that rule
using system_set_tt_cond()
. The name passed to this
function is the name of the rule to which this condition applies. The
cond
argument is a string that will be evaluated
internally. You put any kind of Boolean argument you want here, or even
create a user definable function that returns a Boolean argument (eg,
'myfunction(arguments)'
). When this condition evaluates as
true the string in action
will be evaluated. The string
SI_TT_BOLUS
is a prototype function used to modify dosing
at the titration points. See the help (?system_set_tt_cond
)
for details on prototype functions and the variables available in the
titration environment. This action will define the dosing into the
specified state (as defined by <B:?>
in the system
file) with the values and times shown. The units here are those
specified in the system file and the times are relative to the titration
time point.
cfg=system_set_tt_cond(cfg,
name = "ivdose",
cond = "TRUE",
action = "SI_TT_BOLUS[state='Cc', values=500, times=0]",
value = "1")
Next we simulate the system using the titration function:
som_tt = run_simulation_titrate(parameters, cfg)
Now we can overlay the predictions using both methods to show that they produce the same result:
myfig = ggplot() +
geom_line(data=som_fix$simout, aes(x=ts.days, y=Cc, color="Fixed Dosing"), linetype=1) +
geom_line(data=som_tt$simout, aes(x=ts.days, y=Cc, color="Titration" ), linetype=2) +
scale_colour_manual(values=c("Fixed Dosing"="darkblue", "Titration"="firebrick3")) +
theme(legend.title = element_blank()) +
theme(legend.position = 'bottom')
myfig = prepare_figure('present', myfig)
print(myfig)
The output of run_simulation_titrate()
is similar to
that of run_simulation_ubiquity()
with two extra elements
in the list that is returned:
-
titration
- A data frame with a row for each time course output and the following columns for titration ruletname
:-
tt.tname.value
- Value of the rule for the active condition or -1 if not triggered -
tt.tname.simtime
- Simulation time where the last condition became active -
tt.tname.timescale
- Simulation time in the time scale the rule was specified in Each of these fields is
-
-
titration_history
data frame which contains a summary list of all of the titration events that were triggered.-
tname
- Titration rule name -
value
- Value of the rule for the active condition -
simtime
- Simulation time where the last condition became active -
timescale
- Simulation time in the time scale the rule was specified in
-
Repeated Infusions (analysis_repeat_infusion.r
)
In this example we want to give a 30 minute infusion at 15 mg/min every two weeks. Similar to the previous example we first do this using the fixed dosing methods:
cfg = system_zero_inputs(cfg)
cfg = system_set_rate(cfg, rate = "Dinf",
times = c( 0, 30, 20160, 20190, 40320, 40350, 60480, 60510, 80640, 80670),
levels = c(15 , 0, 15, 0, 15, 0, 15, 0, 15, 0))
som_fix = run_simulation_ubiquity(parameters, cfg)
Now to use the rule-based dosing we enable titration, create the rule
("ivdose"
) to hold the dosing times, and create the
conditions resulting in the dosing. This is all similar to the previous
example except we use the SI_TT_RATE
prototype function.
The rate and the units of times and levels are the same as those
specified in the system file (<R:?>
). The times here
are also relative to the titration time.
cfg=system_set_option(cfg, group = "titration", option = "titrate", value = TRUE)
cfg=system_new_tt_rule(cfg, name = "ivdose", times = c(0, 2, 4, 6, 8), timescale = "weeks")
cfg=system_set_tt_cond(cfg,
name = "ivdose",
cond = "TRUE",
action = "SI_TT_RATE[rate='Dinf', times=c(0,30), levels=c(15,0)]",
value = "1")
som_tt = run_simulation_titrate(parameters, cfg)
myfig = ggplot() +
geom_line(data=som_fix$simout, aes(x=ts.days, y=Cc, color="Fixed Dosing"), linetype=1) +
geom_line(data=som_tt$simout, aes(x=ts.days, y=Cc, color="Titration" ), linetype=2) +
scale_colour_manual(values=c("Fixed Dosing"="darkblue", "Titration"="firebrick3")) +
theme(legend.title = element_blank()) +
theme(legend.position = 'bottom')
myfig = prepare_figure('present', myfig)
print(myfig)
Titrated Dosing
(analysis_visit_dosing_titration.r
)
In the following example we want to administer a subcutaneous dose
(into At
) every two weeks (interval=14
) for 12
weeks. The dose level will be evaluated every 6 months. If the serum
concentration (Cc) is less than 900, we will dose at 700 mg. If Cc it is
greater than 900 we dose at 600 mg. The relevant code to implement this
are shown below:
cfg=system_new_tt_rule(cfg,
name = "ivdose",
times = c(0, 6, 12, 18, 24),
timescale = "months")
cfg=system_set_tt_cond(cfg,
name = "ivdose",
cond = "Cc < 900",
action = "SI_TT_BOLUS[state='At', values=700, times=0, repdose='last', number=11, interval=14]",
value = "700")
cfg=system_set_tt_cond(cfg,
name = "ivdose",
cond = "Cc > 900",
action = "SI_TT_BOLUS[state='At', values=600, times=0, repdose='last', number=11, interval=14]",
value = "600")
som_tt = run_simulation_titrate(parameters, cfg)
myfig = ggplot() +
geom_line(data=som_tt$simout, aes(x=ts.weeks, y=Cc), color="blue")
myfig = prepare_figure('present', myfig)
print(myfig)
Initially the concentration in the serum is 0
(Cc < 900
), so dosing starts at 700. After six months
the titration rule is triggered again. At this point the serum
concentration is greater greater than 900 so the dose level is reduced
to 600. All subsequent measurements are greater than 900 so the dose
remains at 600.
Titration output: som_tt$titration
Titration output: som_tt$titration_history
Monte Carlo Simulations
(analysis_visit_dosing_titration_stochastic.r
)
This example is similar to the last except here we are performing
population simulations (20 subjects). The same function
(simulate_subjects()
) is used but setting the
'titrate'
option to TRUE
tells that function
to use the rule-based dosing.
cfg = system_set_option(cfg, group="stochastic", option="nsub", value=20)
som= simulate_subjects(parameters, cfg)
This will add a data a list element called som$titration
with three fields for each titration rule (tname
):
-
tt.tname.value
- Value of the rule for the active condition -
tt.tname.simtime
- Simulation time where the last condition became active -
tt.tname.timescale
- Simulation time in the time scale the rule was specified in
Each of these fields is a matrix with an entry for each simulation time (column) and each subject (row). In this example these would be accessed through the following list elements:
som$titration$tt.ivdose.simtime
-
som$titration$tt.ivdose.value
som$titration$tt.ivdose.timescaletimescale
This data structure (som
) can be collapsed down to a
data frame using the som_to_df
function. With titration
simulations a column is added for each rule giving the value of that
rule at the indicated time (the first 100 rows are shown):
sdf = som_to_df(cfg, som)
Performing State/Compartment Resets
(analysis_state_reset.r
)
Along with changing dosing at titration time points, it may also be necessary to directly alter state or compartment values. In this last example we will dose every two weeks and on week 3 we will drop the total drug in the system by 1/2.
This portion covers the IV dosing component:
cfg=system_new_tt_rule(cfg,
name = "ivdose",
times = c(0, 2, 4, 6, 8),
timescale = "weeks")
cfg=system_set_tt_cond(cfg,
name = "ivdose",
cond = 'TRUE',
action = "SI_TT_BOLUS[state='Cc', values=500, times=0]",
value = "5")
And this portion reduces the amount of drug in both Cc
and Cp
by 1/2 at week 3:
cfg=system_new_tt_rule(cfg,
name = "state_reset",
times = c(3),
timescale = "weeks")
cfg=system_set_tt_cond(cfg,
name = "state_reset",
cond = 'TRUE',
action = "SI_TT_STATE[Cc][0.5*Cc]",
value = "0")
cfg=system_set_tt_cond(cfg,
name = "state_reset",
cond = 'TRUE',
action = "SI_TT_STATE[Cp][0.5*Cp]",
value = "0")
som_tt = run_simulation_titrate(parameters, cfg)
myfig = ggplot() +
geom_line(data=som_tt$simout, aes(x=ts.weeks, y=Cc), color="red")
myfig = prepare_figure('present', myfig)
print(myfig)
Contents of system.txt
# Implementation of the two compartment model from Davda 2014
#
# Davda, J. P., Dodds, M. G., Gibbs, M. A., Wisdom, W., & Gibbs, J. (2014). A
# model-based meta-analysis of monoclonal antibody pharmacokinetics to guide
# optimal first-in-human study design. mAbs, 6(4), 1094-1102.
# http://doi.org/10.4161/mabs.29095
#
# System Units:
# mass [=] nmoles
# volume [=] L
# concentration [=] nM
# time [=] day
#
# #-------------#
# | Parameters |
# #-------------#
# System parameters
#name value lower upper units editable grouping
# bound bound
<P> F1 0.744 eps inf --- yes System
<P> ka 0.282 eps inf 1/day yes System
<P> CL 0.200 eps inf L/day yes System
<P> Vc 3.61 eps inf L yes System
<P> Vp 2.75 eps inf L yes System
<P> Q 0.747 eps inf L/day yes System
<P> MW 140 eps inf kD yes System
<PSET:default> mAb in Humans
# Interindividual Variability
# Taken from Table 3
<IIV:ETAka> 0.416
<IIV:ETAka:LN> ka
<IIV:ETACL> 0.09875
<IIV:ETACL:LN> CL
<IIV:ETAVc> 0.116
<IIV:ETAVc:LN> Vc
<IIV:ETAVp> 0.0789
<IIV:ETAVp:LN> Vp
<IIV:ETAQ> 0.699
<IIV:ETAQ:LN> Q
<IIVCOR:ETACL:ETAVc> 0.0786
<IIVCOR:ETACL:ETAVp> 0.0619
<IIVCOR:ETAVp:ETAVc> 0.0377
# Covariates
<CV:DOSE> ; times; [ 0 ]; day
<CV:DOSE> ; values; [400]; mg
<CVINTERP:DOSE> step
<CV:WT> ; times; [ 0 ]; day
<CV:WT> ; values; [ 60]; kg
<CVINTERP:WT> step
# static secondary parameters
<As> kel = CL/Vc
<As> kcp = Q/Vc
<As> kpc = Q/Vp
# #-------------------#
# |Input Information |
# #-------------------#
#
# 1e6 ng 1 nmole 1
# X mg x ------ x ----------------- x --- => X*1e3/MW/Vc
# 1 mg MW (KDA) * 1000 V(L)
#
# Bolus Events
# times/events state values scale units
<B:times>; [ 0.0, 7, 14 ]; 1; days
<B:events>; At; [400.0, 0, 0 ]; 1e3/MW; mg
<B:events>; Cc; [ 0.0, 0, 0 ]; 1e3/MW/Vc; mg
<R:Dinf>; times; [0, 30]; 1/60/24; min
<R:Dinf>; levels; [0, 0]; 60*24*1e3/MW; mg/min
# ODEs
<ODE:At> -ka*At
<ODE:Cc> ka*At*F1/Vc -kel*Cc - kcp*Cc + kpc*Cp*Vp/Vc + Dinf/Vc
<ODE:Cp> kcp*Cc*Vc/Vp - kpc*Cp
# #---------#
# | Outputs |
# #---------#
# Outputs that begin with QC will not be displayed in the GUI
# Convert nM to ng/ml
#
# X nM ===> X*MW(KDA)
#
# Convert nM to ug/ml/mg(dose)
#
# X nM ===> X*MW(KDA)/1000/dose
#
<O> C_ng_ml = Cc*MW
<O> C_DOSE = Cc*MW/DOSE/1000
<VP> prop_err 0.1 eps inf -- yes Variance
<VP> add_err 0.1 eps inf ng/ml yes Variance
<EST:LT> Vp; Vc; CL; Q; ka
<EST:P> Vp; Vc; CL; Q; ka; add_err; prop_err
<OE:C_ng_ml> add=add_err; prop=prop_err
<AMTIFY> Cp; Ap; Vp
# #---------#
# | Options #
# #---------#
# General Options:
# specify different time scales
<TS:min> 24.0*60.0
<TS:days> 1.0
<TS:hours> 24.0
<TS:weeks> 1.0/7.0
<TS:months> 1.0/7.0/4.0