├── .Rbuildignore ├── .gitignore ├── DESCRIPTION ├── LICENCE ├── NAMESPACE ├── NEWS.md ├── R ├── classes-fit.R ├── classes-model.R ├── classes-solver.R ├── classes-standecl.R ├── main-declarations.R ├── main-examples.R ├── main-functions.R ├── main-model.R ├── main-plot.R ├── main-solvers.R ├── odemodeling-package.R ├── utils-create_input.R ├── utils-misc.R ├── utils-stancode.R ├── utils-standecl.R └── zzz.R ├── README.md ├── data-raw └── lynxhare.R ├── data └── lynxhare.rda ├── dev ├── covr.R ├── exports.R ├── lint.R └── style.R ├── inst ├── CITATION └── template_functions.stan ├── man ├── AdaptiveOdeSolver.Rd ├── FixedNumStepsOdeSolver.Rd ├── OdeModel.Rd ├── OdeModelFit.Rd ├── OdeModelGQ.Rd ├── OdeModelMCMC.Rd ├── OdeSolver.Rd ├── StanArray.Rd ├── StanDeclaration.Rd ├── StanDimension.Rd ├── StanMatrix.Rd ├── StanParameter.Rd ├── StanTransformation.Rd ├── StanVariable.Rd ├── StanVector.Rd ├── StanVectorArray.Rd ├── compare_odefits.Rd ├── example_ode_model.Rd ├── lynxhare.Rd ├── ode_model.Rd ├── odemodeling-package.Rd ├── odesolvers.Rd ├── odesolvers_lists.Rd ├── plot_metric.Rd ├── stan_array.Rd ├── stan_dim.Rd ├── stan_matrix.Rd ├── stan_param.Rd ├── stan_transform.Rd ├── stan_var.Rd ├── stan_vector.Rd └── stan_vector_array.Rd ├── odemodeling.Rproj ├── tests ├── testthat.R └── testthat │ ├── test-classes-model.R │ ├── test-main-model.R │ ├── test-main-solvers.R │ ├── test-main_declarations.R │ ├── test-utils-stancode.R │ ├── test-workflow-gsir.R │ ├── test-workflow-lv.R │ └── test-workflow-tmdd.R └── vignettes ├── .gitignore └── tutorial.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | 2 | ^.*\.Rproj$ 3 | ^\.Rproj\.user$ 4 | ^\.travis\.yml$ 5 | ^\_config\.yml$ 6 | ^\.github$ 7 | ^CONTRIBUTING\.md$ 8 | ^NEWS\.md$ 9 | ^_pkgdown\.yml$ 10 | pkgdown/ 11 | dev/ 12 | docs/ 13 | tutorials/ 14 | ^data-raw$ 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # History files 2 | .Rhistory 3 | .Rapp.history 4 | 5 | # Session Data files 6 | .RData 7 | .RDataTmp 8 | 9 | # User-specific files 10 | .Ruserdata 11 | 12 | # Example code in package build process 13 | *-Ex.R 14 | 15 | # Output files from R CMD build 16 | /*.tar.gz 17 | 18 | # Output files from R CMD check 19 | /*.Rcheck/ 20 | 21 | # RStudio files 22 | .Rproj.user/ 23 | 24 | # produced vignettes 25 | vignettes/*.html 26 | vignettes/*.pdf 27 | 28 | # OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3 29 | .httr-oauth 30 | 31 | # knitr and R markdown default cache directories 32 | *_cache/ 33 | /cache/ 34 | 35 | # Temporary files created by R markdown 36 | *.utf8.md 37 | *.knit.md 38 | 39 | # R Environment Variables 40 | .Renviron 41 | 42 | # pkgdown site 43 | docs/ 44 | 45 | # translation temp files 46 | po/*~ 47 | 48 | # RStudio Connect folder 49 | rsconnect/ 50 | inst/doc 51 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: odemodeling 2 | Title: Building, fitting, and validating Bayesian ODE models in 'Stan' 3 | Version: 0.2.3 4 | Authors@R: 5 | person(given = "Juho", 6 | family = "Timonen", 7 | role = c("aut", "cre"), 8 | email = "juho.timonen@iki.fi", 9 | comment = c(ORCID = "0000-0003-2341-6765")) 10 | Description: Building and fitting ordinary differential equation (ODE) 11 | models with different numerical solvers in 'Stan'. Designed for efficient 12 | validation of the accuracy of numerical solvers in the Bayesian context. 13 | Using Pareto-smoothed importance sampling (PSIS) and its diagnostics. 14 | License: BSD_3_clause + file LICENCE 15 | Encoding: UTF-8 16 | LazyData: true 17 | Roxygen: list(markdown = TRUE) 18 | RoxygenNote: 7.3.2 19 | SystemRequirements: CmdStan (https://mc-stan.org/users/interfaces/cmdstan) 20 | Imports: 21 | methods, 22 | abind (>= 1.0), 23 | cmdstanr (>= 0.4.0), 24 | checkmate (>= 2.0.0), 25 | posterior (>= 1.1.0), 26 | R6 (>= 2.4.0), 27 | loo (>= 2.4.1), 28 | bayesplot (>= 1.8.0), 29 | ggplot2 (>= 3.3.5), 30 | processx (>= 3.5.2) 31 | Suggests: 32 | knitr, 33 | rlang (>= 0.4.7), 34 | rmarkdown, 35 | testthat (>= 2.1.0) 36 | VignetteBuilder: knitr 37 | Depends: 38 | R (>= 3.5.0) 39 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021, Juho Timonen 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(OdeModel) 4 | export(OdeModelGQ) 5 | export(OdeModelMCMC) 6 | export(adams) 7 | export(bdf) 8 | export(bdf_list) 9 | export(ckrk) 10 | export(compute_reliability_metrics) 11 | export(euler) 12 | export(example_ode_model) 13 | export(log_ratios) 14 | export(max_abs_loglik_diff) 15 | export(max_abs_odesol_diff) 16 | export(midpoint) 17 | export(midpoint_list) 18 | export(ode_model) 19 | export(plot_mad) 20 | export(plot_metric) 21 | export(plot_pareto_k) 22 | export(plot_r_eff) 23 | export(psis) 24 | export(psis_relative_eff) 25 | export(rk4) 26 | export(rk45) 27 | export(rk45_list) 28 | export(rk4_list) 29 | export(stan_array) 30 | export(stan_dim) 31 | export(stan_matrix) 32 | export(stan_param) 33 | export(stan_transform) 34 | export(stan_var) 35 | export(stan_vector) 36 | export(stan_vector_array) 37 | import(R6) 38 | import(ggplot2) 39 | importFrom(methods,is) 40 | importFrom(utils,capture.output) 41 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # Version 0.2 2 | 3 | ## odemodeling 0.2.2 4 | * Improves documentation. 5 | * Exports `example_ode_model()`. 6 | 7 | ## odemodeling 0.2.0 8 | * Adds the `$diagnose()` method for the `OdeModel` class. 9 | * Stores the results of `diagnose` and `stansummary`in the 10 | `OdeModelMCMC` class instances. 11 | 12 | # Version 0.1 13 | 14 | ## odemodeling 0.1.0 15 | 16 | * Exposes the `$reliability()` method for the `OdeModelMCMC` class. Adds a 17 | `recompute_loglik` argument for it. 18 | * Improves the tutorial vignette. 19 | * A feature that is still missing is ability to create 20 | `stan_transform`s 21 | that both depend on the ODE solution AND have effect on model likelihood. 22 | This is because transformed parameters block is created so that 23 | the ODE solution is always second last and log likelihood last. 24 | 25 | # Early development versions 26 | 27 | ## odemodeling 0.0.22 28 | * Fixes the order of transformed parameters so that the ODE solution is 29 | always second last and log likelihood last. 30 | 31 | ## odemodeling 0.0.21 32 | * Fix a bug in `plot_r_eff()` which plotted the wrong metric. 33 | 34 | ## odemodeling 0.0.20 35 | * Edits the `$reliability()` method for the `OdeModelMCMC` class so that 36 | it only ever compares `OdeModelGQ` objects due to possible 37 | i/o information loss. 38 | 39 | ## odemodeling 0.0.19 40 | * Only internal improvements in tests. 41 | 42 | ## odemodeling 0.0.18 43 | * Adds `plot_metric()` and other plotting functions. 44 | 45 | ## odemodeling 0.0.17 46 | * Removes accidentally duplicated code and improves test coverage. 47 | 48 | ## odemodeling 0.0.16 49 | * Fixes the output of the `$sample_manyconf()` method of `OdeModel` class. 50 | * Adds the `compute_reliability_metrics()` function. 51 | * Adds an initial version of the `$reliability()` method for the 52 | `OdeModelMCMC` class. 53 | 54 | ## odemodeling 0.0.15 55 | * Adds more result extraction and plotting methods for `OdeModelFit`s. 56 | * Makes it easier to extract initial state `y0` always in the same format, 57 | no matter if it is a parameter, data, or transformation. 58 | 59 | ## odemodeling 0.0.14 60 | * Includes `lynxhare` data. 61 | * Adds Lotka-Volterra model to example models. 62 | 63 | ## odemodeling 0.0.13 64 | * Renames the `$simulate()` method to `$gqs()` and implement it also for 65 | `OdeModel`. 66 | * Implements the useful `$make_params()` method for `OdeModel`. 67 | 68 | ## odemodeling 0.0.12 69 | * Changes `data vector y0` to `vector y0` in ODE solver function signatures 70 | so it is possible to have initial state be parameter. 71 | * Adds the `name` argument to `example_ode_model()` and adds the `tmdd` 72 | example. 73 | 74 | ## odemodeling 0.0.11 75 | 76 | * Simplifies and makes `stan_param()` and `stan_transform()` less vulnerable 77 | to errors. 78 | * With `ode_model()`, it is now possible to create also a model where 79 | `odefun_vars` and `loglik_vars` are empty lists. 80 | 81 | ## odemodeling 0.0.10 82 | 83 | * Includes `ode_model()` for creating models. 84 | * Includes `stan_var()`, `stan_param()` etc. for model specification. 85 | * Includes `rk45()`, `bdf()`, `midpoint()`, `rk4()` etc. for solver 86 | specification. 87 | * Includes the `OdeModel` and `OdeModelMCMC` and `OdeModelGQ` R6 classes. 88 | * Implements parameter sampling via the `$sample()` method of the 89 | `OdeModel` class. 90 | * Implements generating quantities with possibly different solver or solver 91 | configuration (the `$simulate()` method of `OdeModelMCMC` class) 92 | * Implemented other useful methods of `OdeModelMCMC` and `OdeModelGQ` 93 | classes are for example `$extract_unflattened()`, `$extract_odesol()`, 94 | `$plot_odesol()`, `$dim()` and `$dim_odesol()`. 95 | * Implements some comparison functions between `OdeModelMCMC` and 96 | `OdeModelGQ` objects, such as `log_ratios()`, `psis()`, 97 | `max_abs_odesol_diff()` and `max_abs_loglik_diff()`. 98 | -------------------------------------------------------------------------------- /R/classes-solver.R: -------------------------------------------------------------------------------- 1 | #' An ODE solver (an abstract base class) 2 | #' 3 | #' @field name name of the solver 4 | #' @field stan_number integer that indexes the solver in the Stan code 5 | OdeSolver <- R6::R6Class("OdeSolver", 6 | public = list( 7 | name = NULL, 8 | stan_number = NULL, 9 | 10 | #' @description 11 | #' `OdeSolver` is an abstract class that can't be initialized. 12 | initialize = function() { 13 | stop("OdeSolver is an abstract class that can't be initialized.") 14 | }, 15 | 16 | #' @description 17 | #' Create Stan data fields. 18 | #' @return A list. 19 | standata = function() { 20 | stop("standata() must be overridden by inheriting class!") 21 | }, 22 | 23 | #' @description 24 | #' String description of the solver. 25 | #' @return A string. 26 | to_string = function() { 27 | stop("to_string() must be overridden by inheriting class!") 28 | }, 29 | 30 | #' @description 31 | #' Print info about the object. 32 | print = function() { 33 | cat(self$to_string()) 34 | invisible(self) 35 | } 36 | ) 37 | ) 38 | 39 | #' An ODE solver with adaptive step size 40 | #' 41 | #' @field abs_tol absolute tolerance 42 | #' @field rel_tol relative tolerance 43 | #' @field max_num_steps maximum number of steps 44 | AdaptiveOdeSolver <- R6::R6Class("AdaptiveOdeSolver", 45 | inherit = OdeSolver, 46 | public = list( 47 | abs_tol = NULL, 48 | rel_tol = NULL, 49 | max_num_steps = NULL, 50 | 51 | #' @description 52 | #' Initialize 53 | #' 54 | #' @param name solver name 55 | #' @param abs_tol absolute tolerance 56 | #' @param rel_tol relative tolerance 57 | #' @param max_num_steps maximum number of steps 58 | initialize = function(name, abs_tol, rel_tol, max_num_steps) { 59 | checkmate::assert_number(abs_tol, lower = 0) 60 | checkmate::assert_number(rel_tol, lower = 0) 61 | checkmate::assert_number(max_num_steps) 62 | MAX_INT <- 2^31 - 1 # max int Stan can handle 63 | checkmate::assert_integerish(max_num_steps, lower = 1, upper = MAX_INT) 64 | self$name <- name 65 | self$abs_tol <- abs_tol 66 | self$rel_tol <- rel_tol 67 | self$max_num_steps <- max_num_steps 68 | self$stan_number <- solver_to_num(name) 69 | }, 70 | 71 | #' @description 72 | #' Create Stan data fields. 73 | #' @return A list. 74 | standata = function() { 75 | list( 76 | solver = self$stan_number, 77 | abs_tol = self$abs_tol, 78 | rel_tol = self$rel_tol, 79 | max_num_steps = self$max_num_steps, 80 | num_steps = 1 # dummy 81 | ) 82 | }, 83 | 84 | #' @description 85 | #' String description of the solver. 86 | #' @return A string. 87 | to_string = function() { 88 | paste0( 89 | self$name, "(abs_tol=", number_string(self$abs_tol), ", ", 90 | "rel_tol=", number_string(self$rel_tol), ", ", 91 | "max_num_steps=", number_string(self$max_num_steps), ")" 92 | ) 93 | } 94 | ) 95 | ) 96 | 97 | #' An ODE solver with fixed number of steps 98 | #' 99 | #' @field num_steps maximum number of steps per time point interval 100 | FixedNumStepsOdeSolver <- R6::R6Class("FixedNumStepsOdeSolver", 101 | inherit = OdeSolver, 102 | public = list( 103 | num_steps = NULL, 104 | 105 | #' @description 106 | #' Initialize 107 | #' @param name solver name 108 | #' @param num_steps number of steps per time point interval 109 | initialize = function(name, num_steps) { 110 | checkmate::assert_number(num_steps) 111 | checkmate::assert_integerish(num_steps, lower = 1) 112 | self$name <- name 113 | self$num_steps <- num_steps 114 | self$stan_number <- solver_to_num(name) 115 | }, 116 | 117 | #' @description 118 | #' Create Stan data fields. 119 | #' @return A list. 120 | standata = function() { 121 | list( 122 | solver = self$stan_number, 123 | abs_tol = 1, # dummy 124 | rel_tol = 1, # dummy 125 | max_num_steps = 1, # dummy 126 | num_steps = self$num_steps 127 | ) 128 | }, 129 | 130 | #' @description 131 | #' String description of the solver. 132 | #' @return A string. 133 | to_string = function() { 134 | paste0( 135 | self$name, "(num_steps=", number_string(self$num_steps), ")" 136 | ) 137 | } 138 | ) 139 | ) 140 | -------------------------------------------------------------------------------- /R/main-declarations.R: -------------------------------------------------------------------------------- 1 | #' Create a [StanDimension] object 2 | #' 3 | #' @param name name of the dimension variable 4 | #' @param lower lower bound 5 | #' @param upper upper bound 6 | #' @family Stan variable declaration functions 7 | #' @export 8 | #' @examples 9 | #' N <- stan_dim("N") 10 | #' M <- stan_dim("M", lower = 1, upper = 100) 11 | #' print(N) 12 | #' print(M) 13 | stan_dim <- function(name, lower = NULL, upper = NULL) { 14 | StanDimension$new(name = name, lower = lower, upper = upper) 15 | } 16 | 17 | #' Create a [StanVariable] object. 18 | #' 19 | #' @param name name of the dimension variable 20 | #' @param lower lower bound 21 | #' @param upper upper bound 22 | #' @param type variable type (real or int) 23 | #' @family Stan variable declaration functions 24 | #' @export 25 | #' @examples 26 | #' x <- stan_var("x", type = "real", lower = 0) 27 | #' y <- stan_var("y", type = "int") 28 | #' print(x) 29 | #' print(y) 30 | stan_var <- function(name, type = "real", lower = NULL, upper = NULL) { 31 | StanVariable$new(name = name, type = type, lower = lower, upper = upper) 32 | } 33 | 34 | #' Create a [StanVector] object. 35 | #' 36 | #' @param name name of the vector 37 | #' @param lower lower bound 38 | #' @param upper upper bound 39 | #' @param length length of the vector, must be a [StanDimension] object 40 | #' @family Stan variable declaration functions 41 | #' @export 42 | #' @examples 43 | #' x <- stan_vector("x", length = stan_dim("N", lower = 1), lower = 0) 44 | #' print(x) 45 | stan_vector <- function(name, length, lower = NULL, upper = NULL) { 46 | StanVector$new(name = name, length = length, lower = lower, upper = upper) 47 | } 48 | 49 | #' Create a [StanMatrix] object. 50 | #' 51 | #' @param name name of the matrix 52 | #' @param lower lower bound 53 | #' @param upper upper bound 54 | #' @param nrow number of rows, must be a [StanDimension] object 55 | #' @param ncol number of columns, must be a [StanDimension] object 56 | #' @family Stan variable declaration functions 57 | #' @export 58 | #' @examples 59 | #' N <- stan_dim("N") 60 | #' M <- stan_dim("M", lower = 1, upper = 100) 61 | #' my_mat <- stan_matrix("A", nrow = N, ncol = M, lower = 0, upper = 3.2) 62 | #' print(my_mat) 63 | stan_matrix <- function(name, nrow, ncol, lower = NULL, upper = NULL) { 64 | StanMatrix$new( 65 | name = name, nrow = nrow, ncol = ncol, 66 | lower = lower, upper = upper 67 | ) 68 | } 69 | 70 | #' Create a [StanArray] object. 71 | #' 72 | #' @param name name of the array 73 | #' @param lower lower bound 74 | #' @param upper upper bound 75 | #' @param dims list of array dimensions, must be a list of 76 | #' `StanDimension` objects 77 | #' @param type base type of the array 78 | #' @family Stan variable declaration functions 79 | #' @export 80 | #' @examples 81 | #' N <- stan_dim("N") 82 | #' M <- stan_dim("M") 83 | #' my_arr <- stan_array("A", dims = list(N, N, M), lower = 0, type = "int") 84 | #' print(my_arr) 85 | stan_array <- function(name, dims, type = "real", lower = NULL, upper = NULL) { 86 | StanArray$new( 87 | name = name, dims = dims, type = type, 88 | lower = lower, upper = upper 89 | ) 90 | } 91 | 92 | #' Create a [StanVectorArray] object. 93 | #' 94 | #' @param name name of the vector array 95 | #' @param lower lower bound 96 | #' @param upper upper bound 97 | #' @param dims list of array dimensions, must be a list of 98 | #' [StanDimension] objects 99 | #' @param length length of the vector, must be a [StanDimension] object 100 | #' @family Stan variable declaration functions 101 | #' @export 102 | #' @examples 103 | #' N <- stan_dim("N") 104 | #' D <- stan_dim("D") 105 | #' vec_arr <- stan_vector_array("y", dims = list(N), length = D) 106 | #' print(vec_arr) 107 | stan_vector_array <- function(name, dims, length, lower = NULL, upper = NULL) { 108 | StanVectorArray$new( 109 | name = name, dims = dims, length = length, 110 | lower = lower, upper = upper 111 | ) 112 | } 113 | 114 | #' Create a [StanParameter] object 115 | #' 116 | #' @param decl The Stan variable declaration from which the parameter is 117 | #' created. Must be an object that inherits from [StanDeclaration] and 118 | #' has a real or vector base type. 119 | #' @param prior A string of Stan code that becomes the right-hand side 120 | #' of the sampling statement that is the prior declaration of the parameter. 121 | #' The default is empty string (no prior). 122 | #' @family Stan variable declaration functions 123 | #' @export 124 | #' @examples 125 | #' # Scalar parameter 126 | #' my_par <- stan_param(stan_var("beta"), "normal(0, 1)") 127 | #' print(my_par) 128 | #' 129 | #' # Vector parameter 130 | #' my_vec <- stan_vector("alpha", stan_dim("D"), lower = 0) 131 | #' my_par <- stan_param(my_vec) 132 | #' print(my_par) 133 | stan_param <- function(decl, prior = "") { 134 | StanParameter$new(decl = decl, prior = prior) 135 | } 136 | 137 | 138 | #' Create a [StanTransformation] object 139 | #' 140 | #' @param decl The Stan variable declaration for the quantity. 141 | #' Must be an object that inherits from [StanDeclaration]. 142 | #' @param origin Must be either `"data"`, `"parameters"`, or `"model"`. 143 | #' These correspond to the `transformed data`, `transformed parameters`, and 144 | #' `generated quantities` blocks, respectively. 145 | #' @param code A string of Stan code that defines how the quantity is 146 | #' computed from other variables/parameters. 147 | #' The default is empty string (no definition). If `code` 148 | #' doesn't include any assignments (with `=`), it is prepended 149 | #' with `paste0(decl$name, " = ")`. In this case also a semicolon is 150 | #' added to the end if it is missing. 151 | #' @family Stan variable declaration functions 152 | #' @export 153 | #' @examples 154 | #' N <- stan_dim("N") 155 | #' D <- stan_dim("D") 156 | #' decl <- stan_array("y", dims = list(N, D), type = "int") 157 | #' code <- " 158 | #' for(n in 1:N) { 159 | #' for(d in 1:D) { 160 | #' y[n, d] ~ poisson_rng(0.2); 161 | #' } 162 | #' }" 163 | #' y <- stan_transform(decl, code = code) 164 | #' print(y) 165 | stan_transform <- function(decl, origin = "model", code = "") { 166 | StanTransformation$new(decl = decl, origin = origin, code = code) 167 | } 168 | -------------------------------------------------------------------------------- /R/main-examples.R: -------------------------------------------------------------------------------- 1 | #' Create an example ODE model 2 | #' 3 | #' @param prior_only Create a prior-only version of the model? 4 | #' @param ... Additional arguments to [ode_model()]. 5 | #' @param name Name of model. Must be one of the following: 6 | #' \itemize{ 7 | #' \item `"gsir"` - age-stratified SIR model 8 | #' \item `"tmdd"` - target-mediated drug transmission model 9 | #' \item `"lv"` - Lotka-Volterra model 10 | #' } 11 | #' @return An object of class `OdeModel`. 12 | #' @export 13 | #' @family model constructor functions 14 | example_ode_model <- function(name, prior_only = FALSE, ...) { 15 | choices <- c("gsir", "tmdd", "lv") 16 | checkmate::assert_string(name) 17 | checkmate::assert_choice(name, choices) 18 | if (name == "gsir") { 19 | m <- example_ode_model_gsir(prior_only, ...) 20 | } else if (name == "tmdd") { 21 | m <- example_ode_model_tmdd(prior_only, ...) 22 | } else if (name == "lv") { 23 | m <- example_ode_model_lv(prior_only, ...) 24 | } else { 25 | stop("unknown model name!") 26 | } 27 | return(m) 28 | } 29 | 30 | 31 | # Group-stratified SIR example model 32 | example_ode_model_gsir <- function(prior_only, ...) { 33 | # Time points 34 | N <- stan_dim("N", lower = 0) # number of timepoints 35 | 36 | # Data needed by ODE function 37 | G <- stan_dim("G", lower = 1) # number of groups 38 | pop_sizes <- stan_vector("pop_sizes", G) # population sizes in each group 39 | I0 <- stan_vector("I0", G, lower = 0) # initial no. infected in each group 40 | contacts <- stan_matrix("contacts", G, G) # contact matrix 41 | 42 | # ODE function parameters 43 | beta <- stan_param(stan_var("beta", lower = 0), "normal(2, 1)") 44 | gamma_decl <- stan_vector("gamma", lower = 0, length = G) 45 | gamma <- stan_param(gamma_decl, "normal(0.3, 0.3)") 46 | 47 | # All odefun variables 48 | odefun_vars <- list(pop_sizes, I0, contacts, beta, gamma) 49 | 50 | # Initial value 51 | D <- stan_dim("D", lower = 0) # number of ODE dimensions 52 | y0_var <- stan_vector("y0", length = D) 53 | y0_code <- 54 | " 55 | for(g in 1:G) { 56 | y0[g] = pop_sizes[g] - I0[g]; // initial number of S 57 | } 58 | for(g in 1:G) { 59 | y0[G + g] = I0[g]; // initial number of I 60 | } 61 | " 62 | y0 <- stan_transform(y0_var, "data", y0_code) 63 | 64 | # Observation model data 65 | delta <- stan_var("delta", lower = 0) 66 | I_data <- stan_array("I_data", type = "int", dims = list(N, G), lower = 0) 67 | 68 | # Observation model parameters phi_inv 69 | phi_inv_var <- stan_vector("phi_inv", lower = 0, length = G) 70 | phi_var <- stan_vector("phi", lower = 0, length = G) 71 | phi_inv <- stan_param(phi_inv_var, "exponential(5);") 72 | phi <- stan_transform(phi_var, "parameters", "inv(phi_inv);") 73 | 74 | # All loglik variables 75 | loglik_vars <- list(delta, I_data, phi_inv, phi) 76 | 77 | # Function bodies 78 | odefun_body <- " 79 | vector[2*G] dy_dt; // first G are susceptible, next G are infected 80 | vector[G] infection_rates; 81 | vector[G] recovery_rates; 82 | vector[G] lambda = rep_vector(0.0, G); 83 | for(g in 1:G) { 84 | for(h in 1:G) { 85 | lambda[g] += contacts[g,h] * y[G+h]/pop_sizes[h]; 86 | } 87 | } 88 | for(g in 1:G) { 89 | dy_dt[g] = - beta * lambda[g] * y[g]; 90 | dy_dt[G+g] = beta * lambda[g] * y[g] - gamma[g] * y[G+g]; 91 | } 92 | return dy_dt; 93 | " 94 | 95 | loglik_body <- " 96 | real log_lik = 0.0; 97 | for(n in 1:N) { 98 | for(g in 1:G) { 99 | log_lik += neg_binomial_2_lpmf(I_data[n,g] | y_sol[n][G+g] + delta, 100 | phi[g]); 101 | } 102 | } 103 | return(log_lik); 104 | " 105 | if (prior_only) { 106 | loglik_body <- "" 107 | loglik_vars <- list(delta, phi_inv, phi) # no I_data 108 | } 109 | 110 | # Generated quantity 111 | I_gen_decl <- stan_array("I_gen", type = "int", dims = c(N, G)) 112 | I_gen_code <- " 113 | for(n in 1:N) { 114 | for(g in 1:G) { 115 | I_gen[n,g] = neg_binomial_2_rng(y_sol_gq[n][G+g] + delta, phi[g]); 116 | } 117 | } 118 | " 119 | I_gen <- stan_transform(I_gen_decl, "model", I_gen_code) 120 | 121 | # Return 122 | ode_model( 123 | N = N, 124 | odefun_vars = odefun_vars, 125 | odefun_body = odefun_body, 126 | odefun_init = y0, 127 | loglik_vars = loglik_vars, 128 | loglik_body = loglik_body, 129 | other_vars = list(I_gen), 130 | ... 131 | ) 132 | } 133 | 134 | 135 | # TMDD example model 136 | example_ode_model_tmdd <- function(prior_only, ...) { 137 | # Dimensions and other data 138 | N <- stan_dim("N", lower = 1) # number of time points 139 | D <- stan_dim("D", lower = 1) # ODE system dimension 140 | L0 <- stan_var("L0", lower = 0) # initial bolus 141 | P_obs <- stan_vector("P_obs", length = N) # observations of P 142 | 143 | # Define kinetic parameters and their priors 144 | k_par <- list( 145 | stan_param(stan_var("k_on", lower = 0), "lognormal(-1, 0.3)"), 146 | stan_param(stan_var("k_off", lower = 0), "lognormal(0, 0.3)"), 147 | stan_param(stan_var("k_in", lower = 0), "lognormal(0, 0.3)"), 148 | stan_param(stan_var("k_out", lower = 0), "lognormal(0, 0.3)"), 149 | stan_param(stan_var("k_eL", lower = 0), "lognormal(-1, 0.3)"), 150 | stan_param(stan_var("k_eP", lower = 0), "lognormal(-3, 0.3)") 151 | ) 152 | 153 | # Define noise parameter and its prior 154 | sigma_par <- stan_param(stan_var("sigma", lower = 0), "lognormal(1, 0.3)") 155 | 156 | # Define transformed parameters 157 | R0 <- stan_transform(stan_var("R0"), "parameters", "k_in/k_out") 158 | y0 <- stan_transform( 159 | decl = stan_vector("y0", length = D), 160 | origin = "parameters", 161 | code = "to_vector({L0, R0, 0.0})" 162 | ) 163 | 164 | # Define ODE system right-hand side 165 | odefun_body <- " 166 | vector[3] dy_dt; // L, R, P 167 | real L = y[1]; 168 | real R = y[2]; 169 | real P = y[3]; 170 | real rem = k_on*L*R - k_off*P; 171 | dy_dt[1] = - k_eL*L - rem; 172 | dy_dt[2] = k_in - k_out*R - rem; 173 | dy_dt[3] = rem - k_eP*P; 174 | return dy_dt; 175 | " 176 | 177 | # Define log-likelihood function body 178 | loglik_body <- " 179 | real loglik = 0.0; 180 | for(n in 1:N) { 181 | loglik += normal_lpdf(P_obs[n] | y_sol[n][3], sigma); 182 | } 183 | return(loglik); 184 | " 185 | loglik_vars <- list(sigma_par, P_obs) 186 | if (prior_only) { 187 | loglik_body <- "" 188 | loglik_vars <- list(sigma_par) 189 | } 190 | 191 | # Return 192 | ode_model( 193 | N = N, 194 | odefun_vars = k_par, 195 | odefun_body = odefun_body, 196 | odefun_init = y0, 197 | loglik_vars = loglik_vars, 198 | loglik_body = loglik_body, 199 | other_vars = list(L0, R0), 200 | ... 201 | ) 202 | } 203 | 204 | 205 | # Lotka-Volterra example model 206 | example_ode_model_lv <- function(prior_only = FALSE, ...) { 207 | # Dimensions and other data 208 | N <- stan_dim("N", lower = 1) # number of time points 209 | D <- stan_dim("D", lower = 1) # ODE system dimension 210 | y_obs <- stan_vector_array("y_obs", length = D, dims = list(N)) 211 | y_obs_init <- stan_vector("y_obs_init", length = D) 212 | 213 | # Define ODE system parameters and their priors 214 | lv_par <- list( 215 | stan_param(stan_var("alpha", lower = 0), "normal(1, 0.5)"), 216 | stan_param(stan_var("beta", lower = 0), "normal(0.05, 0.05)"), 217 | stan_param(stan_var("gamma", lower = 0), "normal(1, 0.5)"), 218 | stan_param(stan_var("delta", lower = 0), "normal(0.05, 0.05)") 219 | ) 220 | 221 | # Define noise parameter and its prior 222 | sigma_par <- stan_param( 223 | stan_vector("sigma", lower = 0, length = D), 224 | "lognormal(-1, 1)" 225 | ) 226 | 227 | # Define initial point as parameter and its prior 228 | y0_par <- stan_param( 229 | stan_vector("y0", length = D, lower = 0), 230 | "lognormal(log(10), 1)" 231 | ) 232 | 233 | # Initial point on log scale 234 | log_y0 <- stan_transform( 235 | stan_vector("log_y0", length = D), 236 | "parameters", 237 | "log(y0)" 238 | ) 239 | 240 | # Define ODE system right-hand side 241 | odefun_body <- " 242 | real u = y[1]; // predator 243 | real v = y[2]; // prey 244 | real du_dt = (alpha - beta * v) * u; 245 | real dv_dt = (-gamma + delta * u) * v; 246 | return to_vector({du_dt, dv_dt}); 247 | " 248 | 249 | # Define log-likelihood function body 250 | loglik_body <- " 251 | real loglik = lognormal_lpdf(y_obs_init | log_y0, sigma); 252 | for(n in 1:N) { 253 | loglik += lognormal_lpdf(y_obs[n] | log(y_sol[n]), sigma); 254 | } 255 | return(loglik); 256 | " 257 | 258 | # Set loglik depending on whether creating only prior model 259 | if (prior_only) { 260 | loglik_body <- "" 261 | loglik_vars <- list(log_y0, sigma_par) 262 | } else { 263 | loglik_vars <- list(log_y0, sigma_par, y_obs, y_obs_init) 264 | } 265 | 266 | # Return 267 | odemodeling::ode_model( 268 | N = N, 269 | odefun_vars = lv_par, 270 | odefun_body = odefun_body, 271 | odefun_init = y0_par, 272 | loglik_vars = loglik_vars, 273 | loglik_body = loglik_body, 274 | ... 275 | ) 276 | } 277 | -------------------------------------------------------------------------------- /R/main-functions.R: -------------------------------------------------------------------------------- 1 | #' Compare two objects that contain ODE solutions and ODE model likelihoods 2 | #' 3 | #' @param x An object of class [OdeModelMCMC] or [OdeModelGQ]. 4 | #' @param y An object of class [OdeModelMCMC] or [OdeModelGQ]. 5 | #' @name compare_odefits 6 | NULL 7 | 8 | #' @describeIn compare_odefits Compute maximum absolute difference in 9 | #' ODE solutions of `x` and `y`. 10 | #' @param include_y0 Should the ODE initial state be included in computations? 11 | #' @export 12 | max_abs_odesol_diff <- function(x, y, include_y0 = TRUE) { 13 | checkmate::assert_class(x, "OdeModelFit") 14 | checkmate::assert_class(y, "OdeModelFit") 15 | xx <- x$extract_odesol(include_y0 = include_y0) 16 | yy <- y$extract_odesol(include_y0 = include_y0) 17 | ad <- compute_abs_diff(xx, yy) 18 | max(ad) 19 | } 20 | 21 | #' @describeIn compare_odefits Compute maximum absolute differences in 22 | #' log likelihoods of `x` and `y`. 23 | #' @export 24 | max_abs_loglik_diff <- function(x, y) { 25 | checkmate::assert_class(x, "OdeModelFit") 26 | checkmate::assert_class(y, "OdeModelFit") 27 | xx <- x$loglik() 28 | yy <- y$loglik() 29 | ad <- compute_abs_diff(xx, yy) 30 | max(ad) 31 | } 32 | 33 | #' @describeIn compare_odefits Compute log likelihood ratios (on log scale), 34 | #' i.e. just `x$loglik() - y$loglik()`. 35 | #' @export 36 | log_ratios <- function(x, y) { 37 | checkmate::assert_class(x, "OdeModelFit") 38 | checkmate::assert_class(y, "OdeModelFit") 39 | checkmate::assert_true(all(dim(x) == dim(y))) 40 | x$loglik() - y$loglik() 41 | } 42 | 43 | #' @describeIn compare_odefits Compute relative efficiency needed for PSIS, 44 | #' using [loo::relative_eff()]. 45 | #' @export 46 | psis_relative_eff <- function(x, y) { 47 | checkmate::assert_class(x, "OdeModelFit") 48 | checkmate::assert_class(y, "OdeModelFit") 49 | log_ratios <- log_ratios(x, y) 50 | reciproc_of_importance_ratios <- exp(-log_ratios) 51 | r_eff <- loo::relative_eff(x = reciproc_of_importance_ratios) 52 | as.numeric(r_eff) 53 | } 54 | 55 | #' @describeIn compare_odefits Call [loo::psis()] using the log likelihoods 56 | #' from `x` and `y`. 57 | #' @export 58 | psis <- function(x, y) { 59 | checkmate::assert_class(x, "OdeModelFit") 60 | checkmate::assert_class(y, "OdeModelFit") 61 | r_eff <- psis_relative_eff(x, y) 62 | x <- log_ratios(x, y) 63 | loo::psis(log_ratios = x, r_eff = r_eff) 64 | } 65 | 66 | #' @describeIn compare_odefits Compute all metrics. 67 | #' @export 68 | #' @return A named numeric vector. 69 | compute_reliability_metrics <- function(x, y) { 70 | checkmate::assert_class(x, "OdeModelFit") 71 | checkmate::assert_class(y, "OdeModelFit") 72 | is <- psis(x, y) 73 | r_eff <- psis_relative_eff(x, y) 74 | pdiag <- is$diagnostics 75 | pd <- c(pdiag$pareto_k, pdiag$n_eff, r_eff) 76 | mad_loglik <- max_abs_loglik_diff(x, y) 77 | mad_odesol <- max_abs_odesol_diff(x, y) 78 | met <- c(pd, mad_loglik, mad_odesol) 79 | internal_assert_len(met, 5, "compute_reliability_metrics") 80 | names(met) <- c("pareto_k", "n_eff", "r_eff", "mad_loglik", "mad_odesol") 81 | return(met) 82 | } 83 | 84 | # Helper function 85 | compute_abs_diff <- function(x, y) { 86 | checkmate::assert_true(all(dim(x) == dim(y))) 87 | abs(x - y) 88 | } 89 | -------------------------------------------------------------------------------- /R/main-model.R: -------------------------------------------------------------------------------- 1 | #' Create an ODE model 2 | #' 3 | #' @export 4 | #' @description Generate model given the declarations of variables, 5 | #' parameters, functions etc. The arguments `odefun_vars`, 6 | #' `loglik_vars` and `other_vars` must be lists whose elements must have one 7 | #' of the following three types: 8 | #' \itemize{ 9 | #' \item [StanDeclaration] - can be created using [stan_var()], 10 | #' [stan_vector()], [stan_array()] etc. 11 | #' \item [StanParameter] - can be created using [stan_param()] 12 | #' \item [StanTransformation] - can be created using [stan_transform()] 13 | #' } 14 | #' 15 | #' These will go to different blocks of the 'Stan' model code so that 16 | #' \itemize{ 17 | #' \item [StanDeclaration]s go to `data` 18 | #' \item [StanParameter]s go to `parameters` 19 | #' \item [StanTransformation]s with origin `"data"` go to 20 | #' `transformed data` 21 | #' \item [StanTransformation]s with origin `"parameters"` go to 22 | #' `transformed parameters` 23 | #' \item [StanTransformation]s with origin `"model"` go to 24 | #' `generated quantities` 25 | #' } 26 | #' @export 27 | #' @param N A [StanDimension] variable describing the number of time points. 28 | #' @param odefun_vars Data and parameters needed by the ODE function. Must be a 29 | #' list of [StanDeclaration], [StanParameter], or [StanTransformation] objects. 30 | #' These will be defined in Stan model code blocks 31 | #' @param odefun_body ODE function body (Stan code string). 32 | #' @param odefun_init Initial value for ODE system at t0. 33 | #' Has to be a [StanVector], or alternatively a [StanParameter] or a 34 | #' [StanTransformation] with [StanVector] base declaration. 35 | #' @param loglik_vars Data and parameters needed by the log likelihood 36 | #' function. 37 | #' @param loglik_body Log likelihood function body (Stan code string). 38 | #' @param other_vars Other variables. 39 | #' @param verbose Should this print more information? 40 | #' @param compile Should the model be compiled? 41 | #' @param sig_figs Number of significant figures to use in all 'CmdStan' 42 | #' calls. 43 | #' @return An object of class [OdeModel]. 44 | #' @family model constructor functions 45 | ode_model <- function(N, 46 | odefun_vars = list(), 47 | odefun_body = "", 48 | odefun_init = NULL, 49 | loglik_vars = list(), 50 | loglik_body = "", 51 | other_vars = list(), 52 | verbose = FALSE, 53 | compile = TRUE, 54 | sig_figs = 18) { 55 | # Argument checks 56 | choices_vars <- c("StanParameter", "StanTransformation", "StanDeclaration") 57 | checkmate::assert_class(N, "StanDimension") 58 | checkmate::assert_list(odefun_vars, choices_vars) 59 | checkmate::assert_list(loglik_vars, choices_vars) 60 | checkmate::assert_list(other_vars, choices_vars) 61 | checkmate::assert_string(odefun_body, min.chars = 1) 62 | checkmate::assert_string(loglik_body, min.chars = 0) 63 | 64 | # Check that odefun_init has correct type and name 65 | choices_init <- c("StanVector", "StanParameter", "StanTransformation") 66 | checkmate::assert_multi_class(odefun_init, choices_init) 67 | y0_name <- get_name(odefun_init) 68 | if (y0_name != "y0") { 69 | stop( 70 | "the Stan variable in odefun_init must have name y0! found = ", 71 | y0_name 72 | ) 73 | } 74 | 75 | # Generating prior or posterior model code? 76 | has_loglik <- nchar(loglik_body) > 0 77 | 78 | # ODE function signature 79 | odefun_add_signature <- generate_add_signature(odefun_vars, FALSE) 80 | odefun_add_args <- generate_add_signature(odefun_vars, TRUE) 81 | so_args <- "solver, rel_tol, abs_tol, max_num_steps, num_steps, y0, t0, t" 82 | solve_ode_args <- append_to_signature(so_args, odefun_add_args) 83 | 84 | # Log likelihood function signature 85 | if (has_loglik) { 86 | loglik_add_signature <- generate_add_signature(loglik_vars, FALSE) 87 | loglik_add_args <- generate_add_signature(loglik_vars, TRUE) 88 | loglik_args <- append_to_signature("y_sol_tpar", loglik_add_args) 89 | } else { 90 | loglik_add_signature <- "" 91 | loglik_add_args <- "" 92 | loglik_args <- "" 93 | } 94 | 95 | # All vars and their declarations 96 | base_vars <- list( 97 | stan_var("t0"), stan_array("t", dims = list(N)), odefun_init 98 | ) 99 | solver_vars <- list( 100 | stan_var("abs_tol", lower = 0), 101 | stan_var("rel_tol", lower = 0), 102 | stan_var("max_num_steps", lower = 0, type = "int"), 103 | stan_var("num_steps", lower = 0, type = "int"), 104 | stan_var("solver", lower = 0, type = "int") 105 | ) 106 | D <- get_dims(odefun_init)[[1]] 107 | if (!has_loglik) { 108 | y_sol_gq <- stan_transform( 109 | decl = stan_vector_array("y_sol_gq", dims = list(N), length = D), 110 | origin = "model", 111 | code = paste0("solve_ode(", solve_ode_args, ")") 112 | ) 113 | } else { 114 | y_sol_tpar <- stan_transform( 115 | decl = stan_vector_array("y_sol_tpar", dims = list(N), length = D), 116 | origin = "parameters", 117 | code = paste0("solve_ode(", solve_ode_args, ")") 118 | ) 119 | y_sol_gq <- stan_transform( 120 | decl = stan_vector_array("y_sol_gq", dims = list(N), length = D), 121 | origin = "model", 122 | code = paste0("{\n y_sol_gq = y_sol_tpar; \n}") 123 | ) 124 | log_lik_tpar <- stan_transform( 125 | decl = stan_var("log_lik_tpar", "real"), 126 | origin = "parameters", 127 | code = paste0("log_likelihood(", loglik_args, ")") 128 | ) 129 | log_lik_gq <- stan_transform( 130 | decl = stan_var("log_lik_gq", "real"), 131 | origin = "model", 132 | code = "{\n log_lik_gq = log_lik_tpar; \n}" 133 | ) 134 | } 135 | 136 | # Add y0 as a generated quantity too, so its easy to extract from results 137 | y0_gq <- stan_transform( 138 | stan_vector("y0_gq", length = D), 139 | origin = "model", 140 | code = "{\n y0_gq = y0; \n}" 141 | ) 142 | 143 | if (!has_loglik) { 144 | other_vars_add <- list(y_sol_gq, y0_gq) 145 | } else { 146 | other_vars_add <- list( 147 | y_sol_tpar, y_sol_gq, y0_gq, log_lik_tpar, log_lik_gq 148 | ) 149 | } 150 | 151 | other_vars <- c(other_vars_add, other_vars) 152 | all_vars <- c(odefun_vars, loglik_vars, other_vars, base_vars, solver_vars) 153 | all_vars <- unique(all_vars) 154 | all_decls <- lapply(all_vars, get_decl) 155 | dims <- dims_of_decls(all_decls) 156 | 157 | # Create most blocks 158 | data <- all_vars[sapply(all_vars, is_data)] 159 | tdata <- all_vars[sapply(all_vars, is_tdata)] 160 | params <- all_vars[sapply(all_vars, is_param)] 161 | tparams <- all_vars[sapply(all_vars, is_tparam)] 162 | gqs <- all_vars[sapply(all_vars, is_gq)] 163 | data_b <- generate_data_block(all_decls, data) 164 | tdata_b <- generate_transform_block("transformed data", tdata, FALSE) 165 | pars_b <- generate_params_block(params) 166 | tpars_b <- generate_transform_block("transformed parameters", tparams, TRUE) 167 | model_b <- generate_model_block(params, prior_mode = !has_loglik) 168 | gq_b <- generate_transform_block("generated quantities", gqs, FALSE) 169 | 170 | # Functions block 171 | funs_b <- generate_functions_block( 172 | odefun_add_signature, 173 | odefun_add_args, 174 | odefun_body, 175 | loglik_add_signature, 176 | loglik_body 177 | ) 178 | 179 | # Merge the blocks 180 | code <- paste( 181 | funs_b, data_b, tdata_b, pars_b, tpars_b, model_b, gq_b, 182 | sep = "\n" 183 | ) 184 | code <- autoformat_stancode(code) 185 | 186 | # Create Stan model and create the OdeModel 187 | sm <- StanModelWithCode$new( 188 | code, dims, data, tdata, params, tparams, gqs, compile 189 | ) 190 | OdeModel$new( 191 | has_likelihood = has_loglik, 192 | stanmodel = sm, 193 | sig_figs = sig_figs, 194 | t_dim = N, 195 | ode_dim = D 196 | ) 197 | } 198 | -------------------------------------------------------------------------------- /R/main-plot.R: -------------------------------------------------------------------------------- 1 | #' Plotting different metrics 2 | #' 3 | #' @description Either `tols` or `num_steps` has to be `NULL`. 4 | #' @param values A numeric vector of metric values. 5 | #' @param name Name of metric 6 | #' @param tols A numeric vector of tolerances. Must have same length as 7 | #' `values`. 8 | #' @param num_steps A numeric vector of step amounts. Must have same length as 9 | #' `values`. 10 | #' @param reliability The list returned by the `$reliability()` method of 11 | #' [OdeModelFit] class. 12 | #' @name plot_metric 13 | NULL 14 | 15 | #' @describeIn plot_metric Plot a generic metric. 16 | #' @export 17 | plot_metric <- function(values, name, tols = NULL, num_steps = NULL) { 18 | checkmate::assert_numeric(values) 19 | checkmate::assert_string(name) 20 | if (!is.null(tols)) { 21 | if (!is.null(num_steps)) { 22 | stop("either tols or num_steps must be NULL") 23 | } 24 | confs <- 1 / tols 25 | conf_name <- "inv_tol" 26 | log10 <- TRUE 27 | } else { 28 | if (is.null(num_steps)) { 29 | stop("either tols or num_steps must not be NULL") 30 | } 31 | confs <- num_steps 32 | conf_name <- "num_steps" 33 | log10 <- FALSE 34 | } 35 | plt <- plot_metric.create_plot(confs, values, conf_name, name, log10) 36 | if (log10) { 37 | plt <- add_inv_tol_xlab(plt) 38 | } 39 | return(plt) 40 | } 41 | 42 | #' @describeIn plot_metric Plot pareto-k metric. 43 | #' @export 44 | plot_pareto_k <- function(reliability, tols = NULL, num_steps = NULL) { 45 | values <- reliability$metrics[, "pareto_k"] 46 | plt <- plot_metric(values, "pareto_k", tols, num_steps) 47 | plt <- plt + geom_hline(yintercept = 0.5, lty = 2, color = "firebrick3") 48 | plt <- plt + geom_hline(yintercept = 0.7, lty = 2, color = "steelblue") 49 | plt + ylab("Pareto-k") 50 | } 51 | 52 | #' @describeIn plot_metric Plot relative efficiency. 53 | #' @export 54 | plot_r_eff <- function(reliability, tols = NULL, num_steps = NULL) { 55 | values <- reliability$metrics[, "r_eff"] 56 | plt <- plot_metric(values, "r_eff", tols, num_steps) 57 | plt + ylab("Relative efficiency") 58 | } 59 | 60 | #' @describeIn plot_metric Plot maximum absolute difference. 61 | #' @param loglik If `TRUE`, the maximum absolute difference in log likelihoods 62 | #' is plotted. Otherwise the maximum absolute difference in ODE solutions 63 | #' is plotted (default). 64 | #' @export 65 | plot_mad <- function(reliability, tols = NULL, num_steps = NULL, 66 | loglik = FALSE) { 67 | if (loglik) { 68 | name <- "mad_loglik" 69 | } else { 70 | name <- "mad_odesol" 71 | } 72 | values <- reliability$metrics[, name] 73 | plt <- plot_metric(values, name, tols, num_steps) 74 | plt + ylab(name) 75 | } 76 | 77 | # Edit x label 78 | add_inv_tol_xlab <- function(plt) { 79 | plt + xlab(expression(tol^{ 80 | -1 81 | })) 82 | } 83 | 84 | # Plotting helper function 85 | plot_metric.create_df <- function(confs, values, conf_name, metric_name) { 86 | checkmate::assert_numeric(confs, len = length(values)) 87 | df <- data.frame(confs, values) 88 | colnames(df) <- c(conf_name, metric_name) 89 | return(df) 90 | } 91 | 92 | # Plotting helper function 93 | plot_metric.create_plot <- function(confs, values, conf_name, metric_name, 94 | log10) { 95 | df <- plot_metric.create_df(confs, values, conf_name, metric_name) 96 | plt <- ggplot(df, aes_string(x = conf_name, y = metric_name)) 97 | plt <- plt + geom_line() + geom_point() + theme_bw() 98 | if (log10) { 99 | plt <- plt + scale_x_log10(breaks = confs) 100 | } else { 101 | plt <- plt + scale_x_continuous(breaks = confs) 102 | } 103 | if (log10) { 104 | plt <- plt + theme( 105 | axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5) 106 | ) 107 | } 108 | plt + theme( 109 | panel.grid.minor = element_blank() 110 | ) 111 | } 112 | -------------------------------------------------------------------------------- /R/main-solvers.R: -------------------------------------------------------------------------------- 1 | # odesolvers -------------------------------------------------------------- 2 | 3 | #' Creating ODE solvers 4 | #' 5 | #' @description These constructors should be used for creating the `solver` 6 | #' argument of the `sample()` method of the [OdeModel] class. 7 | #' Each function here returns an [OdeSolver] which can be either 8 | #' \itemize{ 9 | #' \item An [AdaptiveOdeSolver] which can estimate its own error and 10 | #' adapts its step size according to given tolerances for the error 11 | #' \item A [FixedNumStepsOdeSolver] which always takes the same number of 12 | #' steps between consequent output time points 13 | #' } 14 | #' @param abs_tol Absolute tolerance (only for [AdaptiveOdeSolver]s). Will 15 | #' be replaced by `tol` if it is not `NULL`. 16 | #' @param rel_tol Relative tolerance (only for [AdaptiveOdeSolver]s). Will 17 | #' be replaced by `tol` if it is not `NULL`. 18 | #' @param tol Can be used to set both `abs_tol` and `rel_tol` to same value. 19 | #' Have no effect if `NULL` (default). 20 | #' @param max_num_steps Maximum number of steps between output time 21 | #' points (only for [AdaptiveOdeSolver]s). 22 | #' @param num_steps The number of steps between subsequent output time 23 | #' points (only for [FixedNumStepsOdeSolver]s). 24 | #' @name odesolvers 25 | NULL 26 | 27 | #' @describeIn odesolvers Create an RK45 solver ([AdaptiveOdeSolver]) 28 | #' @export 29 | rk45 <- function(abs_tol = 1e-6, rel_tol = 1e-6, max_num_steps = 1e6, 30 | tol = NULL) { 31 | abs_tol <- replace_tol(abs_tol, tol) 32 | rel_tol <- replace_tol(rel_tol, tol) 33 | AdaptiveOdeSolver$new( 34 | name = "rk45", 35 | abs_tol = abs_tol, 36 | rel_tol = rel_tol, 37 | max_num_steps = max_num_steps 38 | ) 39 | } 40 | 41 | #' @describeIn odesolvers Create a BDF solver ([AdaptiveOdeSolver]) 42 | #' @export 43 | bdf <- function(abs_tol = 1e-10, rel_tol = 1e-10, max_num_steps = 1e8, 44 | tol = NULL) { 45 | abs_tol <- replace_tol(abs_tol, tol) 46 | rel_tol <- replace_tol(rel_tol, tol) 47 | AdaptiveOdeSolver$new( 48 | name = "bdf", 49 | abs_tol = abs_tol, 50 | rel_tol = rel_tol, 51 | max_num_steps = max_num_steps 52 | ) 53 | } 54 | 55 | #' @describeIn odesolvers Create an Adams solver ([AdaptiveOdeSolver]) 56 | #' @export 57 | adams <- function(abs_tol = 1e-10, rel_tol = 1e-10, max_num_steps = 1e8, 58 | tol = NULL) { 59 | abs_tol <- replace_tol(abs_tol, tol) 60 | rel_tol <- replace_tol(rel_tol, tol) 61 | AdaptiveOdeSolver$new( 62 | name = "adams", 63 | abs_tol = abs_tol, 64 | rel_tol = rel_tol, 65 | max_num_steps = max_num_steps 66 | ) 67 | } 68 | 69 | #' @describeIn odesolvers Create a Cash-Karp solver ([AdaptiveOdeSolver]). 70 | #' @export 71 | ckrk <- function(abs_tol = 1e-6, rel_tol = 1e-6, max_num_steps = 1e6, 72 | tol = NULL) { 73 | abs_tol <- replace_tol(abs_tol, tol) 74 | rel_tol <- replace_tol(rel_tol, tol) 75 | AdaptiveOdeSolver$new( 76 | name = "ckrk", 77 | abs_tol = abs_tol, 78 | rel_tol = rel_tol, 79 | max_num_steps = max_num_steps 80 | ) 81 | } 82 | 83 | 84 | #' @describeIn odesolvers Create a forward Euler solver 85 | #' ([FixedNumStepsOdeSolver]) 86 | #' @export 87 | euler <- function(num_steps = 1) { 88 | FixedNumStepsOdeSolver$new(name = "euler", num_steps = num_steps) 89 | } 90 | 91 | #' @describeIn odesolvers Create an explicit midpoint solver 92 | #' ([FixedNumStepsOdeSolver]) 93 | #' @export 94 | midpoint <- function(num_steps = 1) { 95 | FixedNumStepsOdeSolver$new(name = "midpoint", num_steps = num_steps) 96 | } 97 | 98 | #' @describeIn odesolvers Create an RK4 solver ([FixedNumStepsOdeSolver]) 99 | #' @export 100 | rk4 <- function(num_steps = 1) { 101 | FixedNumStepsOdeSolver$new(name = "rk4", num_steps = num_steps) 102 | } 103 | 104 | 105 | # odesolvers_lists -------------------------------------------------------- 106 | 107 | #' Creating lists of ODE solvers 108 | #' 109 | #' @description These constructors can be used for creating the `solvers` 110 | #' argument of the `sample_manyconf()` method of the [OdeModel] class. 111 | #' Each function here returns a list of [OdeSolver]s. 112 | #' @param tols A vector of length `L` of tolerance values. 113 | #' @param max_num_steps Maximum number of steps between output time 114 | #' points (one number, same for all solvers in the output list). 115 | #' @param num_steps A vector of length `L` of step amounts. 116 | #' @name odesolvers_lists 117 | NULL 118 | 119 | #' @describeIn odesolvers_lists Create a list of RK45 solvers with different 120 | #' tolerances. 121 | #' @export 122 | rk45_list <- function(tols, max_num_steps = 1e6) { 123 | checkmate::assert_numeric(tols) 124 | creator <- function(x) { 125 | rk45(tol = x, max_num_steps = max_num_steps) 126 | } 127 | sapply(tols, creator) 128 | } 129 | 130 | #' @describeIn odesolvers_lists Create a list of BDF solvers with 131 | #' different tolerances. 132 | #' @export 133 | bdf_list <- function(tols, max_num_steps = 1e8) { 134 | checkmate::assert_numeric(tols) 135 | creator <- function(x) { 136 | bdf(tol = x, max_num_steps = max_num_steps) 137 | } 138 | sapply(tols, creator) 139 | } 140 | 141 | #' @describeIn odesolvers_lists Create a list of explicit midpoint 142 | #' solvers with different fixed number of steps. 143 | #' @export 144 | midpoint_list <- function(num_steps) { 145 | checkmate::assert_numeric(num_steps) 146 | creator <- function(x) { 147 | midpoint(num_steps = x) 148 | } 149 | sapply(num_steps, creator) 150 | } 151 | 152 | #' @describeIn odesolvers_lists Create a list of RK4 153 | #' solvers with different fixed number of steps. 154 | #' @export 155 | rk4_list <- function(num_steps) { 156 | checkmate::assert_numeric(num_steps) 157 | creator <- function(x) { 158 | rk4(num_steps = x) 159 | } 160 | sapply(num_steps, creator) 161 | } 162 | -------------------------------------------------------------------------------- /R/odemodeling-package.R: -------------------------------------------------------------------------------- 1 | #' The 'odemodeling' package 2 | #' 3 | #' @description Building and fitting ordinary differential equation (ODE) 4 | #' models with different numerical solvers in 'Stan'. Designed for efficient 5 | #' validation of the accuracy of numerical solvers in the Bayesian context. 6 | #' Using Pareto-smoothed importance sampling (PSIS) and its diagnostics. 7 | #' The package is based on the \code{R6} object oriented system and uses 8 | #' \code{cmdstanr} as the interface to 'Stan'. 9 | #' 10 | #' @name odemodeling-package 11 | #' @aliases odemodeling 12 | #' 13 | #' @import R6 14 | #' @import ggplot2 15 | #' @importFrom methods is 16 | #' @importFrom utils capture.output 17 | #' 18 | #' @section Creating a model: 19 | #' \itemize{ 20 | #' \item Declare model data, parameters, and other variables using 21 | #' [stan_array()], [stan_dim()], [stan_matrix()], [stan_param()], 22 | #' [stan_transform()], [stan_vector_array()], and [stan_vector()]. 23 | #' \item Create an [OdeModel] model using [ode_model()]. 24 | #' } 25 | #' @section Using different ODE solvers: 26 | #' \itemize{ 27 | #' \item See \code{\link{odesolvers}} for constructors that create objects 28 | #' of class [OdeSolver]. 29 | #' } 30 | #' @section Fitting a model: 31 | #' \itemize{ 32 | #' \item Sample the posterior or prior distribution of the model parameters, 33 | #' and generate corresponding ODE solutions using the `$sample()` method 34 | #' of the [OdeModel] class. 35 | #' \item See methods of the [OdeModelMCMC] class for studying the returned 36 | #' object. 37 | #' } 38 | #' @section Additional simulation of ODE systems: 39 | #' \itemize{ 40 | #' \item See the `$gqs()` method of the [OdeModelMCMC] and [OdeModel] 41 | #' classes. 42 | #' \item See methods of the [OdeModelGQ] class for studying the returned 43 | #' object. 44 | #' \item See \code{\link{compare_odefits}} for functions to compare 45 | #' different ODE model simulations and fits. 46 | #' } 47 | #' @section Importance sampling for reliable and efficient inference in Bayesian ODE models: 48 | #' Our proposed workflow is to 49 | #' \enumerate{ 50 | #' \item Select an initial ODE solver M. 51 | #' \item Sample the parameter posterior using MCMC with M as the ODE solver. 52 | #' \item Compute certain metrics using a more accurate solver M∗. 53 | #' \item Increase the accuracy of M∗ and repeat Step 3 until the metrics converge. 54 | #' If the Pareto-k metric converges to a value larger than 0.7, increase the accuracy 55 | #' of M and go back to Step 2. 56 | #' \item Compute any posterior estimates using final importance weights. See 57 | #' Timonen et al. (2022) below. 58 | #' } 59 | #' The algorithm can be used to validate the reliability, and correct the errors 60 | #' of a given method M, which can be for example a software default. On the other hand, 61 | #' a smart initial selection of M can provide speed gains 62 | #' compared to often rather conservatively set software defaults, while still maintaining 63 | #' reliability of the inferences. 64 | #' 65 | #' We generally recommend selecting M initially so that sampling is as fast as possible. 66 | #' For example, for non-adaptive ODE solvers, one can first try using the smallest 67 | #' sensible number of steps that does not result in immediate failure. 68 | #' Selecting a good M is more difficult in the case of adaptive solvers. 69 | #' We have 70 | #' observed that tolerances on the order of 1e-4 to 1e-3 generally work well. 71 | #' 72 | #' See the \code{reliability()} method of the \code{\link{OdeModelMCMC}} class. 73 | #' 74 | #' @section Tutorial: 75 | #' See the tutorial vignette. 76 | #' @references 77 | #' \enumerate{ 78 | #' \item Timonen, J., Siccha, N., Bales, B., Lähdesmäki, H., & Vehtari, A. 79 | #' (2023). An importance sampling approach for reliable and efficient 80 | #' inference in Bayesian ordinary differential equation models. 81 | #' Stat, 12(1), e614. 82 | #' \url{https://onlinelibrary.wiley.com/doi/full/10.1002/sta4.614} 83 | #' } 84 | #' 85 | "_PACKAGE" 86 | 87 | #' Hudson Bay Company lynx and hare pelt collection data (1900-1920) 88 | #' 89 | #' @format A data frame with 21 rows and 3 variables: 90 | #' \describe{ 91 | #' \item{year}{collection year} 92 | #' \item{lynx}{number of lynx pelts collected (in 1000's)} 93 | #' \item{hare}{number of hare pelts collected (in 1000's)} 94 | #' } 95 | #' @source \url{https://www.math.tamu.edu/~phoward/m442/modbasics.pdf}, 96 | #' downloaded 10th Jan, 2021. 97 | "lynxhare" 98 | -------------------------------------------------------------------------------- /R/utils-create_input.R: -------------------------------------------------------------------------------- 1 | # Create full Stan data for sampling or gq 2 | create_standata <- function(model, t0, t, solver) { 3 | checkmate::assert_class(model, "OdeModel") 4 | checkmate::assertNumber(t0) 5 | checkmate::assert_vector(t) 6 | checkmate::assert_numeric(t) 7 | checkmate::assert_class(solver, "OdeSolver") 8 | if (any(t <= t0)) { 9 | stop("each value in t must be strictly larger than given t0!") 10 | } 11 | 12 | # Create and return full Stan data 13 | N <- list(N = length(t)) 14 | names(N) <- model$t_dim$name 15 | c( 16 | N, 17 | list(t0 = t0, t = t), 18 | solver$standata() 19 | ) 20 | } 21 | 22 | # Replace single_tol by tol if it is not NULL 23 | replace_tol <- function(single_tol, tol) { 24 | if (!is.null(tol)) { 25 | single_tol <- tol 26 | } 27 | single_tol 28 | } 29 | 30 | # Return y if x is NULL, else return x 31 | replace_if_null <- function(x, y) { 32 | if (is.null(x)) { 33 | return(y) 34 | } 35 | x 36 | } 37 | 38 | # Solver name to numeric encoding 39 | solver_to_num <- function(solver) { 40 | ok <- c("rk45", "bdf", "adams", "ckrk", "euler", "midpoint", "rk4") 41 | nums <- c(1, 2, 3, 4, 101, 102, 103) 42 | checkmate::assert_choice(solver, ok) 43 | nums[which(ok == solver)] 44 | } 45 | -------------------------------------------------------------------------------- /R/utils-misc.R: -------------------------------------------------------------------------------- 1 | # Create directory if it doesn't exist 2 | create_dir_if_not_exist <- function(dir) { 3 | if (!dir.exists(dir)) { 4 | message("directory '", dir, "' doesn't exist, creating it") 5 | dir.create(dir) 6 | } 7 | invisible(dir) 8 | } 9 | 10 | # Name ODE dimensions 11 | create_ydim_names <- function(names, D) { 12 | if (is.null(names)) { 13 | out <- paste0("y", c(1:D)) 14 | } else { 15 | checkmate::assert_character(names, len = D) 16 | out <- names 17 | } 18 | return(out) 19 | } 20 | 21 | # Add leading comma to arguments string 22 | add_leading_comma <- function(args) { 23 | args <- trimws(args) 24 | if (nchar(args) > 0) { 25 | args <- paste0(", ", args) 26 | } 27 | return(args) 28 | } 29 | 30 | # Add semicolon if not final character of string 31 | add_semicolon_if_missing <- function(code) { 32 | code <- trimws(code) 33 | L <- nchar(code) 34 | if (L > 0) { 35 | last_char <- substr(code, L, L) 36 | if (last_char != ";") { 37 | code <- paste0(code, ";") 38 | } 39 | } 40 | return(code) 41 | } 42 | 43 | # Short class info as string 44 | class_info <- function(class_name) { 45 | info <- paste0("An object of class ", class_name, ".") 46 | if (interactive()) { 47 | info <- paste0(info, " Type ?", class_name, " for help.") 48 | } 49 | return(info) 50 | } 51 | 52 | # Internal assertion that should never fail 53 | internal_assert_len <- function(vec, expected, source) { 54 | if (length(vec) != expected) { 55 | stop(paste0("Unexpected length in '", source, "'. Please report a bug.")) 56 | } 57 | TRUE 58 | } 59 | 60 | # Create Stan model from model code 61 | stan_model_from_code <- function(code) { 62 | file <- cmdstanr::write_stan_file(code) 63 | cmdstanr::cmdstan_model(file) 64 | } 65 | 66 | # Colorize string 67 | colorize_string <- function(x, col) { 68 | if (interactive()) { 69 | x <- paste0(col, x, "\u001b[0m") 70 | } 71 | x 72 | } 73 | 74 | # Number string 75 | number_string <- function(x) { 76 | col <- "\u001b[34;1m" # bold blue 77 | colorize_string(x, col) 78 | } 79 | 80 | # Stan code string 81 | stancode_string <- function(x) { 82 | col <- "\u001b[33m" # orange 83 | colorize_string(x, col) 84 | } 85 | 86 | # Print a number 87 | cat_number <- function(x) { 88 | cat(number_string(x)) 89 | } 90 | 91 | # Print Stan code 92 | cat_stancode <- function(x) { 93 | cat(stancode_string(x)) 94 | } 95 | 96 | # Read lines from file 97 | read_file_lines <- function(file) { 98 | a <- readLines(file) 99 | paste(a, collapse = "\n") 100 | } 101 | 102 | # Autoformat a 'Stan' code string 103 | autoformat_stancode <- function(code) { 104 | tryCatch( 105 | { 106 | file <- cmdstanr::write_stan_file(code) 107 | model <- cmdstanr::cmdstan_model(file, compile = FALSE) 108 | res <- processx::run( 109 | file.path(cmdstanr::cmdstan_path(), "bin", "stanc"), 110 | args = c(model$stan_file(), "--auto-format") 111 | ) 112 | return(res$stdout) 113 | }, 114 | error = function(e) { 115 | cat("\nTried to format following Stan code:\n\n") 116 | cat(code) 117 | stop(e) 118 | } 119 | ) 120 | } 121 | 122 | # Add boundaries to variable declaration string 123 | add_bounds <- function(decl, lower, upper) { 124 | if (!is.null(lower) && !is.null(upper)) { 125 | add <- paste0("") 126 | } else if (!is.null(lower) && is.null(upper)) { 127 | add <- paste0("") 128 | } else if (is.null(lower) && !is.null(upper)) { 129 | add <- paste0("") 130 | } else { 131 | add <- "" 132 | } 133 | paste0(decl, add) 134 | } 135 | 136 | # Beginning of array declaration or signature 137 | declare_array <- function(name, dims, signature) { 138 | decl <- "array[" 139 | j <- 0 140 | for (dim in dims) { 141 | if (signature) { 142 | dimname <- "" 143 | } else { 144 | dimname <- dim$name 145 | } 146 | j <- j + 1 147 | if (j == 1) { 148 | decl <- paste0(decl, dimname) 149 | } else { 150 | decl <- paste0(decl, ", ", dimname) 151 | } 152 | } 153 | decl <- paste0(decl, "]") 154 | return(decl) 155 | } 156 | 157 | # Append to comma separated list 158 | append_to_signature <- function(code, add) { 159 | if (nchar(add) > 0) { 160 | if (nchar(code) > 0) { 161 | code <- paste0(code, ", ", add) 162 | } else { 163 | code <- add 164 | } 165 | } 166 | return(code) 167 | } 168 | -------------------------------------------------------------------------------- /R/utils-stancode.R: -------------------------------------------------------------------------------- 1 | # Generate 'Stan' code for prior model (only parameters, no ODE solving) 2 | generate_stancode_prior <- function(odefun_vars, loglik_vars, other_vars, 3 | compile) { 4 | all_vars <- c(odefun_vars, loglik_vars) 5 | params <- all_vars[sapply(all_vars, is_param)] 6 | tparams <- all_vars[sapply(all_vars, is_tparam)] 7 | all_vars <- c(params, tparams) 8 | all_decls <- lapply(all_vars, get_decl) 9 | dims <- dims_of_decls(all_decls) 10 | 11 | data_b <- generate_data_block(all_decls, list()) # just dimensions 12 | pars_b <- generate_params_block(params) 13 | tpars_b <- generate_transform_block("transformed parameters", tparams, TRUE) 14 | model_b <- generate_model_block(params, prior_mode = TRUE) 15 | code <- paste(data_b, pars_b, tpars_b, model_b, sep = "\n") 16 | code <- autoformat_stancode(code) 17 | 18 | # Return 19 | StanModelWithCode$new(code, dims, NULL, NULL, params, tparams, NULL, compile) 20 | } 21 | 22 | # Create the functions block 23 | generate_functions_block <- function(odefun_add_sign, 24 | odefun_add_args, 25 | odefun_body, 26 | loglik_add_sign, 27 | loglik_body) { 28 | odefun <- generate_odefun(odefun_add_sign, odefun_body) 29 | if (nchar(loglik_body) > 0) { 30 | loglik <- generate_loglik(loglik_add_sign, loglik_body) 31 | } else { 32 | loglik <- "" 33 | } 34 | solvers <- functions_template() 35 | odefun_add_sign <- add_leading_comma(odefun_add_sign) 36 | odefun_add_args <- add_leading_comma(odefun_add_args) 37 | solvers <- fill_stancode_part(solvers, odefun_add_sign, "__ODEFUN_SIGN__") 38 | solvers <- fill_stancode_part(solvers, odefun_add_args, "__ODEFUN_ARGS__") 39 | code <- generate_block("functions", c(odefun, solvers, loglik)) 40 | autoformat_stancode(code) 41 | } 42 | 43 | # Create additional signature for function 44 | generate_add_signature <- function(all_vars, argmode) { 45 | if (length(all_vars) == 0) { 46 | return("") 47 | } 48 | no_add_signature <- function(x) { 49 | name <- get_name(x) 50 | is_noadd <- name %in% c("t", "t0", "y0") 51 | return(!is_noadd) 52 | } 53 | all_vars <- all_vars[sapply(all_vars, no_add_signature)] 54 | all_vars <- unique(all_vars) 55 | 56 | data <- all_vars[sapply(all_vars, is_data)] 57 | tdata <- all_vars[sapply(all_vars, is_tdata)] 58 | params <- all_vars[sapply(all_vars, is_param)] 59 | tparams <- all_vars[sapply(all_vars, is_tparam)] 60 | 61 | data_vars <- c(data, tdata) 62 | par_vars <- c(params, tparams) 63 | data_decls <- lapply(data_vars, get_decl) 64 | par_decls <- lapply(par_vars, get_decl) 65 | dim_sign <- generate_dim_signatures(c(data_decls, par_decls), argmode) 66 | data_sign <- generate_var_signatures(data_decls, TRUE, argmode) 67 | par_sign <- generate_var_signatures(par_decls, FALSE, argmode) 68 | 69 | signature <- "" 70 | signature <- append_to_signature(signature, dim_sign) 71 | signature <- append_to_signature(signature, data_sign) 72 | signature <- append_to_signature(signature, par_sign) 73 | trimws(signature) 74 | } 75 | 76 | # Generate Stan code for the ODE function 77 | generate_odefun <- function(add_signature, odefun_body) { 78 | signature <- "real t, vector y" 79 | signature <- append_to_signature(signature, add_signature) 80 | comment <- "\n// ODE system right-hand side \n" 81 | code <- paste0(comment, "vector odefun(", signature, ")") 82 | if (nchar(odefun_body) == 0) { 83 | warning("ODE function body is empty!") 84 | } 85 | paste0(code, "{\n", odefun_body, "\n}\n") 86 | } 87 | 88 | # Generate Stan code for the log likelihood function 89 | generate_loglik <- function(add_signature, loglik_body) { 90 | signature <- "array[] vector y_sol" 91 | signature <- append_to_signature(signature, add_signature) 92 | comment <- "\n// Compute log likelihood given ODE solution y_sol\n" 93 | code <- paste0(comment, "real log_likelihood(", signature, ")") 94 | if (nchar(loglik_body) == 0) { 95 | warning("log likelihood function body is empty!") 96 | } 97 | paste0(code, "{\n", loglik_body, "\n}\n") 98 | } 99 | 100 | # Create the data block 101 | generate_data_block <- function(all_decls, data) { 102 | dims_code <- generate_dim_declarations(all_decls) 103 | dvars_code <- generate_var_declarations(data) 104 | code <- generate_block("data", c(dims_code, dvars_code)) 105 | autoformat_stancode(code) 106 | } 107 | 108 | # Create a transform block (transformed data, transformed params, or gq) 109 | generate_transform_block <- function(name, transforms, reorder) { 110 | is_ysol_tpar <- function(x) x$decl$name == "y_sol_tpar" 111 | is_loglik_tpar <- function(x) x$decl$name == "log_lik_tpar" 112 | if (reorder) { 113 | i1 <- which(sapply(transforms, is_ysol_tpar) == TRUE) 114 | i2 <- which(sapply(transforms, is_loglik_tpar) == TRUE) 115 | L <- length(transforms) 116 | i_first <- setdiff(seq_len(L), c(i1, i2)) 117 | transforms <- c(transforms[i_first], transforms[i1], transforms[i2]) 118 | } 119 | 120 | decls <- lapply(transforms, get_decl) 121 | codes <- paste(lapply(transforms, get_code), collapse = "\n") 122 | decls <- generate_var_declarations(decls) 123 | generate_block(name, c(decls, codes)) 124 | } 125 | 126 | # Create the parameters block 127 | generate_params_block <- function(params) { 128 | decls <- lapply(params, get_decl) 129 | dvars_code <- generate_var_declarations(decls) 130 | generate_block("parameters", c(dvars_code)) 131 | } 132 | 133 | # Create the parameters block 134 | generate_model_block <- function(params, prior_mode) { 135 | codes <- paste(lapply(params, get_prior_code), collapse = "\n") 136 | if (prior_mode) { 137 | target <- "" 138 | } else { 139 | target <- "target += log_lik_tpar;" 140 | } 141 | generate_block("model", c(codes, target)) 142 | } 143 | 144 | # Create a block of Stan code 145 | generate_block <- function(name, parts) { 146 | body <- "" 147 | for (p in parts) { 148 | if (nchar(p) > 0) { 149 | body <- paste0(body, "\n", p) 150 | } 151 | } 152 | if (nchar(body) == 0) { 153 | return("") 154 | } 155 | paste0(name, " {\n", body, "\n}\n") 156 | } 157 | 158 | # Dimensions signatures 159 | generate_dim_signatures <- function(vars, argmode) { 160 | checkmate::assert_list(vars, "StanDeclaration") 161 | dim_vars <- list() 162 | for (var in vars) { 163 | dim_vars <- c(dim_vars, var$get_dims()) 164 | } 165 | generate_var_signatures(dim_vars, TRUE, argmode) 166 | } 167 | 168 | # Variables declaration code 169 | generate_var_signatures <- function(vars, data, argmode) { 170 | if (length(vars) == 0) { 171 | return("") 172 | } 173 | vars <- unique(vars) 174 | checkmate::assert_list(vars, "StanDeclaration") 175 | if (argmode) { 176 | getter <- function(x) x$name 177 | } else { 178 | getter <- function(x) x$signature() 179 | } 180 | if (data && !argmode) { 181 | pre <- "data" 182 | } else { 183 | pre <- "" 184 | } 185 | signs <- unique(sapply(vars, getter)) 186 | code <- paste(pre, signs, collapse = ", ") 187 | trimws(code) 188 | } 189 | 190 | # Get dimensions of each declaration 191 | dims_of_decls <- function(decls) { 192 | checkmate::assert_list(decls, "StanDeclaration") 193 | dim_decls <- list() 194 | for (var in decls) { 195 | dim_decls <- c(dim_decls, var$get_dims()) 196 | } 197 | unique(dim_decls) 198 | } 199 | 200 | # Dimensions declaration code 201 | generate_dim_declarations <- function(vars) { 202 | dim_vars <- dims_of_decls(vars) 203 | generate_var_declarations(dim_vars) 204 | } 205 | 206 | # Variables declaration code 207 | generate_var_declarations <- function(vars) { 208 | checkmate::assert_list(vars, "StanDeclaration") 209 | vars <- unique(vars) 210 | get_decl <- function(x) { 211 | x$declaration() 212 | } 213 | lines <- sapply(vars, get_decl) 214 | lines <- unique(lines) 215 | if (length(lines) == 0) { 216 | return("") 217 | } 218 | paste(lines, ";", sep = "", collapse = "\n") 219 | } 220 | 221 | # Template 'Stan' model code 222 | functions_template <- function() { 223 | filepath <- system.file("template_functions.stan", package = "odemodeling") 224 | read_file_lines(filepath) 225 | } 226 | 227 | # Helper function 228 | fill_stancode_part <- function(code, replacement, placeholder) { 229 | if (is.null(replacement)) { 230 | replacement <- paste0(placeholder, " <<<<<<<<<<<< MISSING !") 231 | } 232 | gsub(pattern = placeholder, fixed = TRUE, x = code, replacement = replacement) 233 | } 234 | -------------------------------------------------------------------------------- /R/utils-standecl.R: -------------------------------------------------------------------------------- 1 | # Helpers for filtering lists of StanDeclarations, StanParameters and 2 | # StanTransforms 3 | 4 | # Get decl 5 | get_decl <- function(x) { 6 | ok <- c("StanDeclaration", "StanParameter", "StanTransformation") 7 | checkmate::assert_multi_class(x, classes = ok) 8 | if (is(x, "StanDeclaration")) { 9 | return(x) 10 | } else { 11 | return(x$decl) 12 | } 13 | } 14 | 15 | # Get name 16 | get_name <- function(x) { 17 | ok <- c("StanDeclaration", "StanParameter", "StanTransformation") 18 | checkmate::assert_multi_class(x, classes = ok) 19 | if (is(x, "StanDeclaration")) { 20 | return(x$name) 21 | } else { 22 | return(x$decl$name) 23 | } 24 | } 25 | 26 | # Is data? 27 | is_data <- function(x) { 28 | is(x, "StanDeclaration") 29 | } 30 | 31 | # Is parameter? 32 | is_param <- function(x) { 33 | is(x, "StanParameter") 34 | } 35 | 36 | # Is transformed data? 37 | is_tdata <- function(x) { 38 | is_t <- is(x, "StanTransformation") 39 | if (!is_t) { 40 | return(FALSE) 41 | } 42 | x$origin == "data" 43 | } 44 | 45 | # Is transformed parameter? 46 | is_tparam <- function(x) { 47 | is_t <- is(x, "StanTransformation") 48 | if (!is_t) { 49 | return(FALSE) 50 | } 51 | x$origin == "parameters" 52 | } 53 | 54 | # Is generated quantitity 55 | is_gq <- function(x) { 56 | is_t <- is(x, "StanTransformation") 57 | if (!is_t) { 58 | return(FALSE) 59 | } 60 | x$origin == "model" 61 | } 62 | 63 | # Get dimensions 64 | get_dims <- function(x) { 65 | decl <- get_decl(x) 66 | decl$get_dims() 67 | } 68 | 69 | # Get prior code 70 | get_prior_code <- function(x) { 71 | x$prior_code 72 | } 73 | 74 | # Get code 75 | get_code <- function(x) { 76 | x$code 77 | } 78 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | .onAttach <- function(...) { 2 | msg <- create_startup_message() 3 | packageStartupMessage(msg) 4 | } 5 | 6 | # Create package startup message 7 | create_startup_message <- function() { 8 | v_ot <- pkg_version("odemodeling") 9 | msg <- paste0("Attached odemodeling ", v_ot, ".") 10 | return(msg) 11 | } 12 | 13 | # Create package description 14 | pkg_version <- function(pkg_name) { 15 | Lib <- dirname(system.file(package = pkg_name)) 16 | pkgdesc <- suppressWarnings( 17 | utils::packageDescription(pkg_name, lib.loc = Lib) 18 | ) 19 | if (length(pkgdesc) > 1) { 20 | out <- pkgdesc$Version 21 | } else { 22 | out <- "" 23 | } 24 | return(out) 25 | } 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # odemodeling 2 | 3 | [![codecov](https://codecov.io/gh/jtimonen/odemodeling/branch/main/graph/badge.svg?token=YLMK3KO0L0)](https://codecov.io/gh/jtimonen/odemodeling) 4 | 5 | R-package for building and fitting Bayesian ODE models in Stan. The package might still have some sharp corners but: 6 | 1. once you have learned how to use it, coding up new ODE models should be faster with it than raw Stan 7 | 2. once you have created a model with it, you can do the fitting using different ODE solvers (adaptive, non-adaptive) without needing to write new Stan code 8 | 3. once you have fitted a model with it, you can 9 | * quickly visualize the ODE solutions without needing to extract them yourself 10 | * quickly solve and visualize the ODE solutions using a different solver or at a different set of time points without needing to write new Stan code yourself 11 | * quickly assess whether the solver used during fitting was accurate enough, or if you need to do the fitting again with a more accurate one ([Timonen et al., 2023](https://onlinelibrary.wiley.com/doi/full/10.1002/sta4.614)) 12 | 13 | 14 | ## Installation 15 | 16 | * Install `cmdstanr` following the instructions [here](https://mc-stan.org/cmdstanr/). 17 | * Install `odemodeling` using 18 | 19 | ```r 20 | remotes::install_github("jtimonen/odemodeling", ref = "main", build_vignettes = TRUE) 21 | ``` 22 | 23 | Building the vignette takes around one minute. You can skip it with `build_vignettes = FALSE`. 24 | 25 | ## Getting started 26 | 27 | If you built the vignette, you can view it using 28 | 29 | ```r 30 | browseVignettes("odemodeling") 31 | ``` 32 | 33 | It is also available online [here](https://jtimonen.github.io/om.html). The 34 | vignette is perhaps the best place to start. More detailed info is in documentation, that you can view with 35 | ```r 36 | library(odemodeling) 37 | ?odemodeling 38 | ``` 39 | -------------------------------------------------------------------------------- /data-raw/lynxhare.R: -------------------------------------------------------------------------------- 1 | # Data from http://www.math.tamu.edu/~phoward/m442/modbasics.pdf 2 | # Downloaded 15 October 2017, 4:59 PM EDT 3 | 4 | # Year, Lynx, Hare 5 | x <- c( 6 | 1900, 4.0, 30.0, 7 | 1901, 6.1, 47.2, 8 | 1902, 9.8, 70.2, 9 | 1903, 35.2, 77.4, 10 | 1904, 59.4, 36.3, 11 | 1905, 41.7, 20.6, 12 | 1906, 19.0, 18.1, 13 | 1907, 13.0, 21.4, 14 | 1908, 8.3, 22.0, 15 | 1909, 9.1, 25.4, 16 | 1910, 7.4, 27.1, 17 | 1911, 8.0, 40.3, 18 | 1912, 12.3, 57.0, 19 | 1913, 19.5, 76.6, 20 | 1914, 45.7, 52.3, 21 | 1915, 51.1, 19.5, 22 | 1916, 29.7, 11.2, 23 | 1917, 15.8, 7.6, 24 | 1918, 9.7, 14.6, 25 | 1919, 10.1, 16.2, 26 | 1920, 8.6, 24.7 27 | ) 28 | X <- matrix(x, ncol = 3, byrow = TRUE) 29 | df <- data.frame(X) 30 | colnames(df) <- c("year", "lynx", "hare") 31 | lynxhare <- df 32 | 33 | # Create data 34 | usethis::use_data(lynxhare, overwrite = TRUE) 35 | -------------------------------------------------------------------------------- /data/lynxhare.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtimonen/odemodeling/91618ff39f83cc36d1501262eb5ad07ee67517b9/data/lynxhare.rda -------------------------------------------------------------------------------- /dev/covr.R: -------------------------------------------------------------------------------- 1 | require(covr) 2 | exclusions <- list() 3 | cov <- package_coverage(line_exclusions = exclusions, pre_clean = TRUE) 4 | report(cov) 5 | 6 | # upload to codecov.io with this command 7 | str <- "codecov(coverage = cov, token = tok)" 8 | cat( 9 | "Remember to run", odemodeling:::stancode_string(str), 10 | "using your codecov.io token!\n" 11 | ) 12 | -------------------------------------------------------------------------------- /dev/exports.R: -------------------------------------------------------------------------------- 1 | # Read namespace and extract exported functions 2 | s <- scan("NAMESPACE", what = "character", sep = "\n") 3 | L <- length(s) 4 | funs <- NULL 5 | 6 | # Select rows that define exports 7 | for (i in seq_len(L)) { 8 | line <- s[i] 9 | a <- grepl("export(", line, fixed = TRUE) 10 | if (a) funs <- c(funs, line) 11 | } 12 | 13 | # Print text to be pasted to _pkgdown.yml 14 | L <- length(funs) 15 | for (i in seq_len(L)) { 16 | line <- funs[i] 17 | f <- substr(line, 8, nchar(line) - 1) 18 | cat(" -", f, "\n") 19 | } 20 | -------------------------------------------------------------------------------- /dev/lint.R: -------------------------------------------------------------------------------- 1 | require(lintr) 2 | 3 | # Specify linters 4 | linters <- lintr::with_defaults( 5 | object_name_linter = NULL, 6 | open_curly_linter = NULL 7 | ) 8 | 9 | # Files that are not linted 10 | exclusions <- list() 11 | 12 | # Lint the package 13 | lout <- lintr::lint_package(linters = linters, exclusions = exclusions) 14 | show(summary(lout)) 15 | -------------------------------------------------------------------------------- /dev/style.R: -------------------------------------------------------------------------------- 1 | library(styler) 2 | 3 | # Format the package code according to the tidyverse guide 4 | exclusions <- list() 5 | styler:::style_pkg(exclude_files = exclusions) 6 | -------------------------------------------------------------------------------- /inst/CITATION: -------------------------------------------------------------------------------- 1 | citHeader("To cite odemodeling in publications use:") 2 | 3 | citEntry( 4 | entry = "Article", 5 | title = "An importance sampling approach for reliable and efficient inference in Bayesian ordinary differential equation models", 6 | author = "Juho Timonen, Nikolas Siccha, Ben Bales, Harri Lähdesmäki, Aki Vehtari", 7 | journal = "arXiv", 8 | url = "https://arxiv.org/abs/2205.09059", 9 | year = "2022", 10 | textVersion = paste( 11 | "Juho Timonen, Nikolas Siccha, Ben Bales, Harri Lähdesmäki and Aki Vehtari:", 12 | "An importance sampling approach for reliable and efficient inference in Bayesian ordinary differential equation models", 13 | "(2022).", 14 | "https://arxiv.org/abs/2205.09059" 15 | ) 16 | ) 17 | -------------------------------------------------------------------------------- /inst/template_functions.stan: -------------------------------------------------------------------------------- 1 | 2 | // Euler method 3 | array[] vector ode_euler_fixed_num_steps(vector y0, data real t0, 4 | data array[] real t, data int num_steps 5 | __ODEFUN_SIGN__) { 6 | int N = size(t); 7 | int D = num_elements(y0); 8 | array[N+1] vector[D] y_sol; 9 | array[N+1] real t_sol; 10 | real h; 11 | real ts; 12 | vector[D] ys; 13 | y_sol[1] = y0; 14 | t_sol[1] = t0; 15 | for(n in 1:N){ 16 | t_sol[n+1] = t[n]; 17 | h = (t_sol[n+1] - t_sol[n])/num_steps; 18 | ts = t_sol[n]; 19 | ys = y_sol[n]; 20 | for(s in 1:num_steps) { 21 | ys = ys + h * odefun(ts, ys __ODEFUN_ARGS__); 22 | ts = ts + h; 23 | } 24 | y_sol[n+1] = ys; 25 | } 26 | return(y_sol[2:(N+1)]); 27 | } 28 | 29 | // Midpoint method 30 | array[] vector ode_midpoint_fixed_num_steps(vector y0, data real t0, 31 | data array[] real t, data int num_steps 32 | __ODEFUN_SIGN__) { 33 | int N = size(t); 34 | int D = num_elements(y0); 35 | array[N+1] vector[D] y_sol; 36 | array[N+1] real t_sol; 37 | real h; 38 | real ts; 39 | vector[D] ys; 40 | vector[D] y_mid; 41 | y_sol[1] = y0; 42 | t_sol[1] = t0; 43 | for(n in 1:N){ 44 | t_sol[n+1] = t[n]; 45 | h = (t_sol[n+1] - t_sol[n])/num_steps; 46 | ts = t_sol[n]; 47 | ys = y_sol[n]; 48 | for(s in 1:num_steps) { 49 | // Half-Euler step 50 | y_mid = ys + 0.5 * h * odefun(ts, ys __ODEFUN_ARGS__); 51 | // Full step using derivative at midpoint 52 | ys = ys + h * odefun(ts + 0.5 * h, y_mid __ODEFUN_ARGS__); 53 | ts = ts + h; 54 | } 55 | y_sol[n+1] = ys; 56 | } 57 | return(y_sol[2:(N+1)]); 58 | } 59 | 60 | // RK4 method 61 | array[] vector ode_rk4_fixed_num_steps(vector y0, data real t0, 62 | data array[] real t, data int num_steps 63 | __ODEFUN_SIGN__) { 64 | int N = size(t); 65 | int D = num_elements(y0); 66 | array[N+1] vector[D] y_sol; 67 | array[N+1] real t_sol; 68 | real h; 69 | real ts; 70 | vector[D] ys; 71 | vector[D] k1; 72 | vector[D] k2; 73 | vector[D] k3; 74 | vector[D] k4; 75 | y_sol[1] = y0; 76 | t_sol[1] = t0; 77 | for(n in 1:N){ 78 | t_sol[n+1] = t[n]; 79 | h = (t_sol[n+1] - t_sol[n])/num_steps; 80 | ts = t_sol[n]; 81 | ys = y_sol[n]; 82 | for(s in 1:num_steps) { 83 | k1 = h * odefun(ts, ys __ODEFUN_ARGS__); 84 | k2 = h * odefun(ts + 0.5 * h, ys + 0.5 * k1 __ODEFUN_ARGS__); 85 | k3 = h * odefun(ts + 0.5 * h, ys + 0.5 * k2 __ODEFUN_ARGS__); 86 | k4 = h * odefun(ts + h, ys + k3 __ODEFUN_ARGS__); 87 | ys = ys + (k1 + 2.0 * k2 + 2.0 * k3 + k4) / 6.0; 88 | } 89 | y_sol[n + 1] = ys; 90 | } 91 | return(y_sol[2:(N+1)]); 92 | } 93 | 94 | // Solve ODE 95 | array[] vector solve_ode(data int solver, data real rel_tol, 96 | data real abs_tol, data int max_num_steps, data int num_steps, 97 | vector y0, data real t0, data array[] real t 98 | __ODEFUN_SIGN__) 99 | { 100 | int N = size(t); 101 | int D = num_elements(y0); 102 | array[N] vector[D] y_sol; 103 | if (solver==1) { 104 | y_sol = ode_rk45_tol(odefun, y0, t0, t, rel_tol, abs_tol, max_num_steps 105 | __ODEFUN_ARGS__); 106 | } else if (solver==2) { 107 | y_sol = ode_bdf_tol(odefun, y0, t0, t, rel_tol, abs_tol, max_num_steps 108 | __ODEFUN_ARGS__); 109 | } else if (solver==3) { 110 | y_sol = ode_adams_tol(odefun, y0, t0, t, rel_tol, abs_tol, max_num_steps 111 | __ODEFUN_ARGS__); 112 | } else if (solver==4) { 113 | y_sol = ode_ckrk_tol(odefun, y0, t0, t, rel_tol, abs_tol, max_num_steps 114 | __ODEFUN_ARGS__); 115 | } else if (solver==101) { 116 | y_sol = ode_euler_fixed_num_steps(y0, t0, t, num_steps __ODEFUN_ARGS__); 117 | } else if (solver==102) { 118 | y_sol = ode_midpoint_fixed_num_steps(y0, t0, t, num_steps __ODEFUN_ARGS__); 119 | } else if (solver==103) { 120 | y_sol = ode_rk4_fixed_num_steps(y0, t0, t, num_steps __ODEFUN_ARGS__); 121 | } else { 122 | reject("solver must be 1, 2, 3, 4, 101, 102, or 103!"); 123 | } 124 | return(y_sol); 125 | } 126 | -------------------------------------------------------------------------------- /man/AdaptiveOdeSolver.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/classes-solver.R 3 | \name{AdaptiveOdeSolver} 4 | \alias{AdaptiveOdeSolver} 5 | \title{An ODE solver with adaptive step size} 6 | \description{ 7 | An ODE solver with adaptive step size 8 | 9 | An ODE solver with adaptive step size 10 | } 11 | \section{Super class}{ 12 | \code{\link[odemodeling:OdeSolver]{odemodeling::OdeSolver}} -> \code{AdaptiveOdeSolver} 13 | } 14 | \section{Public fields}{ 15 | \if{html}{\out{
}} 16 | \describe{ 17 | \item{\code{abs_tol}}{absolute tolerance} 18 | 19 | \item{\code{rel_tol}}{relative tolerance} 20 | 21 | \item{\code{max_num_steps}}{maximum number of steps} 22 | } 23 | \if{html}{\out{
}} 24 | } 25 | \section{Methods}{ 26 | \subsection{Public methods}{ 27 | \itemize{ 28 | \item \href{#method-AdaptiveOdeSolver-new}{\code{AdaptiveOdeSolver$new()}} 29 | \item \href{#method-AdaptiveOdeSolver-standata}{\code{AdaptiveOdeSolver$standata()}} 30 | \item \href{#method-AdaptiveOdeSolver-to_string}{\code{AdaptiveOdeSolver$to_string()}} 31 | \item \href{#method-AdaptiveOdeSolver-clone}{\code{AdaptiveOdeSolver$clone()}} 32 | } 33 | } 34 | \if{html}{\out{ 35 |
Inherited methods 36 | 39 |
40 | }} 41 | \if{html}{\out{
}} 42 | \if{html}{\out{}} 43 | \if{latex}{\out{\hypertarget{method-AdaptiveOdeSolver-new}{}}} 44 | \subsection{Method \code{new()}}{ 45 | Initialize 46 | \subsection{Usage}{ 47 | \if{html}{\out{
}}\preformatted{AdaptiveOdeSolver$new(name, abs_tol, rel_tol, max_num_steps)}\if{html}{\out{
}} 48 | } 49 | 50 | \subsection{Arguments}{ 51 | \if{html}{\out{
}} 52 | \describe{ 53 | \item{\code{name}}{solver name} 54 | 55 | \item{\code{abs_tol}}{absolute tolerance} 56 | 57 | \item{\code{rel_tol}}{relative tolerance} 58 | 59 | \item{\code{max_num_steps}}{maximum number of steps} 60 | } 61 | \if{html}{\out{
}} 62 | } 63 | } 64 | \if{html}{\out{
}} 65 | \if{html}{\out{}} 66 | \if{latex}{\out{\hypertarget{method-AdaptiveOdeSolver-standata}{}}} 67 | \subsection{Method \code{standata()}}{ 68 | Create Stan data fields. 69 | \subsection{Usage}{ 70 | \if{html}{\out{
}}\preformatted{AdaptiveOdeSolver$standata()}\if{html}{\out{
}} 71 | } 72 | 73 | \subsection{Returns}{ 74 | A list. 75 | } 76 | } 77 | \if{html}{\out{
}} 78 | \if{html}{\out{}} 79 | \if{latex}{\out{\hypertarget{method-AdaptiveOdeSolver-to_string}{}}} 80 | \subsection{Method \code{to_string()}}{ 81 | String description of the solver. 82 | \subsection{Usage}{ 83 | \if{html}{\out{
}}\preformatted{AdaptiveOdeSolver$to_string()}\if{html}{\out{
}} 84 | } 85 | 86 | \subsection{Returns}{ 87 | A string. 88 | } 89 | } 90 | \if{html}{\out{
}} 91 | \if{html}{\out{}} 92 | \if{latex}{\out{\hypertarget{method-AdaptiveOdeSolver-clone}{}}} 93 | \subsection{Method \code{clone()}}{ 94 | The objects of this class are cloneable with this method. 95 | \subsection{Usage}{ 96 | \if{html}{\out{
}}\preformatted{AdaptiveOdeSolver$clone(deep = FALSE)}\if{html}{\out{
}} 97 | } 98 | 99 | \subsection{Arguments}{ 100 | \if{html}{\out{
}} 101 | \describe{ 102 | \item{\code{deep}}{Whether to make a deep clone.} 103 | } 104 | \if{html}{\out{
}} 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /man/FixedNumStepsOdeSolver.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/classes-solver.R 3 | \name{FixedNumStepsOdeSolver} 4 | \alias{FixedNumStepsOdeSolver} 5 | \title{An ODE solver with fixed number of steps} 6 | \description{ 7 | An ODE solver with fixed number of steps 8 | 9 | An ODE solver with fixed number of steps 10 | } 11 | \section{Super class}{ 12 | \code{\link[odemodeling:OdeSolver]{odemodeling::OdeSolver}} -> \code{FixedNumStepsOdeSolver} 13 | } 14 | \section{Public fields}{ 15 | \if{html}{\out{
}} 16 | \describe{ 17 | \item{\code{num_steps}}{maximum number of steps per time point interval} 18 | } 19 | \if{html}{\out{
}} 20 | } 21 | \section{Methods}{ 22 | \subsection{Public methods}{ 23 | \itemize{ 24 | \item \href{#method-FixedNumStepsOdeSolver-new}{\code{FixedNumStepsOdeSolver$new()}} 25 | \item \href{#method-FixedNumStepsOdeSolver-standata}{\code{FixedNumStepsOdeSolver$standata()}} 26 | \item \href{#method-FixedNumStepsOdeSolver-to_string}{\code{FixedNumStepsOdeSolver$to_string()}} 27 | \item \href{#method-FixedNumStepsOdeSolver-clone}{\code{FixedNumStepsOdeSolver$clone()}} 28 | } 29 | } 30 | \if{html}{\out{ 31 |
Inherited methods 32 | 35 |
36 | }} 37 | \if{html}{\out{
}} 38 | \if{html}{\out{}} 39 | \if{latex}{\out{\hypertarget{method-FixedNumStepsOdeSolver-new}{}}} 40 | \subsection{Method \code{new()}}{ 41 | Initialize 42 | \subsection{Usage}{ 43 | \if{html}{\out{
}}\preformatted{FixedNumStepsOdeSolver$new(name, num_steps)}\if{html}{\out{
}} 44 | } 45 | 46 | \subsection{Arguments}{ 47 | \if{html}{\out{
}} 48 | \describe{ 49 | \item{\code{name}}{solver name} 50 | 51 | \item{\code{num_steps}}{number of steps per time point interval} 52 | } 53 | \if{html}{\out{
}} 54 | } 55 | } 56 | \if{html}{\out{
}} 57 | \if{html}{\out{}} 58 | \if{latex}{\out{\hypertarget{method-FixedNumStepsOdeSolver-standata}{}}} 59 | \subsection{Method \code{standata()}}{ 60 | Create Stan data fields. 61 | \subsection{Usage}{ 62 | \if{html}{\out{
}}\preformatted{FixedNumStepsOdeSolver$standata()}\if{html}{\out{
}} 63 | } 64 | 65 | \subsection{Returns}{ 66 | A list. 67 | } 68 | } 69 | \if{html}{\out{
}} 70 | \if{html}{\out{}} 71 | \if{latex}{\out{\hypertarget{method-FixedNumStepsOdeSolver-to_string}{}}} 72 | \subsection{Method \code{to_string()}}{ 73 | String description of the solver. 74 | \subsection{Usage}{ 75 | \if{html}{\out{
}}\preformatted{FixedNumStepsOdeSolver$to_string()}\if{html}{\out{
}} 76 | } 77 | 78 | \subsection{Returns}{ 79 | A string. 80 | } 81 | } 82 | \if{html}{\out{
}} 83 | \if{html}{\out{}} 84 | \if{latex}{\out{\hypertarget{method-FixedNumStepsOdeSolver-clone}{}}} 85 | \subsection{Method \code{clone()}}{ 86 | The objects of this class are cloneable with this method. 87 | \subsection{Usage}{ 88 | \if{html}{\out{
}}\preformatted{FixedNumStepsOdeSolver$clone(deep = FALSE)}\if{html}{\out{
}} 89 | } 90 | 91 | \subsection{Arguments}{ 92 | \if{html}{\out{
}} 93 | \describe{ 94 | \item{\code{deep}}{Whether to make a deep clone.} 95 | } 96 | \if{html}{\out{
}} 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /man/OdeModel.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/classes-model.R 3 | \name{OdeModel} 4 | \alias{OdeModel} 5 | \title{An ODE model (R6 class)} 6 | \description{ 7 | An ODE model (R6 class). Users are not meant to instantiate 8 | objects of this class directly, instead use the \code{\link[=ode_model]{ode_model()}} function 9 | to create models. 10 | } 11 | \section{Public fields}{ 12 | \if{html}{\out{
}} 13 | \describe{ 14 | \item{\code{has_likelihood}}{Is there a likelihood function?} 15 | 16 | \item{\code{stanmodel}}{An object of class \code{StanModelWithCode}.} 17 | 18 | \item{\code{odemodeling_version}}{of the package used to create the model} 19 | 20 | \item{\code{sig_figs}}{Number of significant figures to use everywhere.} 21 | 22 | \item{\code{t_dim}}{A \code{StanDimension} of the time points array.} 23 | 24 | \item{\code{ode_dim}}{A \code{StanDimension} of the ODE system.} 25 | } 26 | \if{html}{\out{
}} 27 | } 28 | \section{Methods}{ 29 | \subsection{Public methods}{ 30 | \itemize{ 31 | \item \href{#method-OdeModel-new}{\code{OdeModel$new()}} 32 | \item \href{#method-OdeModel-assert_stanfile_exists}{\code{OdeModel$assert_stanfile_exists()}} 33 | \item \href{#method-OdeModel-reinit}{\code{OdeModel$reinit()}} 34 | \item \href{#method-OdeModel-print}{\code{OdeModel$print()}} 35 | \item \href{#method-OdeModel-code}{\code{OdeModel$code()}} 36 | \item \href{#method-OdeModel-make_params}{\code{OdeModel$make_params()}} 37 | \item \href{#method-OdeModel-gqs}{\code{OdeModel$gqs()}} 38 | \item \href{#method-OdeModel-sample}{\code{OdeModel$sample()}} 39 | \item \href{#method-OdeModel-diagnose}{\code{OdeModel$diagnose()}} 40 | \item \href{#method-OdeModel-sample_manyconf}{\code{OdeModel$sample_manyconf()}} 41 | \item \href{#method-OdeModel-clone}{\code{OdeModel$clone()}} 42 | } 43 | } 44 | \if{html}{\out{
}} 45 | \if{html}{\out{}} 46 | \if{latex}{\out{\hypertarget{method-OdeModel-new}{}}} 47 | \subsection{Method \code{new()}}{ 48 | Create an \code{OdeModel} object. 49 | \subsection{Usage}{ 50 | \if{html}{\out{
}}\preformatted{OdeModel$new(has_likelihood, stanmodel, sig_figs, t_dim, ode_dim)}\if{html}{\out{
}} 51 | } 52 | 53 | \subsection{Arguments}{ 54 | \if{html}{\out{
}} 55 | \describe{ 56 | \item{\code{has_likelihood}}{Is there a likelihood function?} 57 | 58 | \item{\code{stanmodel}}{An object of class \code{StanModelWithCode} 59 | (will be deepcopied)..} 60 | 61 | \item{\code{sig_figs}}{Number of significant figures to use in all Stan i/o.} 62 | 63 | \item{\code{t_dim}}{Time points vector dimension variable 64 | (will be deepcopied).} 65 | 66 | \item{\code{ode_dim}}{ODE system dimension variable (will be deepcopied).} 67 | 68 | \item{\code{compile}}{Should the models be compiled.} 69 | } 70 | \if{html}{\out{
}} 71 | } 72 | } 73 | \if{html}{\out{
}} 74 | \if{html}{\out{}} 75 | \if{latex}{\out{\hypertarget{method-OdeModel-assert_stanfile_exists}{}}} 76 | \subsection{Method \code{assert_stanfile_exists()}}{ 77 | Check that the Stan model has been initialized correctly 78 | \subsection{Usage}{ 79 | \if{html}{\out{
}}\preformatted{OdeModel$assert_stanfile_exists()}\if{html}{\out{
}} 80 | } 81 | 82 | } 83 | \if{html}{\out{
}} 84 | \if{html}{\out{}} 85 | \if{latex}{\out{\hypertarget{method-OdeModel-reinit}{}}} 86 | \subsection{Method \code{reinit()}}{ 87 | (Re)initialize the Stan model 88 | \subsection{Usage}{ 89 | \if{html}{\out{
}}\preformatted{OdeModel$reinit()}\if{html}{\out{
}} 90 | } 91 | 92 | } 93 | \if{html}{\out{
}} 94 | \if{html}{\out{}} 95 | \if{latex}{\out{\hypertarget{method-OdeModel-print}{}}} 96 | \subsection{Method \code{print()}}{ 97 | Print information about the model 98 | \subsection{Usage}{ 99 | \if{html}{\out{
}}\preformatted{OdeModel$print()}\if{html}{\out{
}} 100 | } 101 | 102 | } 103 | \if{html}{\out{
}} 104 | \if{html}{\out{}} 105 | \if{latex}{\out{\hypertarget{method-OdeModel-code}{}}} 106 | \subsection{Method \code{code()}}{ 107 | Get the Stan code of the model. 108 | \subsection{Usage}{ 109 | \if{html}{\out{
}}\preformatted{OdeModel$code()}\if{html}{\out{
}} 110 | } 111 | 112 | } 113 | \if{html}{\out{
}} 114 | \if{html}{\out{}} 115 | \if{latex}{\out{\hypertarget{method-OdeModel-make_params}{}}} 116 | \subsection{Method \code{make_params()}}{ 117 | Format a vector into a draws array that can be passed to \verb{$gqs()}. 118 | Currently works only for models with only scalar parameters. 119 | \subsection{Usage}{ 120 | \if{html}{\out{
}}\preformatted{OdeModel$make_params(x)}\if{html}{\out{
}} 121 | } 122 | 123 | \subsection{Arguments}{ 124 | \if{html}{\out{
}} 125 | \describe{ 126 | \item{\code{x}}{A a vector with length equal to total number of model 127 | parameters.} 128 | } 129 | \if{html}{\out{
}} 130 | } 131 | \subsection{Returns}{ 132 | A \link[posterior:draws_array]{posterior::draws_array} object with only one chain and 133 | iteration. 134 | } 135 | } 136 | \if{html}{\out{
}} 137 | \if{html}{\out{}} 138 | \if{latex}{\out{\hypertarget{method-OdeModel-gqs}{}}} 139 | \subsection{Method \code{gqs()}}{ 140 | Run standalone generated quantities. 141 | \subsection{Usage}{ 142 | \if{html}{\out{
}}\preformatted{OdeModel$gqs(t0, t, data = list(), solver = rk45(), params = NULL, ...)}\if{html}{\out{
}} 143 | } 144 | 145 | \subsection{Arguments}{ 146 | \if{html}{\out{
}} 147 | \describe{ 148 | \item{\code{t0}}{Initial time.} 149 | 150 | \item{\code{t}}{Vector of time points.} 151 | 152 | \item{\code{data}}{Additional data.} 153 | 154 | \item{\code{solver}}{ODE solver.} 155 | 156 | \item{\code{params}}{Equal to the \code{fitted_params} argument of the 157 | \verb{$generate_quantities()} method of the underlying 158 | \link[cmdstanr:CmdStanModel]{cmdstanr::CmdStanModel} object.} 159 | 160 | \item{\code{...}}{Arguments passed to the \verb{$generate_quantities()} method of the 161 | underlying \link[cmdstanr:CmdStanModel]{cmdstanr::CmdStanModel} object.} 162 | } 163 | \if{html}{\out{
}} 164 | } 165 | \subsection{Returns}{ 166 | An object of class \link{OdeModelGQ}. 167 | } 168 | } 169 | \if{html}{\out{
}} 170 | \if{html}{\out{}} 171 | \if{latex}{\out{\hypertarget{method-OdeModel-sample}{}}} 172 | \subsection{Method \code{sample()}}{ 173 | Sample parameters of the model 174 | \subsection{Usage}{ 175 | \if{html}{\out{
}}\preformatted{OdeModel$sample(t0, t, data = list(), solver = rk45(), ...)}\if{html}{\out{
}} 176 | } 177 | 178 | \subsection{Arguments}{ 179 | \if{html}{\out{
}} 180 | \describe{ 181 | \item{\code{t0}}{Initial time point.} 182 | 183 | \item{\code{t}}{Vector of time points.} 184 | 185 | \item{\code{data}}{Other needed data as a list.} 186 | 187 | \item{\code{solver}}{An object of class \link{OdeSolver}.} 188 | 189 | \item{\code{...}}{Arguments passed to the \verb{$sample()} method of the 190 | underlying \link[cmdstanr:CmdStanModel]{cmdstanr::CmdStanModel} object.} 191 | } 192 | \if{html}{\out{
}} 193 | } 194 | \subsection{Returns}{ 195 | An object of class \link{OdeModelMCMC}. 196 | } 197 | } 198 | \if{html}{\out{
}} 199 | \if{html}{\out{}} 200 | \if{latex}{\out{\hypertarget{method-OdeModel-diagnose}{}}} 201 | \subsection{Method \code{diagnose()}}{ 202 | Run a gradient diagnosis 203 | \subsection{Usage}{ 204 | \if{html}{\out{
}}\preformatted{OdeModel$diagnose( 205 | t0, 206 | t, 207 | data = list(), 208 | solver = rk45(), 209 | error = Inf, 210 | epsilon = 1e-06, 211 | ... 212 | )}\if{html}{\out{
}} 213 | } 214 | 215 | \subsection{Arguments}{ 216 | \if{html}{\out{
}} 217 | \describe{ 218 | \item{\code{t0}}{Initial time point.} 219 | 220 | \item{\code{t}}{Vector of time points.} 221 | 222 | \item{\code{data}}{Other needed data as a list.} 223 | 224 | \item{\code{solver}}{An object of class \link{OdeSolver}.} 225 | 226 | \item{\code{error}}{Error threshold.} 227 | 228 | \item{\code{epsilon}}{Perturbation size.} 229 | 230 | \item{\code{...}}{Arguments passed to the \verb{$diagnose()} method of the 231 | underlying \link[cmdstanr:CmdStanModel]{cmdstanr::CmdStanModel} object.} 232 | } 233 | \if{html}{\out{
}} 234 | } 235 | \subsection{Returns}{ 236 | Raw 'Stan' output. 237 | } 238 | } 239 | \if{html}{\out{
}} 240 | \if{html}{\out{}} 241 | \if{latex}{\out{\hypertarget{method-OdeModel-sample_manyconf}{}}} 242 | \subsection{Method \code{sample_manyconf()}}{ 243 | Sample parameters of the ODE model using many different ODE solver 244 | configurations 245 | \subsection{Usage}{ 246 | \if{html}{\out{
}}\preformatted{OdeModel$sample_manyconf( 247 | solvers, 248 | t0, 249 | t, 250 | data = list(), 251 | savedir = "results", 252 | basename = "odemodelfit", 253 | chains = 4, 254 | ... 255 | )}\if{html}{\out{
}} 256 | } 257 | 258 | \subsection{Arguments}{ 259 | \if{html}{\out{
}} 260 | \describe{ 261 | \item{\code{solvers}}{List of ODE solvers (possibly the same solver with 262 | different configurations). See \code{\link{odesolvers_lists}} for 263 | creating this.} 264 | 265 | \item{\code{t0}}{Initial time point.} 266 | 267 | \item{\code{t}}{Vector of time points.} 268 | 269 | \item{\code{data}}{Other needed data as a list.} 270 | 271 | \item{\code{savedir}}{Directory where results are saved.} 272 | 273 | \item{\code{basename}}{Base name for saved files.} 274 | 275 | \item{\code{chains}}{Number of MCMC chains.} 276 | 277 | \item{\code{...}}{Additional arguments passed to the \verb{$sample()} method of the 278 | underlying \link[cmdstanr:CmdStanModel]{cmdstanr::CmdStanModel} object.} 279 | } 280 | \if{html}{\out{
}} 281 | } 282 | \subsection{Returns}{ 283 | A named list. 284 | } 285 | } 286 | \if{html}{\out{
}} 287 | \if{html}{\out{}} 288 | \if{latex}{\out{\hypertarget{method-OdeModel-clone}{}}} 289 | \subsection{Method \code{clone()}}{ 290 | The objects of this class are cloneable with this method. 291 | \subsection{Usage}{ 292 | \if{html}{\out{
}}\preformatted{OdeModel$clone(deep = FALSE)}\if{html}{\out{
}} 293 | } 294 | 295 | \subsection{Arguments}{ 296 | \if{html}{\out{
}} 297 | \describe{ 298 | \item{\code{deep}}{Whether to make a deep clone.} 299 | } 300 | \if{html}{\out{
}} 301 | } 302 | } 303 | } 304 | -------------------------------------------------------------------------------- /man/OdeModelGQ.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/classes-fit.R 3 | \name{OdeModelGQ} 4 | \alias{OdeModelGQ} 5 | \title{An ODE model GQ fit (R6 class)} 6 | \description{ 7 | Used for holding the output of the \verb{$gqs()} 8 | method of the \link{OdeModel} and \link{OdeModelMCMC} class. Users are not meant to 9 | instantiate objects of this class directly. 10 | } 11 | \seealso{ 12 | For more useful methods, see the methods inherited from 13 | \link{OdeModelFit}. 14 | 15 | Other model fit classes: 16 | \code{\link{OdeModelFit}}, 17 | \code{\link{OdeModelMCMC}} 18 | } 19 | \concept{model fit classes} 20 | \section{Super class}{ 21 | \code{\link[odemodeling:OdeModelFit]{odemodeling::OdeModelFit}} -> \code{OdeModelGQ} 22 | } 23 | \section{Methods}{ 24 | \subsection{Public methods}{ 25 | \itemize{ 26 | \item \href{#method-OdeModelGQ-print}{\code{OdeModelGQ$print()}} 27 | \item \href{#method-OdeModelGQ-clone}{\code{OdeModelGQ$clone()}} 28 | } 29 | } 30 | \if{html}{\out{ 31 |
Inherited methods 32 | 57 |
58 | }} 59 | \if{html}{\out{
}} 60 | \if{html}{\out{}} 61 | \if{latex}{\out{\hypertarget{method-OdeModelGQ-print}{}}} 62 | \subsection{Method \code{print()}}{ 63 | Print information about the object. 64 | \subsection{Usage}{ 65 | \if{html}{\out{
}}\preformatted{OdeModelGQ$print()}\if{html}{\out{
}} 66 | } 67 | 68 | } 69 | \if{html}{\out{
}} 70 | \if{html}{\out{}} 71 | \if{latex}{\out{\hypertarget{method-OdeModelGQ-clone}{}}} 72 | \subsection{Method \code{clone()}}{ 73 | The objects of this class are cloneable with this method. 74 | \subsection{Usage}{ 75 | \if{html}{\out{
}}\preformatted{OdeModelGQ$clone(deep = FALSE)}\if{html}{\out{
}} 76 | } 77 | 78 | \subsection{Arguments}{ 79 | \if{html}{\out{
}} 80 | \describe{ 81 | \item{\code{deep}}{Whether to make a deep clone.} 82 | } 83 | \if{html}{\out{
}} 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /man/OdeModelMCMC.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/classes-fit.R 3 | \name{OdeModelMCMC} 4 | \alias{OdeModelMCMC} 5 | \title{An ODE model MCMC fit (R6 class)} 6 | \description{ 7 | Used for holding the output of the \verb{$sample()} method of the 8 | \link{OdeModel} class. Users are not meant to instantiate 9 | objects of this class directly. 10 | } 11 | \references{ 12 | \enumerate{ 13 | \item Timonen, J. et al. (2022). 14 | \emph{An importance sampling approach for reliable and efficient 15 | inference in Bayesian ordinary differential equation models}. 16 | \href{https://arxiv.org/abs/2205.09059}{arXiv}. 17 | } 18 | } 19 | \seealso{ 20 | For more useful methods, see the methods inherited from 21 | \link{OdeModelFit}. 22 | 23 | Other model fit classes: 24 | \code{\link{OdeModelFit}}, 25 | \code{\link{OdeModelGQ}} 26 | } 27 | \concept{model fit classes} 28 | \section{Super class}{ 29 | \code{\link[odemodeling:OdeModelFit]{odemodeling::OdeModelFit}} -> \code{OdeModelMCMC} 30 | } 31 | \section{Public fields}{ 32 | \if{html}{\out{
}} 33 | \describe{ 34 | \item{\code{cmdstan_diagnostics}}{Output of the \code{diagnose} program of 'CmdStan'.} 35 | 36 | \item{\code{cmdstan_summary}}{Output of the \code{stansummary} program of 'CmdStan'.} 37 | } 38 | \if{html}{\out{
}} 39 | } 40 | \section{Methods}{ 41 | \subsection{Public methods}{ 42 | \itemize{ 43 | \item \href{#method-OdeModelMCMC-print_diagnostics}{\code{OdeModelMCMC$print_diagnostics()}} 44 | \item \href{#method-OdeModelMCMC-print_summary}{\code{OdeModelMCMC$print_summary()}} 45 | \item \href{#method-OdeModelMCMC-new}{\code{OdeModelMCMC$new()}} 46 | \item \href{#method-OdeModelMCMC-print}{\code{OdeModelMCMC$print()}} 47 | \item \href{#method-OdeModelMCMC-cmdstan_init}{\code{OdeModelMCMC$cmdstan_init()}} 48 | \item \href{#method-OdeModelMCMC-gqs}{\code{OdeModelMCMC$gqs()}} 49 | \item \href{#method-OdeModelMCMC-reliability}{\code{OdeModelMCMC$reliability()}} 50 | \item \href{#method-OdeModelMCMC-clone}{\code{OdeModelMCMC$clone()}} 51 | } 52 | } 53 | \if{html}{\out{ 54 |
Inherited methods 55 | 79 |
80 | }} 81 | \if{html}{\out{
}} 82 | \if{html}{\out{}} 83 | \if{latex}{\out{\hypertarget{method-OdeModelMCMC-print_diagnostics}{}}} 84 | \subsection{Method \code{print_diagnostics()}}{ 85 | Print the 'stdout' of 'CmdStan' diagnostics. 86 | \subsection{Usage}{ 87 | \if{html}{\out{
}}\preformatted{OdeModelMCMC$print_diagnostics()}\if{html}{\out{
}} 88 | } 89 | 90 | } 91 | \if{html}{\out{
}} 92 | \if{html}{\out{}} 93 | \if{latex}{\out{\hypertarget{method-OdeModelMCMC-print_summary}{}}} 94 | \subsection{Method \code{print_summary()}}{ 95 | Print the 'stdout' of 'CmdStan' summary. 96 | \subsection{Usage}{ 97 | \if{html}{\out{
}}\preformatted{OdeModelMCMC$print_summary()}\if{html}{\out{
}} 98 | } 99 | 100 | } 101 | \if{html}{\out{
}} 102 | \if{html}{\out{}} 103 | \if{latex}{\out{\hypertarget{method-OdeModelMCMC-new}{}}} 104 | \subsection{Method \code{new()}}{ 105 | Create an \link{OdeModelMCMC} object. 106 | \subsection{Usage}{ 107 | \if{html}{\out{
}}\preformatted{OdeModelMCMC$new( 108 | model, 109 | t0, 110 | t, 111 | solver, 112 | data, 113 | cmdstanr_fit, 114 | cmdstan_diagnostics, 115 | cmdstan_summary 116 | )}\if{html}{\out{
}} 117 | } 118 | 119 | \subsection{Arguments}{ 120 | \if{html}{\out{
}} 121 | \describe{ 122 | \item{\code{model}}{An object of class \link{OdeModel} (will be deepcopied).} 123 | 124 | \item{\code{t0}}{Used initial time.} 125 | 126 | \item{\code{t}}{Used time points.} 127 | 128 | \item{\code{solver}}{Used solver. An object of class \link{OdeSolver}.} 129 | 130 | \item{\code{data}}{Given additional data.} 131 | 132 | \item{\code{cmdstanr_fit}}{A \link[cmdstanr:CmdStanMCMC]{cmdstanr::CmdStanMCMC} object.} 133 | 134 | \item{\code{cmdstan_diagnostics}}{Output of the \code{diagnose} program of 'CmdStan'.} 135 | 136 | \item{\code{cmdstan_summary}}{Output of the \code{stansummary} program of 'CmdStan'.} 137 | } 138 | \if{html}{\out{
}} 139 | } 140 | } 141 | \if{html}{\out{
}} 142 | \if{html}{\out{}} 143 | \if{latex}{\out{\hypertarget{method-OdeModelMCMC-print}{}}} 144 | \subsection{Method \code{print()}}{ 145 | Print information about the object. 146 | \subsection{Usage}{ 147 | \if{html}{\out{
}}\preformatted{OdeModelMCMC$print()}\if{html}{\out{
}} 148 | } 149 | 150 | } 151 | \if{html}{\out{
}} 152 | \if{html}{\out{}} 153 | \if{latex}{\out{\hypertarget{method-OdeModelMCMC-cmdstan_init}{}}} 154 | \subsection{Method \code{cmdstan_init()}}{ 155 | Get used 'CmdStan' init argument. 156 | \subsection{Usage}{ 157 | \if{html}{\out{
}}\preformatted{OdeModelMCMC$cmdstan_init()}\if{html}{\out{
}} 158 | } 159 | 160 | } 161 | \if{html}{\out{
}} 162 | \if{html}{\out{}} 163 | \if{latex}{\out{\hypertarget{method-OdeModelMCMC-gqs}{}}} 164 | \subsection{Method \code{gqs()}}{ 165 | Simulate ODE solutions (and other possible generated quantities 166 | using) the model and fitted params. This If any 167 | of the arguments are \code{NULL} (default), they are replaced with ones saved 168 | in the \link{OdeModelFit} object. 169 | \subsection{Usage}{ 170 | \if{html}{\out{
}}\preformatted{OdeModelMCMC$gqs( 171 | t0 = NULL, 172 | t = NULL, 173 | data = NULL, 174 | solver = NULL, 175 | fitted_params = NULL, 176 | ... 177 | )}\if{html}{\out{
}} 178 | } 179 | 180 | \subsection{Arguments}{ 181 | \if{html}{\out{
}} 182 | \describe{ 183 | \item{\code{t0}}{Initial time.} 184 | 185 | \item{\code{t}}{Vector of time points.} 186 | 187 | \item{\code{data}}{Additional data.} 188 | 189 | \item{\code{solver}}{ODE solver.} 190 | 191 | \item{\code{fitted_params}}{Will be passed as the \code{fitted_params} argument 192 | to the \verb{$generate_quantities()} method of the underlying 193 | \link[cmdstanr:CmdStanModel]{cmdstanr::CmdStanModel} object. If this is \code{NULL} (default), 194 | parameter draws of the \link{OdeModelFit} object are used.} 195 | 196 | \item{\code{...}}{Arguments passed to the \verb{$generate_quantities()} method of 197 | the underlying \link[cmdstanr:CmdStanModel]{cmdstanr::CmdStanModel} object.} 198 | } 199 | \if{html}{\out{
}} 200 | } 201 | \subsection{Returns}{ 202 | An object of class \link{OdeModelGQ}. 203 | } 204 | } 205 | \if{html}{\out{
}} 206 | \if{html}{\out{}} 207 | \if{latex}{\out{\hypertarget{method-OdeModelMCMC-reliability}{}}} 208 | \subsection{Method \code{reliability()}}{ 209 | Study reliability of results by running standalone generated 210 | quantities using more accurate ODE solver configurations. 211 | See \emph{Timonen, J. et al. (2022)} for description of the method. 212 | Currently it is the user's responsibility to ensure that \code{solvers} 213 | is a list of increasingly accurate solvers. 214 | \subsection{Usage}{ 215 | \if{html}{\out{
}}\preformatted{OdeModelMCMC$reliability( 216 | solvers, 217 | savedir = "results", 218 | basename = "odegq", 219 | recompute_loglik = TRUE, 220 | ... 221 | )}\if{html}{\out{
}} 222 | } 223 | 224 | \subsection{Arguments}{ 225 | \if{html}{\out{
}} 226 | \describe{ 227 | \item{\code{solvers}}{List of ODE solvers (should be the same solver as used 228 | during MCMC, but with increasingly more accurate configurations). 229 | See \code{\link{odesolvers_lists}} for creating this.} 230 | 231 | \item{\code{savedir}}{Directory where results are saved. \emph{NOTE:} it might 232 | be difficult to load the results if you move them to a different place 233 | afterwards, because the file paths get saved in the output. Improving 234 | the file handling should be a future improvement.} 235 | 236 | \item{\code{basename}}{Base name for saved files.} 237 | 238 | \item{\code{recompute_loglik}}{Should the log-likelihoods corresponding to 239 | solver configuration used during MCMC be recomputed?} 240 | 241 | \item{\code{...}}{Additional arguments passed to the \verb{$generate_quantities()} 242 | method of the underlying \link[cmdstanr:CmdStanModel]{cmdstanr::CmdStanModel} object.} 243 | } 244 | \if{html}{\out{
}} 245 | } 246 | \subsection{Returns}{ 247 | A named list. 248 | } 249 | } 250 | \if{html}{\out{
}} 251 | \if{html}{\out{}} 252 | \if{latex}{\out{\hypertarget{method-OdeModelMCMC-clone}{}}} 253 | \subsection{Method \code{clone()}}{ 254 | The objects of this class are cloneable with this method. 255 | \subsection{Usage}{ 256 | \if{html}{\out{
}}\preformatted{OdeModelMCMC$clone(deep = FALSE)}\if{html}{\out{
}} 257 | } 258 | 259 | \subsection{Arguments}{ 260 | \if{html}{\out{
}} 261 | \describe{ 262 | \item{\code{deep}}{Whether to make a deep clone.} 263 | } 264 | \if{html}{\out{
}} 265 | } 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /man/OdeSolver.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/classes-solver.R 3 | \name{OdeSolver} 4 | \alias{OdeSolver} 5 | \title{An ODE solver (an abstract base class)} 6 | \description{ 7 | An ODE solver (an abstract base class) 8 | 9 | An ODE solver (an abstract base class) 10 | } 11 | \section{Public fields}{ 12 | \if{html}{\out{
}} 13 | \describe{ 14 | \item{\code{name}}{name of the solver} 15 | 16 | \item{\code{stan_number}}{integer that indexes the solver in the Stan code} 17 | } 18 | \if{html}{\out{
}} 19 | } 20 | \section{Methods}{ 21 | \subsection{Public methods}{ 22 | \itemize{ 23 | \item \href{#method-OdeSolver-new}{\code{OdeSolver$new()}} 24 | \item \href{#method-OdeSolver-standata}{\code{OdeSolver$standata()}} 25 | \item \href{#method-OdeSolver-to_string}{\code{OdeSolver$to_string()}} 26 | \item \href{#method-OdeSolver-print}{\code{OdeSolver$print()}} 27 | \item \href{#method-OdeSolver-clone}{\code{OdeSolver$clone()}} 28 | } 29 | } 30 | \if{html}{\out{
}} 31 | \if{html}{\out{}} 32 | \if{latex}{\out{\hypertarget{method-OdeSolver-new}{}}} 33 | \subsection{Method \code{new()}}{ 34 | \code{OdeSolver} is an abstract class that can't be initialized. 35 | \subsection{Usage}{ 36 | \if{html}{\out{
}}\preformatted{OdeSolver$new()}\if{html}{\out{
}} 37 | } 38 | 39 | } 40 | \if{html}{\out{
}} 41 | \if{html}{\out{}} 42 | \if{latex}{\out{\hypertarget{method-OdeSolver-standata}{}}} 43 | \subsection{Method \code{standata()}}{ 44 | Create Stan data fields. 45 | \subsection{Usage}{ 46 | \if{html}{\out{
}}\preformatted{OdeSolver$standata()}\if{html}{\out{
}} 47 | } 48 | 49 | \subsection{Returns}{ 50 | A list. 51 | } 52 | } 53 | \if{html}{\out{
}} 54 | \if{html}{\out{}} 55 | \if{latex}{\out{\hypertarget{method-OdeSolver-to_string}{}}} 56 | \subsection{Method \code{to_string()}}{ 57 | String description of the solver. 58 | \subsection{Usage}{ 59 | \if{html}{\out{
}}\preformatted{OdeSolver$to_string()}\if{html}{\out{
}} 60 | } 61 | 62 | \subsection{Returns}{ 63 | A string. 64 | } 65 | } 66 | \if{html}{\out{
}} 67 | \if{html}{\out{}} 68 | \if{latex}{\out{\hypertarget{method-OdeSolver-print}{}}} 69 | \subsection{Method \code{print()}}{ 70 | Print info about the object. 71 | \subsection{Usage}{ 72 | \if{html}{\out{
}}\preformatted{OdeSolver$print()}\if{html}{\out{
}} 73 | } 74 | 75 | } 76 | \if{html}{\out{
}} 77 | \if{html}{\out{}} 78 | \if{latex}{\out{\hypertarget{method-OdeSolver-clone}{}}} 79 | \subsection{Method \code{clone()}}{ 80 | The objects of this class are cloneable with this method. 81 | \subsection{Usage}{ 82 | \if{html}{\out{
}}\preformatted{OdeSolver$clone(deep = FALSE)}\if{html}{\out{
}} 83 | } 84 | 85 | \subsection{Arguments}{ 86 | \if{html}{\out{
}} 87 | \describe{ 88 | \item{\code{deep}}{Whether to make a deep clone.} 89 | } 90 | \if{html}{\out{
}} 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /man/StanArray.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/classes-standecl.R 3 | \name{StanArray} 4 | \alias{StanArray} 5 | \title{A Stan array} 6 | \description{ 7 | A Stan array 8 | 9 | A Stan array 10 | } 11 | \section{Super class}{ 12 | \code{\link[odemodeling:StanDeclaration]{odemodeling::StanDeclaration}} -> \code{StanArray} 13 | } 14 | \section{Public fields}{ 15 | \if{html}{\out{
}} 16 | \describe{ 17 | \item{\code{dims}}{list of array dimensions} 18 | 19 | \item{\code{type}}{base type of the array} 20 | } 21 | \if{html}{\out{
}} 22 | } 23 | \section{Methods}{ 24 | \subsection{Public methods}{ 25 | \itemize{ 26 | \item \href{#method-StanArray-new}{\code{StanArray$new()}} 27 | \item \href{#method-StanArray-declaration}{\code{StanArray$declaration()}} 28 | \item \href{#method-StanArray-signature}{\code{StanArray$signature()}} 29 | \item \href{#method-StanArray-can_be_made_parameter}{\code{StanArray$can_be_made_parameter()}} 30 | \item \href{#method-StanArray-get_dims}{\code{StanArray$get_dims()}} 31 | \item \href{#method-StanArray-clone}{\code{StanArray$clone()}} 32 | } 33 | } 34 | \if{html}{\out{ 35 |
Inherited methods 36 | 39 |
40 | }} 41 | \if{html}{\out{
}} 42 | \if{html}{\out{}} 43 | \if{latex}{\out{\hypertarget{method-StanArray-new}{}}} 44 | \subsection{Method \code{new()}}{ 45 | Create a \link{StanArray} object. 46 | \subsection{Usage}{ 47 | \if{html}{\out{
}}\preformatted{StanArray$new(name, dims, type = "real", lower = NULL, upper = NULL)}\if{html}{\out{
}} 48 | } 49 | 50 | \subsection{Arguments}{ 51 | \if{html}{\out{
}} 52 | \describe{ 53 | \item{\code{name}}{name of the array} 54 | 55 | \item{\code{dims}}{list of array dimensions, must be a list of 56 | \link{StanDimension} objects} 57 | 58 | \item{\code{type}}{base type of the array} 59 | 60 | \item{\code{lower}}{lower bound} 61 | 62 | \item{\code{upper}}{upper bound} 63 | } 64 | \if{html}{\out{
}} 65 | } 66 | } 67 | \if{html}{\out{
}} 68 | \if{html}{\out{}} 69 | \if{latex}{\out{\hypertarget{method-StanArray-declaration}{}}} 70 | \subsection{Method \code{declaration()}}{ 71 | Create a declaration for the array 72 | \subsection{Usage}{ 73 | \if{html}{\out{
}}\preformatted{StanArray$declaration()}\if{html}{\out{
}} 74 | } 75 | 76 | \subsection{Returns}{ 77 | a string 78 | } 79 | } 80 | \if{html}{\out{
}} 81 | \if{html}{\out{}} 82 | \if{latex}{\out{\hypertarget{method-StanArray-signature}{}}} 83 | \subsection{Method \code{signature()}}{ 84 | The variable when used in function signature 85 | \subsection{Usage}{ 86 | \if{html}{\out{
}}\preformatted{StanArray$signature()}\if{html}{\out{
}} 87 | } 88 | 89 | } 90 | \if{html}{\out{
}} 91 | \if{html}{\out{}} 92 | \if{latex}{\out{\hypertarget{method-StanArray-can_be_made_parameter}{}}} 93 | \subsection{Method \code{can_be_made_parameter()}}{ 94 | Can the object be made into a parameter? 95 | \subsection{Usage}{ 96 | \if{html}{\out{
}}\preformatted{StanArray$can_be_made_parameter()}\if{html}{\out{
}} 97 | } 98 | 99 | } 100 | \if{html}{\out{
}} 101 | \if{html}{\out{}} 102 | \if{latex}{\out{\hypertarget{method-StanArray-get_dims}{}}} 103 | \subsection{Method \code{get_dims()}}{ 104 | Get all declared dimensions related to the object. 105 | \subsection{Usage}{ 106 | \if{html}{\out{
}}\preformatted{StanArray$get_dims()}\if{html}{\out{
}} 107 | } 108 | 109 | \subsection{Returns}{ 110 | A list. 111 | } 112 | } 113 | \if{html}{\out{
}} 114 | \if{html}{\out{}} 115 | \if{latex}{\out{\hypertarget{method-StanArray-clone}{}}} 116 | \subsection{Method \code{clone()}}{ 117 | The objects of this class are cloneable with this method. 118 | \subsection{Usage}{ 119 | \if{html}{\out{
}}\preformatted{StanArray$clone(deep = FALSE)}\if{html}{\out{
}} 120 | } 121 | 122 | \subsection{Arguments}{ 123 | \if{html}{\out{
}} 124 | \describe{ 125 | \item{\code{deep}}{Whether to make a deep clone.} 126 | } 127 | \if{html}{\out{
}} 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /man/StanDeclaration.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/classes-standecl.R 3 | \name{StanDeclaration} 4 | \alias{StanDeclaration} 5 | \title{A Stan variable declaration (an abstract base class)} 6 | \description{ 7 | A Stan variable declaration (an abstract base class) 8 | 9 | A Stan variable declaration (an abstract base class) 10 | } 11 | \section{Public fields}{ 12 | \if{html}{\out{
}} 13 | \describe{ 14 | \item{\code{name}}{name of the variable} 15 | 16 | \item{\code{lower}}{lower bound} 17 | 18 | \item{\code{upper}}{upper bound} 19 | } 20 | \if{html}{\out{
}} 21 | } 22 | \section{Methods}{ 23 | \subsection{Public methods}{ 24 | \itemize{ 25 | \item \href{#method-StanDeclaration-new}{\code{StanDeclaration$new()}} 26 | \item \href{#method-StanDeclaration-declaration}{\code{StanDeclaration$declaration()}} 27 | \item \href{#method-StanDeclaration-signature}{\code{StanDeclaration$signature()}} 28 | \item \href{#method-StanDeclaration-print}{\code{StanDeclaration$print()}} 29 | \item \href{#method-StanDeclaration-can_be_made_parameter}{\code{StanDeclaration$can_be_made_parameter()}} 30 | \item \href{#method-StanDeclaration-get_dims}{\code{StanDeclaration$get_dims()}} 31 | \item \href{#method-StanDeclaration-clone}{\code{StanDeclaration$clone()}} 32 | } 33 | } 34 | \if{html}{\out{
}} 35 | \if{html}{\out{}} 36 | \if{latex}{\out{\hypertarget{method-StanDeclaration-new}{}}} 37 | \subsection{Method \code{new()}}{ 38 | \code{StanDeclaration} is an abstract class that can't be initialized. 39 | \subsection{Usage}{ 40 | \if{html}{\out{
}}\preformatted{StanDeclaration$new()}\if{html}{\out{
}} 41 | } 42 | 43 | } 44 | \if{html}{\out{
}} 45 | \if{html}{\out{}} 46 | \if{latex}{\out{\hypertarget{method-StanDeclaration-declaration}{}}} 47 | \subsection{Method \code{declaration()}}{ 48 | The variable declaration as a string. 49 | \subsection{Usage}{ 50 | \if{html}{\out{
}}\preformatted{StanDeclaration$declaration()}\if{html}{\out{
}} 51 | } 52 | 53 | } 54 | \if{html}{\out{
}} 55 | \if{html}{\out{}} 56 | \if{latex}{\out{\hypertarget{method-StanDeclaration-signature}{}}} 57 | \subsection{Method \code{signature()}}{ 58 | The variable when used in function signature 59 | \subsection{Usage}{ 60 | \if{html}{\out{
}}\preformatted{StanDeclaration$signature()}\if{html}{\out{
}} 61 | } 62 | 63 | } 64 | \if{html}{\out{
}} 65 | \if{html}{\out{}} 66 | \if{latex}{\out{\hypertarget{method-StanDeclaration-print}{}}} 67 | \subsection{Method \code{print()}}{ 68 | Print 69 | \subsection{Usage}{ 70 | \if{html}{\out{
}}\preformatted{StanDeclaration$print()}\if{html}{\out{
}} 71 | } 72 | 73 | } 74 | \if{html}{\out{
}} 75 | \if{html}{\out{}} 76 | \if{latex}{\out{\hypertarget{method-StanDeclaration-can_be_made_parameter}{}}} 77 | \subsection{Method \code{can_be_made_parameter()}}{ 78 | Can the object be made into a parameter? 79 | \subsection{Usage}{ 80 | \if{html}{\out{
}}\preformatted{StanDeclaration$can_be_made_parameter()}\if{html}{\out{
}} 81 | } 82 | 83 | } 84 | \if{html}{\out{
}} 85 | \if{html}{\out{}} 86 | \if{latex}{\out{\hypertarget{method-StanDeclaration-get_dims}{}}} 87 | \subsection{Method \code{get_dims()}}{ 88 | Get all declared dimensions related to the object. 89 | \subsection{Usage}{ 90 | \if{html}{\out{
}}\preformatted{StanDeclaration$get_dims()}\if{html}{\out{
}} 91 | } 92 | 93 | \subsection{Returns}{ 94 | A list. 95 | } 96 | } 97 | \if{html}{\out{
}} 98 | \if{html}{\out{}} 99 | \if{latex}{\out{\hypertarget{method-StanDeclaration-clone}{}}} 100 | \subsection{Method \code{clone()}}{ 101 | The objects of this class are cloneable with this method. 102 | \subsection{Usage}{ 103 | \if{html}{\out{
}}\preformatted{StanDeclaration$clone(deep = FALSE)}\if{html}{\out{
}} 104 | } 105 | 106 | \subsection{Arguments}{ 107 | \if{html}{\out{
}} 108 | \describe{ 109 | \item{\code{deep}}{Whether to make a deep clone.} 110 | } 111 | \if{html}{\out{
}} 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /man/StanDimension.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/classes-standecl.R 3 | \name{StanDimension} 4 | \alias{StanDimension} 5 | \title{A dimension for a Stan vector or array} 6 | \description{ 7 | A dimension for a Stan vector or array 8 | 9 | A dimension for a Stan vector or array 10 | } 11 | \section{Super class}{ 12 | \code{\link[odemodeling:StanDeclaration]{odemodeling::StanDeclaration}} -> \code{StanDimension} 13 | } 14 | \section{Methods}{ 15 | \subsection{Public methods}{ 16 | \itemize{ 17 | \item \href{#method-StanDimension-new}{\code{StanDimension$new()}} 18 | \item \href{#method-StanDimension-declaration}{\code{StanDimension$declaration()}} 19 | \item \href{#method-StanDimension-signature}{\code{StanDimension$signature()}} 20 | \item \href{#method-StanDimension-get_dims}{\code{StanDimension$get_dims()}} 21 | \item \href{#method-StanDimension-clone}{\code{StanDimension$clone()}} 22 | } 23 | } 24 | \if{html}{\out{ 25 |
Inherited methods 26 | 30 |
31 | }} 32 | \if{html}{\out{
}} 33 | \if{html}{\out{}} 34 | \if{latex}{\out{\hypertarget{method-StanDimension-new}{}}} 35 | \subsection{Method \code{new()}}{ 36 | Create a \link{StanDimension} object 37 | \subsection{Usage}{ 38 | \if{html}{\out{
}}\preformatted{StanDimension$new(name, lower = NULL, upper = NULL)}\if{html}{\out{
}} 39 | } 40 | 41 | \subsection{Arguments}{ 42 | \if{html}{\out{
}} 43 | \describe{ 44 | \item{\code{name}}{name of the dimension variable} 45 | 46 | \item{\code{lower}}{lower bound} 47 | 48 | \item{\code{upper}}{upper bound} 49 | } 50 | \if{html}{\out{
}} 51 | } 52 | } 53 | \if{html}{\out{
}} 54 | \if{html}{\out{}} 55 | \if{latex}{\out{\hypertarget{method-StanDimension-declaration}{}}} 56 | \subsection{Method \code{declaration()}}{ 57 | Create a data block declaration for the dimension. 58 | \subsection{Usage}{ 59 | \if{html}{\out{
}}\preformatted{StanDimension$declaration()}\if{html}{\out{
}} 60 | } 61 | 62 | } 63 | \if{html}{\out{
}} 64 | \if{html}{\out{}} 65 | \if{latex}{\out{\hypertarget{method-StanDimension-signature}{}}} 66 | \subsection{Method \code{signature()}}{ 67 | The variable when used in function signature 68 | \subsection{Usage}{ 69 | \if{html}{\out{
}}\preformatted{StanDimension$signature()}\if{html}{\out{
}} 70 | } 71 | 72 | } 73 | \if{html}{\out{
}} 74 | \if{html}{\out{}} 75 | \if{latex}{\out{\hypertarget{method-StanDimension-get_dims}{}}} 76 | \subsection{Method \code{get_dims()}}{ 77 | Get all declared dimensions related to the object. 78 | \subsection{Usage}{ 79 | \if{html}{\out{
}}\preformatted{StanDimension$get_dims()}\if{html}{\out{
}} 80 | } 81 | 82 | \subsection{Returns}{ 83 | A list. 84 | } 85 | } 86 | \if{html}{\out{
}} 87 | \if{html}{\out{}} 88 | \if{latex}{\out{\hypertarget{method-StanDimension-clone}{}}} 89 | \subsection{Method \code{clone()}}{ 90 | The objects of this class are cloneable with this method. 91 | \subsection{Usage}{ 92 | \if{html}{\out{
}}\preformatted{StanDimension$clone(deep = FALSE)}\if{html}{\out{
}} 93 | } 94 | 95 | \subsection{Arguments}{ 96 | \if{html}{\out{
}} 97 | \describe{ 98 | \item{\code{deep}}{Whether to make a deep clone.} 99 | } 100 | \if{html}{\out{
}} 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /man/StanMatrix.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/classes-standecl.R 3 | \name{StanMatrix} 4 | \alias{StanMatrix} 5 | \title{A Stan matrix} 6 | \description{ 7 | A Stan matrix 8 | 9 | A Stan matrix 10 | } 11 | \section{Super class}{ 12 | \code{\link[odemodeling:StanDeclaration]{odemodeling::StanDeclaration}} -> \code{StanMatrix} 13 | } 14 | \section{Public fields}{ 15 | \if{html}{\out{
}} 16 | \describe{ 17 | \item{\code{nrow}}{number of rows} 18 | 19 | \item{\code{ncol}}{number of columns} 20 | } 21 | \if{html}{\out{
}} 22 | } 23 | \section{Methods}{ 24 | \subsection{Public methods}{ 25 | \itemize{ 26 | \item \href{#method-StanMatrix-new}{\code{StanMatrix$new()}} 27 | \item \href{#method-StanMatrix-declaration}{\code{StanMatrix$declaration()}} 28 | \item \href{#method-StanMatrix-signature}{\code{StanMatrix$signature()}} 29 | \item \href{#method-StanMatrix-can_be_made_parameter}{\code{StanMatrix$can_be_made_parameter()}} 30 | \item \href{#method-StanMatrix-get_dims}{\code{StanMatrix$get_dims()}} 31 | \item \href{#method-StanMatrix-clone}{\code{StanMatrix$clone()}} 32 | } 33 | } 34 | \if{html}{\out{ 35 |
Inherited methods 36 | 39 |
40 | }} 41 | \if{html}{\out{
}} 42 | \if{html}{\out{}} 43 | \if{latex}{\out{\hypertarget{method-StanMatrix-new}{}}} 44 | \subsection{Method \code{new()}}{ 45 | Create a \link{StanMatrix} object. 46 | \subsection{Usage}{ 47 | \if{html}{\out{
}}\preformatted{StanMatrix$new(name, nrow, ncol, lower = NULL, upper = NULL)}\if{html}{\out{
}} 48 | } 49 | 50 | \subsection{Arguments}{ 51 | \if{html}{\out{
}} 52 | \describe{ 53 | \item{\code{name}}{name of the matrix} 54 | 55 | \item{\code{nrow}}{number of rows, must be a \link{StanDimension} object} 56 | 57 | \item{\code{ncol}}{number of columns, must be a \link{StanDimension} object} 58 | 59 | \item{\code{lower}}{lower bound} 60 | 61 | \item{\code{upper}}{upper bound} 62 | } 63 | \if{html}{\out{
}} 64 | } 65 | } 66 | \if{html}{\out{
}} 67 | \if{html}{\out{}} 68 | \if{latex}{\out{\hypertarget{method-StanMatrix-declaration}{}}} 69 | \subsection{Method \code{declaration()}}{ 70 | Create a declaration for the matrix 71 | \subsection{Usage}{ 72 | \if{html}{\out{
}}\preformatted{StanMatrix$declaration()}\if{html}{\out{
}} 73 | } 74 | 75 | \subsection{Returns}{ 76 | a string 77 | } 78 | } 79 | \if{html}{\out{
}} 80 | \if{html}{\out{}} 81 | \if{latex}{\out{\hypertarget{method-StanMatrix-signature}{}}} 82 | \subsection{Method \code{signature()}}{ 83 | The variable when used in function signature 84 | \subsection{Usage}{ 85 | \if{html}{\out{
}}\preformatted{StanMatrix$signature()}\if{html}{\out{
}} 86 | } 87 | 88 | } 89 | \if{html}{\out{
}} 90 | \if{html}{\out{}} 91 | \if{latex}{\out{\hypertarget{method-StanMatrix-can_be_made_parameter}{}}} 92 | \subsection{Method \code{can_be_made_parameter()}}{ 93 | Can the object be made into a parameter? 94 | \subsection{Usage}{ 95 | \if{html}{\out{
}}\preformatted{StanMatrix$can_be_made_parameter()}\if{html}{\out{
}} 96 | } 97 | 98 | } 99 | \if{html}{\out{
}} 100 | \if{html}{\out{}} 101 | \if{latex}{\out{\hypertarget{method-StanMatrix-get_dims}{}}} 102 | \subsection{Method \code{get_dims()}}{ 103 | Get all declared dimensions related to the object. 104 | \subsection{Usage}{ 105 | \if{html}{\out{
}}\preformatted{StanMatrix$get_dims()}\if{html}{\out{
}} 106 | } 107 | 108 | \subsection{Returns}{ 109 | A list. 110 | } 111 | } 112 | \if{html}{\out{
}} 113 | \if{html}{\out{}} 114 | \if{latex}{\out{\hypertarget{method-StanMatrix-clone}{}}} 115 | \subsection{Method \code{clone()}}{ 116 | The objects of this class are cloneable with this method. 117 | \subsection{Usage}{ 118 | \if{html}{\out{
}}\preformatted{StanMatrix$clone(deep = FALSE)}\if{html}{\out{
}} 119 | } 120 | 121 | \subsection{Arguments}{ 122 | \if{html}{\out{
}} 123 | \describe{ 124 | \item{\code{deep}}{Whether to make a deep clone.} 125 | } 126 | \if{html}{\out{
}} 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /man/StanParameter.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/classes-standecl.R 3 | \name{StanParameter} 4 | \alias{StanParameter} 5 | \title{A Stan parameter} 6 | \description{ 7 | A Stan parameter 8 | 9 | A Stan parameter 10 | } 11 | \section{Public fields}{ 12 | \if{html}{\out{
}} 13 | \describe{ 14 | \item{\code{decl}}{The variable declaration.} 15 | 16 | \item{\code{prior_code}}{The prior declaration.} 17 | } 18 | \if{html}{\out{
}} 19 | } 20 | \section{Methods}{ 21 | \subsection{Public methods}{ 22 | \itemize{ 23 | \item \href{#method-StanParameter-new}{\code{StanParameter$new()}} 24 | \item \href{#method-StanParameter-print}{\code{StanParameter$print()}} 25 | \item \href{#method-StanParameter-clone}{\code{StanParameter$clone()}} 26 | } 27 | } 28 | \if{html}{\out{
}} 29 | \if{html}{\out{}} 30 | \if{latex}{\out{\hypertarget{method-StanParameter-new}{}}} 31 | \subsection{Method \code{new()}}{ 32 | Create a \link{StanParameter} object. 33 | \subsection{Usage}{ 34 | \if{html}{\out{
}}\preformatted{StanParameter$new(decl, prior = "")}\if{html}{\out{
}} 35 | } 36 | 37 | \subsection{Arguments}{ 38 | \if{html}{\out{
}} 39 | \describe{ 40 | \item{\code{decl}}{The underlying variable.} 41 | 42 | \item{\code{prior}}{'Stan' code that defines prior for the parameter.} 43 | } 44 | \if{html}{\out{
}} 45 | } 46 | } 47 | \if{html}{\out{
}} 48 | \if{html}{\out{}} 49 | \if{latex}{\out{\hypertarget{method-StanParameter-print}{}}} 50 | \subsection{Method \code{print()}}{ 51 | Print 52 | \subsection{Usage}{ 53 | \if{html}{\out{
}}\preformatted{StanParameter$print()}\if{html}{\out{
}} 54 | } 55 | 56 | } 57 | \if{html}{\out{
}} 58 | \if{html}{\out{}} 59 | \if{latex}{\out{\hypertarget{method-StanParameter-clone}{}}} 60 | \subsection{Method \code{clone()}}{ 61 | The objects of this class are cloneable with this method. 62 | \subsection{Usage}{ 63 | \if{html}{\out{
}}\preformatted{StanParameter$clone(deep = FALSE)}\if{html}{\out{
}} 64 | } 65 | 66 | \subsection{Arguments}{ 67 | \if{html}{\out{
}} 68 | \describe{ 69 | \item{\code{deep}}{Whether to make a deep clone.} 70 | } 71 | \if{html}{\out{
}} 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /man/StanTransformation.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/classes-standecl.R 3 | \name{StanTransformation} 4 | \alias{StanTransformation} 5 | \title{A Stan transformation} 6 | \description{ 7 | A Stan transformation 8 | 9 | A Stan transformation 10 | } 11 | \section{Public fields}{ 12 | \if{html}{\out{
}} 13 | \describe{ 14 | \item{\code{decl}}{The variable declaration.} 15 | 16 | \item{\code{code}}{The code that assigns to the declared variable.} 17 | 18 | \item{\code{origin}}{Either \code{"data"}, \code{"parameters"}, or \code{"model"}.} 19 | } 20 | \if{html}{\out{
}} 21 | } 22 | \section{Methods}{ 23 | \subsection{Public methods}{ 24 | \itemize{ 25 | \item \href{#method-StanTransformation-new}{\code{StanTransformation$new()}} 26 | \item \href{#method-StanTransformation-print}{\code{StanTransformation$print()}} 27 | \item \href{#method-StanTransformation-clone}{\code{StanTransformation$clone()}} 28 | } 29 | } 30 | \if{html}{\out{
}} 31 | \if{html}{\out{}} 32 | \if{latex}{\out{\hypertarget{method-StanTransformation-new}{}}} 33 | \subsection{Method \code{new()}}{ 34 | Create a \link{StanTransformation} object. 35 | \subsection{Usage}{ 36 | \if{html}{\out{
}}\preformatted{StanTransformation$new(decl, origin = "model", code = "")}\if{html}{\out{
}} 37 | } 38 | 39 | \subsection{Arguments}{ 40 | \if{html}{\out{
}} 41 | \describe{ 42 | \item{\code{decl}}{The underlying variable.} 43 | 44 | \item{\code{origin}}{Must be either \code{"data"}, \code{"parameters"}, or \code{"model"}.} 45 | 46 | \item{\code{code}}{The code that assigns to the declared variable. If this 47 | doesn't include any assignments (with \code{=}), the code is prepended 48 | with \code{paste0(decl$name, " = ")}. In this case also a semicolon is 49 | added to the end if it is missing.} 50 | } 51 | \if{html}{\out{
}} 52 | } 53 | } 54 | \if{html}{\out{
}} 55 | \if{html}{\out{}} 56 | \if{latex}{\out{\hypertarget{method-StanTransformation-print}{}}} 57 | \subsection{Method \code{print()}}{ 58 | Print 59 | \subsection{Usage}{ 60 | \if{html}{\out{
}}\preformatted{StanTransformation$print()}\if{html}{\out{
}} 61 | } 62 | 63 | } 64 | \if{html}{\out{
}} 65 | \if{html}{\out{}} 66 | \if{latex}{\out{\hypertarget{method-StanTransformation-clone}{}}} 67 | \subsection{Method \code{clone()}}{ 68 | The objects of this class are cloneable with this method. 69 | \subsection{Usage}{ 70 | \if{html}{\out{
}}\preformatted{StanTransformation$clone(deep = FALSE)}\if{html}{\out{
}} 71 | } 72 | 73 | \subsection{Arguments}{ 74 | \if{html}{\out{
}} 75 | \describe{ 76 | \item{\code{deep}}{Whether to make a deep clone.} 77 | } 78 | \if{html}{\out{
}} 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /man/StanVariable.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/classes-standecl.R 3 | \name{StanVariable} 4 | \alias{StanVariable} 5 | \title{A Stan variable} 6 | \description{ 7 | A Stan variable 8 | 9 | A Stan variable 10 | } 11 | \section{Super class}{ 12 | \code{\link[odemodeling:StanDeclaration]{odemodeling::StanDeclaration}} -> \code{StanVariable} 13 | } 14 | \section{Public fields}{ 15 | \if{html}{\out{
}} 16 | \describe{ 17 | \item{\code{type}}{type of the variable} 18 | } 19 | \if{html}{\out{
}} 20 | } 21 | \section{Methods}{ 22 | \subsection{Public methods}{ 23 | \itemize{ 24 | \item \href{#method-StanVariable-new}{\code{StanVariable$new()}} 25 | \item \href{#method-StanVariable-declaration}{\code{StanVariable$declaration()}} 26 | \item \href{#method-StanVariable-signature}{\code{StanVariable$signature()}} 27 | \item \href{#method-StanVariable-can_be_made_parameter}{\code{StanVariable$can_be_made_parameter()}} 28 | \item \href{#method-StanVariable-clone}{\code{StanVariable$clone()}} 29 | } 30 | } 31 | \if{html}{\out{ 32 |
Inherited methods 33 | 37 |
38 | }} 39 | \if{html}{\out{
}} 40 | \if{html}{\out{}} 41 | \if{latex}{\out{\hypertarget{method-StanVariable-new}{}}} 42 | \subsection{Method \code{new()}}{ 43 | Create a \link{StanVariable} object. 44 | \subsection{Usage}{ 45 | \if{html}{\out{
}}\preformatted{StanVariable$new(name, type = "real", lower = NULL, upper = NULL)}\if{html}{\out{
}} 46 | } 47 | 48 | \subsection{Arguments}{ 49 | \if{html}{\out{
}} 50 | \describe{ 51 | \item{\code{name}}{name of the dimension variable} 52 | 53 | \item{\code{type}}{variable type (real or int)} 54 | 55 | \item{\code{lower}}{lower bound} 56 | 57 | \item{\code{upper}}{upper bound} 58 | } 59 | \if{html}{\out{
}} 60 | } 61 | } 62 | \if{html}{\out{
}} 63 | \if{html}{\out{}} 64 | \if{latex}{\out{\hypertarget{method-StanVariable-declaration}{}}} 65 | \subsection{Method \code{declaration()}}{ 66 | Create a declaration for the variable 67 | \subsection{Usage}{ 68 | \if{html}{\out{
}}\preformatted{StanVariable$declaration()}\if{html}{\out{
}} 69 | } 70 | 71 | \subsection{Returns}{ 72 | a string 73 | } 74 | } 75 | \if{html}{\out{
}} 76 | \if{html}{\out{}} 77 | \if{latex}{\out{\hypertarget{method-StanVariable-signature}{}}} 78 | \subsection{Method \code{signature()}}{ 79 | The variable when used in function signature 80 | \subsection{Usage}{ 81 | \if{html}{\out{
}}\preformatted{StanVariable$signature()}\if{html}{\out{
}} 82 | } 83 | 84 | } 85 | \if{html}{\out{
}} 86 | \if{html}{\out{}} 87 | \if{latex}{\out{\hypertarget{method-StanVariable-can_be_made_parameter}{}}} 88 | \subsection{Method \code{can_be_made_parameter()}}{ 89 | Can the object be made into a parameter? 90 | \subsection{Usage}{ 91 | \if{html}{\out{
}}\preformatted{StanVariable$can_be_made_parameter()}\if{html}{\out{
}} 92 | } 93 | 94 | } 95 | \if{html}{\out{
}} 96 | \if{html}{\out{}} 97 | \if{latex}{\out{\hypertarget{method-StanVariable-clone}{}}} 98 | \subsection{Method \code{clone()}}{ 99 | The objects of this class are cloneable with this method. 100 | \subsection{Usage}{ 101 | \if{html}{\out{
}}\preformatted{StanVariable$clone(deep = FALSE)}\if{html}{\out{
}} 102 | } 103 | 104 | \subsection{Arguments}{ 105 | \if{html}{\out{
}} 106 | \describe{ 107 | \item{\code{deep}}{Whether to make a deep clone.} 108 | } 109 | \if{html}{\out{
}} 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /man/StanVector.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/classes-standecl.R 3 | \name{StanVector} 4 | \alias{StanVector} 5 | \title{A Stan vector} 6 | \description{ 7 | A Stan vector 8 | 9 | A Stan vector 10 | } 11 | \section{Super class}{ 12 | \code{\link[odemodeling:StanDeclaration]{odemodeling::StanDeclaration}} -> \code{StanVector} 13 | } 14 | \section{Public fields}{ 15 | \if{html}{\out{
}} 16 | \describe{ 17 | \item{\code{length}}{length of the vector} 18 | } 19 | \if{html}{\out{
}} 20 | } 21 | \section{Methods}{ 22 | \subsection{Public methods}{ 23 | \itemize{ 24 | \item \href{#method-StanVector-new}{\code{StanVector$new()}} 25 | \item \href{#method-StanVector-declaration}{\code{StanVector$declaration()}} 26 | \item \href{#method-StanVector-signature}{\code{StanVector$signature()}} 27 | \item \href{#method-StanVector-can_be_made_parameter}{\code{StanVector$can_be_made_parameter()}} 28 | \item \href{#method-StanVector-get_dims}{\code{StanVector$get_dims()}} 29 | \item \href{#method-StanVector-clone}{\code{StanVector$clone()}} 30 | } 31 | } 32 | \if{html}{\out{ 33 |
Inherited methods 34 | 37 |
38 | }} 39 | \if{html}{\out{
}} 40 | \if{html}{\out{}} 41 | \if{latex}{\out{\hypertarget{method-StanVector-new}{}}} 42 | \subsection{Method \code{new()}}{ 43 | Create a \link{StanVector} object. 44 | \subsection{Usage}{ 45 | \if{html}{\out{
}}\preformatted{StanVector$new(name, length, lower = NULL, upper = NULL)}\if{html}{\out{
}} 46 | } 47 | 48 | \subsection{Arguments}{ 49 | \if{html}{\out{
}} 50 | \describe{ 51 | \item{\code{name}}{name of the vector} 52 | 53 | \item{\code{length}}{length of the vector, must be a \link{StanDimension} object} 54 | 55 | \item{\code{lower}}{lower bound} 56 | 57 | \item{\code{upper}}{upper bound} 58 | } 59 | \if{html}{\out{
}} 60 | } 61 | } 62 | \if{html}{\out{
}} 63 | \if{html}{\out{}} 64 | \if{latex}{\out{\hypertarget{method-StanVector-declaration}{}}} 65 | \subsection{Method \code{declaration()}}{ 66 | Create a declaration for the vector 67 | \subsection{Usage}{ 68 | \if{html}{\out{
}}\preformatted{StanVector$declaration()}\if{html}{\out{
}} 69 | } 70 | 71 | \subsection{Returns}{ 72 | a string 73 | } 74 | } 75 | \if{html}{\out{
}} 76 | \if{html}{\out{}} 77 | \if{latex}{\out{\hypertarget{method-StanVector-signature}{}}} 78 | \subsection{Method \code{signature()}}{ 79 | The variable when used in function signature 80 | \subsection{Usage}{ 81 | \if{html}{\out{
}}\preformatted{StanVector$signature()}\if{html}{\out{
}} 82 | } 83 | 84 | } 85 | \if{html}{\out{
}} 86 | \if{html}{\out{}} 87 | \if{latex}{\out{\hypertarget{method-StanVector-can_be_made_parameter}{}}} 88 | \subsection{Method \code{can_be_made_parameter()}}{ 89 | Can the object be made into a parameter? 90 | \subsection{Usage}{ 91 | \if{html}{\out{
}}\preformatted{StanVector$can_be_made_parameter()}\if{html}{\out{
}} 92 | } 93 | 94 | } 95 | \if{html}{\out{
}} 96 | \if{html}{\out{}} 97 | \if{latex}{\out{\hypertarget{method-StanVector-get_dims}{}}} 98 | \subsection{Method \code{get_dims()}}{ 99 | Get all declared dimensions related to the object. 100 | \subsection{Usage}{ 101 | \if{html}{\out{
}}\preformatted{StanVector$get_dims()}\if{html}{\out{
}} 102 | } 103 | 104 | \subsection{Returns}{ 105 | A list. 106 | } 107 | } 108 | \if{html}{\out{
}} 109 | \if{html}{\out{}} 110 | \if{latex}{\out{\hypertarget{method-StanVector-clone}{}}} 111 | \subsection{Method \code{clone()}}{ 112 | The objects of this class are cloneable with this method. 113 | \subsection{Usage}{ 114 | \if{html}{\out{
}}\preformatted{StanVector$clone(deep = FALSE)}\if{html}{\out{
}} 115 | } 116 | 117 | \subsection{Arguments}{ 118 | \if{html}{\out{
}} 119 | \describe{ 120 | \item{\code{deep}}{Whether to make a deep clone.} 121 | } 122 | \if{html}{\out{
}} 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /man/StanVectorArray.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/classes-standecl.R 3 | \name{StanVectorArray} 4 | \alias{StanVectorArray} 5 | \title{A Stan array of vectors} 6 | \description{ 7 | A Stan array of vectors 8 | 9 | A Stan array of vectors 10 | } 11 | \section{Super class}{ 12 | \code{\link[odemodeling:StanDeclaration]{odemodeling::StanDeclaration}} -> \code{StanVectorArray} 13 | } 14 | \section{Public fields}{ 15 | \if{html}{\out{
}} 16 | \describe{ 17 | \item{\code{dims}}{list of array dimensions} 18 | 19 | \item{\code{length}}{length of the vector} 20 | } 21 | \if{html}{\out{
}} 22 | } 23 | \section{Methods}{ 24 | \subsection{Public methods}{ 25 | \itemize{ 26 | \item \href{#method-StanVectorArray-new}{\code{StanVectorArray$new()}} 27 | \item \href{#method-StanVectorArray-declaration}{\code{StanVectorArray$declaration()}} 28 | \item \href{#method-StanVectorArray-signature}{\code{StanVectorArray$signature()}} 29 | \item \href{#method-StanVectorArray-can_be_made_parameter}{\code{StanVectorArray$can_be_made_parameter()}} 30 | \item \href{#method-StanVectorArray-get_dims}{\code{StanVectorArray$get_dims()}} 31 | \item \href{#method-StanVectorArray-clone}{\code{StanVectorArray$clone()}} 32 | } 33 | } 34 | \if{html}{\out{ 35 |
Inherited methods 36 | 39 |
40 | }} 41 | \if{html}{\out{
}} 42 | \if{html}{\out{}} 43 | \if{latex}{\out{\hypertarget{method-StanVectorArray-new}{}}} 44 | \subsection{Method \code{new()}}{ 45 | Create a \link{StanVectorArray} object. 46 | \subsection{Usage}{ 47 | \if{html}{\out{
}}\preformatted{StanVectorArray$new(name, dims, length, lower = NULL, upper = NULL)}\if{html}{\out{
}} 48 | } 49 | 50 | \subsection{Arguments}{ 51 | \if{html}{\out{
}} 52 | \describe{ 53 | \item{\code{name}}{name of the vector array} 54 | 55 | \item{\code{dims}}{list of array dimensions, must be a list of 56 | \link{StanDimension} objects} 57 | 58 | \item{\code{length}}{length of the vector, must be a \link{StanDimension} object} 59 | 60 | \item{\code{lower}}{lower bound} 61 | 62 | \item{\code{upper}}{upper bound} 63 | } 64 | \if{html}{\out{
}} 65 | } 66 | } 67 | \if{html}{\out{
}} 68 | \if{html}{\out{}} 69 | \if{latex}{\out{\hypertarget{method-StanVectorArray-declaration}{}}} 70 | \subsection{Method \code{declaration()}}{ 71 | Create a declaration for the array of vectors 72 | \subsection{Usage}{ 73 | \if{html}{\out{
}}\preformatted{StanVectorArray$declaration()}\if{html}{\out{
}} 74 | } 75 | 76 | \subsection{Returns}{ 77 | a string 78 | } 79 | } 80 | \if{html}{\out{
}} 81 | \if{html}{\out{}} 82 | \if{latex}{\out{\hypertarget{method-StanVectorArray-signature}{}}} 83 | \subsection{Method \code{signature()}}{ 84 | The variable when used in function signature 85 | \subsection{Usage}{ 86 | \if{html}{\out{
}}\preformatted{StanVectorArray$signature()}\if{html}{\out{
}} 87 | } 88 | 89 | } 90 | \if{html}{\out{
}} 91 | \if{html}{\out{}} 92 | \if{latex}{\out{\hypertarget{method-StanVectorArray-can_be_made_parameter}{}}} 93 | \subsection{Method \code{can_be_made_parameter()}}{ 94 | Can the object be made into a parameter? 95 | \subsection{Usage}{ 96 | \if{html}{\out{
}}\preformatted{StanVectorArray$can_be_made_parameter()}\if{html}{\out{
}} 97 | } 98 | 99 | } 100 | \if{html}{\out{
}} 101 | \if{html}{\out{}} 102 | \if{latex}{\out{\hypertarget{method-StanVectorArray-get_dims}{}}} 103 | \subsection{Method \code{get_dims()}}{ 104 | Get all declared dimensions related to the object. 105 | \subsection{Usage}{ 106 | \if{html}{\out{
}}\preformatted{StanVectorArray$get_dims()}\if{html}{\out{
}} 107 | } 108 | 109 | \subsection{Returns}{ 110 | A list. 111 | } 112 | } 113 | \if{html}{\out{
}} 114 | \if{html}{\out{}} 115 | \if{latex}{\out{\hypertarget{method-StanVectorArray-clone}{}}} 116 | \subsection{Method \code{clone()}}{ 117 | The objects of this class are cloneable with this method. 118 | \subsection{Usage}{ 119 | \if{html}{\out{
}}\preformatted{StanVectorArray$clone(deep = FALSE)}\if{html}{\out{
}} 120 | } 121 | 122 | \subsection{Arguments}{ 123 | \if{html}{\out{
}} 124 | \describe{ 125 | \item{\code{deep}}{Whether to make a deep clone.} 126 | } 127 | \if{html}{\out{
}} 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /man/compare_odefits.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/main-functions.R 3 | \name{compare_odefits} 4 | \alias{compare_odefits} 5 | \alias{max_abs_odesol_diff} 6 | \alias{max_abs_loglik_diff} 7 | \alias{log_ratios} 8 | \alias{psis_relative_eff} 9 | \alias{psis} 10 | \alias{compute_reliability_metrics} 11 | \title{Compare two objects that contain ODE solutions and ODE model likelihoods} 12 | \usage{ 13 | max_abs_odesol_diff(x, y, include_y0 = TRUE) 14 | 15 | max_abs_loglik_diff(x, y) 16 | 17 | log_ratios(x, y) 18 | 19 | psis_relative_eff(x, y) 20 | 21 | psis(x, y) 22 | 23 | compute_reliability_metrics(x, y) 24 | } 25 | \arguments{ 26 | \item{x}{An object of class \link{OdeModelMCMC} or \link{OdeModelGQ}.} 27 | 28 | \item{y}{An object of class \link{OdeModelMCMC} or \link{OdeModelGQ}.} 29 | 30 | \item{include_y0}{Should the ODE initial state be included in computations?} 31 | } 32 | \value{ 33 | A named numeric vector. 34 | } 35 | \description{ 36 | Compare two objects that contain ODE solutions and ODE model likelihoods 37 | } 38 | \section{Functions}{ 39 | \itemize{ 40 | \item \code{max_abs_odesol_diff()}: Compute maximum absolute difference in 41 | ODE solutions of \code{x} and \code{y}. 42 | 43 | \item \code{max_abs_loglik_diff()}: Compute maximum absolute differences in 44 | log likelihoods of \code{x} and \code{y}. 45 | 46 | \item \code{log_ratios()}: Compute log likelihood ratios (on log scale), 47 | i.e. just \code{x$loglik() - y$loglik()}. 48 | 49 | \item \code{psis_relative_eff()}: Compute relative efficiency needed for PSIS, 50 | using \code{\link[loo:relative_eff]{loo::relative_eff()}}. 51 | 52 | \item \code{psis()}: Call \code{\link[loo:psis]{loo::psis()}} using the log likelihoods 53 | from \code{x} and \code{y}. 54 | 55 | \item \code{compute_reliability_metrics()}: Compute all metrics. 56 | 57 | }} 58 | -------------------------------------------------------------------------------- /man/example_ode_model.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/main-examples.R 3 | \name{example_ode_model} 4 | \alias{example_ode_model} 5 | \title{Create an example ODE model} 6 | \usage{ 7 | example_ode_model(name, prior_only = FALSE, ...) 8 | } 9 | \arguments{ 10 | \item{name}{Name of model. Must be one of the following: 11 | \itemize{ 12 | \item \code{"gsir"} - age-stratified SIR model 13 | \item \code{"tmdd"} - target-mediated drug transmission model 14 | \item \code{"lv"} - Lotka-Volterra model 15 | }} 16 | 17 | \item{prior_only}{Create a prior-only version of the model?} 18 | 19 | \item{...}{Additional arguments to \code{\link[=ode_model]{ode_model()}}.} 20 | } 21 | \value{ 22 | An object of class \code{OdeModel}. 23 | } 24 | \description{ 25 | Create an example ODE model 26 | } 27 | \seealso{ 28 | Other model constructor functions: 29 | \code{\link{ode_model}()} 30 | } 31 | \concept{model constructor functions} 32 | -------------------------------------------------------------------------------- /man/lynxhare.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/odemodeling-package.R 3 | \docType{data} 4 | \name{lynxhare} 5 | \alias{lynxhare} 6 | \title{Hudson Bay Company lynx and hare pelt collection data (1900-1920)} 7 | \format{ 8 | A data frame with 21 rows and 3 variables: 9 | \describe{ 10 | \item{year}{collection year} 11 | \item{lynx}{number of lynx pelts collected (in 1000's)} 12 | \item{hare}{number of hare pelts collected (in 1000's)} 13 | } 14 | } 15 | \source{ 16 | \url{https://www.math.tamu.edu/~phoward/m442/modbasics.pdf}, 17 | downloaded 10th Jan, 2021. 18 | } 19 | \usage{ 20 | lynxhare 21 | } 22 | \description{ 23 | Hudson Bay Company lynx and hare pelt collection data (1900-1920) 24 | } 25 | \keyword{datasets} 26 | -------------------------------------------------------------------------------- /man/ode_model.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/main-model.R 3 | \name{ode_model} 4 | \alias{ode_model} 5 | \title{Create an ODE model} 6 | \usage{ 7 | ode_model( 8 | N, 9 | odefun_vars = list(), 10 | odefun_body = "", 11 | odefun_init = NULL, 12 | loglik_vars = list(), 13 | loglik_body = "", 14 | other_vars = list(), 15 | verbose = FALSE, 16 | compile = TRUE, 17 | sig_figs = 18 18 | ) 19 | } 20 | \arguments{ 21 | \item{N}{A \link{StanDimension} variable describing the number of time points.} 22 | 23 | \item{odefun_vars}{Data and parameters needed by the ODE function. Must be a 24 | list of \link{StanDeclaration}, \link{StanParameter}, or \link{StanTransformation} objects. 25 | These will be defined in Stan model code blocks} 26 | 27 | \item{odefun_body}{ODE function body (Stan code string).} 28 | 29 | \item{odefun_init}{Initial value for ODE system at t0. 30 | Has to be a \link{StanVector}, or alternatively a \link{StanParameter} or a 31 | \link{StanTransformation} with \link{StanVector} base declaration.} 32 | 33 | \item{loglik_vars}{Data and parameters needed by the log likelihood 34 | function.} 35 | 36 | \item{loglik_body}{Log likelihood function body (Stan code string).} 37 | 38 | \item{other_vars}{Other variables.} 39 | 40 | \item{verbose}{Should this print more information?} 41 | 42 | \item{compile}{Should the model be compiled?} 43 | 44 | \item{sig_figs}{Number of significant figures to use in all 'CmdStan' 45 | calls.} 46 | } 47 | \value{ 48 | An object of class \link{OdeModel}. 49 | } 50 | \description{ 51 | Generate model given the declarations of variables, 52 | parameters, functions etc. The arguments \code{odefun_vars}, 53 | \code{loglik_vars} and \code{other_vars} must be lists whose elements must have one 54 | of the following three types: 55 | \itemize{ 56 | \item \link{StanDeclaration} - can be created using \code{\link[=stan_var]{stan_var()}}, 57 | \code{\link[=stan_vector]{stan_vector()}}, \code{\link[=stan_array]{stan_array()}} etc. 58 | \item \link{StanParameter} - can be created using \code{\link[=stan_param]{stan_param()}} 59 | \item \link{StanTransformation} - can be created using \code{\link[=stan_transform]{stan_transform()}} 60 | } 61 | 62 | These will go to different blocks of the 'Stan' model code so that 63 | \itemize{ 64 | \item \link{StanDeclaration}s go to \code{data} 65 | \item \link{StanParameter}s go to \code{parameters} 66 | \item \link{StanTransformation}s with origin \code{"data"} go to 67 | \verb{transformed data} 68 | \item \link{StanTransformation}s with origin \code{"parameters"} go to 69 | \verb{transformed parameters} 70 | \item \link{StanTransformation}s with origin \code{"model"} go to 71 | \verb{generated quantities} 72 | } 73 | } 74 | \seealso{ 75 | Other model constructor functions: 76 | \code{\link{example_ode_model}()} 77 | } 78 | \concept{model constructor functions} 79 | -------------------------------------------------------------------------------- /man/odemodeling-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/odemodeling-package.R 3 | \docType{package} 4 | \name{odemodeling-package} 5 | \alias{odemodeling-package} 6 | \alias{odemodeling} 7 | \title{The 'odemodeling' package} 8 | \description{ 9 | Building and fitting ordinary differential equation (ODE) 10 | models with different numerical solvers in 'Stan'. Designed for efficient 11 | validation of the accuracy of numerical solvers in the Bayesian context. 12 | Using Pareto-smoothed importance sampling (PSIS) and its diagnostics. 13 | The package is based on the \code{R6} object oriented system and uses 14 | \code{cmdstanr} as the interface to 'Stan'. 15 | } 16 | \section{Creating a model}{ 17 | 18 | \itemize{ 19 | \item Declare model data, parameters, and other variables using 20 | \code{\link[=stan_array]{stan_array()}}, \code{\link[=stan_dim]{stan_dim()}}, \code{\link[=stan_matrix]{stan_matrix()}}, \code{\link[=stan_param]{stan_param()}}, 21 | \code{\link[=stan_transform]{stan_transform()}}, \code{\link[=stan_vector_array]{stan_vector_array()}}, and \code{\link[=stan_vector]{stan_vector()}}. 22 | \item Create an \link{OdeModel} model using \code{\link[=ode_model]{ode_model()}}. 23 | } 24 | } 25 | 26 | \section{Using different ODE solvers}{ 27 | 28 | \itemize{ 29 | \item See \code{\link{odesolvers}} for constructors that create objects 30 | of class \link{OdeSolver}. 31 | } 32 | } 33 | 34 | \section{Fitting a model}{ 35 | 36 | \itemize{ 37 | \item Sample the posterior or prior distribution of the model parameters, 38 | and generate corresponding ODE solutions using the \verb{$sample()} method 39 | of the \link{OdeModel} class. 40 | \item See methods of the \link{OdeModelMCMC} class for studying the returned 41 | object. 42 | } 43 | } 44 | 45 | \section{Additional simulation of ODE systems}{ 46 | 47 | \itemize{ 48 | \item See the \verb{$gqs()} method of the \link{OdeModelMCMC} and \link{OdeModel} 49 | classes. 50 | \item See methods of the \link{OdeModelGQ} class for studying the returned 51 | object. 52 | \item See \code{\link{compare_odefits}} for functions to compare 53 | different ODE model simulations and fits. 54 | } 55 | } 56 | 57 | \section{Importance sampling for reliable and efficient inference in Bayesian ODE models}{ 58 | 59 | Our proposed workflow is to 60 | \enumerate{ 61 | \item Select an initial ODE solver M. 62 | \item Sample the parameter posterior using MCMC with M as the ODE solver. 63 | \item Compute certain metrics using a more accurate solver M∗. 64 | \item Increase the accuracy of M∗ and repeat Step 3 until the metrics converge. 65 | If the Pareto-k metric converges to a value larger than 0.7, increase the accuracy 66 | of M and go back to Step 2. 67 | \item Compute any posterior estimates using final importance weights. See 68 | Timonen et al. (2022) below. 69 | } 70 | The algorithm can be used to validate the reliability, and correct the errors 71 | of a given method M, which can be for example a software default. On the other hand, 72 | a smart initial selection of M can provide speed gains 73 | compared to often rather conservatively set software defaults, while still maintaining 74 | reliability of the inferences. 75 | 76 | We generally recommend selecting M initially so that sampling is as fast as possible. 77 | For example, for non-adaptive ODE solvers, one can first try using the smallest 78 | sensible number of steps that does not result in immediate failure. 79 | Selecting a good M is more difficult in the case of adaptive solvers. 80 | We have 81 | observed that tolerances on the order of 1e-4 to 1e-3 generally work well. 82 | 83 | See the \code{reliability()} method of the \code{\link{OdeModelMCMC}} class. 84 | } 85 | 86 | \section{Tutorial}{ 87 | 88 | See the tutorial vignette. 89 | } 90 | 91 | \references{ 92 | \enumerate{ 93 | \item Timonen, J., Siccha, N., Bales, B., Lähdesmäki, H., & Vehtari, A. 94 | (2023). An importance sampling approach for reliable and efficient 95 | inference in Bayesian ordinary differential equation models. 96 | Stat, 12(1), e614. 97 | \url{https://onlinelibrary.wiley.com/doi/full/10.1002/sta4.614} 98 | } 99 | } 100 | \author{ 101 | \strong{Maintainer}: Juho Timonen \email{juho.timonen@iki.fi} (\href{https://orcid.org/0000-0003-2341-6765}{ORCID}) 102 | 103 | } 104 | -------------------------------------------------------------------------------- /man/odesolvers.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/main-solvers.R 3 | \name{odesolvers} 4 | \alias{odesolvers} 5 | \alias{rk45} 6 | \alias{bdf} 7 | \alias{adams} 8 | \alias{ckrk} 9 | \alias{euler} 10 | \alias{midpoint} 11 | \alias{rk4} 12 | \title{Creating ODE solvers} 13 | \usage{ 14 | rk45(abs_tol = 1e-06, rel_tol = 1e-06, max_num_steps = 1e+06, tol = NULL) 15 | 16 | bdf(abs_tol = 1e-10, rel_tol = 1e-10, max_num_steps = 1e+08, tol = NULL) 17 | 18 | adams(abs_tol = 1e-10, rel_tol = 1e-10, max_num_steps = 1e+08, tol = NULL) 19 | 20 | ckrk(abs_tol = 1e-06, rel_tol = 1e-06, max_num_steps = 1e+06, tol = NULL) 21 | 22 | euler(num_steps = 1) 23 | 24 | midpoint(num_steps = 1) 25 | 26 | rk4(num_steps = 1) 27 | } 28 | \arguments{ 29 | \item{abs_tol}{Absolute tolerance (only for \link{AdaptiveOdeSolver}s). Will 30 | be replaced by \code{tol} if it is not \code{NULL}.} 31 | 32 | \item{rel_tol}{Relative tolerance (only for \link{AdaptiveOdeSolver}s). Will 33 | be replaced by \code{tol} if it is not \code{NULL}.} 34 | 35 | \item{max_num_steps}{Maximum number of steps between output time 36 | points (only for \link{AdaptiveOdeSolver}s).} 37 | 38 | \item{tol}{Can be used to set both \code{abs_tol} and \code{rel_tol} to same value. 39 | Have no effect if \code{NULL} (default).} 40 | 41 | \item{num_steps}{The number of steps between subsequent output time 42 | points (only for \link{FixedNumStepsOdeSolver}s).} 43 | } 44 | \description{ 45 | These constructors should be used for creating the \code{solver} 46 | argument of the \code{sample()} method of the \link{OdeModel} class. 47 | Each function here returns an \link{OdeSolver} which can be either 48 | \itemize{ 49 | \item An \link{AdaptiveOdeSolver} which can estimate its own error and 50 | adapts its step size according to given tolerances for the error 51 | \item A \link{FixedNumStepsOdeSolver} which always takes the same number of 52 | steps between consequent output time points 53 | } 54 | } 55 | \section{Functions}{ 56 | \itemize{ 57 | \item \code{rk45()}: Create an RK45 solver (\link{AdaptiveOdeSolver}) 58 | 59 | \item \code{bdf()}: Create a BDF solver (\link{AdaptiveOdeSolver}) 60 | 61 | \item \code{adams()}: Create an Adams solver (\link{AdaptiveOdeSolver}) 62 | 63 | \item \code{ckrk()}: Create a Cash-Karp solver (\link{AdaptiveOdeSolver}). 64 | 65 | \item \code{euler()}: Create a forward Euler solver 66 | (\link{FixedNumStepsOdeSolver}) 67 | 68 | \item \code{midpoint()}: Create an explicit midpoint solver 69 | (\link{FixedNumStepsOdeSolver}) 70 | 71 | \item \code{rk4()}: Create an RK4 solver (\link{FixedNumStepsOdeSolver}) 72 | 73 | }} 74 | -------------------------------------------------------------------------------- /man/odesolvers_lists.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/main-solvers.R 3 | \name{odesolvers_lists} 4 | \alias{odesolvers_lists} 5 | \alias{rk45_list} 6 | \alias{bdf_list} 7 | \alias{midpoint_list} 8 | \alias{rk4_list} 9 | \title{Creating lists of ODE solvers} 10 | \usage{ 11 | rk45_list(tols, max_num_steps = 1e+06) 12 | 13 | bdf_list(tols, max_num_steps = 1e+08) 14 | 15 | midpoint_list(num_steps) 16 | 17 | rk4_list(num_steps) 18 | } 19 | \arguments{ 20 | \item{tols}{A vector of length \code{L} of tolerance values.} 21 | 22 | \item{max_num_steps}{Maximum number of steps between output time 23 | points (one number, same for all solvers in the output list).} 24 | 25 | \item{num_steps}{A vector of length \code{L} of step amounts.} 26 | } 27 | \description{ 28 | These constructors can be used for creating the \code{solvers} 29 | argument of the \code{sample_manyconf()} method of the \link{OdeModel} class. 30 | Each function here returns a list of \link{OdeSolver}s. 31 | } 32 | \section{Functions}{ 33 | \itemize{ 34 | \item \code{rk45_list()}: Create a list of RK45 solvers with different 35 | tolerances. 36 | 37 | \item \code{bdf_list()}: Create a list of BDF solvers with 38 | different tolerances. 39 | 40 | \item \code{midpoint_list()}: Create a list of explicit midpoint 41 | solvers with different fixed number of steps. 42 | 43 | \item \code{rk4_list()}: Create a list of RK4 44 | solvers with different fixed number of steps. 45 | 46 | }} 47 | -------------------------------------------------------------------------------- /man/plot_metric.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/main-plot.R 3 | \name{plot_metric} 4 | \alias{plot_metric} 5 | \alias{plot_pareto_k} 6 | \alias{plot_r_eff} 7 | \alias{plot_mad} 8 | \title{Plotting different metrics} 9 | \usage{ 10 | plot_metric(values, name, tols = NULL, num_steps = NULL) 11 | 12 | plot_pareto_k(reliability, tols = NULL, num_steps = NULL) 13 | 14 | plot_r_eff(reliability, tols = NULL, num_steps = NULL) 15 | 16 | plot_mad(reliability, tols = NULL, num_steps = NULL, loglik = FALSE) 17 | } 18 | \arguments{ 19 | \item{values}{A numeric vector of metric values.} 20 | 21 | \item{name}{Name of metric} 22 | 23 | \item{tols}{A numeric vector of tolerances. Must have same length as 24 | \code{values}.} 25 | 26 | \item{num_steps}{A numeric vector of step amounts. Must have same length as 27 | \code{values}.} 28 | 29 | \item{reliability}{The list returned by the \verb{$reliability()} method of 30 | \link{OdeModelFit} class.} 31 | 32 | \item{loglik}{If \code{TRUE}, the maximum absolute difference in log likelihoods 33 | is plotted. Otherwise the maximum absolute difference in ODE solutions 34 | is plotted (default).} 35 | } 36 | \description{ 37 | Either \code{tols} or \code{num_steps} has to be \code{NULL}. 38 | } 39 | \section{Functions}{ 40 | \itemize{ 41 | \item \code{plot_metric()}: Plot a generic metric. 42 | 43 | \item \code{plot_pareto_k()}: Plot pareto-k metric. 44 | 45 | \item \code{plot_r_eff()}: Plot relative efficiency. 46 | 47 | \item \code{plot_mad()}: Plot maximum absolute difference. 48 | 49 | }} 50 | -------------------------------------------------------------------------------- /man/stan_array.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/main-declarations.R 3 | \name{stan_array} 4 | \alias{stan_array} 5 | \title{Create a \link{StanArray} object.} 6 | \usage{ 7 | stan_array(name, dims, type = "real", lower = NULL, upper = NULL) 8 | } 9 | \arguments{ 10 | \item{name}{name of the array} 11 | 12 | \item{dims}{list of array dimensions, must be a list of 13 | \code{StanDimension} objects} 14 | 15 | \item{type}{base type of the array} 16 | 17 | \item{lower}{lower bound} 18 | 19 | \item{upper}{upper bound} 20 | } 21 | \description{ 22 | Create a \link{StanArray} object. 23 | } 24 | \examples{ 25 | N <- stan_dim("N") 26 | M <- stan_dim("M") 27 | my_arr <- stan_array("A", dims = list(N, N, M), lower = 0, type = "int") 28 | print(my_arr) 29 | } 30 | \seealso{ 31 | Other Stan variable declaration functions: 32 | \code{\link{stan_dim}()}, 33 | \code{\link{stan_matrix}()}, 34 | \code{\link{stan_param}()}, 35 | \code{\link{stan_transform}()}, 36 | \code{\link{stan_var}()}, 37 | \code{\link{stan_vector}()}, 38 | \code{\link{stan_vector_array}()} 39 | } 40 | \concept{Stan variable declaration functions} 41 | -------------------------------------------------------------------------------- /man/stan_dim.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/main-declarations.R 3 | \name{stan_dim} 4 | \alias{stan_dim} 5 | \title{Create a \link{StanDimension} object} 6 | \usage{ 7 | stan_dim(name, lower = NULL, upper = NULL) 8 | } 9 | \arguments{ 10 | \item{name}{name of the dimension variable} 11 | 12 | \item{lower}{lower bound} 13 | 14 | \item{upper}{upper bound} 15 | } 16 | \description{ 17 | Create a \link{StanDimension} object 18 | } 19 | \examples{ 20 | N <- stan_dim("N") 21 | M <- stan_dim("M", lower = 1, upper = 100) 22 | print(N) 23 | print(M) 24 | } 25 | \seealso{ 26 | Other Stan variable declaration functions: 27 | \code{\link{stan_array}()}, 28 | \code{\link{stan_matrix}()}, 29 | \code{\link{stan_param}()}, 30 | \code{\link{stan_transform}()}, 31 | \code{\link{stan_var}()}, 32 | \code{\link{stan_vector}()}, 33 | \code{\link{stan_vector_array}()} 34 | } 35 | \concept{Stan variable declaration functions} 36 | -------------------------------------------------------------------------------- /man/stan_matrix.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/main-declarations.R 3 | \name{stan_matrix} 4 | \alias{stan_matrix} 5 | \title{Create a \link{StanMatrix} object.} 6 | \usage{ 7 | stan_matrix(name, nrow, ncol, lower = NULL, upper = NULL) 8 | } 9 | \arguments{ 10 | \item{name}{name of the matrix} 11 | 12 | \item{nrow}{number of rows, must be a \link{StanDimension} object} 13 | 14 | \item{ncol}{number of columns, must be a \link{StanDimension} object} 15 | 16 | \item{lower}{lower bound} 17 | 18 | \item{upper}{upper bound} 19 | } 20 | \description{ 21 | Create a \link{StanMatrix} object. 22 | } 23 | \examples{ 24 | N <- stan_dim("N") 25 | M <- stan_dim("M", lower = 1, upper = 100) 26 | my_mat <- stan_matrix("A", nrow = N, ncol = M, lower = 0, upper = 3.2) 27 | print(my_mat) 28 | } 29 | \seealso{ 30 | Other Stan variable declaration functions: 31 | \code{\link{stan_array}()}, 32 | \code{\link{stan_dim}()}, 33 | \code{\link{stan_param}()}, 34 | \code{\link{stan_transform}()}, 35 | \code{\link{stan_var}()}, 36 | \code{\link{stan_vector}()}, 37 | \code{\link{stan_vector_array}()} 38 | } 39 | \concept{Stan variable declaration functions} 40 | -------------------------------------------------------------------------------- /man/stan_param.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/main-declarations.R 3 | \name{stan_param} 4 | \alias{stan_param} 5 | \title{Create a \link{StanParameter} object} 6 | \usage{ 7 | stan_param(decl, prior = "") 8 | } 9 | \arguments{ 10 | \item{decl}{The Stan variable declaration from which the parameter is 11 | created. Must be an object that inherits from \link{StanDeclaration} and 12 | has a real or vector base type.} 13 | 14 | \item{prior}{A string of Stan code that becomes the right-hand side 15 | of the sampling statement that is the prior declaration of the parameter. 16 | The default is empty string (no prior).} 17 | } 18 | \description{ 19 | Create a \link{StanParameter} object 20 | } 21 | \examples{ 22 | # Scalar parameter 23 | my_par <- stan_param(stan_var("beta"), "normal(0, 1)") 24 | print(my_par) 25 | 26 | # Vector parameter 27 | my_vec <- stan_vector("alpha", stan_dim("D"), lower = 0) 28 | my_par <- stan_param(my_vec) 29 | print(my_par) 30 | } 31 | \seealso{ 32 | Other Stan variable declaration functions: 33 | \code{\link{stan_array}()}, 34 | \code{\link{stan_dim}()}, 35 | \code{\link{stan_matrix}()}, 36 | \code{\link{stan_transform}()}, 37 | \code{\link{stan_var}()}, 38 | \code{\link{stan_vector}()}, 39 | \code{\link{stan_vector_array}()} 40 | } 41 | \concept{Stan variable declaration functions} 42 | -------------------------------------------------------------------------------- /man/stan_transform.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/main-declarations.R 3 | \name{stan_transform} 4 | \alias{stan_transform} 5 | \title{Create a \link{StanTransformation} object} 6 | \usage{ 7 | stan_transform(decl, origin = "model", code = "") 8 | } 9 | \arguments{ 10 | \item{decl}{The Stan variable declaration for the quantity. 11 | Must be an object that inherits from \link{StanDeclaration}.} 12 | 13 | \item{origin}{Must be either \code{"data"}, \code{"parameters"}, or \code{"model"}. 14 | These correspond to the \verb{transformed data}, \verb{transformed parameters}, and 15 | \verb{generated quantities} blocks, respectively.} 16 | 17 | \item{code}{A string of Stan code that defines how the quantity is 18 | computed from other variables/parameters. 19 | The default is empty string (no definition). If \code{code} 20 | doesn't include any assignments (with \code{=}), it is prepended 21 | with \code{paste0(decl$name, " = ")}. In this case also a semicolon is 22 | added to the end if it is missing.} 23 | } 24 | \description{ 25 | Create a \link{StanTransformation} object 26 | } 27 | \examples{ 28 | N <- stan_dim("N") 29 | D <- stan_dim("D") 30 | decl <- stan_array("y", dims = list(N, D), type = "int") 31 | code <- " 32 | for(n in 1:N) { 33 | for(d in 1:D) { 34 | y[n, d] ~ poisson_rng(0.2); 35 | } 36 | }" 37 | y <- stan_transform(decl, code = code) 38 | print(y) 39 | } 40 | \seealso{ 41 | Other Stan variable declaration functions: 42 | \code{\link{stan_array}()}, 43 | \code{\link{stan_dim}()}, 44 | \code{\link{stan_matrix}()}, 45 | \code{\link{stan_param}()}, 46 | \code{\link{stan_var}()}, 47 | \code{\link{stan_vector}()}, 48 | \code{\link{stan_vector_array}()} 49 | } 50 | \concept{Stan variable declaration functions} 51 | -------------------------------------------------------------------------------- /man/stan_var.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/main-declarations.R 3 | \name{stan_var} 4 | \alias{stan_var} 5 | \title{Create a \link{StanVariable} object.} 6 | \usage{ 7 | stan_var(name, type = "real", lower = NULL, upper = NULL) 8 | } 9 | \arguments{ 10 | \item{name}{name of the dimension variable} 11 | 12 | \item{type}{variable type (real or int)} 13 | 14 | \item{lower}{lower bound} 15 | 16 | \item{upper}{upper bound} 17 | } 18 | \description{ 19 | Create a \link{StanVariable} object. 20 | } 21 | \examples{ 22 | x <- stan_var("x", type = "real", lower = 0) 23 | y <- stan_var("y", type = "int") 24 | print(x) 25 | print(y) 26 | } 27 | \seealso{ 28 | Other Stan variable declaration functions: 29 | \code{\link{stan_array}()}, 30 | \code{\link{stan_dim}()}, 31 | \code{\link{stan_matrix}()}, 32 | \code{\link{stan_param}()}, 33 | \code{\link{stan_transform}()}, 34 | \code{\link{stan_vector}()}, 35 | \code{\link{stan_vector_array}()} 36 | } 37 | \concept{Stan variable declaration functions} 38 | -------------------------------------------------------------------------------- /man/stan_vector.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/main-declarations.R 3 | \name{stan_vector} 4 | \alias{stan_vector} 5 | \title{Create a \link{StanVector} object.} 6 | \usage{ 7 | stan_vector(name, length, lower = NULL, upper = NULL) 8 | } 9 | \arguments{ 10 | \item{name}{name of the vector} 11 | 12 | \item{length}{length of the vector, must be a \link{StanDimension} object} 13 | 14 | \item{lower}{lower bound} 15 | 16 | \item{upper}{upper bound} 17 | } 18 | \description{ 19 | Create a \link{StanVector} object. 20 | } 21 | \examples{ 22 | x <- stan_vector("x", length = stan_dim("N", lower = 1), lower = 0) 23 | print(x) 24 | } 25 | \seealso{ 26 | Other Stan variable declaration functions: 27 | \code{\link{stan_array}()}, 28 | \code{\link{stan_dim}()}, 29 | \code{\link{stan_matrix}()}, 30 | \code{\link{stan_param}()}, 31 | \code{\link{stan_transform}()}, 32 | \code{\link{stan_var}()}, 33 | \code{\link{stan_vector_array}()} 34 | } 35 | \concept{Stan variable declaration functions} 36 | -------------------------------------------------------------------------------- /man/stan_vector_array.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/main-declarations.R 3 | \name{stan_vector_array} 4 | \alias{stan_vector_array} 5 | \title{Create a \link{StanVectorArray} object.} 6 | \usage{ 7 | stan_vector_array(name, dims, length, lower = NULL, upper = NULL) 8 | } 9 | \arguments{ 10 | \item{name}{name of the vector array} 11 | 12 | \item{dims}{list of array dimensions, must be a list of 13 | \link{StanDimension} objects} 14 | 15 | \item{length}{length of the vector, must be a \link{StanDimension} object} 16 | 17 | \item{lower}{lower bound} 18 | 19 | \item{upper}{upper bound} 20 | } 21 | \description{ 22 | Create a \link{StanVectorArray} object. 23 | } 24 | \examples{ 25 | N <- stan_dim("N") 26 | D <- stan_dim("D") 27 | vec_arr <- stan_vector_array("y", dims = list(N), length = D) 28 | print(vec_arr) 29 | } 30 | \seealso{ 31 | Other Stan variable declaration functions: 32 | \code{\link{stan_array}()}, 33 | \code{\link{stan_dim}()}, 34 | \code{\link{stan_matrix}()}, 35 | \code{\link{stan_param}()}, 36 | \code{\link{stan_transform}()}, 37 | \code{\link{stan_var}()}, 38 | \code{\link{stan_vector}()} 39 | } 40 | \concept{Stan variable declaration functions} 41 | -------------------------------------------------------------------------------- /odemodeling.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | LineEndingConversion: Posix 18 | 19 | BuildType: Package 20 | PackageUseDevtools: Yes 21 | PackageInstallArgs: --no-multiarch --with-keep.source 22 | PackageRoxygenize: rd,collate,namespace 23 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(odemodeling) 3 | 4 | test_check("odemodeling") 5 | -------------------------------------------------------------------------------- /tests/testthat/test-classes-model.R: -------------------------------------------------------------------------------- 1 | a <- example_ode_model(name = "gsir", compile = F) 2 | 3 | test_that("OdeModel methods work correctly", { 4 | expect_error(a$assert_stanfile_exists(), "Model not initialized") 5 | expect_gt(nchar(a$code()), 10) 6 | expect_output(a$print()) 7 | }) 8 | 9 | test_that("model has correct names", { 10 | sm <- a$stanmodel 11 | nam1 <- sm$param_names() 12 | nam2 <- sm$param_names(inc_transformed = T) 13 | nam3 <- sm$data_names() 14 | expect_equal(nam1, c("beta", "gamma", "phi_inv")) 15 | expect_equal(nam2, c( 16 | "beta", "gamma", "phi_inv", "phi", "y_sol_tpar", 17 | "log_lik_tpar" 18 | )) 19 | nam3_real <- c( 20 | "G", "N", "D", "pop_sizes", "I0", "contacts", 21 | "delta", "I_data", "t0", "t", "abs_tol", "rel_tol", 22 | "max_num_steps", "num_steps", "solver" 23 | ) 24 | expect_equal(nam3, nam3_real) 25 | }) 26 | -------------------------------------------------------------------------------- /tests/testthat/test-main-model.R: -------------------------------------------------------------------------------- 1 | test_that("odemodel creation gives correct message", { 2 | expect_message(example_ode_model("gsir", compile = F), "Not compiling") 3 | }) 4 | 5 | test_that("ode_model() works without any variables", { 6 | a <- ode_model( 7 | N = stan_dim("N"), 8 | odefun_body = "return(rep_vector(0.0, 2));", 9 | loglik_body = "return(0);", 10 | odefun_init = stan_vector("y0", length = stan_dim("K")), 11 | compile = FALSE 12 | ) 13 | expect_error(a$assert_stanfile_exists(), "Model not initialized") 14 | expect_gt(nchar(a$code()), 1000) 15 | }) 16 | -------------------------------------------------------------------------------- /tests/testthat/test-main-solvers.R: -------------------------------------------------------------------------------- 1 | test_that("rk45() works correctly", { 2 | tols <- exp(rnorm(2)) 3 | mns <- 999 4 | a <- rk45(abs_tol = tols[1], rel_tol = tols[2], max_num_steps = mns) 5 | expect_true("AdaptiveOdeSolver" %in% class(a)) 6 | expect_true("OdeSolver" %in% class(a)) 7 | expect_equal(a$name, "rk45") 8 | sd <- a$standata() 9 | expect_equal(sd$abs_tol, tols[1]) 10 | expect_equal(sd$rel_tol, tols[2]) 11 | expect_equal(sd$max_num_steps, mns) 12 | expect_equal(sd$solver, 1) 13 | 14 | expect_output(a$print(), "rk45") 15 | }) 16 | 17 | test_that("bdf() works correctly", { 18 | tols <- exp(rnorm(2)) 19 | mns <- 993 20 | a <- bdf(abs_tol = tols[1], rel_tol = tols[2], max_num_steps = mns) 21 | expect_true("AdaptiveOdeSolver" %in% class(a)) 22 | expect_true("OdeSolver" %in% class(a)) 23 | expect_equal(a$name, "bdf") 24 | sd <- a$standata() 25 | expect_equal(sd$abs_tol, tols[1]) 26 | expect_equal(sd$rel_tol, tols[2]) 27 | expect_equal(sd$max_num_steps, mns) 28 | expect_equal(sd$solver, 2) 29 | 30 | expect_output(a$print(), "bdf") 31 | }) 32 | 33 | test_that("adams() works correctly", { 34 | tols <- exp(rnorm(2)) 35 | mns <- 991 36 | a <- adams(abs_tol = tols[1], rel_tol = tols[2], max_num_steps = mns) 37 | expect_true("AdaptiveOdeSolver" %in% class(a)) 38 | expect_true("OdeSolver" %in% class(a)) 39 | expect_equal(a$name, "adams") 40 | sd <- a$standata() 41 | expect_equal(sd$abs_tol, tols[1]) 42 | expect_equal(sd$rel_tol, tols[2]) 43 | expect_equal(sd$max_num_steps, mns) 44 | expect_equal(sd$solver, 3) 45 | 46 | expect_output(a$print(), "adams") 47 | }) 48 | 49 | 50 | test_that("ckrk() works correctly", { 51 | tols <- exp(rnorm(2)) 52 | mns <- 991 53 | a <- ckrk(abs_tol = tols[1], rel_tol = tols[2], max_num_steps = mns) 54 | expect_true("AdaptiveOdeSolver" %in% class(a)) 55 | expect_true("OdeSolver" %in% class(a)) 56 | expect_equal(a$name, "ckrk") 57 | sd <- a$standata() 58 | expect_equal(sd$abs_tol, tols[1]) 59 | expect_equal(sd$rel_tol, tols[2]) 60 | expect_equal(sd$max_num_steps, mns) 61 | expect_equal(sd$solver, 4) 62 | 63 | expect_output(a$print(), "ckrk") 64 | }) 65 | 66 | test_that("euler() works correctly", { 67 | ns <- 2 68 | a <- euler(num_steps = ns) 69 | expect_true("FixedNumStepsOdeSolver" %in% class(a)) 70 | expect_true("OdeSolver" %in% class(a)) 71 | expect_equal(a$name, "euler") 72 | sd <- a$standata() 73 | expect_equal(sd$num_steps, ns) 74 | expect_equal(sd$solver, 101) 75 | 76 | expect_output(a$print(), "euler") 77 | }) 78 | 79 | test_that("midpoint() works correctly", { 80 | ns <- 5 81 | a <- midpoint(num_steps = ns) 82 | expect_true("FixedNumStepsOdeSolver" %in% class(a)) 83 | expect_true("OdeSolver" %in% class(a)) 84 | expect_equal(a$name, "midpoint") 85 | sd <- a$standata() 86 | expect_equal(sd$num_steps, ns) 87 | expect_equal(sd$solver, 102) 88 | 89 | expect_output(a$print(), "midpoint") 90 | }) 91 | 92 | test_that("rk4() works correctly", { 93 | ns <- 3 94 | a <- rk4(num_steps = ns) 95 | expect_true("FixedNumStepsOdeSolver" %in% class(a)) 96 | expect_true("OdeSolver" %in% class(a)) 97 | expect_equal(a$name, "rk4") 98 | sd <- a$standata() 99 | expect_equal(sd$num_steps, ns) 100 | expect_equal(sd$solver, 103) 101 | 102 | expect_output(a$print(), "rk4") 103 | }) 104 | 105 | 106 | test_that("rk45_list() works correctly", { 107 | tols <- c(0.1, 1e-5, 1e-15) 108 | mns <- 103 109 | a <- rk45_list(tols = tols, max_num_steps = mns) 110 | expect_equal(length(a), 3) 111 | for (j in seq_len(3)) { 112 | s <- a[[j]] 113 | expect_equal(s$name, "rk45") 114 | expect_equal(s$abs_tol, tols[j]) 115 | expect_equal(s$rel_tol, tols[j]) 116 | expect_equal(s$max_num_steps, mns) 117 | } 118 | }) 119 | 120 | test_that("bdf_list() works correctly", { 121 | tols <- c(1, 1e-3, 1.343e-12) 122 | mns <- 101 123 | a <- bdf_list(tols = tols, max_num_steps = mns) 124 | expect_equal(length(a), 3) 125 | for (j in seq_len(3)) { 126 | s <- a[[j]] 127 | expect_equal(s$name, "bdf") 128 | expect_equal(s$abs_tol, tols[j]) 129 | expect_equal(s$rel_tol, tols[j]) 130 | expect_equal(s$max_num_steps, mns) 131 | } 132 | }) 133 | 134 | test_that("midpoint_list() works correctly", { 135 | ns <- c(3:5) 136 | a <- midpoint_list(ns) 137 | expect_equal(length(a), 3) 138 | for (j in seq_len(3)) { 139 | s <- a[[j]] 140 | expect_equal(s$name, "midpoint") 141 | expect_equal(s$num_steps, ns[j]) 142 | } 143 | }) 144 | 145 | test_that("rk4_list() works correctly", { 146 | ns <- c(9:10) 147 | a <- rk4_list(ns) 148 | expect_equal(length(a), 2) 149 | for (j in seq_len(2)) { 150 | s <- a[[j]] 151 | expect_equal(s$name, "rk4") 152 | expect_equal(s$num_steps, ns[j]) 153 | } 154 | }) 155 | -------------------------------------------------------------------------------- /tests/testthat/test-main_declarations.R: -------------------------------------------------------------------------------- 1 | test_that("stan_dim() works correctly", { 2 | N <- stan_dim("N") 3 | M <- stan_dim("M", lower = 1, upper = 100) 4 | expect_output(print(N), "int N;") 5 | expect_output(print(M), "int M;") 6 | }) 7 | 8 | test_that("stan_var() works correctly", { 9 | x <- stan_var("x", type = "real", lower = 0) 10 | y <- stan_var("y", type = "int") 11 | expect_output(print(x), "real x;") 12 | expect_output(print(y), "int y;") 13 | }) 14 | 15 | test_that("stan_vector() works correctly", { 16 | x <- stan_vector("x", length = stan_dim("N", lower = 1), lower = 0) 17 | expect_output(print(x), "vector\\[N\\] x;") 18 | }) 19 | 20 | test_that("stan_matrix() works correctly", { 21 | N <- stan_dim("N") 22 | M <- stan_dim("M", lower = 1, upper = 100) 23 | my_mat <- stan_matrix("A", nrow = N, ncol = M, lower = 0, upper = 3.2) 24 | expect_output(print(my_mat), "matrix\\[N, M\\] A;") 25 | }) 26 | 27 | test_that("stan_array() works correctly", { 28 | N <- stan_dim("N") 29 | M <- stan_dim("M") 30 | my_arr <- stan_array("A", dims = list(N, N, M), upper = 1, type = "int") 31 | expect_output(print(my_arr), "array\\[N, N, M\\] int A;") 32 | }) 33 | 34 | test_that("stan_vector_array() works correctly", { 35 | N <- stan_dim("N") 36 | D <- stan_dim("D") 37 | vec_arr <- stan_vector_array("y", dims = list(N), length = D) 38 | expect_output(print(vec_arr), "array\\[N\\] vector\\[D\\] y;") 39 | }) 40 | 41 | test_that("stan_param() works correctly", { 42 | # Scalar parameter 43 | my_par <- stan_param(stan_var("beta"), "normal(0, 1)") 44 | expect_output(print(my_par), "beta ~ normal\\(0, 1\\);") 45 | 46 | # # Vector parameter 47 | my_vec <- stan_vector("alpha", stan_dim("D"), lower = 0) 48 | my_par <- stan_param(my_vec) 49 | expect_output(print(my_par), "No prior set.") 50 | }) 51 | 52 | 53 | test_that("stan_transform() works correctly for gq", { 54 | N <- stan_dim("N") 55 | D <- stan_dim("D") 56 | decl <- stan_array("y", dims = list(N, D), type = "int") 57 | code <- " 58 | for(n in 1:N) { 59 | for(d in 1:D) { 60 | y[n, d] ~ poisson_rng(0.2); 61 | } 62 | }" 63 | y <- stan_transform(decl, code = code) 64 | expect_output(print(y), "Generated quantity:") 65 | }) 66 | 67 | test_that("stan_param() works correctly for transformed param", { 68 | # Scalar parameter 69 | b <- stan_var("beta") 70 | y <- stan_transform(b, origin = "parameters", code = "beta = alpha + 1;") 71 | expect_output(print(y), "Transformed parameter:") 72 | }) 73 | -------------------------------------------------------------------------------- /tests/testthat/test-utils-stancode.R: -------------------------------------------------------------------------------- 1 | test_that("model with only prior sampling (no ODE solving) can be created", { 2 | par <- stan_param(stan_var("dummy"), "normal(0,1)") 3 | gq <- stan_transform(stan_var("foo"), 4 | origin = "model", 5 | code = "2*dummy" 6 | ) 7 | odefun_vars <- list(par) 8 | other_vars <- list(gq) 9 | expect_output(par$print()) 10 | expect_output(gq$print()) 11 | code <- generate_stancode_prior(odefun_vars, list(), other_vars, FALSE) 12 | expect_gt(nchar(code$code), 30) 13 | }) 14 | -------------------------------------------------------------------------------- /tests/testthat/test-workflow-gsir.R: -------------------------------------------------------------------------------- 1 | # Setup ------------------------------------------------------------------- 2 | 3 | SEED <- 353 4 | 5 | # Create data 6 | num_tp <- 15 7 | G <- 3 8 | t0 <- 0 9 | t <- c(1:num_tp) 10 | dat <- list( 11 | G = G, 12 | D = 2 * G, 13 | pop_sizes = rep(1000, G), 14 | contacts = matrix(c(1, 0.5, 0.2, 0.5, 1, 0.5, 0.2, 0.5, 1.0), 3, 3), 15 | I0 = c(5, 0, 0), 16 | delta = 0.001, 17 | I_data = matrix(1, num_tp, G) 18 | ) 19 | 20 | 21 | # Model compilation ------------------------------------------------------- 22 | 23 | # Create models 24 | prior <- example_ode_model(name = "gsir", compile = F, prior_only = TRUE) 25 | prior$reinit() 26 | post <- example_ode_model("gsir") 27 | 28 | 29 | # Prior sampling ---------------------------------------------------------- 30 | 31 | # Sample from prior 32 | fit <- prior$sample( 33 | t0 = t0, t = t, 34 | data = dat, 35 | iter_warmup = 1000, iter_sampling = 1000, chains = 1, refresh = 0, 36 | seed = SEED 37 | ) 38 | 39 | # Get data 40 | idx <- 322 41 | y_sol <- fit$extract_odesol()[idx, , ] 42 | I_gen <- fit$extract_unflattened(variable = "I_gen")[idx, , ] 43 | dat$I_data <- I_gen 44 | 45 | test_that("prior sampling works", { 46 | expect_false(prior$has_likelihood) 47 | expect_true(is(fit, "OdeModelMCMC")) 48 | expect_equal(dim(y_sol), c(15, 6)) 49 | expect_equal(dim(I_gen), c(15, 3)) 50 | expect_equal(dim(fit$extract_y0()), c(1000, 6)) # all rows same, y0 not param 51 | expect_output(fit$print()) 52 | expect_gt(fit$setup_time, 0.0) 53 | expect_gt(fit$time()$total, 0.0) 54 | expect_gt(nchar(fit$cmdstan_version()), 5) 55 | expect_true(fit$model$assert_stanfile_exists()) 56 | expect_equal(dim(fit$summary()), c(146 + 6, 10)) 57 | expect_equal(fit$cmdstan_seed(), SEED) 58 | expect_equal(fit$cmdstan_init(), 2) 59 | expect_error(fit$loglik(), "model has no likelihood function specified") 60 | }) 61 | 62 | test_that("plotting ODE solutions works", { 63 | plt <- fit$plot_odesol() 64 | expect_s3_class(plt, "ggplot") 65 | plt <- fit$plot_odesol(draw_inds = c(2:9)) 66 | expect_s3_class(plt, "ggplot") 67 | }) 68 | 69 | # Posterior sampling ------------------------------------------------------ 70 | 71 | post_fit_solver <- bdf(abs_tol = 1e-4, rel_tol = 1e-4, max_num_steps = 1e3) 72 | post_fit <- post$sample( 73 | t0 = t0, t = t, 74 | data = dat, 75 | iter_warmup = 10, iter_sampling = 10, chains = 2, refresh = 0, 76 | init = 0, step_size = 0.1, 77 | seed = SEED, 78 | solver = post_fit_solver 79 | ) 80 | 81 | test_that("posterior sampling works", { 82 | expect_true(post$has_likelihood) 83 | idx <- 7 84 | y_sol <- post_fit$extract_odesol()[idx, , ] 85 | I_gen <- post_fit$extract_unflattened(variable = "I_gen")[idx, , ] 86 | expect_true(is(post_fit, "OdeModelMCMC")) 87 | expect_equal(dim(y_sol), c(15, 6)) 88 | expect_equal(dim(I_gen), c(15, 3)) 89 | expect_equal(dim(post_fit$loglik()), c(10, 2, 1)) 90 | }) 91 | 92 | test_that("posterior sampling using many configurations works", { 93 | e_tols <- -c(2:5) 94 | confs <- rk45_list(tols = 10^e_tols, max_num_steps = 1000) 95 | res <- post$sample_manyconf( 96 | t0 = t0, t = t, 97 | data = dat, 98 | solvers = confs, 99 | iter_warmup = 10, iter_sampling = 10, chains = 1, refresh = 0, 100 | init = 0, step_size = 0.1, 101 | seed = SEED 102 | ) 103 | expect_length(res$times$grand_total, 4) 104 | unlink("results", recursive = TRUE) 105 | }) 106 | 107 | 108 | # Generating quantities --------------------------------------------------- 109 | 110 | test_that("generating quantities works", { 111 | expect_error( 112 | fit$gqs(t0 = 4.5), 113 | "each value in t must be strictly larger than given t0" 114 | ) 115 | tout <- c(1, 2, 3, 5) 116 | sims <- list() 117 | sims[[1]] <- fit$gqs(solver = rk45(), t = tout) 118 | sims[[2]] <- fit$gqs(solver = bdf(), t = tout) 119 | sims[[3]] <- fit$gqs(solver = adams(), t = tout) 120 | sims[[4]] <- fit$gqs(solver = ckrk(), t = tout) 121 | sims[[5]] <- fit$gqs(solver = euler(num_steps = 30), t = tout) 122 | sims[[6]] <- fit$gqs(solver = midpoint(num_steps = 30), t = tout) 123 | sims[[7]] <- fit$gqs(solver = rk4(num_steps = 30), t = tout) 124 | for (a in sims) { 125 | expect_output(print(a), "An object of class OdeModelGQ") 126 | idx <- 7 127 | y_sol <- a$extract_odesol()[idx, , ] 128 | I_gen <- a$extract_unflattened(variable = "I_gen")[idx, , ] 129 | expect_true(is(a, "OdeModelGQ")) 130 | expect_equal(dim(y_sol), c(4, 6)) 131 | expect_equal(dim(I_gen), c(4, 3)) 132 | expect_equal(a$get_t0(), 0.0) 133 | expect_equal(dim(post_fit$loglik()), c(10, 2, 1)) 134 | } 135 | }) 136 | 137 | 138 | # Workflow ---------------------------------------------------------------- 139 | 140 | sfun <- function(solver) { 141 | post_fit$gqs( 142 | t0 = t0, t = t, 143 | data = dat, 144 | seed = SEED, 145 | solver = solver 146 | ) 147 | } 148 | 149 | test_that("psis works", { 150 | post_sims <- list() 151 | post_sims[[1]] <- sfun(solver = rk45()) 152 | post_sims[[2]] <- sfun(solver = bdf()) 153 | post_sims[[3]] <- sfun(solver = adams()) 154 | post_sims[[4]] <- sfun(solver = ckrk()) 155 | post_sims[[5]] <- sfun(solver = euler(num_steps = 30)) 156 | post_sims[[6]] <- sfun(solver = midpoint(num_steps = 30)) 157 | post_sims[[7]] <- sfun(solver = rk4(num_steps = 30)) 158 | N <- length(t) 159 | 160 | # Simulation works with all solvers 161 | for (a in post_sims) { 162 | expect_output(print(a), "An object of class OdeModelGQ") 163 | expect_equal(a$cmdstan_seed(), SEED) 164 | idx <- 7 165 | y_sol <- a$extract_odesol()[idx, , ] 166 | I_gen <- a$extract_unflattened(variable = "I_gen")[idx, , ] 167 | expect_true(is(a, "OdeModelGQ")) 168 | expect_equal(dim(y_sol), c(N, 6)) 169 | expect_equal(dim(I_gen), c(N, 3)) 170 | expect_equal(a$get_t0(), 0.0) 171 | expect_equal(dim(a$loglik()), c(10, 2, 1)) 172 | 173 | # PSIS works 174 | expect_warning( 175 | { 176 | is <- psis(post_fit, a) 177 | }, 178 | "Not enough tail samples" 179 | ) 180 | expect_equal(names(is), c("log_weights", "diagnostics")) 181 | expect_equal(length(is$log_weights), 20) # 10 times 2 182 | } 183 | 184 | # Simulation actually gives different result for each solver 185 | for (j in 2:length(post_sims)) { 186 | d1 <- max_abs_loglik_diff(post_sims[[1]], post_sims[[j]]) 187 | d2 <- max_abs_odesol_diff(post_sims[[1]], post_sims[[j]]) 188 | expect_gt(d1, 1e-10) 189 | expect_gt(d2, 1e-10) 190 | } 191 | }) 192 | 193 | test_that("sim with same solver as during sampling gives same output", { 194 | post_sim_same <- sfun(post_fit_solver) 195 | d1 <- max_abs_loglik_diff(post_fit, post_sim_same) 196 | d2 <- max_abs_odesol_diff(post_fit, post_sim_same) 197 | expect_lt(d1, 1e-6) # should be 0 but CSV conversion messes this up 198 | expect_lt(d2, 1e-6) # should be 0 but CSV conversion messes this up 199 | }) 200 | 201 | test_that("reliability check works", { 202 | log_tols <- c(-6:-9) 203 | solvers <- bdf_list(tols = 10^log_tols) 204 | expect_warning( 205 | { 206 | rel_norecomp <- post_fit$reliability( 207 | solvers = solvers, 208 | recompute_loglik = F 209 | ) 210 | }, 211 | "Some Pareto k diagnostic values are too high" 212 | ) 213 | expect_warning( 214 | { 215 | rel <- post_fit$reliability(solvers = solvers) 216 | }, 217 | "Some Pareto k diagnostic values are too high" 218 | ) 219 | expect_true(rel$recompute_loglik) 220 | expect_true(!rel_norecomp$recompute_loglik) 221 | 222 | met <- rel$metrics 223 | expect_equal(dim(met), c(length(solvers), 5)) 224 | nams <- c("pareto_k", "n_eff", "r_eff", "mad_loglik", "mad_odesol") 225 | expect_equal(colnames(met), nams) 226 | unlink("results", recursive = TRUE) # purge results directory 227 | 228 | # Plots 229 | tols <- 10^log_tols 230 | plots <- list() 231 | plots[[1]] <- plot_mad(rel, tols = tols, loglik = T) 232 | plots[[2]] <- plot_mad(rel, tols = tols, loglik = F) 233 | plots[[3]] <- plot_pareto_k(rel, tols = tols) 234 | plots[[4]] <- plot_r_eff(rel, tols = tols) 235 | plots[[5]] <- plot_metric(rel$times, "time", tols = tols) 236 | plots[[6]] <- plot_metric(rel$times, "time", num_steps = c(1, 2, 3, 4)) 237 | L <- length(plots) 238 | for (j in seq_len(L)) { 239 | expect_s3_class(plots[[j]], "ggplot") 240 | } 241 | 242 | # Expect errors 243 | expect_error( 244 | plot_mad(rel, tols = tols, num_steps = tols), 245 | "either tols or num_steps must be NULL" 246 | ) 247 | expect_error( 248 | plot_mad(rel), 249 | "either tols or num_steps must not be NULL" 250 | ) 251 | }) 252 | -------------------------------------------------------------------------------- /tests/testthat/test-workflow-lv.R: -------------------------------------------------------------------------------- 1 | # Setup ------------------------------------------------------------------- 2 | SEED <- 123 3 | 4 | # Create data 5 | dat <- lynxhare 6 | N <- nrow(dat) - 1 7 | t <- dat$year[2:(N + 1)] 8 | t0 <- dat$year[1] 9 | y_obs <- cbind(dat$hare[2:(N + 1)], dat$lynx[2:(N + 1)]) 10 | y_obs_init <- c(dat$hare[1], dat$lynx[1]) 11 | add_data <- list( 12 | y_obs = y_obs, 13 | y_obs_init = y_obs_init, 14 | D = 2 15 | ) 16 | 17 | # Model compilation ------------------------------------------------------- 18 | 19 | lv <- example_ode_model(name = "lv", prior_only = FALSE) 20 | 21 | test_that("Lotka-Volterra example can be created", { 22 | expect_true(lv$has_likelihood) 23 | expect_error( 24 | lv$make_params(c(1, 2)), 25 | "currently works only for models with only scalar parameters" 26 | ) 27 | }) 28 | 29 | # Sampling ---------------------------------------------------------------- 30 | 31 | # Sample from posterior 32 | fit <- lv$sample( 33 | t0 = t0, t = t, data = add_data, 34 | iter_warmup = 100, iter_sampling = 100, chains = 1, refresh = 0, 35 | seed = SEED, solver = midpoint(4), init = 0, step_size = 0.1, 36 | show_messages = FALSE 37 | ) 38 | 39 | test_that("sampling works", { 40 | expect_true(lv$has_likelihood) 41 | expect_true(is(fit, "OdeModelMCMC")) 42 | expect_equal(dim(fit$extract_y0()), c(100, 2)) 43 | expect_output(fit$print()) 44 | expect_gt(fit$setup_time, 0.0) 45 | expect_gt(fit$time()$total, 0.0) 46 | expect_gt(nchar(fit$cmdstan_version()), 5) 47 | expect_true(fit$model$assert_stanfile_exists()) 48 | expect_equal(fit$cmdstan_seed(), SEED) 49 | expect_equal(fit$cmdstan_init(), 0) 50 | expect_output(fit$print_diagnostics()) 51 | expect_output(fit$print_summary()) 52 | }) 53 | 54 | test_that("diagnose works", { 55 | diags <- lv$diagnose( 56 | t0 = t0, t = t, data = add_data, solver = midpoint(4), init = 0, 57 | epsilon = 1e-6 58 | ) 59 | expect_equal(names(diags), c("gradients", "lp")) 60 | expect_true(all(diags$gradients$error < 1e-6)) 61 | }) 62 | 63 | test_that("plotting ODE solutions works", { 64 | plt <- fit$plot_odesol() 65 | expect_s3_class(plt, "ggplot") 66 | plt <- fit$plot_odesol(draw_inds = c(2:9)) 67 | expect_s3_class(plt, "ggplot") 68 | }) 69 | 70 | test_that("extracting t and t0 works correctly", { 71 | x <- fit$get_t() 72 | y <- fit$get_t(include_t0 = TRUE) 73 | expect_equal(length(y), length(x) + 1) 74 | }) 75 | 76 | test_that("extracting ODE solutions quantiles works", { 77 | df1 <- fit$extract_odesol_df_dist() 78 | df2 <- fit$extract_odesol_df_dist(include_y0 = TRUE) 79 | expect_equal(dim(df1), c(40, 5)) 80 | expect_equal(dim(df2), c(42, 5)) 81 | }) 82 | 83 | test_that("plotting ODE solutions distributions works", { 84 | yn <- c("foo", "bar") 85 | plt1 <- fit$plot_odesol_dist(ydim_names = yn) 86 | plt2 <- fit$plot_odesol_dist(ydim_names = yn, include_y0 = TRUE) 87 | expect_s3_class(plt1, "ggplot") 88 | expect_s3_class(plt2, "ggplot") 89 | }) 90 | 91 | test_that("plotting on a denser set of time points works", { 92 | t_dense <- seq(1901, 1920, by = 0.1) 93 | add_data_dense <- list( 94 | y_obs_init = add_data$y_obs_init, 95 | y_obs = matrix(0, length(t_dense), 2), # dummy 96 | D = 2 97 | ) 98 | gq <- fit$gqs(t = t_dense, data = add_data_dense) 99 | plt <- gq$plot_odesol_dist(p = 0.8) 100 | expect_s3_class(plt, "ggplot") 101 | }) 102 | -------------------------------------------------------------------------------- /tests/testthat/test-workflow-tmdd.R: -------------------------------------------------------------------------------- 1 | test_that("tmdd example can generate quantities", { 2 | # Create model 3 | tmdd <- example_ode_model(name = "tmdd", prior_only = TRUE) 4 | expect_false(tmdd$has_likelihood) 5 | 6 | # Define simulation parameters 7 | sim_k <- c(0.592, 0.900, 2.212, 0.823, 0.201, 0.024) 8 | sim_sigma <- 0.3 9 | sim_params <- tmdd$make_params(c(sim_k, sim_sigma)) 10 | 11 | # Simulate and plot 12 | gq <- tmdd$gqs( 13 | t0 = 0, 14 | t = seq(0.2, 10, by = 0.2), 15 | data = list(L0 = 5, D = 3), 16 | params = sim_params 17 | ) 18 | plt <- gq$plot_odesol() 19 | expect_s3_class(plt, "ggplot") 20 | }) 21 | -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *.R 3 | *_cache/ 4 | -------------------------------------------------------------------------------- /vignettes/tutorial.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "The 'odemodeling' R package" 3 | author: Juho Timonen 4 | date: 21 Feb 2022 5 | output: 6 | rmarkdown::html_vignette: 7 | toc: true 8 | vignette: > 9 | %\VignetteIndexEntry{The 'odemodeling' R package} 10 | %\VignetteEngine{knitr::rmarkdown} 11 | %\VignetteEncoding{UTF-8} 12 | --- 13 | 14 | ```{r, include = FALSE} 15 | knitr::opts_chunk$set( 16 | collapse = TRUE, 17 | comment = "#>" 18 | ) 19 | ``` 20 | 21 | This vignette demonstrates core functionality of the package. 22 | 23 | ```{r setup} 24 | library(odemodeling) 25 | library(ggplot2) 26 | ``` 27 | 28 | # Creating a model 29 | 30 | All models need to involve an ODE system of the form 31 | \begin{equation} 32 | \label{eq: ode} 33 | \frac{\text{d} \textbf{y}(t)}{\text{d}t} = f_{\psi}\left(\textbf{y}(t), t\right), 34 | \end{equation} 35 | where $f_{\psi}: \mathbb{R}^D \rightarrow \mathbb{R}^D$ with parameters $\psi$. As an example we define an ODE system 36 | \begin{equation} 37 | \label{eq: sho} 38 | f_{\psi}\left(\textbf{y}, t\right) = 39 | \begin{bmatrix} 40 | y_2 \\ 41 | - y_1 - \theta y_2 42 | \end{bmatrix} 43 | \end{equation} 44 | describing a simple harmonic oscillator, where $\psi = \{ k \}$ and dimension $D = 2$. The Stan code for the body of this function is 45 | ```{r sho_body} 46 | sho_fun_body <- " 47 | vector[2] dy_dt; 48 | dy_dt[1] = y[2]; 49 | dy_dt[2] = - y[1] - k*y[2]; 50 | return(dy_dt); 51 | " 52 | ``` 53 | 54 | We need to 55 | define the variable for the initial system state at `t0` as `y0`. The ODE 56 | system dimension is declared as `D` and number of time points as `N`. 57 | ```{r sho_dims} 58 | N <- stan_dim("N", lower = 1) 59 | D <- stan_dim("D") 60 | y0 <- stan_vector("y0", length = D) 61 | k <- stan_param(stan_var("k", lower = 0), "inv_gamma(5, 1)") 62 | ``` 63 | 64 | Finally we declare the parameter `k` and its prior. 65 | ```{r sho_param} 66 | k <- stan_param(stan_var("k", lower = 0), prior = "inv_gamma(5, 1)") 67 | ``` 68 | 69 | The following code creates and compiles the Stan model. 70 | ```{r sho_create_prior} 71 | sho <- ode_model(N, 72 | odefun_vars = list(k), 73 | odefun_body = sho_fun_body, 74 | odefun_init = y0 75 | ) 76 | print(sho) 77 | ``` 78 | As we see, all variables that affect the function $f_{\psi}$ need to be given 79 | as the `odefun_vars` argument. The function body itself is then the `odefun_body` argument. In this function body, we can use the following variables without having to declare them or write Stan code that computes them: 80 | 81 | * The ODE state `y`, which is a vector of same length as dimension of `y0`. 82 | * Any variables that we give as `odefun_vars` for `ode_model`. 83 | * Any variables that are dimensions of `odefun_vars`. 84 | 85 | The initial state needs to be given as `odefun_init`. See the documentation of the `ode_model` function for more information. 86 | 87 | We could call `print(sho$stanmodel)` to see the entire generated Stan model code. 88 | 89 | # Sampling from prior 90 | 91 | We can sample from the prior distribution of model parameters like so. 92 | 93 | ```{r sho_prior_sample} 94 | sho_fit_prior <- sho$sample( 95 | t0 = 0.0, 96 | t = seq(0.1, 10, by = 0.1), 97 | data = list(y0 = c(1, 0), D = 2), 98 | refresh = 0, 99 | solver = rk45( 100 | abs_tol = 1e-13, 101 | rel_tol = 1e-13, 102 | max_num_steps = 1e9 103 | ) 104 | ) 105 | ``` 106 | 107 | We can view a summary of results 108 | ```{r sho_fit_print} 109 | print(sho_fit_prior) 110 | ``` 111 | 112 | We can obtain the ODE solution using each parameter draw by doing 113 | ```{r sho_fit_view_ode1} 114 | ys <- sho_fit_prior$extract_odesol_df() 115 | ``` 116 | 117 | We can plot ODE solutions like so 118 | ```{r sho_fit_view_ode2, fig.width=6.5, fig.height=3.2} 119 | sho_fit_prior$plot_odesol(alpha = 0.3) 120 | ``` 121 | 122 | We can plot the distribution of ODE solutions like so 123 | ```{r sho_fit_view_ode3, fig.width=6.5, fig.height=3.2} 124 | sho_fit_prior$plot_odesol_dist(include_y0 = TRUE) 125 | ``` 126 | 127 | We can plot ODE solution using one draw like so 128 | ```{r sho_fit_view_ode4, fig.width=6.5, fig.height=3.2} 129 | sho_fit_prior$plot_odesol(draw_inds = 45) 130 | ``` 131 | 132 | # Using different ODE solvers 133 | We generate quantities using a different `solver` and different output time points `t`. Possible solvers are `rk45()`,`bdf()`, `adams()`, `ckrk()`, `midpoint()`, and 134 | `rk4()`. Of these the first four are adaptive and built-in to Stan, where as 135 | the last two take a fixed number of steps and are written in Stan code. 136 | 137 | ```{r sho_gq_bdf, fig.width=6.5, fig.height=3.2} 138 | gq_bdf <- sho_fit_prior$gqs(solver = bdf(tol = 1e-4), t = seq(0.5, 10, by = 0.5)) 139 | ``` 140 | 141 | ```{r sho_gq_mp, fig.width=6.5, fig.height=3.2} 142 | gq_mp <- sho_fit_prior$gqs(solver = midpoint(num_steps = 4), t = seq(0.5, 10, by = 0.5)) 143 | ``` 144 | 145 | We can again plot ODE solution using one draw like so 146 | ```{r sho_view_gq, fig.width=6.5, fig.height=3.2} 147 | gq_bdf$plot_odesol(draw_inds = 45) 148 | gq_mp$plot_odesol(draw_inds = 45) 149 | ``` 150 | 151 | # Defining a likelihood 152 | 153 | Next we assume that we have some data vector `y1_obs` and define a likelihood 154 | function. 155 | ```{r sho_loglik} 156 | sho_loglik_body <- " 157 | real loglik = 0.0; 158 | for(n in 1:N) { 159 | loglik += normal_lpdf(y1_obs[n] | y_sol[n][1], sigma); 160 | } 161 | return(loglik); 162 | " 163 | ``` 164 | 165 | In this function body, we can use the following variables without 166 | having to declare them or write Stan code that computes them: 167 | 168 | * The ODE solution `y_sol`. 169 | * Any variables that we give as `loglik_vars` for `ode_model`. 170 | * Any variables that are dimensions of `loglik_vars`. 171 | 172 | Here we define as `loglik_vars` a `sigma` which is a noise magnitude parameter, and the data `y1_obs`. Notice that we can also use the `N` variable in `loglik_body`, because it is a dimension (length) of `y1_obs`. 173 | 174 | ```{r sho_loglik_vars} 175 | sigma <- stan_param(stan_var("sigma", lower = 0), prior = "normal(0, 2)") 176 | y1_obs <- stan_vector("y1_obs", length = N) 177 | ``` 178 | 179 | The following code creates and compiles the posterior Stan model. 180 | ```{r sho_create} 181 | sho_post <- ode_model(N, 182 | odefun_vars = list(k), 183 | odefun_body = sho_fun_body, 184 | odefun_init = y0, 185 | loglik_vars = list(sigma, y1_obs), 186 | loglik_body = sho_loglik_body 187 | ) 188 | print(sho_post) 189 | ``` 190 | 191 | # Sampling from posterior 192 | 193 | Now if we have some data 194 | ```{r sho_data} 195 | y1_obs <- c( 196 | 0.801, 0.391, 0.321, -0.826, -0.234, -0.663, -0.756, -0.717, 197 | -0.078, -0.083, 0.988, 0.878, 0.300, 0.307, 0.270, -0.464, -0.403, 198 | -0.295, -0.186, 0.158 199 | ) 200 | t_obs <- seq(0.5, 10, by = 0.5) 201 | ``` 202 | and assume that initial state `y0 = c(1, 0)` is known, we can fit the model 203 | ```{r sho_fit_post} 204 | sho_fit_post <- sho_post$sample( 205 | t0 = 0.0, 206 | t = t_obs, 207 | data = list(y0 = c(1, 0), D = 2, y1_obs = y1_obs), 208 | refresh = 0, 209 | solver = midpoint(2) 210 | ) 211 | ``` 212 | 213 | We fit the posterior distribution of ODE solutions against the data 214 | ```{r sho_post_plot, fig.width=6.5, fig.height=3.2} 215 | plt <- sho_fit_post$plot_odesol_dist() 216 | df_data <- data.frame(t_obs, y1_obs, ydim = rep("y1", length(t_obs))) 217 | colnames(df_data) <- c("t", "y", "ydim") 218 | df_data$ydim <- as.factor(df_data$ydim) 219 | plt <- plt + geom_point(data = df_data, aes(x = t, y = y), inherit.aes = FALSE) 220 | plt 221 | ``` 222 | 223 | # Reliability of ODE solver 224 | 225 | Finally we can study whether the solver we used during MCMC (`midpoint(2)`) was accurate enough. This is done by solving the system using increasingly more numbers of steps in 226 | the solver, and studying different metrics computed using the ODE solutions and corresponding likelihood values. 227 | ```{r sho_rel} 228 | solvers <- midpoint_list(c(4, 6, 8, 10, 12, 14, 16, 18)) 229 | rel <- sho_fit_post$reliability(solvers = solvers) 230 | print(rel$metrics) 231 | unlink("results") 232 | ``` 233 | 234 | The `mad_odesol` and `mad_loglik` are the maximum absolute difference in the ODE solutions and log likelihood, respectively, over all MCMC draws. The former is denoted *MAE* in *Timonen et. al (2023)*. Please refer to that paper in order to interpret the `pareto_k` column. Briefly we note that the Pareto-k values seem to be converging to a value smaller than 0.5, meaning that importance sampling is possible and we don't need to run MCMC again. 235 | 236 | # References 237 | 238 | * Timonen, J., Siccha, N., Bales, B., Lähdesmäki, H., & Vehtari, A. (2023). **An importance sampling approach for reliable and efficient inference in Bayesian ordinary differential equation models.** Stat, 12(1), e614. [link](https://onlinelibrary.wiley.com/doi/full/10.1002/sta4.614) 239 | 240 | --------------------------------------------------------------------------------