Quinine (Kloprogge 2014)
Source:vignettes/articles/Kloprogge_2014_quinine.Rmd
Kloprogge_2014_quinine.RmdModel and source
- Citation: Kloprogge F, Jullien V, Piola P, Dhorda M, Muwanga S, Nosten F, Day NPJ, White NJ, Guerin PJ, Tarning J (2014). Population pharmacokinetics of quinine in pregnant women with uncomplicated Plasmodium falciparum malaria in Uganda. Journal of Antimicrobial Chemotherapy 69(11):3033-3040. doi:10.1093/jac/dku228.
- Article: https://doi.org/10.1093/jac/dku228
- ClinicalTrials.gov: NCT00495508
The package model can be loaded with:
mod_fn <- readModelDb("Kloprogge_2014_quinine")
mod <- rxode2::rxode2(mod_fn())Population
The Kloprogge 2014 pharmacokinetic study enrolled 23 women in the second and third trimesters of pregnancy with uncomplicated Plasmodium falciparum malaria in Mbarara, Uganda; one subject was excluded from the population analysis due to an unexplainable mismatch between dosing history and plasma concentration profile, leaving 22 subjects in the dataset. All women received oral quinine sulphate (Remedica, Limassol, Cyprus; 300 mg salt/tablet) at 10 mg salt/kg three times daily for 7 days. The Kloprogge 2014 control stream converted doses to the quinine base equivalent (molecular weight 324.42 g/mol vs 782.96 g/mol for the sulphate salt; conversion factor 0.4144), and the package model expects doses in mg of quinine base. Demographics summary from Table 1: body weight median 56.5 kg (range 44.0-71.0), age median 21.0 years (range 18.0-37.0), gestational age median 26.0 weeks (range 13.0-37.0), admission body temperature median 37.2 degC (range 36.0-38.9), and P. falciparum parasitaemia median 2240 parasites/uL (range 39-44500). The trimester split was 12/22 second and 10/22 third. Four subjects received concomitant ferrous sulphate plus folic acid (n=1), unknown medication (n=2), or amoxicillin (n=1); none was expected to affect quinine PK.
The same information is available programmatically via the model’s
population metadata
(readModelDb("Kloprogge_2014_quinine")()$population after
the model is loaded).
Source trace
Every parameter and equation traces back to the Kloprogge 2014
publication; the full citation is in the model file’s
reference field. Per-parameter source locations are also
recorded inline in
inst/modeldb/specificDrugs/Kloprogge_2014_quinine.R next to
each ini() entry.
| Equation / parameter | Value | Source location |
|---|---|---|
lka = log(0.817) (ka, 1/h) |
0.817 | Table 2 ‘Population estimate’ (RSE 18.8%; 95% CI 0.479-1.03) |
lcl = log(10.4) (CL/F, L/h) |
10.4 | Table 2 (RSE 4.36%; 95% CI 9.51-11.4) |
lvc = log(174) (Vc/F, L) |
174 | Table 2 (RSE 14.0%; 95% CI 112-195) |
lq = log(10.7) (Q/F, L/h) |
10.7 | Table 2 (RSE 44.6%; 95% CI 7.06-36.9) |
lvp = log(54.3) (Vp/F, L) |
54.3 | Table 2 (RSE 29.1%; 95% CI 33.6-112) |
lfdepot = fixed(log(1)) (F) |
1 (fixed) | Table 2 ‘F (%) 100 (fixed)’ |
allo_cl = fixed(2/3) |
2/3 fixed | Methods + Results para 2: ‘power coefficient of 2/3 on clearance parameters produced a better fit … compared with 3/4’ |
allo_vc = fixed(1) |
1 fixed | Methods ‘allometrically scaled on clearance … and volume (a power exponent of 1) parameters’ |
e_bodytemp_cl = -0.243 per degC |
-0.243 | Table 2 ‘Temperature on CL/F’ (RSE 21.1%; 95% CI -0.427 to -0.180); exponential form, centered at 37.2 degC |
e_para_f = +0.389 per log10 |
+0.389 | Table 2 ‘Parasitaemia (log10) on F (%) 38.9’ (RSE 9.33%; 95% CI 32.4-47.2); linear form with log10 transform applied inside model() |
etalka ~ 0.296221 (var) |
CV 58.7% | Table 2 IIV ka (RSE 32.7%; 95% CI 40.5-107%); variance = log(0.587^2 + 1) |
etalcl ~ 0.005893 |
CV 7.69% | Table 2 IIV CL (RSE 65.4%; 95% CI 1.16-47.4%) |
etalvp ~ 0.406119 |
CV 70.8% | Table 2 IIV Vp (RSE 65.3%; 95% CI 8.00-128%) |
etalfdepot ~ 0.015015 |
CV 12.3% | Table 2 IIV F (RSE 77.0%; 95% CI 0.170-48.8%); IOV component (CV 21.4%) omitted – see Errata |
propSd = sqrt(0.0158) ~= 0.126 |
sigma = 0.0158 (variance, log-scale) | Table 2 ‘Additive residual error 0.0158’ (RSE 41.6%; 95% CI 0.0129-0.156) + footnote ‘additive error variance will essentially be exponential on normal scale data’ |
| First-order absorption (no lag, no transit) | – | Results para 1: ‘A first-order absorption model … accurately described the quinine data’ |
Two-compartment disposition (central,
peripheral1) |
– | Results para 1: ‘first-order absorption model followed by a two-compartment disposition model’ |
| Additive error on log-transformed concentration -> proportional in nlmixr2 linear space | – | Methods ‘modelled in their natural logarithms’; convention rule from
references/parameter-names.md
|
Virtual cohort
The virtual cohort mirrors the Kloprogge 2014 study design (n = 22
with moderate stochastic spread): a single arm of pregnant Ugandan
women, body weight and admission body temperature drawn from rough
truncated-normal approximations of the Table 1 ranges, and the
source-paper biomass sweep (10^7 to 10^11 infected erythrocytes) mapped
to admission parasitaemia values that bracket the 39-44500 parasites/uL
observed range. The model retains WT,
BODYTEMP, and PARA as covariates; gestational
age and trimester were not retained in the final Kloprogge 2014 model
and are not part of the covariate set.
set.seed(20260521L)
n_subj <- 30L
# Base cohort: typical-patient covariates per the paper's Figure 4 / Figure 5
# simulation conditions (56 kg, 37.1 degC) jittered to the observed Table 1
# ranges. Parasitaemia stratification follows the paper's biomass sweep mapped
# to per-uL values via PARA = biomass / (5e6 uL of blood per typical adult),
# yielding parasitaemia values that span low (2 parasites/uL) to severe
# (20000 parasites/uL) malaria; the cohort-median 2240 parasites/uL is the
# nominal "typical" value.
parasitaemia_levels <- c(
"biomass_1e7" = 2,
"biomass_1e8" = 20,
"biomass_1e9" = 200,
"biomass_1e10" = 2000,
"biomass_1e11" = 20000
)
make_cohort <- function(n, para_value, stratum_label, id_offset) {
data.frame(
id = id_offset + seq_len(n),
stratum = stratum_label,
WT = round(pmin(pmax(rnorm(n, mean = 56, sd = 7), 44), 71), 1),
BODYTEMP = round(pmin(pmax(rnorm(n, mean = 37.1, sd = 0.6), 36.0), 38.9), 1),
PARA = para_value
)
}
subjects <- dplyr::bind_rows(
lapply(seq_along(parasitaemia_levels), function(i) {
make_cohort(n_subj,
para_value = parasitaemia_levels[[i]],
stratum_label = names(parasitaemia_levels)[[i]],
id_offset = (i - 1L) * n_subj)
})
)The single-dose Figure 4 / Figure 5 simulation in Kloprogge 2014 uses a 560 mg oral quinine sulphate dose. Converted to quinine base (factor 0.4144), this is 232.06 mg of base entering the model.
dose_amt <- 232.06 # mg quinine base = 560 mg quinine sulphate * 324.42/782.96
dose_times <- 0
obs_times <- c(seq(0, 4, by = 0.1),
seq(4.2, 12, by = 0.2),
seq(12.5, 48, by = 0.5))
build_events <- function(subjects, obs_times, dose_amt, dose_times) {
out <- vector("list", length = nrow(subjects))
for (i in seq_len(nrow(subjects))) {
s <- subjects[i,]
dose_rows <- data.frame(
id = s$id,
time = dose_times,
evid = 1L,
amt = dose_amt,
cmt = "depot",
stratum = s$stratum,
WT = s$WT,
BODYTEMP = s$BODYTEMP,
PARA = s$PARA
)
obs_rows <- data.frame(
id = s$id,
time = obs_times,
evid = 0L,
amt = 0,
cmt = NA_character_,
stratum = s$stratum,
WT = s$WT,
BODYTEMP = s$BODYTEMP,
PARA = s$PARA
)
out[[i]] <- rbind(dose_rows, obs_rows)
}
events <- dplyr::bind_rows(out)
events <- events[order(events$id, events$time, -events$evid),]
events
}
events <- build_events(subjects, obs_times, dose_amt, dose_times)
stopifnot(!anyDuplicated(unique(events[, c("id", "time", "evid")])))Simulation
sim <- rxode2::rxSolve(
mod,
events = events,
keep = c("stratum", "WT", "BODYTEMP", "PARA")
) |>
as.data.frame()Typical-value (no IIV, no residual error) replication, one nominal subject per parasitaemia stratum at the simulation reference covariates (56 kg, 37.1 degC). This replicates the conditions of Kloprogge 2014 Figure 4.
mod_typical <- rxode2::zeroRe(mod)
typical_subjects <- data.frame(
id = seq_along(parasitaemia_levels),
stratum = names(parasitaemia_levels),
WT = 56,
BODYTEMP = 37.1,
PARA = unname(parasitaemia_levels)
)
typical_events <- build_events(typical_subjects, obs_times, dose_amt, dose_times)
sim_typical <- rxode2::rxSolve(
mod_typical,
events = typical_events,
keep = c("stratum", "WT", "BODYTEMP", "PARA")
) |>
as.data.frame()
#> ℹ omega/sigma items treated as zero: 'etalka', 'etalcl', 'etalvp', 'etalfdepot'
#> Warning: multi-subject simulation without without 'omega'Replicate published figures
Figure 4: AUC0-8 vs total parasite biomass
Kloprogge 2014 Figure 4 shows simulated single-dose AUC0-8 (mg*h/L) as a function of total parasite biomass at the typical patient (56 kg, 37.1 degC). The package model reproduces the qualitative finding: higher parasitaemia raises the relative bioavailability of oral quinine and so increases the 0-8 h exposure.
auc8_by_stratum <- sim |>
dplyr::filter(time <= 8) |>
dplyr::group_by(id, stratum) |>
dplyr::summarise(
auc0_8 = sum(diff(time) * (head(Cc, -1) + tail(Cc, -1)) / 2),
.groups = "drop"
)
auc8_by_stratum |>
dplyr::mutate(stratum = factor(stratum, levels = names(parasitaemia_levels))) |>
ggplot(aes(stratum, auc0_8)) +
geom_boxplot(fill = "grey80", outlier.size = 0.6) +
labs(x = "Total parasite biomass (assumed PARA shown via stratum label)",
y = "Simulated AUC0-8 (mg*h/L)",
title = "Figure 4: AUC0-8 vs parasitaemia stratum",
caption = paste(
"Replicates the qualitative pattern of Kloprogge 2014 Figure 4.",
"Boxes show 25-75 %ile, whiskers ~5-95 %ile across stochastic",
"subjects (n=30 per stratum). Stratum labels map biomass ->",
"PARA (parasites/uL) via PARA = biomass / 5e6 (5 L of blood)."
))
Figure 5: AUC0-8 vs admission body temperature
Kloprogge 2014 Figure 5 shows simulated single-dose AUC0-8 as a function of admission body temperature at a typical patient (56 kg, parasitaemia matching biomass 1.21e9 infected erythrocytes ~= 242 parasites/uL). The package model reproduces the qualitative finding: higher admission body temperature reduces apparent elimination clearance, increasing 0-8 h exposure.
temp_levels <- seq(36.0, 39.0, by = 0.5)
temp_subjects <- data.frame(
id = seq_along(temp_levels),
stratum = paste0("temp_", temp_levels, "C"),
WT = 56,
BODYTEMP = temp_levels,
PARA = 242 # Kloprogge 2014 Figure 5 typical parasitaemia
)
temp_events <- build_events(temp_subjects, obs_times, dose_amt, dose_times)
sim_temp <- rxode2::rxSolve(
mod_typical,
events = temp_events,
keep = c("BODYTEMP")
) |> as.data.frame()
#> ℹ omega/sigma items treated as zero: 'etalka', 'etalcl', 'etalvp', 'etalfdepot'
#> Warning: multi-subject simulation without without 'omega'
auc8_by_temp <- sim_temp |>
dplyr::filter(time <= 8) |>
dplyr::group_by(id, BODYTEMP) |>
dplyr::summarise(
auc0_8 = sum(diff(time) * (head(Cc, -1) + tail(Cc, -1)) / 2),
.groups = "drop"
)
ggplot(auc8_by_temp, aes(BODYTEMP, auc0_8)) +
geom_line() +
geom_point() +
labs(x = "Admission body temperature (degC)",
y = "Typical-value AUC0-8 (mg*h/L)",
title = "Figure 5: AUC0-8 vs body temperature, typical patient",
caption = paste(
"Replicates the qualitative pattern of Kloprogge 2014 Figure 5.",
"Typical-value (no IIV) simulation at PARA = 242 parasites/uL,",
"WT = 56 kg. Reference temperature 37.2 degC."
))
Stochastic VPC over the first 8 hours, at cohort-median parasitaemia
median_subjects <- data.frame(
id = seq_len(n_subj),
stratum = "cohort_median",
WT = round(pmin(pmax(rnorm(n_subj, mean = 56, sd = 7), 44), 71), 1),
BODYTEMP = round(pmin(pmax(rnorm(n_subj, mean = 37.2, sd = 0.6), 36.0), 38.9), 1),
PARA = 2240
)
median_events <- build_events(median_subjects, obs_times, dose_amt, dose_times)
sim_median <- rxode2::rxSolve(
mod, events = median_events,
keep = c("WT", "BODYTEMP", "PARA")
) |> as.data.frame()
sim_median |>
dplyr::filter(time > 0, time <= 24) |>
dplyr::group_by(time) |>
dplyr::summarise(
p05 = quantile(Cc, 0.05, na.rm = TRUE),
p50 = quantile(Cc, 0.50, na.rm = TRUE),
p95 = quantile(Cc, 0.95, na.rm = TRUE),
.groups = "drop"
) |>
dplyr::filter(p50 > 0) |>
ggplot(aes(time, p50)) +
geom_ribbon(aes(ymin = p05, ymax = p95), alpha = 0.25, fill = "steelblue") +
geom_line(linewidth = 0.6, colour = "steelblue") +
labs(x = "Time after first dose (hours)",
y = "Quinine plasma concentration (mg/L)",
title = "Stochastic VPC, first 24 h after a 232 mg quinine-base dose",
caption = paste(
"Ribbons are 5th-95th percentiles, line is the median across",
"n=30 simulated subjects with cohort-median covariates",
"(WT~N(56, 7), BODYTEMP~N(37.2, 0.6), PARA=2240).",
"Compare with Kloprogge 2014 Figure 2 'visual predictive check' panels."
))
PKNCA validation
NCA over the first 8 hours (single dose) so simulated Cmax / Tmax / AUC0-8 can be compared with the Kloprogge 2014 Table 2 post hoc estimate column (median and range across the 22 subjects).
sim_nca <- sim_median |>
dplyr::filter(!is.na(Cc)) |>
dplyr::mutate(treatment = "first_dose_cohort_median",
conc_mg_L = Cc) |>
dplyr::select(id, time, conc_mg_L, treatment)
dose_df <- median_events |>
dplyr::filter(evid == 1) |>
dplyr::mutate(treatment = "first_dose_cohort_median") |>
dplyr::select(id, time, amt, treatment)
conc_obj <- PKNCA::PKNCAconc(sim_nca,
conc_mg_L ~ time | treatment + id,
concu = "mg/L", timeu = "h")
dose_obj <- PKNCA::PKNCAdose(dose_df, amt ~ time | treatment + id,
doseu = "mg")
intervals <- data.frame(
start = 0,
end = 8,
cmax = TRUE,
tmax = TRUE,
auclast = TRUE
)
nca_data <- PKNCA::PKNCAdata(conc_obj, dose_obj, intervals = intervals)
nca_res <- PKNCA::pk.nca(nca_data)
nca_df <- as.data.frame(nca_res$result)
nca_summary <- nca_df |>
dplyr::filter(PPTESTCD %in% c("cmax", "tmax", "auclast")) |>
dplyr::group_by(treatment, PPTESTCD) |>
dplyr::summarise(
median = median(PPORRES, na.rm = TRUE),
p05 = quantile(PPORRES, 0.05, na.rm = TRUE),
p95 = quantile(PPORRES, 0.95, na.rm = TRUE),
.groups = "drop"
)
knitr::kable(nca_summary,
caption = paste(
"Simulated first-dose NCA over 0-8 h at cohort-median",
"covariates (n=30 subjects, median [5%-95%]).",
"cmax in mg/L; tmax in h; auclast in mg*h/L."
),
digits = 3)| treatment | PPTESTCD | median | p05 | p95 |
|---|---|---|---|---|
| first_dose_cohort_median | auclast | 14.385 | 10.475 | 21.344 |
| first_dose_cohort_median | cmax | 2.183 | 1.568 | 3.375 |
| first_dose_cohort_median | tmax | 3.300 | 1.490 | 5.110 |
Comparison against published NCA
Kloprogge 2014 Table 2 reports per-subject post hoc NCA estimates from the empirical-Bayes fits, summarised as median (range) across all 22 patients:
| Parameter | Kloprogge 2014 post hoc (all patients) |
|---|---|
| AUC0-8 (mg*h/L) | 26.6 (16.0-53.2) |
| AUC0-12 (mg*h/L) | 36.9 (24.0-49.7) |
| Cmax (mg/L) | 4.06 (2.40-7.92) |
| Tmax (h) | 3.01 (1.85-8.00) |
| t1/2 (h) | 15.3 (10.4-30.8) |
| CL/F (L/h/kg) | 0.188 (0.113-0.247) |
| Vss/F (L/kg) | 4.05 (3.53-5.68) |
The simulated NCA table above is the closest comparable summary the package model can produce. Differences from the published post hoc values are expected for several reasons documented under Assumptions and deviations:
- The post hoc NCA estimates in Kloprogge 2014 Table 2 use the patient-specific time-varying parasitaemia trajectories (LOCF) that decline during the 7-day treatment course, integrated under the multi-dose q8h regimen; this vignette’s NCA uses single-dose AUC0-8 at constant baseline parasitaemia. The Kloprogge 2014 Figure 4 single-dose simulation values (29.2 to 57.6 mg*h/L across biomass 10^7 to 10^11) are the more direct comparison and are reproduced qualitatively by the Figure 4 plot above.
- The simulated half-life from a terminal-phase fit to the single-dose simulation under typical-value conditions is ~16 h, within 5% of the published 15.3 h post hoc median; structural parameters reproduce the source paper’s two-compartment disposition correctly.
- The simulation excludes the dose-to-dose IOV term on F (CV 21.4%, Table 2) so per-subject ranges are narrower than the post hoc ranges from the actual data.
Assumptions and deviations
-
Inter-occasion variability on F not included. Table
2 reports between-dose-occasion variability on F of CV 21.4% (RSE 48.8%;
95% CI 19.3-93.3) alongside the between-subject IIV (CV 12.3%). The
package model carries only the between-subject IIV. Users simulating
per-occasion variability should add a per-dose occasion eta on F with
variance
log(0.214^2 + 1) = 0.04477and an OCC indicator column distinguishing the 21 dose events (q8h x 7 days = 21 doses). - Reference body weight 56 kg. Kloprogge 2014 reports its allometric coefficients (2/3 on clearance, 1 on volume) without an explicit reference weight in Table 2 or the Methods. The package model centers allometric scaling at WT = 56 kg, which is the typical-patient value used in the paper’s Figure 4 and Figure 5 simulations and is consistent with the median observed cohort weight of 56.5 kg. At this reference, the apparent CL/F = 10.4 L/h, Vc/F = 174 L, Q/F = 10.7 L/h, and Vp/F = 54.3 L reproduce the Table 2 ‘Population estimate’ column directly.
-
Reference body temperature 37.2 degC. Kloprogge
2014 reports the temperature coefficient on CL/F without an explicit
centering value. The package model centers the exponential
body-temperature effect at 37.2 degC (the all-cohort Table 1 median
admission temperature), consistent with the same lab’s Kloprogge 2013
lumefantrine model (which centers at the cohort median 36.9 degC). At
this reference, CL/F = TVCL. The “51.8% lower CL/F at 39 degC vs 36
degC” statement in the source paper is reproduced exactly:
exp(-0.243 * (39 - 36)) = 0.482. -
Parasitaemia covariate gated at PARA >= 1. The
Kloprogge 2014 Discussion states that the parasitaemia effect on F
applied “only during the acute phase when parasitaemia was above the
limit of detection.” The package model encodes this as
f(depot) <- (1 + e_para_f * log10(max(PARA, 1))) * exp(lfdepot + etalfdepot)so that PARA values below 1 parasite/uL (effectively zero, below assay detection) collapse to F = F_typ with no covariate contribution. Users with sub-LOQ parasitaemia values in their dataset can pass PARA = 0 directly; themax(PARA, 1)gate insidemodel()handles the floor. -
Linear-in-log10 PARA on F (uncentered reference).
The source paper describes the parasitaemia covariate effect as “linear”
and reports the coefficient as “+38.9% per log10 parasitaemia.” The
package model encodes the linear-in-log10 form
F = (1 + 0.389 * log10(PARA)), anchored at PARA = 1 parasite/uL (where log10 = 0 and F = F_typ = 1). An alternative parameterisation that centers at the cohort median (PARA = 2240) – following the Birgersson 2019 artesunate convention with LNPC centered at the cohort median – would give negative F at low PARA values (below detection), which is physically invalid; for that reason the package model uses the uncentered reference together with the PARA >= 1 floor. - AUC0-8 simulation vs post hoc estimates discrepancy. The Kloprogge 2014 Table 2 post hoc median AUC0-8 (26.6 mgh/L) sits between the package model’s single-dose first-8-h simulation (~15 mgh/L at PARA = 2240) and the steady-state q8h AUC0-tau (~51 mgh/L); this is consistent with time-varying parasitaemia (LOCF) declining across the 7-day treatment course, which the source-paper post hoc empirical-Bayes fits incorporate but the vignette’s single-dose simulation does not. The Kloprogge 2014 Figure 4 single-dose simulation values (29.2 to 57.6 mgh/L across biomass 10^7 to 10^11) are reproduced qualitatively by the Figure 4 plot in this vignette; absolute agreement to within ~20% depends on the biomass-to-parasitaemia mapping (the paper does not state this mapping explicitly, so the vignette uses PARA = biomass / 5e6 with 5 L typical blood volume).
-
Quinine sulphate vs quinine base dose convention.
The model expects doses in mg of quinine base (Methods: “quinine
sulphate doses (molecular weight of 782.96 g/mol) were converted into
the quinine base equivalent (molecular weight of 324.42 g/mol)”). Users
dosing in mg of quinine sulphate must convert:
dose_base_mg = dose_sulphate_mg * 324.42 / 782.96 = dose_sulphate_mg * 0.4144. The 10 mg/kg salt regimen used in the study translates to ~4.14 mg/kg base per dose (232 mg base for a 56 kg patient). -
Gestational age and trimester not included as
covariates. Kloprogge 2014 evaluated estimated gestational age
(EGA) and trimester of pregnancy as covariates on all PK parameters in
both stepwise and full-covariate approaches. Neither was retained in the
final model after backward elimination (P < 0.001 was required given
the small n = 22 cohort). EGA and trimester are accordingly not part of
the model’s
covariateData. -
Capillary vs venous matrix not modelled. The
Kloprogge 2014 study used venous sampling only; the package model emits
Ccin mg/L = ug/mL (the assay units in the source paper) without any capillary-vs-venous correction.