using Random
using Pumas
using PumasUtilities
using CairoMakie
using AlgebraOfGraphics
using DataFramesMeta
using CSV
using Dates
PK47 - Plasma protein binding modeling
1 Background
- Structural Model - Plasma Protein Binding Model
- Number of Subjects - 4
- Number of Compounds - 2
2 Learning Outcome
- To get an understanding of the determinants of the unbound concentration, free fraction and total concentration.
- How the modeling of plasma protein data is done
- To understand how the binding protein concentration affects the unbound drug concentration
3 Objectives
- To analyze In vitro plasma protein data of two compounds
- To analyze binding data at two different binding concentration
- To show and understand the relationship between Cu and fu
- To understand the properties of binding sites that can be modeled
4 Libraries
Call the necessary libraries to get started
5 Model
pk_47 = @model begin
@metadata begin
desc = "Plasma Protein Binding Model"
end
@param begin
"""
Affinity constant between drug and protein
"""
tvka ∈ RealDomain(lower = 0)
"""
Number of binding sites per molecule
"""
tvn ∈ RealDomain(lower = 0)
Ω ∈ PDiagDomain(2)
"""
Additive RUV
"""
σ_add ∈ RealDomain(lower = 0)
end
@random begin
η ~ MvNormal(Ω)
end
@covariates dose Pt
@pre begin
Ka = tvka * exp(η[1])
n = tvn * exp(η[2])
_dose = dose
_Pt = Pt
end
@vars begin
fu = (1 - (1 / (1 + (_dose / (n * _Pt)) + (1 / (Ka * n * _Pt))))) * 100
end
@derived begin
dv = @. Normal(fu, σ_add)
end
endPumasModel
Parameters: tvka, tvn, Ω, σ_add
Random effects: η
Covariates: dose, Pt
Dynamical system variables:
Dynamical system type: No dynamical model
Derived: dv, fu
Observed: dv, fu
6 Parameters
The parameters are as given below. Note that tv represents the typical value for parameters.
tvka- Affinity constant between drug and proteintvn- Number of binding sites per molecule
6.1 Compound 1
param1 = (; tvka = 6.09, tvn = 2.833, Ω = Diagonal([0.04, 0.04, 0.04]), σ_add = 2.0398)6.2 Compound 2
param2 = (; tvka = 10.2353, tvn = 1.937, Ω = Diagonal([0.04, 0.04, 0.04]), σ_add = 2.2774)7 Dosage Regimen
Since there is no dosage regimen, we will create a DataFrame with no events and read the file using read_pumas, which will be used for simulation.
7.1 Compound 1
df_sub1 = DataFrame(
id = "0.3mg Protein Conc",
time = 0:1:9999,
dv = missing,
dose = 0.01:0.01:100,
Pt = 0.3,
)
df_sub2 = DataFrame(
id = "50mg Protein Conc",
time = 0:1:9999,
dv = missing,
dose = 0.01:0.01:100,
Pt = 50,
)
df1 = vcat(df_sub1, df_sub2)
pop1 = read_pumas(df1, observations = [:dv], covariates = [:dose, :Pt], event_data = false)Population
Subjects: 2
Covariates: dose, Pt
Observations: dv
7.2 Compound 2
df_sub3 = DataFrame(
id = "0.3mg Protein Conc",
time = 0:1:9999,
dv = missing,
dose = 0.01:0.01:100,
Pt = 0.1,
)
df_sub4 = DataFrame(
id = "50mg Protein Conc",
time = 0:1:9999,
dv = missing,
dose = 0.01:0.01:100,
Pt = 10,
)
df2 = vcat(df_sub3, df_sub4)
pop2 = read_pumas(df2, observations = [:dv], covariates = [:dose, :Pt], event_data = false)Population
Subjects: 2
Covariates: dose, Pt
Observations: dv
8 Simulation
We will now simulate the experimental data for Compound 1 at two different levels of protein concentration (Pt) 0.3 and 50.Since we are simulating only a single subject, we can zero out the random effects.
Random.seed!(123)8.1 Compound 1
zfx = zero_randeffs(pk_47, pop1, param1)
sim_1 = simobs(pk_47, pop1, param1, zfx)
df47_cmp1 = reduce(
vcat,
map(sim_1) do subj
subdf = DataFrame(
id = subj.subject.id,
fu = subj.observations.fu,
dose = subj.covariates.dose,
)
end,
)
first(df47_cmp1, 5)5×3 DataFrame
| Row | id | fu | dose |
|---|---|---|---|
| String | Float64 | Float64 | |
| 1 | 0.3mg Protein Conc | 17.0104 | 0.01 |
| 2 | 0.3mg Protein Conc | 17.8129 | 0.02 |
| 3 | 0.3mg Protein Conc | 18.6 | 0.03 |
| 4 | 0.3mg Protein Conc | 19.3723 | 0.04 |
| 5 | 0.3mg Protein Conc | 20.13 | 0.05 |
8.2 Compound 2
zfx = zero_randeffs(pk_47, pop2, param2)
sim_2 = simobs(pk_47, pop2, param2, zfx)
df47_cmp2 = reduce(
vcat,
map(sim_2) do subj
subdf = DataFrame(
id = subj.subject.id,
fu = subj.observations.fu,
dose = subj.covariates.dose,
)
end,
)
first(df47_cmp2, 5)5×3 DataFrame
| Row | id | fu | dose |
|---|---|---|---|
| String | Float64 | Float64 | |
| 1 | 0.3mg Protein Conc | 35.7335 | 0.01 |
| 2 | 0.3mg Protein Conc | 37.7973 | 0.02 |
| 3 | 0.3mg Protein Conc | 39.7326 | 0.03 |
| 4 | 0.3mg Protein Conc | 41.5512 | 0.04 |
| 5 | 0.3mg Protein Conc | 43.2632 | 0.05 |
9 Visualization
9.1 Compound 1
@chain df47_cmp1 begin
@rsubset :dose ∈ [0.01, 0.05, 0.1, 0.5, 1, 5, 10, 50, 100]
data(_) *
mapping(
:dose => "Unbound concentration",
:fu => "Free Fraction (%)",
color = :id => "",
) *
visual(ScatterLines; linewidth = 4, markersize = 12)
draw(;
figure = (; fontsize = 22),
axis = (;
yticks = 0:20:120,
xscale = log10,
xtickformat = i -> (@. string(round(i; digits = 1))),
title = "Compound 1 - Free fraction vs Unbound Concentration",
),
legend = (; position = :bottom),
)
end9.2 Compound 2
@chain df47_cmp2 begin
@rsubset :dose ∈ [0.01, 0.05, 0.1, 0.5, 1, 5, 10, 50, 100]
data(_) *
mapping(
:dose => "Unbound concentration",
:fu => "Free Fraction (%)",
color = :id => "",
) *
visual(ScatterLines; linewidth = 4, markersize = 12)
draw(;
figure = (; fontsize = 22),
axis = (;
yticks = 0:20:120,
xscale = log10,
xtickformat = i -> (@. string(round(i; digits = 1))),
title = "Compound 2 - Free fraction vs Unbound Concentration",
),
legend = (; position = :bottom),
)
end10 Simulating Multiple Experiments
## Compound 1
par1 = (; tvka = 6.09, tvn = 2.833, Ω = Diagonal([0.042, 0.0926, 0.0623]), σ_add = 2.0398)
time1 = [0, 1, 2, 3, 4, 5, 6, 7, 8]
dose = [0.01, 0.05, 0.1, 0.5, 1, 5, 10, 50, 100]
df1_cmp1 = map(
i -> DataFrame(
id = i,
time = time1,
dv = missing,
dose = dose,
Pt = 0.3,
Compound = "A",
),
1:12,
)
df2_cmp1 = map(
i -> DataFrame(
id = i,
time = time1,
dv = missing,
dose = dose,
Pt = 50,
Compound = "A",
),
13:24,
)
df12_cmp1 = vcat(df1_cmp1, df2_cmp1)
df_cmp1 = vcat(DataFrame.(df12_cmp1)...)
pop_cmp1 = read_pumas(
df_cmp1,
observations = [:dv],
covariates = [:dose, :Pt, :Compound],
event_data = false,
)
sim_cmp1 = simobs(pk_47, pop_cmp1, par1)
df_sim_cmp1 = DataFrame(sim_cmp1)
## Compound 2
par2 =
(; tvka = 10.2353, tvn = 1.937, Ω = Diagonal([0.0225, 0.0378, 0.0135]), σ_add = 2.2774)
df1_cmp2 = map(
i -> DataFrame(
id = i,
time = time1,
dv = missing,
dose = dose,
Pt = 0.1,
Compound = "B",
),
1:12,
)
df2_cmp2 = map(
i -> DataFrame(
id = i,
time = time1,
dv = missing,
dose = dose,
Pt = 10,
Compound = "B",
),
13:24,
)
df12_cmp2 = vcat(df1_cmp2, df2_cmp2)
df_cmp2 = vcat(DataFrame.(df12_cmp2)...)
pop_cmp2 = read_pumas(
df_cmp2,
observations = [:dv],
covariates = [:dose, :Pt, :Compound],
event_data = false,
)
sim_cmp2 = simobs(pk_47, pop_cmp2, par2)
df_sim_cmp2 = DataFrame(sim_cmp2)
df_sim = vcat(df_sim_cmp1, df_sim_cmp2);
#CSV.write("pk_47.csv", df_sim)