Skip to contents

Model 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)
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.
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.04477 and 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; the max(PARA, 1) gate inside model() 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 Cc in mg/L = ug/mL (the assay units in the source paper) without any capillary-vs-venous correction.