Interesting discussion! I tried a different approach from @Rahulub3r i tested three scenarios. All of them are without giving At3. Just to see how the turnover model looks like. So the short answer is i think your two compartment code wasn’t really at steady state . Here is how i reached the conclusion.
Firstly i tested the two-compartment without giving AT3 using your code. Below are the code and graph. So essentially we see a bouncing-back all the way till 192 hours. Basically, it is the time for a two-compartment turnover model to reach ss. This is probably why you see the bouncing for ID1.
code for original two cmpt-no drug
using Pumas
using CairoMakie
using PumasUtilities
data = DataFrame(id = 1,
time = 0,
amt = 0,
evid = 1,
cmt = 1,
rate = 640,
weight_kg = 3.2)
data[!, :at3_plasma] .= missing
pkdata = read_pumas(data,
observations = [:at3_plasma,],
id = :id,
time = :time,
amt = :amt,
rate = :rate,
evid = :evid,
cmt = :cmt,
covariates = [:weight_kg])
############## two cmpt #####################
twocmpt_model = @model begin
@param begin
tvcl ∈ RealDomain(lower=0.001)
tvvc ∈ RealDomain(lower=0.001)
tvvp ∈ RealDomain(lower=0.001)
tvq ∈ RealDomain(lower=0.001)
tvkin ∈ RealDomain(lower=0.001)
Ω ∈ PDiagDomain(2)
σ_prop ∈ RealDomain(lower=0.001)
end
@random begin
η ~ MvNormal(Ω)
end
@covariates weight_kg
@pre begin
CL = tvcl * weight_kg
Vc = tvvc * weight_kg
Vp = tvvp * weight_kg *exp(η[1])
Q = tvq * weight_kg * exp(η[2])
Kin = tvkin * weight_kg
end
@init begin
Central = Kin/(CL/Vc)
end
@dynamics begin
# 2cmt
Central' = Kin - (CL/Vc)*Central - (Q/Vc)*Central + (Q/Vp)*Peripheral
Peripheral' = (Q/Vc)*Central - (Q/Vp)*Peripheral
end
@derived begin
CP = @. Central/Vc
Cperi = @. Peripheral/Vp
at3_plasma ~ @. Normal(CP, abs(CP) * σ_prop)
end
end
rhAT3_param = (tvcl = 0.0383*60/100,
tvvc = 41.1/100,
tvvp = 74.3/100,
tvq = 0.0763*60/100,
tvkin = 2.1,
Ω = Diagonal([0.1785, 0.0275]),
σ_prop = 0.114)
zero_rand_eff = zero_randeffs(twocmpt_model, rhAT3_param, pkdata)
sims_zero = simobs(twocmpt_model, pkdata, rhAT3_param, zero_rand_eff, obstimes = 0:1:596)
e, f, p = sim_plot(twocmpt_model, [sims_zero][1],
observations = :CP,
color = :redsblues,
linewidth = 4,
axis = (xlabel = "Time (hrs)",
ylabel = "2cmpt_Conc",
xticks = 0:96:596))
axislegend(f)
e
Profile for original two cmpt-no drug
And i applied the same logic to the one-cmpt turnover model. We see a straight line, which is the way it supposed to be. Below are the one-cmpt code and graph.
one cmpt code
############## one cmpt #####################
#
data = DataFrame(id = 1,
time = 0,
amt = 0,
evid = 1,
cmt = 1,
rate = 640,
weight_kg = 3.2)
data[!, :at3_plasma] .= missing
#
pkdata = read_pumas(data,
observations = [:at3_plasma,],
id = :id,
time = :time,
amt = :amt,
rate = :rate,
evid = :evid,
cmt = :cmt,
covariates = [:weight_kg])
#
onecmpt_model = @model begin
@param begin
tvcl ∈ RealDomain(lower=0.001)
tvvc ∈ RealDomain(lower=0.001)
#tvvp ∈ RealDomain(lower=0.001)
#tvq ∈ RealDomain(lower=0.001)
tvkin ∈ RealDomain(lower=0.001)
Ω ∈ PDiagDomain(2)
σ_prop ∈ RealDomain(lower=0.001)
end
@random begin
η ~ MvNormal(Ω)
end
@covariates weight_kg
@pre begin
CL = tvcl * weight_kg
Vc = tvvc * weight_kg
#Vp = tvvp * weight_kg *exp(η[1])
#Q = tvq * weight_kg * exp(η[2])
Kin = tvkin * weight_kg
end
@init begin
Central = Kin/(CL/Vc)
end
@dynamics begin
# 1cmt
Central' = Kin - (CL/Vc)*Central
end
@derived begin
CP = @. Central/Vc
at3_plasma ~ @. Normal(CP, abs(CP) * σ_prop)
end
end
rhAT3_param = (tvcl = 0.0383*60/100,
tvvc = 41.1/100,
#tvvp = 74.3/100,
#tvq = 0.0763*60/100,
tvkin = 2.1,
Ω = Diagonal([0.1785, 0.0275]),
σ_prop = 0.114)
zero_rand_eff = zero_randeffs(onecmpt_model, rhAT3_param, pkdata)
sims_zero = simobs(onecmpt_model, pkdata, rhAT3_param, zero_rand_eff, obstimes = 0:0.01:96)
e, f, p = sim_plot(onecmpt_model, [sims_zero][1],
observations = :CP,
color = :redsblues,
linewidth = 4,
axis = (xlabel = "Time (hrs)",
ylabel = "1cmpt_Conc",
xticks = 0:24:96))
axislegend(f)
e
Therefore i added a command to your original code to make sure that peripheral cmpt is also at ss in the beginning, below are the code and graph. Basically, it is to make the Peripheral’ = 0 => Peripheral = Central * Vp/Vc, then plug in Central = Kin/ (CL/Vc) => Peripheral = Kin * Vp/CL
code for modified two cmpt - no drug
data = DataFrame(id = 1,
time = 0,
amt = 0,
evid = 1,
cmt = 1,
rate = 640,
weight_kg = 3.2)
data[!, :at3_plasma] .= missing
pkdata = read_pumas(data,
observations = [:at3_plasma,],
id = :id,
time = :time,
amt = :amt,
rate = :rate,
evid = :evid,
cmt = :cmt,
covariates = [:weight_kg])
############## two cmpt #####################
twocmpt_model = @model begin
@param begin
tvcl ∈ RealDomain(lower=0.001)
tvvc ∈ RealDomain(lower=0.001)
tvvp ∈ RealDomain(lower=0.001)
tvq ∈ RealDomain(lower=0.001)
tvkin ∈ RealDomain(lower=0.001)
Ω ∈ PDiagDomain(2)
σ_prop ∈ RealDomain(lower=0.001)
end
@random begin
η ~ MvNormal(Ω)
end
@covariates weight_kg
@pre begin
CL = tvcl * weight_kg
Vc = tvvc * weight_kg
Vp = tvvp * weight_kg *exp(η[1])
Q = tvq * weight_kg * exp(η[2])
Kin = tvkin * weight_kg
end
@init begin
Central = Kin/(CL/Vc)
Peripheral = Kin * Vp/CL
end
@dynamics begin
# 2cmt
Central' = Kin - (CL/Vc)*Central - (Q/Vc)*Central + (Q/Vp)*Peripheral
Peripheral' = (Q/Vc)*Central - (Q/Vp)*Peripheral
end
@derived begin
CP = @. Central/Vc
Cperi = @. Peripheral/Vp
at3_plasma ~ @. Normal(CP, abs(CP) * σ_prop)
end
end
rhAT3_param = (tvcl = 0.0383*60/100,
tvvc = 41.1/100,
tvvp = 74.3/100,
tvq = 0.0763*60/100,
tvkin = 2.1,
Ω = Diagonal([0.1785, 0.0275]),
σ_prop = 0.114)
zero_rand_eff = zero_randeffs(twocmpt_model, rhAT3_param, pkdata)
sims_zero = simobs(twocmpt_model, pkdata, rhAT3_param, zero_rand_eff, obstimes = 0:1:96)
e, f, p = sim_plot(twocmpt_model, [sims_zero][1],
observations = :CP,
color = :redsblues,
linewidth = 4,
axis = (xlabel = "Time (hrs)",
ylabel = "2cmpt_Conc",
xticks = 0:24:96))
axislegend(f)
e
Then we see this beautiful straight line in the profile for the two cmpt.
So i further updated the code by giving AT3. Below are the code and the profile for ID1. Doesn’t have any abnormality any more!!
modified two cmpt-with drug
data = DataFrame(id = 1,
time = 0,
amt = 160,
evid = 1,
cmt = 1,
rate = 640,
weight_kg = 3.2)
data[!, :at3_plasma] .= missing
pkdata = read_pumas(data,
observations = [:at3_plasma,],
id = :id,
time = :time,
amt = :amt,
rate = :rate,
evid = :evid,
cmt = :cmt,
covariates = [:weight_kg])
############## two cmpt #####################
twocmpt_model = @model begin
@param begin
tvcl ∈ RealDomain(lower=0.001)
tvvc ∈ RealDomain(lower=0.001)
tvvp ∈ RealDomain(lower=0.001)
tvq ∈ RealDomain(lower=0.001)
tvkin ∈ RealDomain(lower=0.001)
Ω ∈ PDiagDomain(2)
σ_prop ∈ RealDomain(lower=0.001)
end
@random begin
η ~ MvNormal(Ω)
end
@covariates weight_kg
@pre begin
CL = tvcl * weight_kg
Vc = tvvc * weight_kg
Vp = tvvp * weight_kg *exp(η[1])
Q = tvq * weight_kg * exp(η[2])
Kin = tvkin * weight_kg
end
@init begin
Central = Kin/(CL/Vc)
Peripheral = Kin * Vp/CL
end
@dynamics begin
# 2cmt
Central' = Kin - (CL/Vc)*Central - (Q/Vc)*Central + (Q/Vp)*Peripheral
Peripheral' = (Q/Vc)*Central - (Q/Vp)*Peripheral
end
@derived begin
CP = @. Central/Vc
Cperi = @. Peripheral/Vp
at3_plasma ~ @. Normal(CP, abs(CP) * σ_prop)
end
end
rhAT3_param = (tvcl = 0.0383*60/100,
tvvc = 41.1/100,
tvvp = 74.3/100,
tvq = 0.0763*60/100,
tvkin = 2.1,
Ω = Diagonal([0.1785, 0.0275]),
σ_prop = 0.114)
zero_rand_eff = zero_randeffs(twocmpt_model, rhAT3_param, pkdata)
sims_zero = simobs(twocmpt_model, pkdata, rhAT3_param, zero_rand_eff, obstimes = 0:1:96)
e, f, p = sim_plot(twocmpt_model, [sims_zero][1],
observations = :CP,
color = :redsblues,
linewidth = 4,
axis = (xlabel = "Time (hrs)",
ylabel = "2cmpt_Conc",
xticks = 0:24:96))
axislegend(f)
e
profile for ID1