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)
= workshop_fetch(section="Titration", overwrite=TRUE) fr
This should provide you with the following scripts:
analysis_repeat_dosing.r
- Implement fixed bolus dosing
using the titration frameworkanalysis_repeat_infusion.r
- Implement fixed infusion
rates using the titration frameworkanalysis_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 resetTitration or rule-based simulations are run using the following functions:
system_new_tt_rule()
- Defines a new rule and the times
when it is evaluatedsystem_set_tt_cond()
- Adds a condition to a rule and
an associated action to perform when that condition is truerun_simulation_titrate()
- Runs an individual
simulation using titration rulesanalysis_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:
= build_system()
cfg = system_select_set(cfg, "default")
cfg = system_fetch_parameters(cfg)
parameters =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",
cfg times = c(0, 14, 28, 42, 56),
values = c(500, 500, 500, 500, 500))
= run_simulation_ubiquity(parameters, cfg) som_fix
To use rule-based control of the simulation we have to enable the titration option:
=system_set_option(cfg,
cfggroup = "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:
=system_new_tt_rule(cfg,
cfgname = "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.
=system_set_tt_cond(cfg,
cfgname = "ivdose",
cond = "TRUE",
action = "SI_TT_BOLUS[state='Cc', values=500, times=0]",
value = "1")
Next we simulate the system using the titration function:
= run_simulation_titrate(parameters, cfg) som_tt
Now we can overlay the predictions using both methods to show that they produce the same result:
= ggplot() +
myfig 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')
= prepare_figure('present', myfig)
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 rule
tname
:
tt.tname.value
- Value of the rule for the active
condition or -1 if not triggeredtt.tname.simtime
- Simulation time where the last
condition became activett.tname.timescale
- Simulation time in the time scale
the rule was specified in Each of these fields istitration_history
data frame which contains a summary
list of all of the titration events that were triggered.
tname
- Titration rule namevalue
- Value of the rule for the active conditionsimtime
- Simulation time where the last condition
became activetimescale
- Simulation time in the time scale the rule
was specified inanalysis_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:
= system_zero_inputs(cfg)
cfg = system_set_rate(cfg, rate = "Dinf",
cfg times = c( 0, 30, 20160, 20190, 40320, 40350, 60480, 60510, 80640, 80670),
levels = c(15 , 0, 15, 0, 15, 0, 15, 0, 15, 0))
= run_simulation_ubiquity(parameters, cfg) som_fix
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.
=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,
cfgname = "ivdose",
cond = "TRUE",
action = "SI_TT_RATE[rate='Dinf', times=c(0,30), levels=c(15,0)]",
value = "1")
= run_simulation_titrate(parameters, cfg) som_tt
= ggplot() +
myfig 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')
= prepare_figure('present', myfig)
myfig
print(myfig)
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:
=system_new_tt_rule(cfg,
cfgname = "ivdose",
times = c(0, 6, 12, 18, 24),
timescale = "months")
=system_set_tt_cond(cfg,
cfgname = "ivdose",
cond = "Cc < 900",
action = "SI_TT_BOLUS[state='At', values=700, times=0, repdose='last', number=11, interval=14]",
value = "700")
=system_set_tt_cond(cfg,
cfgname = "ivdose",
cond = "Cc > 900",
action = "SI_TT_BOLUS[state='At', values=600, times=0, repdose='last', number=11, interval=14]",
value = "600")
= run_simulation_titrate(parameters, cfg) som_tt
= ggplot() +
myfig geom_line(data=som_tt$simout, aes(x=ts.weeks, y=Cc), color="blue")
= prepare_figure('present', myfig)
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
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.
= system_set_option(cfg, group="stochastic", option="nsub", value=20)
cfg = simulate_subjects(parameters, cfg) som
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
conditiontt.tname.simtime
- Simulation time where the last
condition became activett.tname.timescale
- Simulation time in the time scale
the rule was specified inEach 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):
= som_to_df(cfg, som) sdf
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:
=system_new_tt_rule(cfg,
cfgname = "ivdose",
times = c(0, 2, 4, 6, 8),
timescale = "weeks")
=system_set_tt_cond(cfg,
cfgname = "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:
=system_new_tt_rule(cfg,
cfgname = "state_reset",
times = c(3),
timescale = "weeks")
=system_set_tt_cond(cfg,
cfgname = "state_reset",
cond = 'TRUE',
action = "SI_TT_STATE[Cc][0.5*Cc]",
value = "0")
=system_set_tt_cond(cfg,
cfgname = "state_reset",
cond = 'TRUE',
action = "SI_TT_STATE[Cp][0.5*Cp]",
value = "0")
= run_simulation_titrate(parameters, cfg) som_tt
= ggplot() +
myfig geom_line(data=som_tt$simout, aes(x=ts.weeks, y=Cc), color="red")
= prepare_figure('present', myfig)
myfig print(myfig)
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
<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