Model and source
- Citation: Rhee SJ, Shin SH, Oh J, Jung YH, Choi CW, Kim HS, Yu KS. Population pharmacokinetic analysis of sildenafil in term and preterm infants with pulmonary arterial hypertension. Sci Rep. 2022;12:7393. doi:10.1038/s41598-022-11038-6.
- Description: Joint parent + metabolite population PK model for oral sildenafil and its active metabolite N-desmethyl sildenafil (DMS) in 19 term and preterm infants with pulmonary arterial hypertension (Rhee 2022). Sildenafil is described by a one-compartment disposition with first-order absorption; its whole apparent clearance is assumed to form DMS (complete conversion, molar basis), which has its own one-compartment disposition. Current body weight enters both apparent clearances through power functions referenced to 3.14 kg. Correlated IIV on sildenafil V/F, sildenafil CL/F and DMS CL/F’; separate log-scale additive (exponential) residual errors per analyte.
- Article: https://doi.org/10.1038/s41598-022-11038-6 (open access)
The paper fitted sildenafil and its metabolite N-desmethyl sildenafil
(DMS) simultaneously on a molar scale: doses were converted to
micromoles and both concentrations to nmol/L using molecular weights of
474.6 g/mol (sildenafil) and 460.6 g/mol (DMS), and all eliminated
sildenafil was assumed to form DMS. The packaged model keeps the dose in
mg of sildenafil and multiplies the sildenafil elimination flux by 460.6
/ 474.6 when it enters the DMS compartment. That is the same molar mass
balance, and both Cc (sildenafil) and
Cc_ndmsil (DMS) come out in ng/mL.
Population
Nineteen term and preterm neonates with pulmonary arterial hypertension (10 male, 9 female) were enrolled in the neonatal intensive care units of Seoul National University Hospital and Seoul National University Bundang Hospital between February 2015 and July 2016 (NCT02244528). Gestational age was 24-41 weeks (median 36), postnatal age 5-98 days (median 11) and current body weight 0.79-4.09 kg (median 3.18). Indications were persistent pulmonary hypertension of the newborn (7), congenital heart disease (4), bronchopulmonary dysplasia (6) and other (2). Oral sildenafil was started at 0.5 mg/kg four times daily and increased to 0.75 mg/kg four times daily after 2 weeks if the echocardiogram did not improve. In total, 99 samples were collected opportunistically during routine blood draws, after at least four doses (paper Table 1 and Results).
The same information is available programmatically via
readModelDb("Rhee_2022_sildenafil")()$population.
Source trace
| Equation / parameter | Value | Source location |
|---|---|---|
lka |
log(0.414) 1/h | Table 2, KA, final model |
lvc |
log(19.8) L | Table 2, V_Sil/F |
lcl |
log(10.1) L/h | Table 2, theta_CL(Sil) |
e_wt_cl |
0.899 | Table 2, theta_weight (sildenafil CL) |
lvc_ndmsil |
log(1.78) L | Table 2, V_DMS/F’ |
lcl_ndmsil |
log(14.3) L/h | Table 2, theta_CL(DMS) |
e_wt_cl_ndmsil |
1.34 | Table 2, theta_weight (DMS CL) |
etalvc, etalcl, etalcl_ndmsil
variances |
log(1 + CV^2) of 143.7%, 63.5%, 49.2% | Table 2, interindividual variability (%CV) |
| eta covariances | r = 0.295, 0.178, 0.0606 times the product of the two SDs | Table 2, correlation between etas |
expSd |
0.553 | Table 2, residual variability (SD), sildenafil |
expSd_ndmsil |
0.472 | Table 2, residual variability (SD), DMS |
CL = theta * (WT / 3.14)^theta_weight |
n/a | Table 2 covariate equations (both clearances) |
| One-compartment sildenafil with first-order absorption, complete conversion to a one-compartment DMS | n/a | Methods ‘Population pharmacokinetic analysis’; Results ‘Final population pharmacokinetic model’ |
| Molecular weights 474.6 and 460.6 g/mol | n/a | Methods ‘Population pharmacokinetic analysis’ |
Additive error on log-transformed concentrations
(lnorm) |
n/a | Methods ‘Population pharmacokinetic analysis’ |
Virtual cohort
The paper’s dose-finding simulation (Methods ‘Simulation to investigate an optimal sildenafil dose’) generated virtual infants with body weights from 0.8 to 4.2 kg and gave 0.5-2 mg/kg sildenafil four times daily for 2 weeks. The paper does not state the weight distribution; here the 200 infants’ weights are evenly spaced over that range, which removes weight-sampling noise from the comparisons below.
To make the cohort identical on every machine, the random effects are
drawn with R’s random number generator from the model’s own
omega matrix, adjusted so that their sample mean and
covariance match the model exactly, and passed to rxSolve()
as event-table columns with omega = NA. Every dose arm
reuses the same 200 infants, so differences between arms are due to dose
alone. Concentrations are individual predictions without residual error,
which is what the paper’s NCA summaries describe.
mod <- readModelDb("Rhee_2022_sildenafil")
ui <- rxode2::rxode2(mod)
omega <- ui$omega
set.seed(20220505)
n_sub <- 200
z <- matrix(rnorm(n_sub * nrow(omega)), n_sub)
# Moment-match the draw: centre it and rescale it so the sample mean is
# exactly zero and the sample covariance is exactly `omega`. With 200 infants
# an unadjusted draw can sit 2-3 standard errors off zero on CL, which would
# move every exposure median by several percent for reasons unrelated to the
# model.
z <- scale(z, center = TRUE, scale = FALSE)
z <- z %*% solve(chol(cov(z)))
eta <- z %*% chol(omega)
colnames(eta) <- colnames(omega)
infants <- tibble(
subj = seq_len(n_sub),
WT = seq(0.8, 4.2, length.out = n_sub)
) |>
bind_cols(as_tibble(eta))
dose_levels <- c(0.5, 0.75, 1, 1.25, 1.5, 1.75, 2)
# One arm: q6h dosing for `n_dose` doses, observations at `obs_times`.
# `id_offset` keeps subject ids disjoint across arms. The model has two
# endpoints (Cc and Cc_ndmsil), so observation rows name an ODE state AND
# carry `dvid`; both concentrations are returned as columns on every row.
make_arm <- function(dose_mgkg, n_dose, obs_times, id_offset) {
base <- infants |>
mutate(id = id_offset + subj, treatment = paste(dose_mgkg, "mg/kg"))
doses <- base |>
mutate(
time = 0, evid = 1L, cmt = "depot", amt = dose_mgkg * WT,
ii = 6, addl = n_dose - 1L
)
obs <- base |>
tidyr::crossing(time = obs_times) |>
mutate(evid = 0L, cmt = "central", dvid = 1L, amt = NA_real_, ii = 0, addl = 0L)
bind_rows(doses, obs)
}
solve_arms <- function(events) {
events <- events |>
arrange(id, time, desc(evid)) |>
relocate(id, time, evid, cmt, amt, ii, addl)
stopifnot(!anyDuplicated(unique(events[, c("id", "time", "evid")])))
out <- rxode2::rxSolve(
mod, events,
omega = NA, sigma = NA,
keep = c("treatment", "WT"),
returnType = "data.frame"
)
# rxSolve drops the id column when only one subject is solved.
if (!"id" %in% names(out)) {
out$id <- events$id[1]
}
out
}Typical-value mass balance
At steady state, the AUC over one dosing interval equals dose / CL for sildenafil and dose x (460.6 / 474.6) / CL’ for DMS, because the model assumes complete conversion. The check below gives a 3.14 kg infant (the covariate reference weight, so each clearance equals its typical value) 1 mg/kg every 6 hours for 2 weeks and compares the PKNCA AUC over the last interval with those closed forms. Both sides use the same parameters, so the tolerance is tight.
typ_events <- tibble(
id = 1L, WT = 3.14, treatment = "typical",
etalcl = 0, etalvc = 0, etalcl_ndmsil = 0
) |>
(\(b) bind_rows(
b |> mutate(time = 0, evid = 1L, cmt = "depot", amt = 3.14, ii = 6, addl = 55L),
b |> tidyr::crossing(time = c(0, seq(330, 336, by = 0.02))) |>
mutate(evid = 0L, cmt = "central", dvid = 1L, amt = NA_real_, ii = 0, addl = 0L)
))()
typ <- solve_arms(typ_events)
typ_long <- typ |>
select(id, time, Cc, Cc_ndmsil) |>
pivot_longer(c(Cc, Cc_ndmsil), names_to = "analyte", values_to = "conc")
typ_nca <- PKNCA::pk.nca(PKNCA::PKNCAdata(
PKNCA::PKNCAconc(typ_long, conc ~ time | analyte + id),
PKNCA::PKNCAdose(
typ_events |> filter(evid == 1) |> select(id, time, amt),
amt ~ time | id
),
intervals = data.frame(start = 330, end = 336, auclast = TRUE)
))
typ_auc <- as.data.frame(typ_nca) |>
filter(PPTESTCD == "auclast") |>
select(analyte, simulated = PPORRES)
ini_val <- ui$theta
closed <- tibble(
analyte = c("Cc", "Cc_ndmsil"),
closed_form = 1000 * 3.14 * c(1, 460.6 / 474.6) /
exp(c(ini_val[["lcl"]], ini_val[["lcl_ndmsil"]]))
)
mb <- left_join(typ_auc, closed, by = "analyte") |>
mutate(pct_diff = 100 * (simulated / closed_form - 1))
mb |>
rename(
"Analyte" = analyte,
"PKNCA AUC0-6 (ng*h/mL)" = simulated,
"Closed form (ng*h/mL)" = closed_form,
"% difference" = pct_diff
) |>
knitr::kable(digits = 2)| Analyte | PKNCA AUC0-6 (ng*h/mL) | Closed form (ng*h/mL) | % difference |
|---|---|---|---|
| Cc | 310.89 | 310.89 | 0 |
| Cc_ndmsil | 213.10 | 213.10 | 0 |
Simulated profiles (Figure 4)
fig4_doses <- c(0.5, 0.75, 1, 2)
fig4 <- solve_arms(bind_rows(lapply(seq_along(fig4_doses), function(i) {
make_arm(fig4_doses[i], n_dose = 28L, obs_times = seq(0, 168, by = 0.5),
id_offset = 1000L * i)
}))) |>
mutate(treatment = factor(treatment, levels = paste(fig4_doses, "mg/kg")))
fig4 |>
group_by(treatment, time) |>
summarise(
Q05 = quantile(Cc, 0.05), Q50 = median(Cc), Q95 = quantile(Cc, 0.95),
.groups = "drop"
) |>
ggplot(aes(time, Q50)) +
geom_line(aes(y = Q05), linetype = "dotted") +
geom_line(aes(y = Q95), linetype = "dotted") +
geom_line() +
geom_hline(yintercept = c(47, 140, 373), linetype = "dashed", colour = "grey50") +
facet_wrap(~treatment) +
scale_x_continuous(breaks = seq(0, 168, by = 24)) +
coord_cartesian(ylim = c(0, 500)) +
labs(
x = "Time (h)", y = "Sildenafil concentration (ng/mL)",
title = "Sildenafil every 6 h in infants of 0.8-4.2 kg",
caption = paste0(
"Replicates Figure 4 of Rhee 2022: median (solid), 5th/95th percentiles\n",
"(dotted); dashed lines are the 47, 140 and 373 ng/mL Cmax references."
)
)
Steady-state exposure by dose (Figures 5 and 6)
Exposure is computed by PKNCA over the last 24 hours of the 2-week course (312-336 h). Following the paper, the exposure AUC is the sildenafil AUC plus half the DMS AUC, and the Cmax target is attained when the sildenafil Cmax is between 47 and 373 ng/mL.
ss <- solve_arms(bind_rows(lapply(seq_along(dose_levels), function(i) {
make_arm(dose_levels[i], n_dose = 56L,
obs_times = c(0, seq(312, 336, by = 0.25)), id_offset = 1000L * i)
}))) |>
mutate(treatment = factor(treatment, levels = paste(dose_levels, "mg/kg")))
ss_long <- ss |>
select(id, treatment, time, Cc, Cc_ndmsil) |>
pivot_longer(c(Cc, Cc_ndmsil), names_to = "analyte", values_to = "conc") |>
filter(!is.na(conc))
dose_df <- ss |>
distinct(id, treatment, WT) |>
mutate(
time = 0,
amt = as.numeric(sub(" mg/kg", "", as.character(treatment))) * WT
) |>
select(id, treatment, time, amt)
nca_ss <- PKNCA::pk.nca(PKNCA::PKNCAdata(
PKNCA::PKNCAconc(ss_long, conc ~ time | treatment + analyte + id),
PKNCA::PKNCAdose(dose_df, amt ~ time | treatment + id),
intervals = data.frame(start = 312, end = 336, cmax = TRUE, auclast = TRUE)
))
exposure <- as.data.frame(nca_ss) |>
filter(PPTESTCD %in% c("cmax", "auclast")) |>
select(id, treatment, analyte, PPTESTCD, PPORRES) |>
pivot_wider(names_from = c(PPTESTCD, analyte), values_from = PPORRES) |>
mutate(
cmax = cmax_Cc,
auc_combined = auclast_Cc + 0.5 * auclast_Cc_ndmsil
)
exposure |>
select(treatment, `Cmax (ng/mL)` = cmax, `AUC (ng*h/mL)` = auc_combined) |>
pivot_longer(-treatment) |>
ggplot(aes(treatment, value)) +
geom_boxplot(outlier.size = 0.6) +
geom_hline(
data = tibble(
name = c(rep("Cmax (ng/mL)", 3), "AUC (ng*h/mL)"),
ref = c(47, 140, 373, 2650)
),
aes(yintercept = ref), linetype = "dashed", colour = "grey50"
) +
facet_wrap(~name, scales = "free_y") +
labs(
x = "Dose", y = NULL,
caption = paste0(
"Replicates Figure 5 of Rhee 2022\n",
"(steady-state Cmax and combined AUC over 24 h)."
)
) +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
The published medians below were digitised by the maintainers from the box plots of Figure 5 (about +/- 5 ng/mL for Cmax and +/- 100 ng*h/mL for AUC).
published_fig5 <- tibble(
treatment = paste(dose_levels, "mg/kg"),
cmax = c(32, 48, 64, 78, 99, 115, 131),
auclast = c(850, 1220, 1630, 2070, 2520, 2930, 3410)
)
sim_fig5 <- exposure |>
transmute(treatment = as.character(treatment), cmax, auclast = auc_combined) |>
pivot_longer(c(cmax, auclast), names_to = "PPTESTCD", values_to = "PPORRES")
cmp <- nlmixr2lib::ncaComparisonTable(
simulated = sim_fig5,
reference = published_fig5,
by = "treatment",
units = c(cmax = "ng/mL", auclast = "ng*h/mL"),
tolerance_pct = 20
)
knitr::kable(
cmp,
caption = paste(
"Median steady-state sildenafil Cmax and combined AUC (sildenafil + 0.5 x DMS,",
"24 h) versus Figure 5 of Rhee 2022. * differs from reference by >20%."
)
)| NCA parameter | treatment | Reference | Simulated | % diff |
|---|---|---|---|---|
| Cmax (ng/mL) | 0.5 mg/kg | 32 | 31.9 | -0.4% |
| Cmax (ng/mL) | 0.75 mg/kg | 48 | 47.8 | -0.4% |
| Cmax (ng/mL) | 1 mg/kg | 64 | 63.8 | -0.4% |
| Cmax (ng/mL) | 1.25 mg/kg | 78 | 79.7 | +2.2% |
| Cmax (ng/mL) | 1.5 mg/kg | 99 | 95.6 | -3.4% |
| Cmax (ng/mL) | 1.75 mg/kg | 115 | 112 | -3.0% |
| Cmax (ng/mL) | 2 mg/kg | 131 | 128 | -2.7% |
| AUClast (ng*h/mL) | 0.5 mg/kg | 850 | 872 | +2.6% |
| AUClast (ng*h/mL) | 0.75 mg/kg | 1220 | 1310 | +7.3% |
| AUClast (ng*h/mL) | 1 mg/kg | 1630 | 1740 | +7.0% |
| AUClast (ng*h/mL) | 1.25 mg/kg | 2070 | 2180 | +5.4% |
| AUClast (ng*h/mL) | 1.5 mg/kg | 2520 | 2620 | +3.9% |
| AUClast (ng*h/mL) | 1.75 mg/kg | 2930 | 3050 | +4.2% |
| AUClast (ng*h/mL) | 2 mg/kg | 3410 | 3490 | +2.3% |
published_fig6 <- tibble(
treatment = paste(dose_levels, "mg/kg"),
cmax_pub = c(26.5, 51.5, 69, 80.5, 87, 90.5, 91.5),
auc_pub = c(1, 7.5, 19.5, 33.5, 47, 58.3, 69)
)
attain <- exposure |>
group_by(treatment) |>
summarise(
cmax_sim = 100 * mean(cmax >= 47 & cmax <= 373),
auc_sim = 100 * mean(auc_combined > 2650),
.groups = "drop"
) |>
mutate(treatment = as.character(treatment)) |>
left_join(published_fig6, by = "treatment")
attain |>
select(treatment, cmax_pub, cmax_sim, auc_pub, auc_sim) |>
rename(
"Dose" = treatment,
"Cmax target, paper (%)" = cmax_pub,
"Cmax target, simulated (%)" = cmax_sim,
"AUC target, paper (%)" = auc_pub,
"AUC target, simulated (%)" = auc_sim
) |>
knitr::kable(
digits = 1,
caption = paste(
"Percentage of infants reaching the Cmax (47-373 ng/mL) and AUC",
"(> 2650 ng*h/mL) targets. Paper values were digitised by the",
"maintainers from Figure 6 (1.75 mg/kg AUC value quoted in the text)."
)
)| Dose | Cmax target, paper (%) | Cmax target, simulated (%) | AUC target, paper (%) | AUC target, simulated (%) |
|---|---|---|---|---|
| 0.5 mg/kg | 26.5 | 26.0 | 1.0 | 1.0 |
| 0.75 mg/kg | 51.5 | 50.5 | 7.5 | 7.5 |
| 1 mg/kg | 69.0 | 67.5 | 19.5 | 19.5 |
| 1.25 mg/kg | 80.5 | 80.5 | 33.5 | 33.5 |
| 1.5 mg/kg | 87.0 | 90.5 | 47.0 | 49.5 |
| 1.75 mg/kg | 90.5 | 92.0 | 58.3 | 61.0 |
| 2 mg/kg | 91.5 | 93.5 | 69.0 | 69.5 |
fig5_cmp <- exposure |>
group_by(treatment) |>
summarise(cmax = median(cmax), auc = median(auc_combined), .groups = "drop") |>
mutate(treatment = as.character(treatment)) |>
left_join(published_fig5, by = "treatment") |>
mutate(
cmax_pct = 100 * (cmax.x / cmax.y - 1),
auc_pct = 100 * (auc / auclast - 1)
)
# The cohort is deterministic (R's RNG, moment-matched etas, omega = NA), so
# these values do not move between machines or rxode2 builds. Realised:
# median Cmax -0.4%, median AUC +4.2%, worst attainment differences 3.5
# (Cmax) and 2.7 (AUC) points. A 10% error in sildenafil CL/F, or a wrong
# molecular-weight ratio or unit factor, breaks the median bounds. The
# attainment bounds are there to catch a gross change in the between-subject
# spread; they cannot separate the two plausible IIV scales (see
# Assumptions and deviations).
stopifnot(
abs(median(fig5_cmp$cmax_pct)) < 5,
abs(median(fig5_cmp$auc_pct)) < 10,
max(abs(attain$cmax_sim - attain$cmax_pub)) < 7,
max(abs(attain$auc_sim - attain$auc_pub)) < 7
)Assumptions and deviations
-
IIV scale. Table 2 reports the between-subject
variability only as %CV for exponential random effects. The variances
use the exact log-normal relation
omega^2 = log(1 + CV^2). The alternative reading (omega^2 = CV^2) gives a much larger variance for V/F (2.06 versus 1.12), because that CV is 143.7%. In a closed-form check by the maintainers (20000 infants, weight uniform on 0.8-4.2 kg), the exact reading reproduced the Figure 6 Cmax attainment better (mean absolute difference about 1.3 percentage points versus about 1.9; worst case 2.3 versus 3.2 points). The evidence is modest, because only the V/F variability differs much between the two readings; the exact relation is also the library’s usual convention. -
Correlations. Table 2 reports correlation
coefficients between the three etas. The covariances in the model are
cov = r * omega_i * omega_j. - Reference weight. The covariate equations in Table 2 normalise body weight to 3.14 kg, while Table 1 reports a median of 3.18 kg. The model uses 3.14 kg, the value printed in the equations.
- Units. The paper fitted the model in micromoles and nmol/L. The packaged model doses in mg and returns ng/mL; see the ‘Model and source’ section for why the two are equivalent.
-
Residual error. The paper used an additive error on
log-transformed concentrations, coded here as
lnorm()with the Table 2 SDs. The validation above uses individual predictions without residual error. - Virtual-cohort weight distribution. The paper gives only the 0.8-4.2 kg range for its simulated infants; weights evenly spaced over that range are used.
- Exposure versus Figures 5 and 6. In this 200-infant cohort the median Cmax is -3 to +2% and the median combined AUC +2 to +7% different from the values digitised from Figure 5, in line with a closed-form check by the maintainers with 20000 infants (-1 to +5% for Cmax, +3 to +8% for AUC). The small, consistent AUC excess is therefore not cohort noise; it may come from NCA settings the paper does not describe (for example the AUC method or which 24 h it used), or from the digitisation. The target attainment percentages follow from the same exposures and differ from Figure 6 by at most 3.5 (Cmax) and 2.7 (AUC) percentage points.
-
Covariates screened but not retained. Sex
(theta_female = 1.78 on sildenafil CL/F) and postnatal-age maturation
(theta = 4.28) were in the full model but not the final one.
Postmenstrual age was significant but dropped in favour of body weight,
with which it was strongly correlated (r = 0.803). These and the other
screened covariates are listed in
covariatesDataExcluded. - No erratum or correction notice for this article was found as of 2026-10-01.