Ephedrine + caffeine + norephedrine (Csajka 2005)
Source:vignettes/articles/Csajka_2005_ephedrine_caffeine.Rmd
Csajka_2005_ephedrine_caffeine.RmdModel and source
mod_fn <- readModelDb("Csajka_2005_ephedrine_caffeine")
mod <- rxode2::rxode(mod_fn)
#> ℹ parameter labels from comments will be replaced by 'label()'- Citation: Csajka C, Haller CA, Benowitz NL, Verotta D. Mechanistic pharmacokinetic modelling of ephedrine, norephedrine and caffeine in healthy subjects. Br J Clin Pharmacol. 2005;59(3):335-345. doi:10.1111/j.1365-2125.2005.02254.x
- Article: https://doi.org/10.1111/j.1365-2125.2005.02254.x
This vignette validates the simultaneous mechanistic PK model of Csajka et al. (2005) for co-administered ephedrine, its N-demethylation metabolite norephedrine, and caffeine after single oral doses in healthy adults.
Population
Twenty-four healthy adults (14 female, 10 male; age 22-39 years; body weight 52-91.5 kg) participated across two single-dose cross-over studies at UCSF. Study 1 (n=8) received a single oral dose of a commercial herbal supplement (Metabolift, two capsules) containing 17.3 mg ephedrine and 175 mg caffeine. Study 2 (n=16) received single oral doses of 25 mg ephedrine sulphate and / or 200 mg caffeine sulphate, alone and in combination. Six of the 24 subjects (25%) were on concurrent oral contraceptives. Race / ethnicity was reported only for Study 2 (10 Caucasian, 1 African American, 3 Asian / Pacific Islander, 2 Latino). Demographics are from Csajka 2005 Table 1.
The same information is available programmatically via the model’s
population metadata:
str(mod$population, max.level = 1)
#> List of 12
#> $ species : chr "human"
#> $ n_subjects : int 24
#> $ n_studies : int 2
#> $ age_range : chr "22-39 years (Study 1 25-38; Study 2 22-39)"
#> $ weight_range : chr "52-91.5 kg (Study 1 52-88.9; Study 2 58.6-91.5)"
#> $ height_range : chr "144-188 cm (Study 2 only; not reported for Study 1)"
#> $ sex_female_pct: num 58.3
#> $ race_ethnicity: Named num [1:4] 62.5 6.25 18.75 12.5
#> ..- attr(*, "names")= chr [1:4] "White" "Black_or_African_American" "Asian_or_Pacific_Islander" "Hispanic_or_Latino"
#> $ disease_state : chr "Healthy adults. 6 of 24 subjects (25%) were on concurrent oral contraceptive therapy. Race / ethnicity reported"| __truncated__
#> $ dose_range : chr "Study 1 (n=8): single oral dose of a commercial herbal supplement (Metabolift, two capsules) containing 17.3 mg"| __truncated__
#> $ regions : chr "USA (University of California, San Francisco)"
#> $ notes : chr "Csajka 2005 Table 1 demographics. 379 ephedrine, 352 norephedrine, 417 caffeine plasma samples and 40 urinary e"| __truncated__Source trace
The per-parameter origin is recorded as an in-file comment next to
each ini() entry in
inst/modeldb/specificDrugs/Csajka_2005_ephedrine_caffeine.R.
The table below collects them in one place.
| Equation / parameter | Value | Source location |
|---|---|---|
lka_caf (caffeine ka_C) |
log(0.064 1/min) | Csajka 2005 Table 3 |
lcl_caf (caffeine CL_C/F_C) |
log(0.083 L/min) | Csajka 2005 Table 3 |
lvc_caf (caffeine V_C/F_C) |
log(38.6 L) | Csajka 2005 Table 3 |
e_conmed_birthcontrol_cl_caf |
0.54 | Csajka 2005 Table 3 (d_OC_CL) |
lka (ephedrine ka_E) |
log(0.036 1/min) | Csajka 2005 Table 3 |
lcl_renal (CL_RE/F_E) |
log(0.34 L/min) | Csajka 2005 Table 3 |
lvc (V_E/F_E) |
log(181 L) | Csajka 2005 Table 3 |
ltlag (ephedrine lag) |
log(16.7 min) | Csajka 2005 Table 3 |
lfdepot (F_E,pharm) |
fixed(log(0.59)) | Csajka 2005 Table 3 |
lvmax_neph (Vmax/V_NE) |
log(1.96e-4 mg/(min*L)) | Csajka 2005 Table 3 |
lkm (Michaelis-Menten Km) |
log(2.77 mg) | Csajka 2005 Table 3 |
lkel_neph (norephedrine ke_NE) |
log(0.037 1/min) | Csajka 2005 Table 3, Methods text |
la50_caf (ka_E,50) |
log(31.4 mg) | Csajka 2005 Table 3 |
d_caf |
fixed(0.99) | Csajka 2005 Table 3 (d = expit(theta_e = 19.5)) |
propSd (ephedrine plasma) |
0.17 | Csajka 2005 Table 3 |
propSd_caf (caffeine plasma) |
0.17 | Csajka 2005 Table 3 |
propSd_neph (norephedrine) |
0.15 | Csajka 2005 Table 3 |
| IIVs (omega^2 = log(CV^2 + 1)) | derived from %CV | Csajka 2005 Table 3 |
| Caffeine equation | n/a | Csajka 2005 Methods ‘Caffeine pharmacokinetics’, equation 1 |
| Ephedrine + norephedrine MM | n/a | Csajka 2005 Methods ‘Ephedrine and norephedrine pharmacokinetics’, equation 6 |
| Caffeine effect on ephedrine ka | n/a | Csajka 2005 Methods ‘Interaction of caffeine and ephedrine’, equations 10b / 10e (final) |
| OC effect on caffeine CL | n/a | Csajka 2005 Methods ‘Caffeine pharmacokinetics’, equation 5 |
Virtual cohort
Original observed data are not publicly available. The virtual cohort below mirrors the Study 2 design (single oral 25 mg ephedrine + 200 mg caffeine, no oral contraceptive use), with a small parallel oral-contraceptive cohort to demonstrate the d_OC_CL effect on caffeine.
set.seed(20260604)
obs_times <- c(0, 15, 30, 45, 60, 75, 90, 120, 150, 180, 210, 240, 300, 360, 420,
480, 600, 660, 720, 840, 960, 1080, 1200, 1320, 1440)
make_cohort <- function(n, cohort_label, oc_status, id_offset) {
cov <- tibble(
id = id_offset + seq_len(n),
CONMED_BIRTHCONTROL = oc_status
)
doses <- bind_rows(
cov |> mutate(time = 0, amt = 25, cmt = "depot", evid = 1L),
cov |> mutate(time = 0, amt = 200, cmt = "depot_caf", evid = 1L)
)
obs <- tidyr::crossing(cov, tibble(time = obs_times)) |>
mutate(amt = NA_real_, cmt = "Cc", evid = 0L)
bind_rows(doses, obs) |>
arrange(id, time, evid) |>
mutate(cohort = cohort_label)
}
events <- bind_rows(
make_cohort(60, "Study 2 pharmaceutical (no OC)", 0, id_offset = 0L),
make_cohort(20, "Study 2 pharmaceutical (with OC)", 1, id_offset = 100L)
)
stopifnot(!anyDuplicated(unique(events[, c("id", "time", "evid")])))Simulation
sim <- rxode2::rxSolve(
mod,
events = events,
keep = c("cohort", "CONMED_BIRTHCONTROL"),
addCov = TRUE,
nStud = 1
) |>
as.data.frame()
sim_typical <- rxode2::rxSolve(
rxode2::zeroRe(mod),
events = events,
keep = c("cohort", "CONMED_BIRTHCONTROL"),
addCov = TRUE
) |>
as.data.frame()
#> ℹ omega/sigma items treated as zero: 'etalka_caf', 'etalcl_caf', 'etalvc_caf', 'etalka', 'etalcl_renal', 'etalvc', 'etaltlag', 'etalvmax_neph', 'etalkm', 'etalkel_neph'
#> Warning: multi-subject simulation without without 'omega'Replicate published figures
Figure 2 - Caffeine plasma profile, +/- oral contraceptive
sim_typical |>
filter(time <= 24 * 60) |>
mutate(Cc_caf_ug_per_L = Cc_caf * 1000,
OC = ifelse(CONMED_BIRTHCONTROL == 1, "On oral contraceptive", "Not on oral contraceptive")) |>
distinct(time, OC, .keep_all = TRUE) |>
ggplot(aes(time / 60, Cc_caf_ug_per_L, colour = OC)) +
geom_line(linewidth = 0.7) +
labs(x = "Time (h)", y = "Plasma caffeine (ug/L)",
colour = "Cohort",
title = "Figure 2 - caffeine plasma profile",
caption = "Pharmaceutical 200 mg caffeine; typical-value simulation.\nReplicates the shape of Csajka 2005 Figure 2.")
Figure 3 - Norephedrine plasma profile from ephedrine metabolism
sim_typical |>
filter(time <= 24 * 60, cohort == "Study 2 pharmaceutical (no OC)") |>
mutate(Cc_neph_ug_per_L = Cc_neph * 1000) |>
distinct(time, .keep_all = TRUE) |>
ggplot(aes(time / 60, Cc_neph_ug_per_L)) +
geom_line(linewidth = 0.7) +
labs(x = "Time (h)", y = "Plasma norephedrine (ug/L)",
title = "Figure 3 - plasma norephedrine from saturable conversion",
caption = "Pharmaceutical 25 mg ephedrine; typical-value simulation.\nReplicates the shape of Csajka 2005 Figure 3 (solid line = MM model).")
Figure 4 - Ephedrine plasma profile
sim_typical |>
filter(time <= 24 * 60, cohort == "Study 2 pharmaceutical (no OC)") |>
mutate(Cc_ug_per_L = Cc * 1000) |>
distinct(time, .keep_all = TRUE) |>
ggplot(aes(time / 60, Cc_ug_per_L)) +
geom_line(linewidth = 0.7) +
labs(x = "Time (h)", y = "Plasma ephedrine (ug/L)",
title = "Figure 4 - plasma ephedrine after pharmaceutical 25 mg",
caption = "Caffeine-modulated absorption (d_caf = 0.99, ka_E,50 = 31.4 mg).\nReplicates the shape of Csajka 2005 Figure 4.")
PKNCA validation
Three independent PKNCA blocks - one per plasma output (caffeine,
ephedrine, norephedrine). The treatment grouping
(cohort + id) carries the with / without oral-contraceptive
subgroups so per-cohort half-lives can be compared against the
paper.
# Caffeine plasma NCA, both cohorts (no OC and with OC).
sim_caf <- sim |>
filter(!is.na(Cc_caf)) |>
mutate(Cc_caf_ug_per_L = Cc_caf * 1000) |>
select(id, time, Cc_caf_ug_per_L, cohort)
dose_caf <- events |>
filter(evid == 1, cmt == "depot_caf") |>
select(id, time, amt, cohort)
conc_caf <- PKNCA::PKNCAconc(sim_caf, Cc_caf_ug_per_L ~ time | cohort + id,
concu = "ug/L", timeu = "min")
dose_caf <- PKNCA::PKNCAdose(dose_caf, amt ~ time | cohort + id, doseu = "mg")
ints_caf <- data.frame(start = 0, end = Inf, cmax = TRUE, tmax = TRUE,
aucinf.obs = TRUE, half.life = TRUE)
nca_caf <- PKNCA::pk.nca(PKNCA::PKNCAdata(conc_caf, dose_caf, intervals = ints_caf))
nca_caf_tbl <- nca_caf$result |>
filter(PPTESTCD %in% c("cmax", "tmax", "aucinf.obs", "half.life")) |>
group_by(cohort, PPTESTCD) |>
summarise(median = median(PPORRES, na.rm = TRUE),
q05 = quantile(PPORRES, 0.05, na.rm = TRUE),
q95 = quantile(PPORRES, 0.95, na.rm = TRUE), .groups = "drop")
knitr::kable(nca_caf_tbl, caption = "Simulated caffeine NCA (per cohort).", digits = 2)| cohort | PPTESTCD | median | q05 | q95 |
|---|---|---|---|---|
| Study 2 pharmaceutical (no OC) | aucinf.obs | 2461784.34 | 1334984.00 | 5189510.48 |
| Study 2 pharmaceutical (no OC) | cmax | 4666.71 | 3409.00 | 6005.30 |
| Study 2 pharmaceutical (no OC) | half.life | 348.98 | 166.65 | 746.42 |
| Study 2 pharmaceutical (no OC) | tmax | 60.00 | 44.25 | 120.00 |
| Study 2 pharmaceutical (with OC) | aucinf.obs | 5729865.73 | 3097906.72 | 11064482.70 |
| Study 2 pharmaceutical (with OC) | cmax | 5145.44 | 3803.88 | 5844.68 |
| Study 2 pharmaceutical (with OC) | half.life | 704.08 | 355.13 | 1506.85 |
| Study 2 pharmaceutical (with OC) | tmax | 67.50 | 45.00 | 121.50 |
# Ephedrine plasma NCA, no-OC cohort only (no OC effect on ephedrine).
sim_eph <- sim |>
filter(!is.na(Cc), cohort == "Study 2 pharmaceutical (no OC)") |>
mutate(Cc_ug_per_L = Cc * 1000) |>
select(id, time, Cc_ug_per_L, cohort)
dose_eph <- events |>
filter(evid == 1, cmt == "depot", cohort == "Study 2 pharmaceutical (no OC)") |>
select(id, time, amt, cohort)
conc_eph <- PKNCA::PKNCAconc(sim_eph, Cc_ug_per_L ~ time | cohort + id,
concu = "ug/L", timeu = "min")
dose_eph <- PKNCA::PKNCAdose(dose_eph, amt ~ time | cohort + id, doseu = "mg")
ints_eph <- data.frame(start = 0, end = Inf, cmax = TRUE, tmax = TRUE,
aucinf.obs = TRUE, half.life = TRUE)
nca_eph <- PKNCA::pk.nca(PKNCA::PKNCAdata(conc_eph, dose_eph, intervals = ints_eph))
nca_eph_tbl <- nca_eph$result |>
filter(PPTESTCD %in% c("cmax", "tmax", "aucinf.obs", "half.life")) |>
group_by(PPTESTCD) |>
summarise(median = median(PPORRES, na.rm = TRUE),
q05 = quantile(PPORRES, 0.05, na.rm = TRUE),
q95 = quantile(PPORRES, 0.95, na.rm = TRUE), .groups = "drop")
knitr::kable(nca_eph_tbl, caption = "Simulated ephedrine NCA (no-OC cohort).", digits = 2)| PPTESTCD | median | q05 | q95 |
|---|---|---|---|
| aucinf.obs | 43446.79 | 38198.10 | 49823.70 |
| cmax | 65.32 | 47.99 | 87.91 |
| half.life | 377.24 | 258.74 | 517.66 |
| tmax | 150.00 | 75.00 | 210.00 |
# Norephedrine plasma NCA, no-OC cohort. Norephedrine is a metabolite
# (no direct dose), so a dose object is omitted from PKNCAdata.
sim_neph <- sim |>
filter(!is.na(Cc_neph), cohort == "Study 2 pharmaceutical (no OC)") |>
mutate(Cc_neph_ug_per_L = Cc_neph * 1000) |>
select(id, time, Cc_neph_ug_per_L, cohort)
conc_neph <- PKNCA::PKNCAconc(sim_neph, Cc_neph_ug_per_L ~ time | cohort + id,
concu = "ug/L", timeu = "min")
ints_neph <- data.frame(start = 0, end = Inf, cmax = TRUE, tmax = TRUE,
auclast = TRUE, half.life = TRUE)
nca_neph <- PKNCA::pk.nca(PKNCA::PKNCAdata(conc_neph, intervals = ints_neph))
#> No dose information provided, calculations requiring dose will return NA.
nca_neph_tbl <- nca_neph$result |>
filter(PPTESTCD %in% c("cmax", "tmax", "auclast", "half.life")) |>
group_by(PPTESTCD) |>
summarise(median = median(PPORRES, na.rm = TRUE),
q05 = quantile(PPORRES, 0.05, na.rm = TRUE),
q95 = quantile(PPORRES, 0.95, na.rm = TRUE), .groups = "drop")
knitr::kable(nca_neph_tbl, caption = "Simulated norephedrine NCA (no-OC cohort).", digits = 2)| PPTESTCD | median | q05 | q95 |
|---|---|---|---|
| auclast | 4890.96 | 1587.31 | 8915.80 |
| cmax | 4.88 | 1.68 | 8.78 |
| half.life | 601.30 | 335.96 | 1284.42 |
| tmax | 210.00 | 120.00 | 300.00 |
Comparison against published NCA
The paper reports terminal half-lives derived from the population PK fit (not full NCA tables). Compare the simulated half-lives below against the reported values.
| Analyte / cohort | Simulated median t1/2 (h) | Published t1/2 (h) | Source |
|---|---|---|---|
| Caffeine, no oral contraceptive | 5.8 | 5.3 | Csajka 2005 Results ‘Caffeine pharmacokinetics’ |
| Caffeine, on oral contraceptive | 11.7 | 11.8 | Csajka 2005 Results ‘Caffeine pharmacokinetics’ |
| Ephedrine, no oral contraceptive | 6.3 | 6.1 | Csajka 2005 Results ‘Ephedrine and norephedrine pharmacokinetics’ |
A peak-amount sanity check against the paper’s observed-concentration ranges (Csajka 2005 Results):
| Analyte | Simulated median Cmax (ug/L) | Published observed range (ug/L) |
|---|---|---|
| Caffeine, no OC | 4667 | 0 - 8470 |
| Ephedrine, no OC | 65 | 1.59 - 101.40 |
| Norephedrine | 4.88 | 0.51 - 8.18 |
Assumptions and deviations
-
Pharmaceutical formulation default. The model’s
ini()carries the pharmaceutical-formulation values (F_E,pharm = 0.59, no caffeine absorption lag). For herbal-formulation simulations, overridelfdepot <- log(0.78)for F_E,herbal and prepend a 22.2-minute time shift to caffeine doses (the herbal caffeine lag); the paper reports no significant difference in caffeine bioavailability between formulations, so no herbal lfdepot_caf is required. -
Norephedrine metabolic pathway treated as
formation-only. The Michaelis-Menten conversion term
vmax_neph * mm_factordrives the norephedrine pseudo-concentration but does NOT subtract from ephedrinecentral. The paper (Csajka 2005, Discussion paragraph 3) characterises this pathway as “minor compared with the renal elimination of ephedrine”; the publishedVmax/V_NEis a compound parameter that pins the norephedrine concentration rate but does not identify the absolute Vmax required to deplete the parent. This is the standard mechanistic simplification for a saturable-but-minor conversion; ephedrine cumulative urinary recovery in the no-OC cohort matches the paper’s observed 0-24 h range (7.35 - 22.2 mg) under this simplification, which it would not under a fully-coupled depletion form. -
Norephedrine compartment carries a
pseudo-concentration. Because the norephedrine volume V_NE is
unidentifiable,
central_nephstores the norephedrine concentration directly (= A5 / V_NE), and the reportedVmax/V_NEis the rate of change of that concentration when the MM is saturated. The observationCc_nephis thereforecentral_nephitself (no division by a volume). -
Caffeine baseline omitted. The paper integrates a
per-subject baseline caffeine concentration
C0(range 14.2 - 3820 ug/L due to dietary intake) for 22 of 24 subjects. The model file defaults toC0 = 0(washout); users who want to reproduce the paper’s pre-dose concentrations can add an earlier-time dose or initialisecentral_cafaccordingly. -
OCR-derived unit ambiguity in Vmax/V_NE. Csajka
2005 Table 3 reports
Vmax/V_NE = 1.96e-4with a unit heading rendered ambiguously in the source PDF / trimmed-markdown (the character that should be “mu g” is rendered as “m g”); the same OCR rendering applies to plasma concentrations (e.g. “8470 m g L^-1” for caffeine, which can only mean “ug / L”). The numerical interpretation that reproduces the paper’s observed norephedrine concentration range (0.51 - 8.18 ug/L) is1.96e-4 mg / (min L)(equivalently 0.196 ug / (min L)); the model file uses this interpretation, which is consistent with the table heading taken literally asmg. If a future re-extraction confirms that the heading was meant to beugwith no compensating order-of-magnitude shift elsewhere in the paper, the model file should be updated accordingly. -
Km on amount, not concentration. Csajka 2005 Table
3 reports
Km = 2.77in the same heading-ambiguous unit as Vmax/V_NE. The model file encodes Km as a mg amount (compared against the ephedrine central state amount, not the central concentration); under this encoding the MM transitions from saturated to linear over the observed ephedrine concentration range, which is the structural improvement the paper attributes to the MM term (DOBJ = -124 vs the linear-formation alternative). - No effect of caffeine on its own absorption from the ephedrine indirect-action model. The paper confirms “No statistically significant effect of ephedrine on caffeine absorption was observed.” The caffeine ODE is independent of the ephedrine state.
-
OC encoding inverted from the paper’s source
column. The paper’s source column is named
OC(1 = on oral contraceptive); the canonicalCONMED_BIRTHCONTROLhas the same 1 = on-OC orientation, so no value transformation is required (covariateData$CONMED_BIRTHCONTROL$source_name = "OC"). -
Urine pH covariate excluded. The paper reports a
post-hoc inverse linear association between urine pH and ephedrine renal
clearance (
CL_R = 0.4723 - 0.0172 * pH, p = 0.013) but does not retain pH in the final population PK model; the model file documents the screen viacovariatesDataExcluded$URINE_PHrather than introducing pH as a covariate effect. - Norephedrine elimination unit. Csajka 2005 Table 3 prints the ke_NE row’s unit heading as “L / h” which is dimensionally wrong for a first-order rate constant. The prose text in the Results section gives the correct unit (“0.037 1 min^-1”); the model file uses the prose value.