Chapter 7: Direct and Indirect Continuous Pop PK-PD Models

MI-210 Essentials of Population PKPD M&S — Pumas Edition

Author

Adapted from Marc R. Gastonguay, Ph.D. (Metrum Institute)

Published

April 18, 2026

1 Overview

This chapter covers continuous PK-PD models linking drug concentrations to pharmacodynamic response:

  • Direct PK-PD (Emax)
  • Effect Compartment PK-PD
  • Non-Parametric Effect Compartment
  • PK-PD with Tolerance
  • Indirect Response Models (Types I-IV)

2 Background

PK-PD models link the pharmacokinetic profile to an observed pharmacodynamic response. The approach depends on the relationship between drug concentration and effect:

  • Direct PK-PD: Effect is an instantaneous function of concentration
  • Indirect PK-PD: Effect is mediated through a rate process (production or loss)
  • Effect Compartment: Accounts for temporal delay between concentration and effect
Pharmacological Basis: Why Emax Models Work

Most drugs exert their effects by binding to receptors, inhibiting enzymes, or modulating ion channels. The concentration-effect relationship follows the law of mass action: at low concentrations, the effect increases approximately linearly with concentration; at high concentrations, binding sites saturate and the effect plateaus. This saturable behavior is captured by the \(E_{max}\) model:

\[E = \frac{E_{max} \cdot C}{EC_{50} + C}\]

which is mathematically identical to the Michaelis-Menten equation for enzyme kinetics. Here, \(EC_{50}\) is the concentration producing 50% of maximum effect (analogous to \(K_M\)), and \(E_{max}\) is the maximum achievable effect (analogous to \(V_{max}\)). The sigmoid (Hill) extension introduces a shape parameter \(\gamma\) that controls the steepness of the curve: \(E = E_{max} \cdot C^{\gamma} / (EC_{50}^{\gamma} + C^{\gamma})\). When \(\gamma > 1\), the curve is steeper (switch-like behavior); when \(\gamma < 1\), it is shallower. This pharmacological foundation — grounded in receptor occupancy theory — is why the \(E_{max}\) model is the fundamental building block of virtually all PD modeling.

3 Data

The exercises use three datasets:

  • ch7_pk.csv — PK-only data (TYPE=0)
  • ch7_pkpd.csv — Combined PK+PD data (TYPE=0 for PK, TYPE=1 for PD)
  • ch7_indirect_pkpd.csv — Combined PK+PD with indirect response endpoint
pk_df = CSV.read(joinpath(data_dir, "ch7_pk.csv"), DataFrame)
pkpd_df = CSV.read(joinpath(data_dir, "ch7_pkpd.csv"), DataFrame)
ind_df = CSV.read(joinpath(data_dir, "ch7_indirect_pkpd.csv"), DataFrame)

println("PK data: ", nrow(pk_df), " rows, ", length(unique(pk_df.ID)), " subjects")
println("PKPD data: ", nrow(pkpd_df), " rows")
println("Indirect data: ", nrow(ind_df), " rows")
PK data: 240 rows, 20 subjects
PKPD data: 460 rows
Indirect data: 480 rows

4 Base PK Model

All PK-PD models build on a 1-compartment oral PK model (ADVAN2 TRANS2):

# Prepare PK-only data
pk_only = @rsubset(pk_df, :TYPE == 0 || :AMT > 0)
rename!(pk_only, :ID => :id, :AMT => :amt, :TIME => :time, :DV => :dv, :CMT => :cmt)
pk_only.evid = ifelse.(pk_only.amt .> 0, 1, 0)
pk_only.dv = ifelse.(pk_only.evid .== 1, missing, pk_only.dv)

pop_pk = read_pumas(pk_only)
println("PK subjects: ", length(pop_pk))
PK subjects: 20
pk_base = @model begin
    @metadata begin
        desc = "Base PK: 1-Cpt Oral (ADVAN2 TRANS2)"
    end
    @param begin
        tvKa   ∈ RealDomain(lower = 0.0, init = 1.5)
        tvCL   ∈ RealDomain(lower = 0.0, init = 5.0)
        tvV    ∈ RealDomain(lower = 0.0, init = 35.0)
        ω²_Ka  ∈ RealDomain(lower = 0.0, init = 0.04)
        Ω_pk   ∈ PSDDomain(2)
        σ_prop ∈ RealDomain(lower = 0.0, init = 0.2)
        σ_add  ∈ RealDomain(lower = 0.0, init = 1.41)
    end
    @random begin
        η_Ka ~ Normal(0.0, sqrt(ω²_Ka))
        η_pk ~ MvNormal(Ω_pk)
    end
    @pre begin
        Ka = tvKa * exp(η_Ka)
        CL = tvCL * exp(η_pk[1])
        Vc = tvV  * exp(η_pk[2])
    end
    @dynamics Depots1Central1
    @derived begin
        cp := @. Central / Vc
        dv ~ @. Normal(cp, sqrt((cp * σ_prop)^2 + σ_add^2))
    end
end
PumasModel
  Parameters: tvKa, tvCL, tvV, ω²_Ka, Ω_pk, σ_prop, σ_add
  Random effects: η_Ka, η_pk
  Covariates:
  Dynamical system variables: Depot, Central
  Dynamical system type: Closed form
  Derived: dv
  Observed: dv
pk_params = (
    tvKa = 1.5, tvCL = 5.0, tvV = 35.0,
    ω²_Ka = 0.04,
    Ω_pk = [0.04 0.01; 0.01 0.04],
    σ_prop = 0.2, σ_add = sqrt(2.0),
)
pk_fit = fit(pk_base, pop_pk, pk_params, Pumas.FOCEI())
pk_fit
[ Info: Checking the initial parameter values.
[ Info: The initial negative log likelihood and its gradient are finite. Check passed.
Iter     Function value   Gradient norm 
     0     4.166856e+02     8.017131e+01
 * time: 0.012240886688232422
     1     3.840650e+02     1.104225e+02
 * time: 0.9147119522094727
     2     3.635721e+02     9.730302e+01
 * time: 0.9207980632781982
     3     3.356405e+02     6.707764e+01
 * time: 1.3415138721466064
     4     3.303805e+02     7.860668e+01
 * time: 1.3440001010894775
     5     3.056468e+02     3.189815e+01
 * time: 1.3465189933776855
     6     2.983179e+02     3.407148e+01
 * time: 1.3493680953979492
     7     2.905084e+02     2.502687e+01
 * time: 1.3522889614105225
     8     2.880127e+02     3.378228e+01
 * time: 1.3551630973815918
     9     2.826686e+02     1.290026e+01
 * time: 1.3582608699798584
    10     2.794418e+02     1.799054e+01
 * time: 1.3612990379333496
    11     2.792528e+02     4.548804e+01
 * time: 1.364326000213623
    12     2.775762e+02     1.039404e+01
 * time: 1.367258071899414
    13     2.774304e+02     5.744242e+00
 * time: 1.3702049255371094
    14     2.773809e+02     4.769231e+00
 * time: 1.3729090690612793
    15     2.773574e+02     7.912850e-01
 * time: 1.3756749629974365
    16     2.773483e+02     8.209608e-01
 * time: 1.3783490657806396
    17     2.773398e+02     5.726275e-01
 * time: 1.380910873413086
    18     2.773378e+02     3.253195e-01
 * time: 1.3833298683166504
    19     2.773345e+02     6.370831e-01
 * time: 1.385840892791748
    20     2.773308e+02     8.950136e-01
 * time: 1.3883519172668457
    21     2.773274e+02     7.043970e-01
 * time: 1.3907949924468994
    22     2.773262e+02     2.542502e-01
 * time: 1.3934369087219238
    23     2.773260e+02     2.813574e-02
 * time: 1.3957879543304443
    24     2.773260e+02     1.032549e-03
 * time: 1.398103952407837
    25     2.773260e+02     1.032549e-03
 * time: 1.4015600681304932
    26     2.773260e+02     1.032549e-03
 * time: 1.4054369926452637
    27     2.773260e+02     1.032549e-03
 * time: 1.407926082611084
FittedPumasModel

Dynamical system type:                 Closed form

Number of subjects:                             20

Observation records:         Active        Missing
    dv:                         220              0
    Total:                      220              0

Number of parameters:      Constant      Optimized
                                  0              9

Likelihood approximation:                     FOCE
Likelihood optimizer:                         BFGS

Termination Reason:                      NoXChange
Log-likelihood value:                   -277.32599

---------------------
          Estimate
---------------------
tvKa       1.3593
tvCL       4.7674
tvV       35.795
ω²_Ka      0.049835
Ω_pk₁,₁    0.046159
Ω_pk₂,₁    0.0091618
Ω_pk₂,₂    0.019243
σ_prop     0.20066
σ_add      0.0027741
---------------------

5 Direct PK-PD

In the direct model, effect is an instantaneous function of plasma concentration:

\[E = E_0 + \frac{E_{max} \cdot C_p}{EC_{50} + C_p}\]

This requires no additional dynamics — the PD is computed directly from the PK prediction in the error block.

$ERROR
EMAX=THETA(4)*EXP(ETA(4))
EC50=THETA(5)*EXP(ETA(5))
E0=THETA(6)*EXP(ETA(6))
EFF=E0+EMAX*F/(EC50+F)+ERR(2)
CONC=F + F*ERR(1)
Y=EFF*TYPE + CONC*(1-TYPE)
# Prepare combined PK+PD data — pivot to wide format for multi-DV
# PK and PD observations at same times need to be on same row
pkpd_dose = @rsubset(pkpd_df, :AMT > 0)
pkpd_pk = @rsubset(pkpd_df, :TYPE == 0, :AMT == 0)
pkpd_pd = @rsubset(pkpd_df, :TYPE == 1)

pk_w = select(pkpd_pk, :ID, :TIME, :DV => :dv_pk)
pd_w = select(pkpd_pd, :ID, :TIME, :DV => :dv_pd)
obs_w = outerjoin(pk_w, pd_w, on = [:ID, :TIME])
obs_w.AMT .= 0; obs_w.CMT .= 2; obs_w.evid .= 0

dose_w = select(pkpd_dose, :ID, :TIME, :AMT, :CMT)
dose_w.dv_pk .= missing; dose_w.dv_pd .= missing; dose_w.evid .= 1

pkpd_combined = vcat(dose_w, obs_w, cols = :union)
pkpd_combined.AMT = coalesce.(pkpd_combined.AMT, 0)
pkpd_combined.evid = coalesce.(pkpd_combined.evid, 0)
pkpd_combined.CMT = coalesce.(pkpd_combined.CMT, 2)
sort!(pkpd_combined, [:ID, :TIME, order(:evid, rev = true)])

rename!(pkpd_combined, :ID => :id, :TIME => :time, :AMT => :amt, :CMT => :cmt)
pop_pkpd = read_pumas(pkpd_combined; observations = [:dv_pk, :dv_pd])
println("PKPD subjects: ", length(pop_pkpd))
PKPD subjects: 20
direct_pkpd = @model begin
    @metadata begin
        desc = "Direct Emax PK-PD"
    end
    @param begin
        tvKa   ∈ RealDomain(lower = 0.0, init = 1.7)
        tvCL   ∈ RealDomain(lower = 0.0, init = 4.7)
        tvV    ∈ RealDomain(lower = 0.0, init = 38.0)
        tvEmax ∈ RealDomain(lower = 0.0, init = 100.0)
        tvEC50 ∈ RealDomain(lower = 0.0, init = 5.0)
        tvE0   ∈ RealDomain(lower = 0.0, init = 60.0)
        Ω      ∈ PDiagDomain(6)
        σ_prop ∈ RealDomain(lower = 0.0, init = 0.2)
        σ_pd   ∈ RealDomain(lower = 0.0, init = 2.24)
    end
    @random begin
        η ~ MvNormal(Ω)
    end
    @pre begin
        Ka   = tvKa * exp(η[1])
        CL   = tvCL * exp(η[2])
        Vc   = tvV  * exp(η[3])
        Emax = tvEmax * exp(η[4])
        EC50 = tvEC50 * exp(η[5])
        E0   = tvE0 * exp(η[6])
    end
    @dynamics Depots1Central1
    @derived begin
        cp := @. Central / Vc
        # PK observation (proportional error)
        dv_pk ~ @. Normal(cp, abs(cp) * σ_prop)
        # PD observation (direct Emax + additive error)
        eff := @. E0 + Emax * cp / (EC50 + cp)
        dv_pd ~ @. Normal(eff, σ_pd)
    end
end
PumasModel
  Parameters: tvKa, tvCL, tvV, tvEmax, tvEC50, tvE0, Ω, σ_prop, σ_pd
  Random effects: η
  Covariates:
  Dynamical system variables: Depot, Central
  Dynamical system type: Closed form
  Derived: dv_pk, dv_pd
  Observed: dv_pk, dv_pd
direct_params = (
    tvKa = 1.7, tvCL = 4.7, tvV = 38.0,
    tvEmax = 100.0, tvEC50 = 5.0, tvE0 = 60.0,
    Ω = Diagonal(fill(0.04, 6)),
    σ_prop = 0.2, σ_pd = sqrt(5.0),
)
direct_fit = fit(direct_pkpd, pop_pkpd, direct_params, Pumas.FOCEI())
direct_fit
[ Info: Checking the initial parameter values.
[ Info: The initial negative log likelihood and its gradient are finite. Check passed.
Iter     Function value   Gradient norm 
     0     4.430762e+03     2.671248e+03
 * time: 2.4080276489257812e-5
     1     1.880925e+03     7.344425e+02
 * time: 0.4339730739593506
     2     1.622390e+03     3.990711e+02
 * time: 0.47350215911865234
     3     1.483465e+03     1.754307e+02
 * time: 0.5082571506500244
     4     1.434739e+03     1.742967e+02
 * time: 0.5240612030029297
     5     1.403106e+03     1.501704e+02
 * time: 0.5356919765472412
     6     1.367590e+03     1.074723e+02
 * time: 0.5466799736022949
     7     1.337474e+03     9.630342e+01
 * time: 0.5573689937591553
     8     1.311637e+03     7.083317e+01
 * time: 0.5661871433258057
     9     1.301092e+03     6.381741e+01
 * time: 0.5771100521087646
    10     1.297023e+03     5.227391e+01
 * time: 0.5878980159759521
    11     1.290880e+03     5.008124e+01
 * time: 0.5992081165313721
    12     1.283336e+03     4.209421e+01
 * time: 0.6103291511535645
    13     1.279130e+03     3.196621e+01
 * time: 0.621068000793457
    14     1.277250e+03     3.342941e+01
 * time: 0.6314880847930908
    15     1.275162e+03     3.544695e+01
 * time: 0.642009973526001
    16     1.272034e+03     3.599997e+01
 * time: 0.652860164642334
    17     1.268091e+03     3.734853e+01
 * time: 0.6638860702514648
    18     1.265099e+03     3.073979e+01
 * time: 0.6724221706390381
    19     1.263518e+03     2.997748e+01
 * time: 0.6830651760101318
    20     1.262309e+03     2.198757e+01
 * time: 0.6934599876403809
    21     1.261183e+03     1.388066e+01
 * time: 0.7041330337524414
    22     1.260288e+03     1.395191e+01
 * time: 0.7143909931182861
    23     1.259688e+03     9.460054e+00
 * time: 0.7246911525726318
    24     1.259260e+03     1.114251e+01
 * time: 0.7351970672607422
    25     1.258915e+03     1.086839e+01
 * time: 0.7453181743621826
    26     1.258592e+03     1.359211e+01
 * time: 0.7536201477050781
    27     1.258173e+03     1.399207e+01
 * time: 0.7639131546020508
    28     1.257620e+03     1.059567e+01
 * time: 0.7741191387176514
    29     1.257057e+03     3.906807e+00
 * time: 0.7847881317138672
    30     1.256645e+03     3.027562e+00
 * time: 0.7953720092773438
    31     1.256399e+03     5.341539e+00
 * time: 0.8059489727020264
    32     1.256293e+03     4.735702e+00
 * time: 0.8163871765136719
    33     1.256256e+03     2.778442e+00
 * time: 0.8262491226196289
    34     1.256242e+03     2.759952e+00
 * time: 0.8342320919036865
    35     1.256230e+03     2.743791e+00
 * time: 0.8441421985626221
    36     1.256203e+03     2.792107e+00
 * time: 0.8541491031646729
    37     1.256142e+03     5.444348e+00
 * time: 0.8644289970397949
    38     1.256010e+03     8.507416e+00
 * time: 0.8748250007629395
    39     1.255787e+03     9.921506e+00
 * time: 0.8851850032806396
    40     1.255555e+03     5.924178e+00
 * time: 0.8958830833435059
    41     1.255459e+03     5.772958e+00
 * time: 0.9041461944580078
    42     1.255430e+03     5.041421e+00
 * time: 0.9141101837158203
    43     1.255406e+03     3.888541e+00
 * time: 0.9241981506347656
    44     1.255373e+03     3.311506e+00
 * time: 0.9344980716705322
    45     1.255348e+03     1.877533e+00
 * time: 0.9443581104278564
    46     1.255340e+03     4.856092e-01
 * time: 0.9544970989227295
    47     1.255339e+03     1.496839e-01
 * time: 0.964259147644043
    48     1.255339e+03     7.223538e-02
 * time: 0.9720339775085449
    49     1.255339e+03     5.311650e-02
 * time: 0.9819941520690918
    50     1.255339e+03     5.302798e-02
 * time: 0.9916059970855713
    51     1.255339e+03     7.495599e-02
 * time: 1.0013229846954346
    52     1.255339e+03     1.422723e-01
 * time: 1.0111169815063477
    53     1.255339e+03     2.386357e-01
 * time: 1.0211031436920166
    54     1.255339e+03     2.896828e-01
 * time: 1.0291271209716797
    55     1.255339e+03     2.201049e-01
 * time: 1.0394160747528076
    56     1.255338e+03     7.956383e-02
 * time: 1.0492970943450928
    57     1.255338e+03     2.816678e-02
 * time: 1.0593011379241943
    58     1.255338e+03     2.747591e-02
 * time: 1.068636178970337
    59     1.255338e+03     2.685499e-02
 * time: 1.077991008758545
    60     1.255338e+03     2.521360e-02
 * time: 1.0852270126342773
    61     1.255338e+03     3.234450e-02
 * time: 1.0947070121765137
    62     1.255338e+03     4.915159e-02
 * time: 1.1044790744781494
    63     1.255338e+03     5.993211e-02
 * time: 1.1141769886016846
    64     1.255338e+03     4.873833e-02
 * time: 1.1241250038146973
    65     1.255338e+03     2.008924e-02
 * time: 1.1339490413665771
    66     1.255338e+03     6.519858e-03
 * time: 1.1414320468902588
    67     1.255338e+03     6.722397e-03
 * time: 1.150170087814331
    68     1.255338e+03     6.726560e-03
 * time: 1.1598801612854004
    69     1.255338e+03     6.750421e-03
 * time: 1.1701080799102783
    70     1.255338e+03     6.780828e-03
 * time: 1.1802921295166016
    71     1.255338e+03     6.780981e-03
 * time: 1.1916990280151367
    72     1.255338e+03     7.025447e-03
 * time: 1.1992521286010742
    73     1.255338e+03     7.088923e-03
 * time: 1.2087490558624268
    74     1.255338e+03     7.316282e-03
 * time: 1.218116044998169
    75     1.255338e+03     7.549789e-03
 * time: 1.2279651165008545
    76     1.255338e+03     1.287682e-02
 * time: 1.2373809814453125
    77     1.255338e+03     2.019855e-02
 * time: 1.2468681335449219
    78     1.255338e+03     2.861089e-02
 * time: 1.2546730041503906
    79     1.255338e+03     3.329259e-02
 * time: 1.2644331455230713
    80     1.255338e+03     2.690672e-02
 * time: 1.2741131782531738
    81     1.255338e+03     1.025398e-02
 * time: 1.2834820747375488
    82     1.255338e+03     1.576771e-03
 * time: 1.2930700778961182
    83     1.255338e+03     4.714151e-03
 * time: 1.3026700019836426
    84     1.255338e+03     5.461691e-03
 * time: 1.309993028640747
    85     1.255338e+03     3.443923e-03
 * time: 1.319566011428833
    86     1.255338e+03     6.368910e-04
 * time: 1.3289129734039307
FittedPumasModel

Dynamical system type:                 Closed form

Number of subjects:                             20

Observation records:         Active        Missing
    dv_pk:                      220              0
    dv_pd:                      220              0
    Total:                      440              0

Number of parameters:      Constant      Optimized
                                  0             14

Likelihood approximation:                     FOCE
Likelihood optimizer:                         BFGS

Termination Reason:                   GradientNorm
Log-likelihood value:                   -1255.3375

----------------------
         Estimate
----------------------
tvKa       1.3668
tvCL       4.8346
tvV       36.392
tvEmax     0.00043429
tvEC50   301.46
tvE0      80.148
Ω₁,₁       0.042081
Ω₂,₂       0.04042
Ω₃,₃       0.015019
Ω₄,₄       0.059114
Ω₅,₅       0.043285
Ω₆,₆       0.033018
σ_prop     0.24476
σ_pd      16.466
----------------------

6 Effect Compartment PK-PD

When there is a temporal delay between plasma concentration and effect, an effect compartment links the PK to PD:

\[\frac{dC_e}{dt} = K_{e0} \cdot (C_p - C_e)\]

\[E = E_0 + \frac{E_{max} \cdot C_e}{EC_{50} + C_e}\]

In NONMEM, this uses ADVAN4 TRANS1 with a negligible-mass trick (K23 very small). In Pumas, we write the ODE explicitly:

ecomp_pkpd = @model begin
    @metadata begin
        desc = "Effect Compartment PK-PD (Emax)"
    end
    @param begin
        tvKa   ∈ RealDomain(lower = 0.0, init = 1.5)
        tvCL   ∈ RealDomain(lower = 0.0, init = 5.0)
        tvV    ∈ RealDomain(lower = 0.0, init = 35.0)
        tvKe0  ∈ RealDomain(lower = 0.0, init = 0.07)
        tvEmax ∈ RealDomain(lower = 0.0, init = 100.0)
        tvEC50 ∈ RealDomain(lower = 0.0, init = 5.0)
        tvE0   ∈ RealDomain(lower = 0.0, init = 60.0)
        Ω      ∈ PDiagDomain(7)
        σ_prop ∈ RealDomain(lower = 0.0, init = 0.2)
        σ_pd   ∈ RealDomain(lower = 0.0, init = 4.47)
    end
    @random begin
        η ~ MvNormal(Ω)
    end
    @pre begin
        Ka   = tvKa * exp(η[1])
        CL   = tvCL * exp(η[2])
        Vc   = tvV  * exp(η[3])
        Ke0  = tvKe0 * exp(η[4])
        Emax = tvEmax * exp(η[5])
        EC50 = tvEC50 * exp(η[6])
        E0   = tvE0 * exp(η[7])
    end
    @dynamics begin
        Depot'   = -Ka * Depot
        Central' =  Ka * Depot - (CL / Vc) * Central
        Ce'      =  Ke0 * (Central / Vc - Ce)  # effect compartment
    end
    @derived begin
        cp := @. Central / Vc
        dv_pk ~ @. Normal(cp, abs(cp) * σ_prop)
        eff := @. E0 + Emax * Ce / (EC50 + Ce)
        dv_pd ~ @. Normal(eff, σ_pd)
    end
end
PumasModel
  Parameters: tvKa, tvCL, tvV, tvKe0, tvEmax, tvEC50, tvE0, Ω, σ_prop, σ_pd
  Random effects: η
  Covariates:
  Dynamical system variables: Depot, Central, Ce
  Dynamical system type: Matrix exponential
  Derived: dv_pk, dv_pd
  Observed: dv_pk, dv_pd
ecomp_params = (
    tvKa = 1.5, tvCL = 5.0, tvV = 35.0, tvKe0 = 0.07,
    tvEmax = 100.0, tvEC50 = 5.0, tvE0 = 60.0,
    Ω = Diagonal(fill(0.04, 7)),
    σ_prop = 0.2, σ_pd = sqrt(20.0),
)
ecomp_fit = fit(ecomp_pkpd, pop_pkpd, ecomp_params, Pumas.FOCEI())
ecomp_fit
[ Info: Checking the initial parameter values.
[ Info: The initial negative log likelihood and its gradient are finite. Check passed.
Iter     Function value   Gradient norm 
     0     1.041844e+03     7.813852e+01
 * time: 2.193450927734375e-5
     1     1.032660e+03     1.643447e+01
 * time: 0.6318747997283936
     2     1.031822e+03     1.605007e+01
 * time: 1.186776876449585
     3     1.030301e+03     1.120108e+01
 * time: 1.304297924041748
     4     1.029732e+03     1.234478e+01
 * time: 1.441051959991455
     5     1.028827e+03     1.014558e+01
 * time: 1.5635600090026855
     6     1.028150e+03     7.359745e+00
 * time: 1.7196099758148193
     7     1.027831e+03     3.514978e+00
 * time: 1.8462138175964355
     8     1.027685e+03     8.220644e+00
 * time: 1.9627950191497803
     9     1.027330e+03     6.509045e+00
 * time: 2.078159809112549
    10     1.026941e+03     6.448416e+00
 * time: 2.187788963317871
    11     1.026697e+03     4.987798e+00
 * time: 2.3104448318481445
    12     1.026643e+03     2.087857e+00
 * time: 2.446316957473755
    13     1.026612e+03     2.553588e+00
 * time: 2.566248893737793
    14     1.026594e+03     5.541514e-01
 * time: 2.67667293548584
    15     1.026562e+03     1.553446e+00
 * time: 2.788827896118164
    16     1.026527e+03     2.853394e+00
 * time: 2.899765968322754
    17     1.026507e+03     1.105801e+00
 * time: 3.0131609439849854
    18     1.026496e+03     5.009212e-01
 * time: 3.132354974746704
    19     1.026479e+03     1.710960e+00
 * time: 3.2540957927703857
    20     1.026445e+03     3.409969e+00
 * time: 3.3743679523468018
    21     1.026393e+03     4.453273e+00
 * time: 3.4846668243408203
    22     1.026345e+03     3.209626e+00
 * time: 3.6196999549865723
    23     1.026322e+03     9.979654e-01
 * time: 3.7394909858703613
    24     1.026311e+03     5.373233e-01
 * time: 3.8607168197631836
    25     1.026300e+03     1.773934e+00
 * time: 3.97986102104187
    26     1.026277e+03     3.145893e+00
 * time: 4.10134482383728
    27     1.026238e+03     3.969622e+00
 * time: 4.221444845199585
    28     1.026194e+03     3.226069e+00
 * time: 4.343890905380249
    29     1.026165e+03     1.214667e+00
 * time: 4.463124990463257
    30     1.026151e+03     3.600419e-01
 * time: 4.5829918384552
    31     1.026142e+03     1.192578e+00
 * time: 4.704821825027466
    32     1.026128e+03     1.663870e+00
 * time: 4.824930906295776
    33     1.026109e+03     1.542272e+00
 * time: 4.947938919067383
    34     1.026092e+03     7.513828e-01
 * time: 5.058568954467773
    35     1.026085e+03     2.936937e-01
 * time: 5.179253816604614
    36     1.026080e+03     4.414037e-01
 * time: 5.288574934005737
    37     1.026074e+03     7.133445e-01
 * time: 5.4088029861450195
    38     1.026067e+03     6.797723e-01
 * time: 5.5283730030059814
    39     1.026059e+03     3.402265e-01
 * time: 5.647954940795898
    40     1.026052e+03     1.611210e-01
 * time: 5.769176959991455
    41     1.026047e+03     3.530193e-01
 * time: 5.886362791061401
    42     1.026041e+03     4.084936e-01
 * time: 6.0068747997283936
    43     1.026034e+03     2.622676e-01
 * time: 6.126940011978149
    44     1.026029e+03     6.850675e-02
 * time: 6.249473810195923
    45     1.026027e+03     8.098138e-02
 * time: 6.367302894592285
    46     1.026026e+03     6.915900e-02
 * time: 6.476688861846924
    47     1.026026e+03     2.881101e-02
 * time: 6.5859739780426025
    48     1.026026e+03     5.638900e-03
 * time: 6.7020368576049805
    49     1.026026e+03     6.999274e-03
 * time: 6.820204973220825
    50     1.026026e+03     2.338743e-02
 * time: 6.925599813461304
    51     1.026026e+03     4.251728e-02
 * time: 7.041100025177002
    52     1.026026e+03     5.633183e-02
 * time: 7.158589839935303
    53     1.026026e+03     5.015280e-02
 * time: 7.266171932220459
    54     1.026026e+03     2.272181e-02
 * time: 7.3820250034332275
    55     1.026026e+03     4.855109e-04
 * time: 7.499140977859497
FittedPumasModel

Dynamical system type:          Matrix exponential

Number of subjects:                             20

Observation records:         Active        Missing
    dv_pk:                      220              0
    dv_pd:                      220              0
    Total:                      440              0

Number of parameters:      Constant      Optimized
                                  0             16

Likelihood approximation:                     FOCE
Likelihood optimizer:                         BFGS

Termination Reason:                   GradientNorm
Log-likelihood value:                   -1026.0258

--------------------
         Estimate
--------------------
tvKa      1.3658
tvCL      4.8343
tvV      36.378
tvKe0     0.070617
tvEmax   73.583
tvEC50    3.1168
tvE0     56.528
Ω₁,₁      0.048684
Ω₂,₂      0.040628
Ω₃,₃      0.014049
Ω₄,₄      0.032244
Ω₅,₅      0.074529
Ω₆,₆      1.0522e-6
Ω₇,₇      0.049157
σ_prop    0.2443
σ_pd      4.6243
--------------------

7 Indirect Response Models

Indirect response models describe drug effects on the production or loss of a response variable. The core concept is turnover: at steady state, the rate of production (\(K_{in}\)) equals the rate of loss (\(K_{out} \cdot R\)), giving baseline \(R_0 = K_{in} / K_{out}\).

\[\frac{dR}{dt} = K_{in} \cdot S(C_p) - K_{out} \cdot R\]

where \(S(C_p)\) is a stimulation or inhibition function applied to either \(K_{in}\) or \(K_{out}\):

Type Target Function Equation Response Direction
I Inhibit \(K_{in}\) \(1 - \frac{I_{max} \cdot C}{IC_{50} + C}\) \(\frac{dR}{dt} = K_{in}(1-E) - K_{out} \cdot R\) ↓ Decrease
II Inhibit \(K_{out}\) \(1 - \frac{I_{max} \cdot C}{IC_{50} + C}\) \(\frac{dR}{dt} = K_{in} - K_{out}(1-E) \cdot R\) ↑ Increase
III Stimulate \(K_{in}\) \(1 + \frac{E_{max} \cdot C}{EC_{50} + C}\) \(\frac{dR}{dt} = K_{in}(1+E) - K_{out} \cdot R\) ↑ Increase
IV Stimulate \(K_{out}\) \(1 + \frac{E_{max} \cdot C}{EC_{50} + C}\) \(\frac{dR}{dt} = K_{in} - K_{out}(1+E) \cdot R\) ↓ Decrease
Key IDR Characteristics
  • Turnover half-life: \(t_{1/2} = \ln(2) / K_{out}\) — determines how quickly the response changes
  • Effect persistence: Response continues to change after drug is eliminated (because the turnover system takes time to re-equilibrate)
  • Types I & IV decrease the response; Types II & III increase it — but through different mechanisms
  • Distinguishing Types I vs IV (or II vs III): Requires dense PD sampling at early time points — the onset/offset kinetics differ
The Turnover Concept: Why Biological Responses Have Inherent Delays

Most biological responses — blood pressure, clotting factors, cholesterol, blood glucose, cortisol — exist in a dynamic equilibrium where a production process (\(K_{in}\)) is balanced by a degradation or loss process (\(K_{out}\)). At baseline, this equilibrium satisfies \(K_{in} = K_{out} \times R_0\), where \(R_0\) is the baseline response. Drugs perturb this equilibrium by altering either the production or the loss rate, but the response cannot change instantaneously because the existing pool of response variable must turn over. The characteristic time scale for this process is the turnover half-life:

\[t_{1/2,\text{turnover}} = \frac{\ln 2}{K_{out}}\]

This delay is fundamentally different from a distributional delay modeled by an effect compartment (\(k_{e0}\)). The effect compartment delay arises from the time required for drug to equilibrate between plasma and the biophase; the turnover delay arises from the time required for the biological system itself to respond to the perturbation. Distinguishing these two mechanisms — pharmacokinetic delay vs. pharmacodynamic (systems-level) delay — is essential for selecting the appropriate model structure and for making correct predictions about the time course of drug effect.

Clinical Examples by IDR Type
Type Clinical Examples
Type I (↓ Kin) Corticosteroid suppression of cortisol, warfarin inhibition of clotting factor synthesis
Type II (↓ Kout) Heparin reducing factor Xa clearance, EPO reducing RBC destruction
Type III (↑ Kin) EPO stimulating RBC production, GH stimulating IGF-1 synthesis
Type IV (↑ Kout) Diuretics increasing sodium excretion, furosemide increasing urine output

7.1 Indirect Response Type I: Inhibition of Kin

# Prepare indirect PK-PD data — pivot to wide format for multi-DV
# PK and PD observations are at the same time points, so we merge them into one row

dose_rows = @rsubset(ind_df, :AMT > 0)
pk_rows = @rsubset(ind_df, :TYPE == 0, :AMT == 0)
pd_rows = @rsubset(ind_df, :TYPE == 1)

# Merge PK + PD at same (ID, TIME) into wide format
pk_wide = select(pk_rows, :ID, :TIME, :DV => :dv_pk)
pd_wide = select(pd_rows, :ID, :TIME, :DV => :dv_pd)
obs_wide = outerjoin(pk_wide, pd_wide, on = [:ID, :TIME])
obs_wide.AMT .= 0
obs_wide.CMT .= 2
obs_wide.evid .= 0

# Dose rows
dose_prep = select(dose_rows, :ID, :TIME, :AMT, :CMT)
dose_prep.dv_pk .= missing
dose_prep.dv_pd .= missing
dose_prep.evid .= 1

# Combine and sort
combined = vcat(dose_prep, obs_wide, cols = :union)
combined.AMT = coalesce.(combined.AMT, 0)
combined.evid = coalesce.(combined.evid, 0)
combined.CMT = coalesce.(combined.CMT, 2)
sort!(combined, [:ID, :TIME, order(:evid, rev = true)])

rename!(combined, :ID => :id, :TIME => :time, :AMT => :amt, :CMT => :cmt)
pop_ind = read_pumas(combined; observations = [:dv_pk, :dv_pd])
println("Indirect PKPD subjects: ", length(pop_ind))
Indirect PKPD subjects: 20
# Type I: Inhibit Kin
# From ind1_pkpd.ctl: ADVAN6, $DES with DADT(3) = KIN*(1-E) - KOUT*A(3)
ind1_model = @model begin
    @metadata begin
        desc = "Indirect Response Type I: Inhibit Kin"
    end
    @param begin
        tvKa   ∈ RealDomain(lower = 0.0, init = 1.5)
        tvCL   ∈ RealDomain(lower = 0.0, init = 5.0)
        tvV    ∈ RealDomain(lower = 0.0, init = 35.0)
        tvKin  ∈ RealDomain(lower = 0.0, init = 10.0)
        tvKout ∈ RealDomain(lower = 0.0, init = 0.05)
        tvIC50 ∈ RealDomain(lower = 0.0, init = 5.0)
        Ω      ∈ PDiagDomain(3)
        σ_prop ∈ RealDomain(lower = 0.0, init = 0.2)
        σ_pd   ∈ RealDomain(lower = 0.0, init = 4.47)
    end
    @random begin
        η ~ MvNormal(Ω)
    end
    @pre begin
        Ka   = tvKa * exp(η[1])
        CL   = tvCL * exp(η[2])
        Vc   = tvV  * exp(η[3])
        Kin  = tvKin
        Kout = tvKout
        IC50 = tvIC50
        # Emax fixed at 1 (as in ctl: THETA(6) = 1 FIX)
    end
    @init begin
        Response = Kin / Kout  # steady-state baseline
    end
    @dynamics begin
        Depot'    = -Ka * Depot
        Central'  =  Ka * Depot - (CL / Vc) * Central
        Response' =  Kin * (1 - Central / Vc / (IC50 + Central / Vc)) - Kout * Response
    end
    @derived begin
        cp := @. Central / Vc
        dv_pk ~ @. Normal(cp, abs(cp) * σ_prop)
        dv_pd ~ @. Normal(Response, σ_pd)
    end
end
PumasModel
  Parameters: tvKa, tvCL, tvV, tvKin, tvKout, tvIC50, Ω, σ_prop, σ_pd
  Random effects: η
  Covariates:
  Dynamical system variables: Depot, Central, Response
  Dynamical system type: Nonlinear ODE
  Derived: dv_pk, dv_pd
  Observed: dv_pk, dv_pd
ind1_params = (
    tvKa = 1.5, tvCL = 5.0, tvV = 35.0,
    tvKin = 10.0, tvKout = 0.05, tvIC50 = 5.0,
    Ω = Diagonal([0.04, 0.04, 0.04]),
    σ_prop = 0.2, σ_pd = sqrt(20.0),
)
ind1_fit = fit(ind1_model, pop_ind, ind1_params, Pumas.FOCEI())
ind1_fit
[ Info: Checking the initial parameter values.
[ Info: The initial negative log likelihood and its gradient are finite. Check passed.
Iter     Function value   Gradient norm 
     0     4.755777e+04     1.564310e+05
 * time: 3.790855407714844e-5
     1     8.252584e+03     1.428514e+04
 * time: 0.49408793449401855
     2     6.793205e+03     1.134338e+04
 * time: 1.0144600868225098
     3     3.241463e+03     4.109670e+03
 * time: 1.0658290386199951
     4     2.207731e+03     1.943402e+03
 * time: 1.1155118942260742
     5     1.662031e+03     8.773268e+02
 * time: 1.164668083190918
     6     1.463031e+03     4.925989e+02
 * time: 1.2349519729614258
     7     1.396012e+03     2.604774e+02
 * time: 1.2819089889526367
     8     1.380507e+03     1.403022e+02
 * time: 1.3285460472106934
     9     1.378426e+03     9.163802e+01
 * time: 1.3828730583190918
    10     1.378204e+03     7.853435e+01
 * time: 1.429434061050415
    11     1.377989e+03     6.930610e+01
 * time: 1.476172924041748
    12     1.377331e+03     6.141801e+01
 * time: 1.5306730270385742
    13     1.375991e+03     6.228986e+01
 * time: 1.579176902770996
    14     1.373506e+03     5.314549e+01
 * time: 1.6345460414886475
    15     1.370248e+03     8.670850e+01
 * time: 1.6892790794372559
    16     1.367310e+03     7.744327e+01
 * time: 1.7444300651550293
    17     1.366853e+03     4.312742e+01
 * time: 1.7886130809783936
    18     1.366820e+03     4.177335e+01
 * time: 1.8394880294799805
    19     1.366715e+03     3.843575e+01
 * time: 1.8894360065460205
    20     1.366470e+03     3.335661e+01
 * time: 1.9385919570922852
    21     1.365865e+03     2.798016e+01
 * time: 1.9907588958740234
    22     1.364607e+03     2.452838e+01
 * time: 2.043911933898926
    23     1.362592e+03     3.261922e+01
 * time: 2.093794107437134
    24     1.360506e+03     3.841668e+01
 * time: 2.1494359970092773
    25     1.359252e+03     3.392255e+01
 * time: 2.2037270069122314
    26     1.358972e+03     3.011402e+01
 * time: 2.2575249671936035
    27     1.358937e+03     2.927429e+01
 * time: 2.3080780506134033
    28     1.358895e+03     2.789962e+01
 * time: 2.358457088470459
    29     1.358806e+03     2.594693e+01
 * time: 2.410141944885254
    30     1.358561e+03     2.563835e+01
 * time: 2.461894989013672
    31     1.357944e+03     2.655573e+01
 * time: 2.5110859870910645
    32     1.356405e+03     3.503901e+01
 * time: 2.566922903060913
    33     1.353000e+03     4.379359e+01
 * time: 2.6222898960113525
    34     1.347292e+03     5.077442e+01
 * time: 2.6795051097869873
    35     1.341773e+03     7.641960e+01
 * time: 2.735551118850708
    36     1.339054e+03     8.209362e+01
 * time: 2.789168119430542
    37     1.338549e+03     7.829311e+01
 * time: 2.8432490825653076
    38     1.338463e+03     7.591879e+01
 * time: 2.8956139087677
    39     1.338315e+03     7.264755e+01
 * time: 2.9500560760498047
    40     1.337929e+03     6.665891e+01
 * time: 3.005450963973999
    41     1.336981e+03     5.646896e+01
 * time: 3.0610110759735107
    42     1.334723e+03     4.550099e+01
 * time: 3.112504005432129
    43     1.329940e+03     4.783224e+01
 * time: 3.1673450469970703
    44     1.321739e+03     4.039079e+01
 * time: 3.2229390144348145
    45     1.313190e+03     3.903493e+01
 * time: 3.2774569988250732
    46     1.309752e+03     2.705504e+01
 * time: 3.331799030303955
    47     1.308883e+03     2.010338e+01
 * time: 3.3858349323272705
    48     1.308613e+03     2.241320e+01
 * time: 3.4392900466918945
    49     1.308418e+03     2.523691e+01
 * time: 3.4901609420776367
    50     1.308290e+03     2.707148e+01
 * time: 3.5420761108398438
    51     1.308249e+03     2.793325e+01
 * time: 3.594316005706787
    52     1.308232e+03     2.786212e+01
 * time: 3.6412389278411865
    53     1.308182e+03     2.747150e+01
 * time: 3.6950459480285645
    54     1.308067e+03     2.648734e+01
 * time: 3.7477409839630127
    55     1.307793e+03     2.415459e+01
 * time: 3.7991371154785156
    56     1.307267e+03     1.974072e+01
 * time: 3.85109806060791
    57     1.306609e+03     1.846943e+01
 * time: 3.9030261039733887
    58     1.306265e+03     1.431225e+01
 * time: 3.9569509029388428
    59     1.306176e+03     1.388629e+01
 * time: 4.009790897369385
    60     1.306152e+03     1.388508e+01
 * time: 4.056091070175171
    61     1.306141e+03     1.347836e+01
 * time: 4.105571985244751
    62     1.306132e+03     1.319476e+01
 * time: 4.154879093170166
    63     1.306126e+03     1.320401e+01
 * time: 4.204988956451416
    64     1.306116e+03     1.333036e+01
 * time: 4.2545530796051025
    65     1.306095e+03     1.345132e+01
 * time: 4.304358959197998
    66     1.306042e+03     1.334455e+01
 * time: 4.355125904083252
    67     1.305923e+03     1.237722e+01
 * time: 4.402370929718018
    68     1.305701e+03     1.257703e+01
 * time: 4.451747894287109
    69     1.305423e+03     9.202730e+00
 * time: 4.502279996871948
    70     1.305224e+03     3.506630e+00
 * time: 4.564260005950928
    71     1.305154e+03     1.511361e+00
 * time: 4.62161111831665
    72     1.305142e+03     1.570455e+00
 * time: 4.672765016555786
    73     1.305140e+03     1.602894e+00
 * time: 4.721342086791992
    74     1.305139e+03     1.626363e+00
 * time: 4.766513109207153
    75     1.305139e+03     1.632320e+00
 * time: 4.813076019287109
    76     1.305139e+03     1.632919e+00
 * time: 4.858532905578613
    77     1.305139e+03     1.633059e+00
 * time: 4.902517080307007
    78     1.305138e+03     1.632778e+00
 * time: 4.947504043579102
    79     1.305138e+03     1.631258e+00
 * time: 4.98873496055603
    80     1.305137e+03     1.626047e+00
 * time: 5.035805940628052
    81     1.305135e+03     1.610563e+00
 * time: 5.084630966186523
    82     1.305129e+03     1.671784e+00
 * time: 5.132312059402466
    83     1.305114e+03     2.557289e+00
 * time: 5.180783987045288
    84     1.305082e+03     3.574486e+00
 * time: 5.231458902359009
    85     1.305028e+03     4.056522e+00
 * time: 5.278901100158691
    86     1.304972e+03     3.018565e+00
 * time: 5.33053994178772
    87     1.304946e+03     1.063332e+00
 * time: 5.380239963531494
    88     1.304941e+03     9.327573e-02
 * time: 5.428741931915283
    89     1.304941e+03     8.023067e-02
 * time: 5.476744890213013
    90     1.304941e+03     7.799598e-02
 * time: 5.521553039550781
    91     1.304941e+03     7.765627e-02
 * time: 5.560059070587158
    92     1.304941e+03     7.711810e-02
 * time: 5.602461099624634
    93     1.304941e+03     7.639031e-02
 * time: 5.6450440883636475
    94     1.304941e+03     7.512634e-02
 * time: 5.68911600112915
    95     1.304941e+03     7.312195e-02
 * time: 5.733319044113159
    96     1.304941e+03     6.982247e-02
 * time: 5.773839950561523
    97     1.304941e+03     6.445591e-02
 * time: 5.820050954818726
    98     1.304941e+03     7.373950e-02
 * time: 5.864423990249634
    99     1.304941e+03     1.203593e-01
 * time: 5.90929388999939
   100     1.304941e+03     1.855943e-01
 * time: 5.957979917526245
   101     1.304940e+03     2.547643e-01
 * time: 6.002300024032593
   102     1.304939e+03     2.731362e-01
 * time: 6.048641920089722
   103     1.304938e+03     1.855887e-01
 * time: 6.095395088195801
   104     1.304937e+03     6.430116e-02
 * time: 6.1450419425964355
   105     1.304937e+03     6.036127e-02
 * time: 6.19192910194397
   106     1.304937e+03     5.790253e-02
 * time: 6.231722116470337
   107     1.304937e+03     5.742226e-02
 * time: 6.27214503288269
   108     1.304937e+03     5.728444e-02
 * time: 6.313309907913208
   109     1.304937e+03     5.728001e-02
 * time: 6.365746021270752
   110     1.304937e+03     5.725461e-02
 * time: 6.418610095977783
   111     1.304937e+03     5.725346e-02
 * time: 6.482558965682983
   112     1.304937e+03     5.507446e-02
 * time: 6.522576093673706
   113     1.304937e+03     5.448164e-02
 * time: 6.563766956329346
   114     1.304937e+03     5.161668e-02
 * time: 6.6073620319366455
   115     1.304937e+03     4.807144e-02
 * time: 6.649915933609009
   116     1.304937e+03     4.141528e-02
 * time: 6.693708896636963
   117     1.304937e+03     3.546336e-02
 * time: 6.735208988189697
   118     1.304937e+03     5.200178e-02
 * time: 6.781368017196655
   119     1.304936e+03     6.945191e-02
 * time: 6.829306125640869
   120     1.304935e+03     7.984134e-02
 * time: 6.876703977584839
   121     1.304933e+03     7.806182e-02
 * time: 6.922899961471558
   122     1.304932e+03     6.038412e-02
 * time: 6.963927984237671
   123     1.304931e+03     3.127192e-02
 * time: 7.010651111602783
   124     1.304930e+03     1.330297e-02
 * time: 7.056174039840698
   125     1.304930e+03     8.942073e-03
 * time: 7.09987211227417
   126     1.304930e+03     5.363511e-03
 * time: 7.143901109695435
   127     1.304930e+03     5.783611e-03
 * time: 7.187226057052612
   128     1.304930e+03     5.493837e-03
 * time: 7.245162010192871
   129     1.304930e+03     4.038644e-03
 * time: 7.3080220222473145
   130     1.304930e+03     2.091960e-03
 * time: 7.382246017456055
   131     1.304930e+03     5.980395e-04
 * time: 7.465126991271973
FittedPumasModel

Dynamical system type:               Nonlinear ODE
Solver(s): (OrdinaryDiffEqVerner.Vern7,OrdinaryDiffEqRosenbrock.Rodas5P)

Number of subjects:                             20

Observation records:         Active        Missing
    dv_pk:                      220              0
    dv_pd:                      220              0
    Total:                      440              0

Number of parameters:      Constant      Optimized
                                  0             11

Likelihood approximation:                     FOCE
Likelihood optimizer:                         BFGS

Termination Reason:                   GradientNorm
Log-likelihood value:                   -1304.9297

---------------------
         Estimate
---------------------
tvKa      1.3668
tvCL      4.8346
tvV      36.392
tvKin     0.00013041
tvKout    1.6216e-6
tvIC50    1.4509e7
Ω₁,₁      0.042084
Ω₂,₂      0.040423
Ω₃,₃      0.015019
σ_prop    0.24476
σ_pd     22.874
---------------------

7.2 Model Comparison

println("PK-PD Model Comparison")
println("=" ^ 50)
println("Direct Emax     AIC: ", round(aic(direct_fit), digits = 1))
println("Effect Comp     AIC: ", round(aic(ecomp_fit), digits = 1))
println("Indirect Type I AIC: ", round(aic(ind1_fit), digits = 1))
PK-PD Model Comparison
==================================================
Direct Emax     AIC: 2538.7
Effect Comp     AIC: 2084.1
Indirect Type I AIC: 2631.9

7.3 Diagnostic Plots

ind_insp = inspect(ind1_fit)
ind_insp_df = DataFrame(ind_insp)

# PD observations only
pd_obs = @rsubset(ind_insp_df, !ismissing(:dv_pd))

fig = Figure(size = (800, 400))

ax1 = Axis(fig[1, 1], xlabel = "PRED", ylabel = "DV (PD)", title = "DV vs PRED")
scatter!(ax1, pd_obs.dv_pd_pred, pd_obs.dv_pd, color = :navy, markersize = 5, alpha = 0.6)
ablines!(ax1, 0, 1, color = :black)

ax2 = Axis(fig[1, 2], xlabel = "IPRED", ylabel = "DV (PD)", title = "DV vs IPRED")
scatter!(ax2, pd_obs.dv_pd_ipred, pd_obs.dv_pd, color = :navy, markersize = 5, alpha = 0.6)
ablines!(ax2, 0, 1, color = :black)

fig
[ Info: Calculating predictions.
[ Info: Calculating weighted residuals.
[ Info: Calculating empirical bayes.
[ Info: Evaluating dose control parameters.
[ Info: Evaluating individual parameters.
[ Info: Done.
Figure 1: Indirect Response Model Type I: GOF Diagnostics

8 K-PD Models: PD Without PK Data

When PK data are unavailable (PD-only studies, retrospective analyses, sparse sampling), K-PD models use a virtual compartment to replace the PK model:

\[\frac{dA}{dt} = -K_{DE} \cdot A\]

where \(A\) is the virtual drug amount and \(K_{DE}\) is the apparent elimination rate (\(= CL/V\)). The drug effect is then driven by \(K_{DE} \cdot A\) (analogous to \(CL \cdot C_p\)) rather than by concentration.

Key parameters:

  • \(K_{DE}\) = apparent elimination rate (replaces CL/V)
  • \(EDK_{50}\) = apparent potency (replaces \(EC_{50}\); \(EDK_{50} = EC_{50} \cdot CL\))
kpd_model = @model begin
    @param begin
        tvKDE   ∈ RealDomain(lower = 0.0, init = 0.1)
        tvEmax  ∈ RealDomain(lower = 0.0, init = 100.0)
        tvEDK50 ∈ RealDomain(lower = 0.0, init = 5.0)
        tvE0    ∈ RealDomain(init = 60.0)
        Ω       ∈ PDiagDomain(2)
        σ_pd    ∈ RealDomain(lower = 0.0, init = 5.0)
    end
    @random begin
        η ~ MvNormal(Ω)
    end
    @pre begin
        KDE   = tvKDE * exp(η[1])
        Emax  = tvEmax
        EDK50 = tvEDK50 * exp(η[2])
        E0    = tvE0
    end
    @dynamics begin
        A' = -KDE * A  # virtual compartment
    end
    @derived begin
        rate_out := @. KDE * A
        effect := @. E0 + Emax * rate_out / (EDK50 + rate_out)
        dv ~ @. Normal(effect, σ_pd)
    end
end
Warning

K-PD limitations:

  • Assumes linear PK (first-order elimination)
  • Cannot predict concentrations — only effects
  • May overestimate IIV (conflates PK and PD variability)
  • Requires ≥ 3 dose levels for identifiability
  • Not recommended for regulatory submissions where PK data exist

9 The Four PD Paradigms: Decision Framework

When choosing a PD model structure, follow this decision tree:

Question If Yes → If No →
Is there a measurable delay between Cp and effect? Effect compartment or IDR Direct response
Does the drug affect a turnover process? IDR (Types I–IV) Effect compartment
Is the CE plot loop counter-clockwise? Effect compartment (ke0) Direct, tolerance, or IDR
Is PK data available? PK-PD model K-PD model
Is the effect reversible and dose-dependent? Standard Emax/IDR Consider more complex models

10 PK-PD Modeling Steps

  1. Develop and qualify the PK model first (using PK-only data)
  2. Fix PK parameters and estimate PD parameters (sequential approach)
  3. Or estimate PK and PD simultaneously (combined data approach — as shown above)
  4. Evaluate GOF diagnostics for both PK and PD
  5. Compare structural PD models (direct vs. effect compartment vs. indirect)
Sequential vs. Simultaneous Estimation
Approach Pros Cons
Sequential (fix PK, estimate PD) Faster, PK model already validated Ignores PK uncertainty, may bias PD estimates
Simultaneous (estimate PK + PD together) Full uncertainty propagation, optimal use of data Slower, larger parameter space, harder to converge

Recommendation: Start sequential for model development (faster iteration), then switch to simultaneous for the final model.

11 Study Guide Questions

  1. What is the difference between a direct and indirect PK-PD model?
  2. When would you use an effect compartment model instead of a direct model?
  3. What are the four types of indirect response models and how do they differ?
  4. Why is Emax often fixed to 1 in indirect response models?
  5. What are the advantages of simultaneous PK-PD estimation vs. sequential?
  6. When would a K-PD model be appropriate instead of a full PK-PD model?
  7. How does turnover half-life affect the time course of an indirect response?

12 Supplementary Material

Topic Tutorial Key Additions
Lecture: Intrinsic CL & Enzyme Kinetics PK W7a Vmax/KM enzyme kinetics — the pharmacological foundation of the Emax model
Lecture: Clearance & Hepatic Extraction PK W6 Drug elimination physiology underlying PK-PD model structure
Lecture: Oral Absorption PK W8 First-order absorption, bioavailability — the PK driving function for PD
PD model overview Introduction to PD Models Four PD paradigms, Emax/Hill curves, potency vs efficacy, decision flowchart
Direct response models Direct Response Stimulatory + inhibitory Emax, population simulation, full fitting workflow
Effect compartment models Effect Compartment Hysteresis visualization, ke0 sensitivity analysis, Cp vs Ce comparison, clinical examples
Indirect response models Indirect Response All 4 IDR types with code, comparative simulation, turnover time sensitivity, clinical examples
K-PD models K-PD Models Virtual compartment concept, KDE/EDK50 parameterization, limitations, K-PD vs PK-PD decision framework
Model selection PD Model Selection Systematic selection (EDA → mechanism → statistics), warfarin case study, common pitfalls
HCV viral dynamics HCV GSA QSP-style PK-PD with viral kinetics and global sensitivity analysis
TMDD models TMDD Foundations → TMDD Workflows Target-mediated drug disposition: full model, approximations, special cases