diff --git a/R/LongitudinalClaretBruno.R b/R/LongitudinalClaretBruno.R index a0a987c6..8ebabe0f 100755 --- a/R/LongitudinalClaretBruno.R +++ b/R/LongitudinalClaretBruno.R @@ -77,10 +77,10 @@ LongitudinalClaretBruno <- function( Parameter(name = "lm_clbr_mu_c", prior = mu_c, size = "n_arms"), Parameter(name = "lm_clbr_mu_p", prior = mu_p, size = "n_arms"), - Parameter(name = "lm_clbr_omega_b", prior = omega_b, size = 1), - Parameter(name = "lm_clbr_omega_g", prior = omega_g, size = 1), - Parameter(name = "lm_clbr_omega_c", prior = omega_c, size = 1), - Parameter(name = "lm_clbr_omega_p", prior = omega_p, size = 1), + Parameter(name = "lm_clbr_omega_b", prior = omega_b, size = "n_studies"), + Parameter(name = "lm_clbr_omega_g", prior = omega_g, size = "n_arms"), + Parameter(name = "lm_clbr_omega_c", prior = omega_c, size = "n_arms"), + Parameter(name = "lm_clbr_omega_p", prior = omega_p, size = "n_arms"), Parameter(name = "lm_clbr_sigma", prior = sigma, size = 1) ) diff --git a/R/SimLongitudinalClaretBruno.R b/R/SimLongitudinalClaretBruno.R index 7c949c34..7c64d456 100644 --- a/R/SimLongitudinalClaretBruno.R +++ b/R/SimLongitudinalClaretBruno.R @@ -81,6 +81,12 @@ SimLongitudinalClaretBruno <- function( link_identity = 0, link_growth = 0 ) { + + if (length(omega_b) == 1) omega_b <- rep(omega_b, length(mu_b)) + if (length(omega_g) == 1) omega_g <- rep(omega_g, length(mu_g)) + if (length(omega_c) == 1) omega_c <- rep(omega_c, length(mu_c)) + if (length(omega_p) == 1) omega_p <- rep(omega_p, length(mu_p)) + .SimLongitudinalClaretBruno( times = times, sigma = sigma, @@ -111,8 +117,23 @@ setValidity( if (length(unique(par_lengths)) != 1) { return("The parameters `mu_g`, `mu_c` & `mu_p` must have the same length.") } + pairs <- list( + "omega_b" = "mu_b", + "omega_g" = "mu_g", + "omega_c" = "mu_c", + "omega_p" = "mu_p" + ) + for (i in seq_along(pairs)) { + omega <- slot(object, names(pairs)[[i]]) + mu <- slot(object, pairs[[i]]) + if (!(length(omega) == length(mu))) { + return( + sprintf("`%s` must be length 1 or the same length as `%s`", omega, mu) + ) + } + } len_1_pars <- c( - "sigma", "omega_b", "omega_g", "omega_c", "omega_p", + "sigma", "link_dsld", "link_ttg", "link_identity", "link_growth" ) @@ -164,10 +185,26 @@ sampleSubjects.SimLongitudinalClaretBruno <- function(object, subjects_df) { dplyr::distinct(.data$subject, .data$arm, .data$study) |> dplyr::mutate(study_idx = as.numeric(.data$study)) |> dplyr::mutate(arm_idx = as.numeric(.data$arm)) |> - dplyr::mutate(ind_b = stats::rlnorm(dplyr::n(), object@mu_b[.data$study_idx], object@omega_b)) |> - dplyr::mutate(ind_g = stats::rlnorm(dplyr::n(), object@mu_g[.data$arm_idx], object@omega_g)) |> - dplyr::mutate(ind_c = stats::rlnorm(dplyr::n(), object@mu_c[.data$arm_idx], object@omega_c)) |> - dplyr::mutate(ind_p = stats::rlnorm(dplyr::n(), object@mu_p[.data$arm_idx], object@omega_p)) + dplyr::mutate(ind_b = stats::rlnorm( + dplyr::n(), + object@mu_b[.data$study_idx], + object@omega_b[.data$study_idx] + )) |> + dplyr::mutate(ind_g = stats::rlnorm( + dplyr::n(), + object@mu_g[.data$arm_idx], + object@omega_g[.data$arm_idx] + )) |> + dplyr::mutate(ind_c = stats::rlnorm( + dplyr::n(), + object@mu_c[.data$arm_idx], + object@omega_c[.data$arm_idx] + )) |> + dplyr::mutate(ind_p = stats::rlnorm( + dplyr::n(), + object@mu_p[.data$arm_idx], + object@omega_p[.data$arm_idx] + )) res[, c("subject", "arm", "study", "ind_b", "ind_g", "ind_c", "ind_p")] } diff --git a/inst/stan/lm-claret-bruno/model.stan b/inst/stan/lm-claret-bruno/model.stan index 2b8ce625..fbf3fd38 100755 --- a/inst/stan/lm-claret-bruno/model.stan +++ b/inst/stan/lm-claret-bruno/model.stan @@ -12,10 +12,10 @@ parameters{ vector[n_arms] lm_clbr_mu_c; vector[n_arms] lm_clbr_mu_p; - real lm_clbr_omega_b; - real lm_clbr_omega_g; - real lm_clbr_omega_c; - real lm_clbr_omega_p; + vector[n_studies] lm_clbr_omega_b; + vector[n_arms] lm_clbr_omega_g; + vector[n_arms] lm_clbr_omega_c; + vector[n_arms] lm_clbr_omega_p; {% if centred -%} vector[n_subjects] lm_clbr_ind_b; @@ -45,16 +45,16 @@ transformed parameters{ {% if not centred -%} vector[n_subjects] lm_clbr_ind_b = exp( - lm_clbr_mu_b[subject_study_index] + (lm_clbr_eta_b * lm_clbr_omega_b) + lm_clbr_mu_b[subject_study_index] + (lm_clbr_eta_b .* lm_clbr_omega_b[subject_study_index]) ); vector[n_subjects] lm_clbr_ind_g = exp( - lm_clbr_mu_g[subject_arm_index] + (lm_clbr_eta_g * lm_clbr_omega_g) + lm_clbr_mu_g[subject_arm_index] + (lm_clbr_eta_g .* lm_clbr_omega_g[subject_arm_index]) ); vector[n_subjects] lm_clbr_ind_c = exp( - lm_clbr_mu_c[subject_arm_index] + (lm_clbr_eta_c * lm_clbr_omega_c) + lm_clbr_mu_c[subject_arm_index] + (lm_clbr_eta_c .* lm_clbr_omega_c[subject_arm_index]) ); vector[n_subjects] lm_clbr_ind_p = exp( - lm_clbr_mu_p[subject_arm_index] + (lm_clbr_eta_p * lm_clbr_omega_p) + lm_clbr_mu_p[subject_arm_index] + (lm_clbr_eta_p .* lm_clbr_omega_p[subject_arm_index]) ); {%- endif -%} @@ -89,10 +89,10 @@ model { // Source - lm-claret-bruno/model.stan // {% if centred %} - lm_clbr_ind_b ~ lognormal(lm_clbr_mu_b[subject_study_index], lm_clbr_omega_b); - lm_clbr_ind_g ~ lognormal(lm_clbr_mu_g[subject_arm_index], lm_clbr_omega_g); - lm_clbr_ind_c ~ lognormal(lm_clbr_mu_c[subject_arm_index], lm_clbr_omega_c); - lm_clbr_ind_p ~ lognormal(lm_clbr_mu_p[subject_arm_index], lm_clbr_omega_p); + lm_clbr_ind_b ~ lognormal(lm_clbr_mu_b[subject_study_index], lm_clbr_omega_b[subject_study_index]); + lm_clbr_ind_g ~ lognormal(lm_clbr_mu_g[subject_arm_index], lm_clbr_omega_g[subject_arm_index]); + lm_clbr_ind_c ~ lognormal(lm_clbr_mu_c[subject_arm_index], lm_clbr_omega_c[subject_arm_index]); + lm_clbr_ind_p ~ lognormal(lm_clbr_mu_p[subject_arm_index], lm_clbr_omega_p[subject_arm_index]); {%- endif -%} } diff --git a/tests/testthat/test-LongitudinalClaretBruno.R b/tests/testthat/test-LongitudinalClaretBruno.R index 6f576438..7bf4ac04 100644 --- a/tests/testthat/test-LongitudinalClaretBruno.R +++ b/tests/testthat/test-LongitudinalClaretBruno.R @@ -97,10 +97,10 @@ test_that("Can recover known distributional parameters from a SF joint model", { mu_g = log(c(0.9, 1.1)), mu_c = log(c(0.45, 0.35)), mu_p = log(c(2.4, 1.8)), - omega_b = 0.12, - omega_g = 0.12, - omega_c = 0.12, - omega_p = 0.12, + omega_b = 0.1, + omega_g = c(0.3, 0.1), + omega_c = c(0.1, 0.3), + omega_p = c(0.3, 0.1), link_ttg = 0.3, link_dsld = -0.02, link_identity = 0, diff --git a/vignettes/statistical-specification.Rmd b/vignettes/statistical-specification.Rmd index 57101b98..fcfd9910 100644 --- a/vignettes/statistical-specification.Rmd +++ b/vignettes/statistical-specification.Rmd @@ -393,10 +393,10 @@ SLD_{ij} &= b_i \cdot \exp\left(g_i t_{ij} - \frac{p_i}{c_i} \left(1 - e^{-c_i t_{ij} }\right)\right) & \text{if } t_{ij} \geq 0. \end{cases}\\ \\ -b_i &\sim \text{LogNormal}(\mu_{bl(i)}, \omega_b) \\ -g_i &\sim \text{LogNormal}(\mu_{gk(i)}, \omega_g) \\ -c_i &\sim \text{LogNormal}(\mu_{ck(i)}, \omega_c) \\ -p_i &\sim \text{LogNormal}(\mu_{pk(i)}, \omega_p) \\ +b_i &\sim \text{LogNormal}(\mu_{bl(i)}, \omega_{b l(i)}) \\ +g_i &\sim \text{LogNormal}(\mu_{gk(i)}, \omega_{g k(i)}) \\ +c_i &\sim \text{LogNormal}(\mu_{ck(i)}, \omega_{c k(i)}) \\ +p_i &\sim \text{LogNormal}(\mu_{pk(i)}, \omega_{p k(i)}) \\ \end{align*} $$ @@ -414,7 +414,23 @@ Where: * $k(i)$ is the treatment arm index for subject $i$ * $l(i)$ is the study index for subject $i$ * $\mu_{\theta k(i)}$ is the population mean for parameter $\theta$ in group $k(i)$ -* $\omega_{\theta}$ is the population variance for parameter $\theta$. +* $\omega_{\theta k(i)}$ is the population variance for parameter $\theta$ in group $k(i)$ + + +If using the non-centred parameterisation then the following alternative formulation is used: +$$ +\begin{align*} +b_i &= exp(\mu_{b l(i)} + \omega_{b l(i)} * \eta_{b i}) \\ +g_i &= exp(\mu_{g k(i)} + \omega_{g k(i)} * \eta_{g i}) \\ +c_i &= exp(\mu_{c k(i)} + \omega_{c k(i)} * \eta_{c i}) \\ +p_i &= exp(\mu_{p k(i)} + \omega_{p k(i)} * \eta_{p i}) \\ +\\ +\eta_{b i} &\sim N(0, 1)\\ +\eta_{g i} &\sim N(0, 1) \\ +\eta_{c i} &\sim N(0, 1) \\ +\eta_{p i} &\sim N(0, 1) \\ +\end{align*} +$$ ### Derivative of the SLD Trajectory Link