Skip to content

Autoinduction

PK model for drugs that induce their own metabolism, leading to time-varying clearance that increases with chronic dosing.


Function Signature

neopkpd.simulate_pk_autoinduction(
    cl0: float,
    v: float,
    emax: float,
    ec50: float,
    kenz: float,
    doses: list[dict],
    t0: float,
    t1: float,
    saveat: list[float],
    alg: str = "Tsit5",
    reltol: float = 1e-10,
    abstol: float = 1e-12,
    maxiters: int = 10**7,
) -> dict

Parameters

Parameter Type Description
cl0 float Baseline clearance (L/h)
v float Volume of distribution (L)
emax float Maximum enzyme induction (fold increase)
ec50 float Concentration for 50% of max induction
kenz float Enzyme turnover rate constant (1/h)
doses list[dict] Dose events

Derived Parameters

  • Enzyme half-life: \(t_{1/2,enz} = \ln(2) / k_{enz}\)
  • Maximum clearance: \(CL_{max} = CL_0 \cdot (1 + E_{max})\)

Model Equations

Two-state system (drug and enzyme):

Enzyme induction signal: $\(E_{induced} = 1 + \frac{E_{max} \cdot C}{EC_{50} + C}\)$

Enzyme dynamics (indirect response): $\(\frac{dE}{dt} = k_{enz} \cdot (E_{induced} - E)\)$

Drug elimination with induced clearance: $\(\frac{dA_c}{dt} = -\frac{CL_0 \cdot E}{V} \cdot A_c\)$

\[C = \frac{A_c}{V}\]

Initial condition: \(E(0) = 1.0\) (baseline enzyme)


Returns

{
    "t": [0.0, 1.0, ...],
    "states": {
        "A_central": [...],   # Amount in central compartment
        "E_enzyme": [...]     # Enzyme level (relative to baseline)
    },
    "observations": {
        "conc": [...]         # Plasma concentration
    },
    "metadata": {...}
}

Basic Example

import neopkpd

# Single dose - minimal induction
result = neopkpd.simulate_pk_autoinduction(
    cl0=10.0,     # Baseline clearance (L/h)
    v=50.0,       # Volume (L)
    emax=2.0,     # Max 3-fold increase in enzyme
    ec50=5.0,     # EC50 for induction
    kenz=0.1,     # Enzyme turnover (~7 hour half-life)
    doses=[{"time": 0.0, "amount": 500.0}],
    t0=0.0,
    t1=48.0,
    saveat=[i * 0.5 for i in range(97)]
)

conc = result['observations']['conc']
enzyme = result['states']['E_enzyme']
t = result['t']

print("Single Dose Profile:")
print(f"  Initial enzyme: {enzyme[0]:.2f}")
print(f"  Peak enzyme: {max(enzyme):.2f}")
print(f"  Enzyme at 48h: {enzyme[-1]:.2f}")

Chronic Dosing - Time-Varying Clearance

import neopkpd

# Daily dosing for 2 weeks
doses = [{"time": i * 24.0, "amount": 200.0} for i in range(14)]

result = neopkpd.simulate_pk_autoinduction(
    cl0=10.0, v=50.0, emax=2.0, ec50=5.0, kenz=0.05,
    doses=doses,
    t0=0.0, t1=336.0,  # 14 days
    saveat=[i * 1.0 for i in range(337)]
)

conc = result['observations']['conc']
enzyme = result['states']['E_enzyme']
t = result['t']

# Compare day 1 vs day 14
day1_cmax = max(conc[:24])
day14_cmax = max(conc[312:336])

print("Autoinduction Effect:")
print(f"  Day 1 Cmax: {day1_cmax:.2f} mg/L")
print(f"  Day 14 Cmax: {day14_cmax:.2f} mg/L")
print(f"  Cmax decrease: {(1 - day14_cmax/day1_cmax) * 100:.1f}%")
print(f"  Enzyme level day 14: {enzyme[312]:.2f}x baseline")
print(f"  Effective clearance: {10.0 * enzyme[312]:.1f} L/h")

Clinical Example: Carbamazepine

import neopkpd

# Carbamazepine-like autoinduction
# Enzyme t1/2 ~3-5 days, full induction ~2-4 weeks

kenz = 0.693 / (4 * 24)  # ~4 day enzyme half-life

# BID dosing for 4 weeks
doses = [{"time": i * 12.0, "amount": 200.0} for i in range(56)]

result = neopkpd.simulate_pk_autoinduction(
    cl0=2.0,      # Initial low clearance
    v=80.0,       # Volume
    emax=1.5,     # Can increase enzyme 2.5-fold
    ec50=4.0,     # EC50 for induction
    kenz=kenz,
    doses=doses,
    t0=0.0, t1=672.0,  # 4 weeks
    saveat=[i * 2.0 for i in range(337)]
)

conc = result['observations']['conc']
enzyme = result['states']['E_enzyme']
t = result['t']

# Weekly Cmax comparison
print("Carbamazepine-like Autoinduction:")
for week in range(4):
    start = week * 168
    end = start + 168
    start_idx = int(start / 2)
    end_idx = int(end / 2)
    week_cmax = max(conc[start_idx:end_idx])
    week_enzyme = enzyme[end_idx - 1]
    print(f"  Week {week+1}: Cmax = {week_cmax:.2f} mg/L, Enzyme = {week_enzyme:.2f}x")

Dose Adjustment for Autoinduction

import neopkpd

# Strategy: Increase dose over time to maintain target concentration
target_conc = 6.0  # Target trough

# Week 1: Start low
# Week 2: Increase
# Week 3+: Maintenance

kenz = 0.693 / (5 * 24)  # 5-day enzyme half-life

# Stepped dosing regimen
doses = (
    [{"time": i * 24.0, "amount": 200.0} for i in range(7)] +      # Week 1
    [{"time": (7 + i) * 24.0, "amount": 300.0} for i in range(7)] +  # Week 2
    [{"time": (14 + i) * 24.0, "amount": 400.0} for i in range(7)]   # Week 3
)

result = neopkpd.simulate_pk_autoinduction(
    cl0=5.0, v=50.0, emax=1.5, ec50=4.0, kenz=kenz,
    doses=doses,
    t0=0.0, t1=504.0,
    saveat=[i * 2.0 for i in range(253)]
)

conc = result['observations']['conc']
t = result['t']

# Check trough levels at end of each week
print("Dose Titration Strategy:")
for week, dose in enumerate([200, 300, 400]):
    trough_time = (week + 1) * 168 - 2  # 2h before next dose
    trough_idx = int(trough_time / 2)
    trough = conc[trough_idx]
    print(f"  Week {week+1} ({dose} mg QD): Trough = {trough:.2f} mg/L")

Time to Steady State

import neopkpd

# With autoinduction, steady state takes longer
kenz = 0.693 / (4 * 24)  # 4-day enzyme half-life

doses = [{"time": i * 24.0, "amount": 200.0} for i in range(42)]  # 6 weeks

result = neopkpd.simulate_pk_autoinduction(
    cl0=5.0, v=50.0, emax=2.0, ec50=3.0, kenz=kenz,
    doses=doses,
    t0=0.0, t1=1008.0,
    saveat=[i * 6.0 for i in range(169)]
)

enzyme = result['states']['E_enzyme']
t = result['t']

# Time to 90% of steady-state enzyme
e_ss = enzyme[-1]
e_90 = 1.0 + 0.9 * (e_ss - 1.0)

for i, e in enumerate(enzyme):
    if e >= e_90:
        print(f"Time to 90% enzyme steady state: {t[i]:.0f} h ({t[i]/24:.1f} days)")
        break

print(f"Final enzyme level: {e_ss:.2f}x baseline")

Drug Washout - Enzyme Recovery

import neopkpd

kenz = 0.693 / (5 * 24)

# 2 weeks dosing, then stop
doses = [{"time": i * 24.0, "amount": 200.0} for i in range(14)]

result = neopkpd.simulate_pk_autoinduction(
    cl0=5.0, v=50.0, emax=2.0, ec50=3.0, kenz=kenz,
    doses=doses,
    t0=0.0, t1=672.0,  # Continue simulation 2 more weeks
    saveat=[i * 4.0 for i in range(169)]
)

enzyme = result['states']['E_enzyme']
t = result['t']

print("Enzyme Recovery After Drug Discontinuation:")
print(f"  Enzyme at day 14 (stop): {enzyme[84]:.2f}x")
print(f"  Enzyme at day 21: {enzyme[126]:.2f}x")
print(f"  Enzyme at day 28: {enzyme[-1]:.2f}x")
print(f"  Recovery t1/2: ~{0.693/kenz/24:.1f} days")

Comparison: With vs Without Autoinduction

import neopkpd

# Daily dosing for 2 weeks
doses = [{"time": i * 24.0, "amount": 200.0} for i in range(14)]

# With autoinduction
result_auto = neopkpd.simulate_pk_autoinduction(
    cl0=5.0, v=50.0, emax=1.5, ec50=3.0, kenz=0.693/(3*24),
    doses=doses,
    t0=0.0, t1=336.0,
    saveat=[i * 1.0 for i in range(337)]
)

# Without autoinduction (standard IV)
result_linear = neopkpd.simulate_pk_iv_bolus(
    cl=5.0, v=50.0,
    doses=doses,
    t0=0.0, t1=336.0,
    saveat=[i * 1.0 for i in range(337)]
)

auto_conc = result_auto['observations']['conc']
linear_conc = result_linear['observations']['conc']

print("Day 14 Comparison:")
print(f"  Linear PK Cmax: {max(linear_conc[312:336]):.2f} mg/L")
print(f"  Autoinduction Cmax: {max(auto_conc[312:336]):.2f} mg/L")

# AUC comparison
auc_linear = sum(linear_conc[312:336])
auc_auto = sum(auto_conc[312:336])
print(f"  Linear AUC (day 14): {auc_linear:.1f} mg*h/L")
print(f"  Autoinduction AUC (day 14): {auc_auto:.1f} mg*h/L")
print(f"  AUC reduction: {(1 - auc_auto/auc_linear) * 100:.1f}%")

Equations Summary

Quantity Formula
Induction signal \(E_{induced} = 1 + E_{max} \cdot C / (EC_{50} + C)\)
Enzyme rate \(dE/dt = k_{enz} \cdot (E_{induced} - E)\)
Effective clearance \(CL_{eff} = CL_0 \cdot E\)
Max clearance \(CL_{max} = CL_0 \cdot (1 + E_{max})\)
Enzyme t1/2 \(\ln(2) / k_{enz}\)

See Also