diff --git a/NAMESPACE b/NAMESPACE index 59639e896..79aa958f8 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -8,7 +8,6 @@ S3method(StructuredVector,StructuredVector) S3method(StructuredVector,data.frame) S3method(StructuredVector,numeric) S3method(TMBTV,RBFArg) -S3method(TMBTV,TVArg) S3method(TMBTV,character) S3method(TMBTraj,"function") S3method(TMBTraj,TrajArg) @@ -38,6 +37,8 @@ S3method(length,StructuredVector) S3method(macpan2::TMBPar,ParArg) S3method(macpan2::TMBPar,character) S3method(macpan2::TMBPar,list) +S3method(macpan2::TMBTV,TVArg) +S3method(macpan2::TMBTV,list) S3method(mp_default,TMBCalibrator) S3method(mp_default,TMBModelSpec) S3method(mp_default,TMBSimulator) @@ -109,6 +110,8 @@ S3method(mp_tmb_fixef_cov,TMBCalibrator) S3method(mp_tmb_fixef_cov,TMBSimulator) S3method(mp_tmb_objective,TMBCalibrator) S3method(mp_tmb_objective,TMBSimulator) +S3method(mp_tmb_profile,TMBCalibrator) +S3method(mp_tmb_profile,TMBSimulator) S3method(mp_tmb_test,TMBModelSpec) S3method(mp_tmbstan_coef,TMBCalibrator) S3method(mp_tmbstan_coef,TMBSimulator) @@ -295,6 +298,7 @@ export(mp_print_before) export(mp_print_during) export(mp_print_spec) export(mp_rbf) +export(mp_rbf_exper) export(mp_read_rds) export(mp_reduce) export(mp_reference) @@ -334,6 +338,7 @@ export(mp_tmb_insert_trans) export(mp_tmb_library) export(mp_tmb_model_spec) export(mp_tmb_objective) +export(mp_tmb_profile) export(mp_tmb_update) export(mp_tmbstan_coef) export(mp_traj) diff --git a/R/calibrator_arg_constructors.R b/R/calibrator_arg_constructors.R index eded8e91a..757f982ab 100644 --- a/R/calibrator_arg_constructors.R +++ b/R/calibrator_arg_constructors.R @@ -11,7 +11,10 @@ #' effects. #' @concept create-model-calibrator-args #' @export -mp_par = function(params, random) { +mp_par = function( + params = empty_named_list() + , random = empty_named_list() + ) { arg = list() arg$params = params arg$random = random @@ -22,9 +25,17 @@ mp_par = function(params, random) { #' @param parameters List of time-variation specifications for parameters. #' @noRd -mp_tv = function(parameters) { +mp_tv = function( + params = empty_named_list() + , random = empty_named_list() + , known = empty_named_list() + , linear = empty_named_list() + ) { arg = list() - arg$parameters = parameters + arg$params = params + arg$random = random + arg$known = known + arg$linear = linear structure(arg, class = "TVArg") } @@ -74,6 +85,16 @@ mp_rbf = function(tv, dimension, initial_weights, seed, prior_sd = 1, fit_prior_ structure(arg, class = "RBFArg") } +#' @export +mp_rbf_exper = function(dimension + , initial_weights + , seed + , prior_sd = 1 + , fit_prior_sd = TRUE + , sparse_tol = 1e-2) { + mp_rbf("", dimension, initial_weights, seed, prior_sd, fit_prior_sd, sparse_tol) +} + mp_piecewise = function(tv, data) { arg = list() diff --git a/R/distributions.R b/R/distributions.R index 5f2ef9680..7e39dbfbe 100644 --- a/R/distributions.R +++ b/R/distributions.R @@ -335,6 +335,7 @@ DistrList = function(distr_list = list(), model_spec = mp_tmb_model_spec()) { nms = names(obj[[mth]]()) for (i in seq_along(nms)) self$distr_list[[nms[i]]]$update_variable_name(tv_nms[i]) } + # section 2: distributional parameters that need to be added as ## _new_ defaults to model spec to be updated by calibration machinery @@ -674,9 +675,14 @@ mp_normal = function(location = mp_distr_param_null("location") #' @description * Log-Normal Distribution - `mp_log_normal` #' @name distribution #' @export -mp_log_normal = function(location = mp_distr_param_null("location") - , sd - , trans_distr_param = list(location = mp_identity, sd = mp_identity)) { +mp_log_normal = function( + location = mp_distr_param_null("location") + , sd + , trans_distr_param = list( + location = mp_identity + , sd = mp_identity + ) + ) { self = DistrSpec( distr_param_objs = nlist(location, sd) # identity transformations because distributional parameters are already @@ -689,6 +695,7 @@ mp_log_normal = function(location = mp_distr_param_null("location") , par , self$distr_param_objs$location$expr_ref() , self$distr_param_objs$sd$expr_ref() + #, par ) } self$likelihood = \(obs, sim) { @@ -696,6 +703,7 @@ mp_log_normal = function(location = mp_distr_param_null("location") , obs , sim , self$distr_param_objs$sd$expr_ref() + #, obs ) } self$check_variable = function(variable) { @@ -723,17 +731,19 @@ mp_logit_normal = function(location = mp_distr_param_null("location") ) self$prior = \(par) { - sprintf("-sum(dnorm(log(%s) - log(1 - %s), %s, %s))" + sprintf("-sum(dnorm(log(%s) - log(1 - %s), %s, %s) / (%s * (1 - %s)))" , par, par , self$distr_param_objs$location$expr_ref() , self$distr_param_objs$sd$expr_ref() + , par, par ) } self$likelihood = \(obs, sim) { - sprintf("-sum(dnorm(log(%s) - log(1 - %s), log(%s) - log(1 - %s), %s))" + sprintf("-sum(dnorm(log(%s) - log(1 - %s), log(%s) - log(1 - %s), %s) / (%s * (1 - %s)))" , obs, obs , sim, sim , self$distr_param_objs$sd$expr_ref() + , obs, obs ) } self$check_variable = function(variable) { @@ -930,7 +940,7 @@ to_distr_param.character = function(x) mp_nofit(x) #' @noRd mp_poisson2 = function(location) { self = DistrSpec() - self$distr_params = \() list() + self$distr_params = \() empty_named_list() self$expr_char = \(x, location) sprintf("-sum(dpois(%s, %s))", x, location) return_object(self, "Poisson") } diff --git a/R/frame_utils.R b/R/frame_utils.R index c7ed22e02..5607cd881 100644 --- a/R/frame_utils.R +++ b/R/frame_utils.R @@ -74,9 +74,6 @@ bind_rows <- function(..., .id = NULL) { y }) } - - # some_rows = function(x) isTRUE(nrow(x) != 0L) - # lsts <- Filter() nms <- unique(unlist(lapply(lsts, names))) lsts <- lapply( lsts, diff --git a/R/lists.R b/R/lists.R index ce5de0bc7..f5b6552b5 100644 --- a/R/lists.R +++ b/R/lists.R @@ -157,3 +157,4 @@ simplify_row_col_ids = function(data_frame) { if (identical(uc, "0")) data_frame$col = character(nrow(data_frame)) return(data_frame) } + diff --git a/R/mp_cal_time.R b/R/mp_cal_time.R index 2094493e3..a81d63090 100644 --- a/R/mp_cal_time.R +++ b/R/mp_cal_time.R @@ -30,31 +30,44 @@ mp_sim_bounds = function(sim_start, sim_end, time_scale = "steps", time_column = self$sim_end = sim_end self$time_scale = time_scale self$time_column = time_column - self$extend = function(steps_to_extend) { - new_obj = mp_sim_offset( - self$sim_start_offset - , self$sim_end_offset + steps_to_extend - , self$time_scale - , self$time_column - ) - return(new_obj) - } +# <<<<<<< HEAD self$cal_time_steps = function(data, original_coercer = force) { column = data[[self$time_column]] - check_valid_time_scales(self$time_scale) - constr = get_time_constructor(self$time_scale) - if (length(column) == 0L) { - dat_start = self$sim_start - dat_end = self$sim_end - } else { - dat_start = min(column) - dat_end = max(column) - } + dat_start = min(column) + dat_end = max(column) + ## TODO: check type consistency + constr = switch(self$time_scale + , steps = CalTimeStepsInt + , daily = CalTimeStepsDaily + ) +# ======= +# self$extend = function(steps_to_extend) { +# new_obj = mp_sim_offset( +# self$sim_start_offset +# , self$sim_end_offset + steps_to_extend +# , self$time_scale +# , self$time_column +# ) +# return(new_obj) +# } +# self$cal_time_steps = function(data, original_coercer = force) { +# column = data[[self$time_column]] +# check_valid_time_scales(self$time_scale) +# constr = get_time_constructor(self$time_scale) +# if (length(column) == 0L) { +# dat_start = self$sim_start +# dat_end = self$sim_end +# } else { +# dat_start = min(column) +# dat_end = max(column) +# } +# >>>>>>> main constr(self$sim_start, self$sim_end, dat_start, dat_end, original_coercer) } return_object(self, "SimBounds") } + #' Simulation Offsets #' #' Offset the starting and ending times of the simulation, from the @@ -102,6 +115,11 @@ mp_sim_offset = function(sim_start_offset, sim_end_offset, time_scale = "steps", } sim_start = dat_start - self$sim_start_offset sim_end = dat_end + self$sim_end_offset + ## TODO: check type consistency + constr = switch(self$time_scale + , steps = CalTimeStepsInt + , daily = CalTimeStepsDaily + ) constr(sim_start, sim_end, dat_start, dat_end, original_coercer) } return_object(self, "SimOffset") diff --git a/R/mp_tmb_calibrator.R b/R/mp_tmb_calibrator.R index eb5ba6e48..694ecd485 100644 --- a/R/mp_tmb_calibrator.R +++ b/R/mp_tmb_calibrator.R @@ -259,6 +259,7 @@ print.TMBCalibrator = function(x, ...) { } } + #' Optimize Simulation Model #' #' Calibrate a model that has been parameterized, typically by using @@ -484,12 +485,28 @@ TMBCalDataStruc = function(data, time) { , col = c("col", "Col", "column", "Column") , value = c("value", "Value", "val", "Val", "default", "Default") ) - time_column_test_value = data$time +# <<<<<<< HEAD if (is.character(data$time)) { original_coercer = as.character } else if (is.integer(data$time)) { - if (inherits(data$time, "Date")) { - original_coercer = as.Date + original_coercer = as.integer + } else if (inherits(data$time, "Date")) { + original_coercer = as.Date + } else { + original_coercer = force + } + if (is.null(time)) { + if (infer_time_step(data$time)) { + data$time = as.integer(data$time) + time = mp_sim_bounds(min(data$time), max(data$time), "steps") +# ======= +# time_column_test_value = data$time +# if (is.character(data$time)) { +# original_coercer = as.character +# } else if (is.integer(data$time)) { +# if (inherits(data$time, "Date")) { +# original_coercer = as.Date +# >>>>>>> main } else { original_coercer = as.integer } @@ -512,7 +529,10 @@ TMBCalDataStruc = function(data, time) { } } self$time_steps_obj = time$cal_time_steps(data, original_coercer) - self$time_steps_obj$conversion_check(time_column_test_value) +#<<<<<<< HEAD +#======= +# self$time_steps_obj$conversion_check(time_column_test_value) +# >>>>>>> main data$time_ids = self$time_steps_obj$external_to_internal(data$time) ## TODO: Still splitting on matrices, which doesn't allow flexibility ## in what counts as an 'output'. In general, an output could be @@ -773,6 +793,23 @@ NameHandlerAbstract = function() { unlist(self$global_names(), recursive = TRUE, use.names = FALSE) ) } + self$global_names_subset = function(model_vars) { + + ## list of character vectors. each element of this list + ## corresponds to a method that returns a named vector. + ## the names of these vectors have local and global + ## forms. the character vectors in this gnms list + ## are the global forms of these names. + gnms = self$global_names() + mths = names(gnms) + + for (mth in mths) { + model_vars_mth = names(self[[mth]]()) + i = model_vars_mth %in% model_vars + gnms[[mth]] = setNames(gnms[[mth]][i], model_vars_mth[i]) + } + return(gnms) + } ## check_assumptions has no return value. while running ## it is allowed to throw messages, warnings, errors, @@ -877,6 +914,9 @@ TMBTVAbstract = function() { self$tv_params_frame = function(tv_pars) self$empty_params_frame self$tv_random_frame = function() self$empty_params_frame + self$tv_distr_params = function() list() + self$tv_distr_random = function() list() + self$local_names = function() { make_names_list(self @@ -932,6 +972,316 @@ TMBTV = function(tv, struc, spec, existing_global_names = character()) { UseMethod("TMBTV") } + +#' @exportS3Method macpan2::TMBTV +TMBTV.list = function(tv + , struc, spec + , existing_global_names = character() + ) { + TMBTV( + mp_tv(params = tv, random = list(), known = list(), linear = list()) + , struc, spec + , existing_global_names + ) +} + +#' @exportS3Method macpan2::TMBTV +TMBTV.TVArg = function(tv + , struc, spec + , existing_global_names = character() + ) { + self = macpan2:::TMBTVAbstract() + self$tv = tv + self$struc = struc + self$spec = spec + self$existing_global_names = existing_global_names + + fix_tv_list = function(tv_list) { + for (p in names(tv_list)) { + tv_list[[p]] = macpan2:::rename_synonyms(tv_list[[p]] + , mat = c("matrix", "Matrix", "mat", "Mat", "variable", "var", "Variable", "Var") + , row = c("row", "Row") + , col = c("col", "Col", "column", "Column") + , default = c("value", "Value", "val", "Val", "default", "Default") + ) + if (isTRUE(!any(tv_list[[p]]$time_ids == 0))) { + ## if the data do not define what value to + ## give at time-id zero, then look for the + ## default value of the parameter that is + ## being converted to a time-varying parameter + ## at calibration time. + baseline = self$spec$default[[p]] + if (is.null(baseline)) { + stop("Baseline value not specified for time-varying parameter, ", p) + } + tv_list[[p]] = macpan2:::add_row(tv_list[[p]] + , mat = p + , row = 0L + , col = 0L + , time_ids = 0L + , default = baseline + ) + } + } + return(tv_list) + } + + # self$data_time_ids = struc$time_steps_obj$dat_vec() + # self$par_name = tv$tv + # self$prior_sd_default = tv$prior_sd + # self$fit_prior_sd = tv$fit_prior_sd + + fix_linear_list = function(sm_list) { + for (nm in names(sm_list)) { + sm_list[[nm]]$tv = nm + sm_list[[nm]]$sparse_basis_data = macpan2:::sparse_rbf_notation( + struc$time_steps_obj$dat_len() + , sm_list[[nm]]$dimension + , zero_based = TRUE + , tol = sm_list[[nm]]$sparse_tol + ) + sm_list[[nm]]$initial_outputs = c(sm_list[[nm]]$sparse_basis_data$M %*% sm_list[[nm]]$initial_weights) + } + return(sm_list) + } + + # internal data structure + self$pnms = names(self$tv$params) + self$rnms = names(self$tv$random) + self$knms = names(self$tv$known) + self$lnms = names(self$tv$linear) + + # local name utility: return list of outputs of self$global_names, + # organized by the type of time-varying variable + self$global_names_by_tv_type = function() { + list( + params = self$global_names_subset(self$pnms) + , random = self$global_names_subset(self$rnms) + , known = self$global_names_subset(self$knms) + , linear = self$global_names_subset(self$lnms) + ) + } + + self$anms = c(self$pnms, self$rnms, self$knms, self$lnms) + dups = duplicated(self$anms) + if (any(dups)) stop("duplicates: ", unique(self$anms[dups])) + + self$ptv_list = struc$matrix_list[self$pnms] |> fix_tv_list() + self$rtv_list = struc$matrix_list[self$rnms] |> fix_tv_list() + self$ktv_list = struc$matrix_list[self$knms] |> fix_tv_list() + self$ltv_list = self$tv$linear |> fix_linear_list() + + self$time_var = function() { + l = list() + for (nm in self$pnms) l[[nm]] = self$ptv_list[[nm]]$default + for (nm in self$rnms) l[[nm]] = self$rtv_list[[nm]]$default + for (nm in self$knms) l[[nm]] = self$ktv_list[[nm]]$default + for (nm in self$lnms) l[[nm]] = self$ltv_list[[nm]]$initial_weights + return(l) + } + + self$change_points = function() { + l = list() + for (nm in self$pnms) l[[nm]] = self$ptv_list[[nm]]$time_ids + for (nm in self$rnms) l[[nm]] = self$rtv_list[[nm]]$time_ids + for (nm in self$knms) l[[nm]] = self$ktv_list[[nm]]$time_ids + return(l) + } + + self$change_pointer = function() { + ## Depended upon to return a list of length-one + ## integer vectors with a single zero. Names of + ## the list are the time-varying matrices in the + ## spec. + nms = names(self$change_points()) + (nms + |> macpan2:::zero_vector() + |> as.integer() + |> as.list() + |> setNames(nms) + ) + } + + self$values_var = function() { + l = list() + for (nm in self$lnms) l[[nm]] = self$ltv_list[[nm]]$sparse_basis_data$values + return(l) + } + + self$prior_sd = function() { + l = list() + for (nm in self$lnms) l[[nm]] = self$ltv_list[[nm]]$prior_sd + return(l) + } + + self$row_indexes = function() { + l = list() + for (nm in self$lnms) { + l[[nm]] = as.integer(self$ltv_list[[nm]]$sparse_basis_data$row_index) + } + return(l) + } + + self$col_indexes = function() { + l = list() + for (nm in self$lnms) { + l[[nm]] = as.integer(self$ltv_list[[nm]]$sparse_basis_data$col_index) + } + return(l) + } + + self$outputs_var = function() { + l = list() + for (nm in self$lnms) l[[nm]] = self$ltv_list[[nm]]$initial_outputs + return(l) + } + + self$data_time_indexes = function() { + l = list() + for (nm in self$lnms) { + l[[nm]] = as.integer(c(0, self$struc$time_steps_obj$dat_vec())) + } + return(l) + } + + self$var_update_exprs = function() { + nms = self$global_names_by_tv_type() + s = character() + s = c(s, sprintf("%s ~ time_var(%s, %s)" + , self$pnms + , nms$params$time_var + , nms$params$change_points + )) + s = c(s, sprintf("%s ~ time_var(%s, %s)" + , self$rnms + , nms$random$time_var + , nms$random$change_points + )) + s = c(s, sprintf("%s ~ time_var(%s, %s)" + , self$knms + , nms$known$time_var + , nms$known$change_points + )) + s = c(s, sprintf("%s ~ exp(time_var(%s, %s))" + , self$lnms + , nms$linear$outputs_var + , nms$linear$data_time_indexes + )) + lapply(s, as.formula) + } + + self$prior_expr_chars = function() { + nms = self$global_names_by_tv_type() + s = character() + s = c(s, sprintf( + "-sum(dnorm(%s, 0, %s))" + , nms$linear$values_var, nms$linear$prior_sd + )) + for (i in seq_along(self$pnms)) { + nm = self$pnms[i] + pp = self$tv$params$distr_list[[nm]] + s = c(s, pp$prior(nm)) + } + for (i in seq_along(self$rnms)) { + nm = self$rnms[i] + pp = self$tv$random$distr_list[[nm]] + s = c(s, pp$prior(nm)) + } + return(s) + } + + self$.util_params_frame = function(gnms) { + + ## default values of the variables that are + ## time varying, indexed using the 'model + ## names' (see below) + time_var = self$time_var() + + ## model names: names of the variables that are + ## time varying as they are represented in the model + ## (e.g., beta) + mnms = names(gnms) + + l = list() + for (nm in mnms) { + l[[nm]] = data.frame( + mat = gnms[[nm]] + , row = seq_along(time_var[[nm]]) - 1L + , col = 0L + , default = time_var[[nm]] + ) + } + + if (length(l) == 0L) { + cols = c("mat", "row", "col", "default") + frame = empty_frame(cols) + } else { + frame = bind_rows(l) + } + return(frame) + } + + self$tv_params_frame = function(tv_pars) { + ## global names: names of the variables that + ## are time varying as they are represented + ## as vectors giving how they vary in time + ## during calibration + ## (e.g., time_var_beta) + gnms = self$global_names_by_tv_type() + nms = c(gnms$params$time_var, gnms$linear$time_var) + d = self$.util_params_frame(nms) + linear = self$tv$linear + for (nms in names(linear)) { + p = linear[[nms]] + if (p$fit_prior_sd) { + d_prior = data.frame( + mat = gnms$linear$prior_sd[[nms]] + , row = 0L + , col = 0L + , default = p$prior_sd + ) + d = rbind(d, d_prior) + } + } + return(d) + } + + self$tv_random_frame = function() { + ## global names: names of the variables that + ## are time varying as they are represented + ## as vectors giving how they vary in time + ## during calibration + ## (e.g., time_var_beta) + gnms = self$global_names_by_tv_type() + gnms = c(gnms$random$time_var) + self$.util_params_frame(gnms) + } + + self$before_loop = function() { + nms = self$global_names_by_tv_type()$linear + s = sprintf("%s ~ group_sums(%s * %s[%s], %s, %s)" + , nms$outputs_var, nms$values_var, nms$time_var + , nms$col_indexes, nms$row_indexes, nms$outputs_var + ) + s2 = sprintf("%s ~ c(%s[0], %s)" + , nms$outputs_var, nms$outputs_var, nms$outputs_var + ) + as.list(c(lapply(s, as.formula), lapply(s2, as.formula))) + } + + #self$tv_distr_params = function() self$tv$params$default() + #self$tv_distr_random = function() self$tv$random$default() + + self$tv$params = macpan2:::DistrList(self$tv$params, spec) + self$tv$random = macpan2:::DistrList(self$tv$random, spec) + self$tv$params$update_global_names(self, "tv_distr_params") + self$tv$random$update_global_names(self, "tv_distr_random") + self$tv$params$error_if_not_all_have_location() + self$tv$random$error_if_not_all_have_location() + + return_object(self, "TMBTV") +} + #' @export TMBTV.character = function( tv @@ -994,7 +1344,7 @@ TMBTV.character = function( ## Depended upon to return a list of length-one ## integer vectors with a single zero. Names of ## the list are the time-varying matrices in the - ## spec. + ## spec. nms = names(self$change_points()) (nms |> zero_vector() @@ -1037,45 +1387,45 @@ TMBTV.character = function( return_object(self, "TMBTV") } -#' @export -TMBTV.TVArg = function( - tv - , struc - , spec - , existing_global_names = character() -) { - self = TMBTVAbstract() - self$existing_global_names = existing_global_names - self$spec = spec - - self$before_loop = function() list() - self$after_loop = function() list() - - ## List with the values of each - ## time varying parameter at the change points. The - ## names of the list are the time-varying matrices - ## in the spec. - self$time_var = function() list() - - ## List of the integers - ## giving the time-steps of the changepoints with - ## the first time-step always being 0 (the initial) - ## The names of the list are the time-varying - ## matrices in the spec. - self$change_points = function() list() - self$change_pointer = function() list() - - ## List of expressions that update parameters that - ## are time-varying - self$var_update_exprs = function() list() - - ## data frames describing the fixed and random effects corresponding - ## to time-varying parameters - self$tv_params_frame = function(tv_pars) self$empty_params_frame - self$tv_random_frame = function() self$empty_params_frame - - return_object(self, "TMBTV") -} + +#' TMBTV.TVArg = function( +#' tv +#' , struc +#' , spec +#' , existing_global_names = character() +#' ) { +#' self = TMBTVAbstract() +#' self$existing_global_names = existing_global_names +#' self$spec = spec +#' +#' self$before_loop = function() list() +#' self$after_loop = function() list() +#' +#' ## List with the values of each +#' ## time varying parameter at the change points. The +#' ## names of the list are the time-varying matrices +#' ## in the spec. +#' self$time_var = function() list() +#' +#' ## List of the integers +#' ## giving the time-steps of the changepoints with +#' ## the first time-step always being 0 (the initial) +#' ## The names of the list are the time-varying +#' ## matrices in the spec. +#' self$change_points = function() list() +#' self$change_pointer = function() list() +#' +#' ## List of expressions that update parameters that +#' ## are time-varying +#' self$var_update_exprs = function() list() +#' +#' ## data frames describing the fixed and random effects corresponding +#' ## to time-varying parameters +#' self$tv_params_frame = function(tv_pars) self$empty_params_frame +#' self$tv_random_frame = function() self$empty_params_frame +#' +#' return_object(self, "TMBTV") +#' } #' @export TMBTV.RBFArg = function( @@ -1487,43 +1837,113 @@ TMBPar.ParArg = function(par , tv, traj, spec , existing_global_names = character() ) { + self = TMBParAbstract() + self$existing_global_names = existing_global_names + self$par = par + self$tv = tv + self$traj = traj + self$spec = spec par$params = assert_distributional_component(par$params) par$random = assert_distributional_component(par$random) self = TMBPar(names(par$params), tv, traj, spec, existing_global_names) - self$par_ranef = names(par$random) + # internal data structure + self$pnms = names(self$par$params) + self$rnms = names(self$par$random) - self$distr_params = function() self$arg$params$default() - self$distr_random = function() self$arg$random$default() - - self$random_frame = function() { - pf = (self$spec$default[self$par_ranef] - |> melt_default_matrix_list(FALSE) - |> rename_synonyms(mat = "matrix", default = "value") - ) - bind_rows(pf, self$tv$tv_random_frame()) +#<<<<<<< HEAD + self$local_names = function() { + macpan2:::make_names_list(self, c("trans_vars", "hyperparams", "distr_params")) } + ## make distr + self$par$params = macpan2:::DistrList(self$par$params, spec) + self$par$random = macpan2:::DistrList(self$par$random, spec) + self$prior_expr_chars = function() { - # union to get both parameters and - # time-varying pars we are estimating - par_nms = union(self$par, self$tv_par) y = character() - for (i in seq_along(par_nms)) { - nm = par_nms[i] - pp = self$arg$params$distr_list[[nm]] + for (i in seq_along(self$pnms)) { + nm = self$pnms[i] + pp = self$par$params$distr_list[[nm]] y = c(y, pp$prior(nm)) } - for (i in seq_along(self$par_ranef)) { - nm = self$par_ranef[i] - pp = self$arg$random$distr_list[[nm]] + for (i in seq_along(self$rnms)) { + nm = self$rnms[i] + pp = self$par$random$distr_list[[nm]] y = c(y, pp$prior(nm)) } - y + return(y) + } + + self$params_frame = function() { + pf = (self$spec$default[self$pnms] +# ======= +# self$distr_params = function() self$arg$params$default() +# self$distr_random = function() self$arg$random$default() +# +# self$random_frame = function() { +# pf = (self$spec$default[self$par_ranef] +# >>>>>>> main + |> melt_default_matrix_list(FALSE) + |> rename_synonyms(mat = "matrix", default = "value") + ) + if (is.null(pf)) pf = self$empty_params_frame + bind_rows(pf + , self$traj$distr_params_frame() + , self$distr_params_frame() + #, self$tv_distr_params_frame() + ) } + self$random_frame = function() { + pf = (self$spec$default[self$rnms] + |> melt_default_matrix_list(FALSE) + |> rename_synonyms(mat = "matrix", default = "value") + ) + if (is.null(pf)) pf = self$empty_params_frame + bind_rows(pf + ## do we need tv params here? + ) + } + +#<<<<<<< HEAD + self$distr_params = function() self$par$params$default() # self$tv$params$default() + self$distr_random = function() self$par$random$default() + self$distr_params_frame = function() self$par$params$distr_params_frame() + self$distr_random_frame = function() self$par$random$distr_params_frame() + + self$par$params$update_global_names(self, "distr_params") + self$par$random$update_global_names(self, "distr_random") + self$par$params$error_if_not_all_have_location() + self$par$random$error_if_not_all_have_location() + self$check_assumptions_basic = function(orig_spec, data_struc) { + pnms = c(self$pnms, self$rnms) # union(self$par, self$tv_par) + bad_pars = !pnms %in% names(orig_spec$default) + if (any(bad_pars)) { + spec_mats = names(orig_spec$all_matrices()) + sprintf("%s (including %s) %s:\n %s%s%s" + , "Requested parameters and/or random effects" + , paste0(pnms[bad_pars], collapse = ", ") + , "are either not available in the model spec, which includes the following" + , paste(spec_mats, collapse = ", ") + , "\nor cannot be fit because they are not default model parameters. See " + , "mp_default(spec) for all default model parameters." + ) |> stop() +# ======= +# self$prior_expr_chars = function() { +# # union to get both parameters and +# # time-varying pars we are estimating +# par_nms = union(self$par, self$tv_par) +# y = character() +# for (i in seq_along(par_nms)) { +# nm = par_nms[i] +# pp = self$arg$params$distr_list[[nm]] +# y = c(y, pp$prior(nm)) +# >>>>>>> main + } + } self$distr_params_frame = function() self$arg$params$distr_params_frame() self$distr_random_frame = function() self$arg$random$distr_params_frame() @@ -1535,12 +1955,16 @@ TMBPar.ParArg = function(par self$arg$random$update_global_names(self, "distr_random") self$arg$params$error_if_not_all_have_location() self$arg$random$error_if_not_all_have_location() - + self$check_assumptions = function(orig_spec, data_struc) { self$check_assumptions_basic(orig_spec, data_struc) - self$arg$params$check_variables(data_struc$matrix_list) - for (p in self$par) { - self$arg$params$distr_list[[p]]$check_args(self$arg$params$distr_list[[p]]$distr_param_objs) + self$par$params$check_variables(data_struc$matrix_list) + self$par$random$check_variables(data_struc$matrix_list) + for (p in self$pnms) { + self$par$params$distr_list[[p]]$check_args(self$par$params$distr_list[[p]]$distr_param_objs) + } + for (p in self$rnms) { + self$par$random$distr_list[[p]]$check_args(self$par$random$distr_list[[p]]$distr_param_objs) } NULL } @@ -1572,8 +1996,8 @@ TMBPar.character = function(par ## internal data structure tv_names = self$tv$time_var() |> names() - self$par = setdiff(par, tv_names) - self$tv_par = intersect(par, tv_names) + self$par = par # setdiff(par, tv_names) + self$tv_par = tv_names # intersect(par, tv_names) self$local_names = function() { make_names_list(self, c("trans_vars", "hyperparams", "distr_params")) @@ -1587,12 +2011,13 @@ TMBPar.character = function(par , self$tv$tv_params_frame(self$tv_par) , self$traj$distr_params_frame() , self$distr_params_frame() + ## need a self$tv$distr_params_frame() ) } self$random_frame = function() self$tv$tv_random_frame() self$check_assumptions_basic = function(orig_spec, data_struc) { - pnms = union(self$par, self$tv_par) + pnms = self$par # union(self$par, self$tv_par) bad_pars = !pnms %in% names(orig_spec$default) if (any(bad_pars)) { spec_mats = names(orig_spec$all_matrices()) diff --git a/R/mp_tmb_model_spec.R b/R/mp_tmb_model_spec.R index 66960efc6..188084af3 100644 --- a/R/mp_tmb_model_spec.R +++ b/R/mp_tmb_model_spec.R @@ -414,7 +414,7 @@ spec_printer = function(x, include_defaults) { "Discover more about model specifications here:\n" , "https://canmod.github.io/macpan2/reference#specifications \n" ) - # cat(more_help) + cat(more_help) } #' Print Model Specification diff --git a/inst/starter_models/macpan_base/README.R b/inst/starter_models/macpan_base/README.R index b503f8275..6650ab4a2 100644 --- a/inst/starter_models/macpan_base/README.R +++ b/inst/starter_models/macpan_base/README.R @@ -2,7 +2,9 @@ knitr::opts_chunk$set( collapse = TRUE, comment = "#>", - fig.path = "./figures/" + fig.path = "./figures/", + message = FALSE, + warning = FALSE ) round_coef_tab = function(x, digits = 4) { id_cols = c("term", "mat", "row", "col", "type") @@ -24,6 +26,10 @@ library(ggplot2) library(dplyr) +## ----options------------------------------------------------------------------ +options(macpan2_verbose = FALSE) + + ## ----model_lib---------------------------------------------------------------- spec = mp_tmb_library( "starter_models" @@ -37,3 +43,305 @@ system.file("utils", "box-drawing.R", package = "macpan2") |> source() layout = mp_layout_paths(spec, x_gap = 0.1, y_gap = 0.1) plot_flow_diagram(layout) + +## ----get_data----------------------------------------------------------------- +ts_data = ("https://github.com/canmod/macpan2" + |> file.path("releases/download/macpan1.5_data/covid_on.RDS") + |> url() + |> readRDS() +) + + +## ----prep_ts------------------------------------------------------------------ +prepped_ts_data = (ts_data + |> rename(matrix = var) + # dates from base model calibration (Figure 4) + |> filter(date >= "2020-02-24" & date < "2020-08-31") + # create unique time identifier + |> arrange(date) + |> group_by(date) + |> mutate(time = cur_group_id()) + |> ungroup() + # one negative value for daily deaths (removing for now time==178) + # this explains negative values: + # https://github.com/ccodwg/Covid19Canada?tab=readme-ov-file#datasets + |> filter(matrix %in% c("death","report") & value >= 0) +) + + +## ----prep_mob----------------------------------------------------------------- +prepped_mobility_data = (ts_data + |> filter(var == "mobility_index") + # dates from base model calibration (Figure 4) + |> filter(date >= "2020-02-24" & date < "2020-08-31") + # create unique time identifier + |> arrange(date) + |> group_by(date) + |> mutate(time = cur_group_id()) + |> ungroup() + |> mutate(log_mobility_ind = log(value)) +) + + +## ----mob_breaks--------------------------------------------------------------- +mobility_breaks = (prepped_ts_data + |> filter(date %in% c("2020-04-01", "2020-08-07"), matrix == "report") + |> pull(time) +) + + +## ----time_steps--------------------------------------------------------------- +time_steps = nrow(prepped_ts_data %>% select(date) %>% unique()) +prepped_ts_data = select(prepped_ts_data, -date) + + +## ----mobility_matrix---------------------------------------------------------- +S_j = function(t, tau_j, s) 1/(1 + exp((t - tau_j) / s)) +X = cbind( + prepped_mobility_data$log_mobility_ind + , S_j(1:time_steps, mobility_breaks[1], 3) + , S_j(1:time_steps, mobility_breaks[1], 3) * prepped_mobility_data$log_mobility_ind + , S_j(1:time_steps, mobility_breaks[2], 3) + , S_j(1:time_steps, mobility_breaks[2], 3) * prepped_mobility_data$log_mobility_ind + ) %>% as.matrix() +X_sparse = macpan2:::sparse_matrix_notation(X, TRUE) +model_matrix_values = X_sparse$values +row_ind = X_sparse$row_index +col_ind = X_sparse$col_index + + +## ----focal_model-------------------------------------------------------------- +focal_model = (spec + # add variable transformations: + |> mp_tmb_insert(phase = "before" + , at = 1L + , expressions = list( + zeta ~ exp(log_zeta) + , beta0 ~ exp(log_beta0) + , nonhosp_mort ~ 1/(1+exp((-logit_nonhosp_mort))) + , E ~ exp(log_E) + ) + , default = list( + log_zeta = empty_matrix + , log_beta0 = empty_matrix + , logit_nonhosp_mort = empty_matrix + , log_E = empty_matrix + ) + + ) + + # add accumulator variables: + # death - new deaths each time step + |> mp_tmb_insert(phase = "during" + , at = Inf + , expressions = list(death ~ ICUd.D + Is.D) + ) + + # add phenomenological heterogeneity: + |> mp_tmb_update(phase = "during" + , at = 1L + , expressions = list( + mp_per_capita_flow( + "S", "E" + , "((S/N)^zeta) * (beta / N) * (Ia * Ca + Ip * Cp + Im * Cm * (1 - iso_m) + Is * Cs *(1 - iso_s))" + , "S.E" + )) + + ) + + # compute gamma-density delay kernel for convolution: + |> mp_tmb_insert_reports("S.E" + , report_prob = 0.1 + , mean_delay = 11 + , cv_delay = 0.25 + , reports_name = "report" + ) + + # add time-varying transmission with mobility data: + |> mp_tmb_insert(phase = "before" + , at = Inf + , expressions = list(relative_beta_values ~ group_sums(model_matrix_values * log_mobility_coefficients[col_ind], row_ind, model_matrix_values)) + , default = list(log_mobility_coefficients = empty_matrix, model_matrix_values = empty_matrix) + , integers = list(row_ind = row_ind, col_ind = col_ind) + ) + |> mp_tmb_insert(phase = "during" + , at = 1L + , expressions = list( + beta ~ exp(log_beta0 + relative_beta_values[time_step(1)]) + ) + ) + +) + + +## ----calibrator--------------------------------------------------------------- +focal_calib = mp_tmb_calibrator( + spec = focal_model |> mp_rk4() + , data = prepped_ts_data + , traj = c("report","death") + , par = c( + "log_zeta" + , "log_beta0" + , "logit_nonhosp_mort" + , "log_mobility_coefficients" + , "log_E" + # negative binomial dispersion parameters for reports and deaths get added + # automatically with options(macpan2_default_loss = "neg_bin") set above + ) + , outputs = c("death","report") + , default = list( + + # states + # Population of Ontario (2019) from: + # https://github.com/mac-theobio/macpan_base/blob/main/code/ontario_calibrate_comb.R + S = 14.57e6 - 5 + , log_E = log(5) + , Ia = 0 + , Ip = 0 + , Im = 0 + , Is = 0 + , R = 0 + , H = 0 + , ICUs = 0 + , ICUd = 0 + , H2 = 0 + , D = 0 + + , model_matrix_values = model_matrix_values + + # set initial parameter values for optimizer + + , log_beta0 = log(5) + , logit_nonhosp_mort = -0.5 + , log_mobility_coefficients = rep(0, 5) + , log_zeta = 1 + + ) +) +# converges +mp_optimize(focal_calib) + + +## ----get_trajectory----------------------------------------------------------- +fitted_data = mp_trajectory_sd(focal_calib, conf.int = TRUE) + + +## ----coefficients------------------------------------------------------------- +mp_tmb_coef(focal_calib, conf.int = TRUE) |> round_coef_tab() + + +## ----plot_fit----------------------------------------------------------------- +(ggplot(prepped_ts_data, aes(time,value)) + + geom_point() + + geom_line(aes(time, value) + , data = fitted_data |> filter(matrix %in% c("death","report")) + , colour = "red" + ) + + geom_ribbon(aes(time, ymin = conf.low, ymax = conf.high) + , data = fitted_data |> filter(matrix %in% c("death","report")) + , alpha = 0.2 + , colour = "red" + ) + + facet_wrap(vars(matrix),scales = 'free') + + theme_bw() +) + + +## ----cohort_model------------------------------------------------------------- +cohort_model_ph = ( + focal_model + %>% mp_tmb_update(phase="during" + , at = 2L + , expressions = list(S.E ~ (S^zeta) * (beta / (N^(zeta) * N_cohort)) * (Ia * Ca + Ip * Cp + Im * Cm * (1 - iso_m) + Is * Cs *(1 - iso_s))) + , default = list(S.E = 0)) +) + + +## ----simulate_cohort---------------------------------------------------------- +cohort_sim_ph = (mp_simulator(cohort_model_ph + , time_steps = 100L + , outputs = "S.E" + , default = list( + S = 14.57e6 - 1 + , log_E = log(1) + , Ia = 0 + , Ip = 0 + , Im = 0 + , Is = 0 + , R = 0 + , H = 0 + , ICUs = 0 + , ICUd = 0 + , H2 = 0 + , D = 0 + , N_cohort = 1 + , model_matrix_values = model_matrix_values + , qmax = 34 + , log_beta0=log(1) + , logit_nonhosp_mort = -0.5 + , log_mobility_coefficients = rep(0,5) + , log_zeta = 1 + ) + ) |> mp_trajectory() +) + + +## ----R0----------------------------------------------------------------------- +R0_ph = sum(cohort_sim_ph$value) +print(R0_ph) + + +## ----cohort_no_ph------------------------------------------------------------- +cohort_model = (focal_model + %>% mp_tmb_update(phase="during" + , at = 2L + , expressions = list(mp_per_capita_flow( + "S", "E" + , "(beta / N) * (Ia * Ca + Ip * Cp + Im * Cm * (1 - iso_m) + Is * Cs * (1 - iso_s))" + , "S.E" + ) + )) + %>% mp_tmb_insert(phase="during" + , at = Inf + , expressions = list(foi ~ (beta / N) * (Ia * Ca + Ip * Cp + Im * Cm * (1 - iso_m) + Is * Cs *(1 - iso_s))) + ) +) + +cohort_sim = (mp_simulator(cohort_model + , time_steps = 100L + , outputs = "foi" + , default = list( + S = 0 + , log_E = log(1) + , Ia = 0 + , Ip = 0 + , Im = 0 + , Is = 0 + , R = 0 + , H = 0 + , ICUs = 0 + , ICUd = 0 + , H2 = 0 + , D = 0 + , N = 1 + , model_matrix_values = model_matrix_values + , qmax = 34 + , log_beta0=log(1) + , logit_nonhosp_mort = -0.5 + , log_mobility_coefficients = rep(0,5) + , log_zeta = 1) # not actually used + ) |> mp_trajectory() +) + +R0 = sum(cohort_sim$value) +print(R0) + + +## ----check_R0----------------------------------------------------------------- +all.equal(R0_ph, R0) + + +## ----euler_lotka-------------------------------------------------------------- +euler_lotka = function(r) sum(cohort_sim$value * exp(-r * cohort_sim$time)) - 1 +uniroot(euler_lotka, c(0,10)) + diff --git a/inst/starter_models/shiver/README.R b/inst/starter_models/shiver/README.R index 07c14232a..fe616b20f 100644 --- a/inst/starter_models/shiver/README.R +++ b/inst/starter_models/shiver/README.R @@ -466,21 +466,36 @@ dd = rbind(reported_hospitalizations, reported_cases) # calibrate shiver_calibrator = mp_tmb_calibrator( +<<<<<<< HEAD + spec = (multi_traj_spec + |> mp_hazard() + ) +======= spec = mp_hazard(multi_traj_spec) +>>>>>>> main # row bind both observed data , data = dd # fit both trajectories with log-normal distributions # (changed from negative binomial because apparently it is easier # to fit standard deviations than dispersion parameters) +<<<<<<< HEAD + , traj = list(H = mp_log_normal(sd = mp_fit(1)) + , reported_incidence = mp_log_normal(sd = mp_fit(1)) +======= , traj = list( H = mp_normal(sd = mp_fit(1)) , reported_incidence = mp_normal(sd = mp_fit(1)) +>>>>>>> main ) , par = prior_distributions # fit the transmission rate using five radial basis functions for # a flexible model of time variation. , tv = mp_rbf("rbf_beta", 5, sparse_tol = 1e-8) +<<<<<<< HEAD + , outputs = c(states, "reported_incidence", "beta") +======= , outputs = c(mp_state_vars(spec), "reported_incidence", "beta") +>>>>>>> main ) diff --git a/inst/starter_models/shiver/README.Rmd b/inst/starter_models/shiver/README.Rmd index 86158d8ab..2bd091cc0 100644 --- a/inst/starter_models/shiver/README.Rmd +++ b/inst/starter_models/shiver/README.Rmd @@ -742,4 +742,3 @@ We are able to recover the transmission rate `beta` but not the proportion `p`, This model has been specified in the `shiver` directory [here](https://github.com/canmod/macpan2/blob/main/inst/starter_models/shiver/tmb.R) and is accessible from the `macpan2` model library (see [Example Models](https://canmod.github.io/macpan2/articles/example_models.html) for details). # References - diff --git a/inst/starter_models/shiver/README.md b/inst/starter_models/shiver/README.md index 2bd088274..a67947051 100644 --- a/inst/starter_models/shiver/README.md +++ b/inst/starter_models/shiver/README.md @@ -2,37 +2,25 @@ SHIVER = SEIR + H + V ================ Jennifer Freeman, Steve Walker -- Packages Used and Settings -- Model - Specification -- States -- Parameters -- Variable Vaccination Rate -- Dynamics -- Calibration - Example - - Calibration Scenario - - Deciding - on Defaults - - Simulating - Dynamics - - Estimating Parameters - - Re-parameterizing - and Introducing Transformations - - Runge-Kutta 4 - - Fitting to Multiple - Trajectories - - Parameter Identifiability -- Model - Specification -- References +- [Packages Used and Settings](#packages-used-and-settings) +- [Model Specification](#model-specification) +- [States](#states) +- [Parameters](#parameters) +- [Variable Vaccination Rate](#variable-vaccination-rate) +- [Dynamics](#dynamics) +- [Calibration Example](#calibration-example) + - [Calibration Scenario](#calibration-scenario) + - [Deciding on Defaults](#deciding-on-defaults) + - [Simulating Dynamics](#simulating-dynamics) + - [Estimating Parameters](#estimating-parameters) + - [Re-parameterizing and Introducing + Transformations](#re-parameterizing-and-introducing-transformations) + - [Runge-Kutta 4](#runge-kutta-4) + - [Fitting to Multiple + Trajectories](#fitting-to-multiple-trajectories) + - [Parameter Identifiability](#parameter-identifiability) +- [Model Specification](#model-specification-1) +- [References](#references) This model builds on the basic SEIR model, with two additional compartments for vaccination and hospitalizations. @@ -115,22 +103,22 @@ article](https://github.com/canmod/macpan2/blob/main/inst/starter_models/shiver/ | E | Number of exposed individuals | | R | Number of recovered individuals | -The size of the total population is, $N = S + H + I + V + E + R$, and +The size of the total population is, $N = S + H + I + V + E + R$, and the disease spreads through homogeneous mixing of the subpopulation $N_{\text{mix}}=N -H$. # Parameters -| variable | description | -|------------|-----------------------------------------------------------------------------------------------------| -| $\phi$ | per capita vaccination rate of susceptibles | -| $\rho$ | per capita vaccine waning rate | -| $\beta_S$ | per capita transmission rate for susceptibles (in $N_{\text{mix}}$ population) | -| $\beta_V$ | per capita transmission rate for vaccinated individuals (in $N_{\text{mix}}$ population) | -| $\alpha$ | per capita infection rate (average time spent in compartment $E$ is $1/\alpha$) | -| $\gamma_I$ | per capita recovery rate for infected individuals | -| $\gamma_H$ | per capita recovery rate for hospitalized individuals | -| $\sigma$ | per capita rate at which infected individuals develop severe infections and require hospitalization | +| variable | description | +|----|----| +| $\phi$ | per capita vaccination rate of susceptibles | +| $\rho$ | per capita vaccine waning rate | +| $\beta_S$ | per capita transmission rate for susceptibles (in $N_{\text{mix}}$ population) | +| $\beta_V$ | per capita transmission rate for vaccinated individuals (in $N_{\text{mix}}$ population) | +| $\alpha$ | per capita infection rate (average time spent in compartment $E$ is $1/\alpha$) | +| $\gamma_I$ | per capita recovery rate for infected individuals | +| $\gamma_H$ | per capita recovery rate for hospitalized individuals | +| $\sigma$ | per capita rate at which infected individuals develop severe infections and require hospitalization | # Variable Vaccination Rate @@ -882,6 +870,47 @@ shiver_calibrator = mp_tmb_calibrator( Next we optimize, and look at our estimates. +<<<<<<< HEAD + #> mat row default estimate std.error + #> 1 time_var_rbf_beta 1 0.0000 -0.0236 0.0262 + #> 2 time_var_rbf_beta 2 0.0000 0.0292 0.0250 + #> 3 time_var_rbf_beta 3 0.0000 -0.0283 0.0249 + #> 4 time_var_rbf_beta 4 0.0000 0.0286 0.0247 + #> 5 prior_sd_rbf_beta 0 1.0000 0.5297 0.0177 + #> 6 distr_params_sd_H 0 1.0000 0.0757 0.0089 + #> 7 distr_params_sd_reported_incidence 0 1.0000 0.2221 0.0185 + #> 8 time_var_rbf_beta 0 0.0000 -0.0305 0.0257 + #> 9 beta 0 0.0100 0.3136 0.0362 + #> 10 sigma 0 0.0498 0.0341 0.0104 + #> 11 gamma_h 0 0.0498 0.9937 0.1872 + #> 12 E_I_ratio 0 0.0100 0.0880 0.1034 + #> 13 I 0 2718.5714 2948.4429 839.7054 + #> 14 H 0 63.0000 0.1378 2.8151 + #> 15 R 0 1.0000 1.0000 54.5980 + #> 16 report_prob 0 0.5000 0.8340 0.1891 + #> 17 p 0 0.0100 0.2354 9.6937 + #> conf.low conf.high + #> 1 -0.0750 2.780000e-02 + #> 2 -0.0197 7.810000e-02 + #> 3 -0.0771 2.060000e-02 + #> 4 -0.0198 7.710000e-02 + #> 5 0.4951 5.643000e-01 + #> 6 0.0582 9.330000e-02 + #> 7 0.1859 2.584000e-01 + #> 8 -0.0808 1.980000e-02 + #> 9 0.2500 3.933000e-01 + #> 10 0.0188 6.200000e-02 + #> 11 0.6870 1.437400e+00 + #> 12 0.0088 8.801000e-01 + #> 13 1687.2279 5.152425e+03 + #> 14 0.0000 3.347001e+16 + #> 15 0.0000 2.978521e+46 + #> 16 0.2568 9.865000e-01 + #> 17 0.0000 1.000000e+00 + +Our prior for `sigma` is similar to the posterior, but `gamma_h` seems +to have been pushed up by the data from about `0.05` to about 0.99. We +======= #> mat row default estimate std.error #> 1 time_var_rbf_beta 2 0.000 0.0146 0.0056 #> 2 time_var_rbf_beta 3 0.000 -0.0099 0.0111 @@ -919,6 +948,7 @@ Next we optimize, and look at our estimates. Our prior for `sigma` is similar to the posterior, but `gamma_h` seems to have been pushed up by the data from about `0.05` to about 2.06. We +>>>>>>> main still do not have confidence in our estimate of `p`. We now have five other parameters controlling transmission, and so to interpret them we really need a plot of how transmission varies over time in the model. We @@ -1050,7 +1080,10 @@ for details). # References -