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,
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:
system_new_tt_rule(cfg,
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.
system_set_tt_cond(cfg,
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:
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,
cfg=name = "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,
cfg=name = "ivdose",
times = c(0, 6, 12, 18, 24),
timescale = "months")
system_set_tt_cond(cfg,
cfg=name = "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,
cfg=name = "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,
cfg=name = "ivdose",
times = c(0, 2, 4, 6, 8),
timescale = "weeks")
system_set_tt_cond(cfg,
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:
system_new_tt_rule(cfg,
cfg=name = "state_reset",
times = c(3),
timescale = "weeks")
system_set_tt_cond(cfg,
cfg=name = "state_reset",
cond = 'TRUE',
action = "SI_TT_STATE[Cc][0.5*Cc]",
value = "0")
system_set_tt_cond(cfg,
cfg=name = "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
<CVTYPE:DOSE> step
<CV:WT> ; times; [ 0 ]; day
<CV:WT> ; values; [ 60]; kg
<CVTYPE: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
# #---------#
# | 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