Skip to content

Michaelis-Menten Elimination

One-compartment model with saturable (capacity-limited) elimination kinetics.


Function Signature

neopkpd.simulate_pk_michaelis_menten(
    vmax: float,
    km: float,
    v: 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,
    alag: float | None = None,
    bioavailability: float | None = None,
) -> dict

Parameters

Parameter Type Description
vmax float Maximum elimination rate (mg/h)
km float Michaelis constant (mg/L)
v float Volume of distribution (L)
doses list[dict] Dose events

Model Equation

\[\frac{dA}{dt} = -\frac{V_{max} \cdot C}{K_m + C}\]
\[C = \frac{A}{V}\]

Kinetic Behavior

Condition Behavior Apparent CL
C << Km First-order (linear) CL ≈ Vmax/Km
C ≈ Km Mixed-order Variable
C >> Km Zero-order (saturated) Rate ≈ Vmax

Basic Example

import neopkpd

result = neopkpd.simulate_pk_michaelis_menten(
    vmax=500.0,   # Maximum rate (mg/h)
    km=10.0,      # Km (mg/L)
    v=50.0,       # Volume (L)
    doses=[{"time": 0.0, "amount": 1000.0}],
    t0=0.0,
    t1=48.0,
    saveat=[i * 0.25 for i in range(193)]
)

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

# Initial concentration
c0 = conc[0]  # 1000/50 = 20 mg/L

print(f"C0: {c0:.1f} mg/L (C >> Km: saturated)")
print(f"C at 6h: {conc[24]:.2f} mg/L")
print(f"C at 24h: {conc[96]:.3f} mg/L (C < Km: linear)")

Dose-Dependent Half-Life

With Michaelis-Menten kinetics, half-life increases with dose:

import neopkpd

doses_list = [100.0, 500.0, 1000.0, 2000.0]

print("Dose (mg) | C0 (mg/L) | t1/2 (h)")
print("-" * 40)

for dose in doses_list:
    result = neopkpd.simulate_pk_michaelis_menten(
        vmax=500.0, km=10.0, v=50.0,
        doses=[{"time": 0.0, "amount": dose}],
        t0=0.0, t1=96.0,
        saveat=[i * 0.5 for i in range(193)]
    )

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

    # Find t1/2 (time to reach half of initial)
    c0 = conc[0]
    target = c0 / 2

    t_half = None
    for i, c in enumerate(conc):
        if c <= target:
            t_half = t[i]
            break

    if t_half:
        print(f"{dose:9.0f} | {c0:9.1f} | {t_half:7.1f}")
    else:
        print(f"{dose:9.0f} | {c0:9.1f} | > 96")

Expected Pattern: - Higher doses → Longer t1/2 (saturation) - Low doses → Shorter t1/2 (linear kinetics)


Dose Proportionality

AUC increases more than proportionally with dose:

import neopkpd
import numpy as np

doses_list = [100.0, 200.0, 500.0, 1000.0]
auc_values = []

print("Dose (mg) | AUC (mg*h/L)")
print("-" * 30)

for dose in doses_list:
    result = neopkpd.simulate_pk_michaelis_menten(
        vmax=500.0, km=10.0, v=50.0,
        doses=[{"time": 0.0, "amount": dose}],
        t0=0.0, t1=120.0,
        saveat=[i * 0.1 for i in range(1201)]
    )

    conc = np.array(result['observations']['conc'])
    t = np.array(result['t'])

    auc = np.trapz(conc, t)
    auc_values.append(auc)

    print(f"{dose:9.0f} | {auc:12.1f}")

# Check proportionality
print(f"\nDose ratio (10x): {doses_list[-1] / doses_list[0]:.0f}")
print(f"AUC ratio: {auc_values[-1] / auc_values[0]:.2f}")
# AUC ratio > 10 indicates saturation

Clinical Example: Phenytoin

import neopkpd

# Phenytoin typical parameters (for 70 kg patient)
# Vmax ≈ 7 mg/kg/day, Km ≈ 4-6 mg/L, V ≈ 0.65 L/kg
vmax = 7.0 * 70 / 24  # mg/h
km = 5.0              # mg/L
v = 0.65 * 70         # L

# Loading dose
loading = 15 * 70  # 15 mg/kg = 1050 mg

result = neopkpd.simulate_pk_michaelis_menten(
    vmax=vmax, km=km, v=v,
    doses=[{"time": 0.0, "amount": loading}],
    t0=0.0, t1=24.0,
    saveat=[i * 0.5 for i in range(49)]
)

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

# Therapeutic range: 10-20 mg/L
print(f"Post-loading C: {conc[0]:.1f} mg/L")
print(f"24h C: {conc[-1]:.1f} mg/L")
print("Therapeutic range: 10-20 mg/L")

Steady-State Considerations

At steady state with constant infusion rate R:

\[C_{ss} = \frac{R \cdot K_m}{V_{max} - R}\]

This only applies when R < Vmax.

vmax = 500.0  # mg/h
km = 10.0     # mg/L

print(f"Maximum sustainable infusion rate: {vmax} mg/h")

# At different infusion rates
for fraction in [0.5, 0.8, 0.9, 0.95]:
    r = fraction * vmax
    css = (r * km) / (vmax - r)
    print(f"At R = {r:.0f} mg/h ({fraction*100:.0f}% of Vmax): Css = {css:.1f} mg/L")

# If R >= Vmax, no steady state is achievable!
print("\nWARNING: If R >= Vmax, concentrations increase indefinitely!")

Comparison with Linear Model

import neopkpd

# Michaelis-Menten at low dose (approximately linear)
result_mm = neopkpd.simulate_pk_michaelis_menten(
    vmax=500.0, km=10.0, v=50.0,
    doses=[{"time": 0.0, "amount": 100.0}],  # Low dose: C0 = 2 mg/L << Km
    t0=0.0, t1=24.0,
    saveat=[i * 0.1 for i in range(241)]
)

# Equivalent linear model: CL = Vmax/Km = 50 L/h
result_linear = neopkpd.simulate_pk_iv_bolus(
    cl=50.0, v=50.0,
    doses=[{"time": 0.0, "amount": 100.0}],
    t0=0.0, t1=24.0,
    saveat=[i * 0.1 for i in range(241)]
)

# At low dose, profiles should be nearly identical
mm_conc = result_mm['observations']['conc']
lin_conc = result_linear['observations']['conc']

print("Low dose (C << Km): MM ≈ Linear")
print(f"MM at 4h: {mm_conc[40]:.3f} mg/L")
print(f"Linear at 4h: {lin_conc[40]:.3f} mg/L")

Visualization

import neopkpd
from neopkpd.viz import plot_pk_profile

# Compare different doses
doses = [100.0, 500.0, 1000.0]

for dose in doses:
    result = neopkpd.simulate_pk_michaelis_menten(
        vmax=500.0, km=10.0, v=50.0,
        doses=[{"time": 0.0, "amount": dose}],
        t0=0.0, t1=48.0,
        saveat=[i * 0.25 for i in range(193)]
    )

    # Plot each dose level
    # fig = plot_pk_profile(result['t'], result['observations']['conc'], ...)

Apparent Clearance

\[CL_{app} = \frac{V_{max}}{K_m + C}\]

At low concentrations: \(CL_{max} = V_{max}/K_m\)

vmax = 500.0  # mg/h
km = 10.0     # mg/L

print("C (mg/L) | CL_app (L/h)")
print("-" * 25)

for c in [0.1, 1.0, 5.0, 10.0, 20.0, 50.0, 100.0]:
    cl_app = vmax / (km + c)
    print(f"{c:8.1f} | {cl_app:11.1f}")

print(f"\nCL_max (C→0): {vmax/km:.1f} L/h")

Equations Summary

Quantity Formula
Elimination rate \(-V_{max} \cdot C / (K_m + C)\)
CL_apparent \(V_{max} / (K_m + C)\)
CL_max (C→0) \(V_{max} / K_m\)
t1/2 (apparent) \(0.693 \cdot V \cdot (K_m + C) / V_{max}\)
Css (infusion R) \(R \cdot K_m / (V_{max} - R)\)

See Also