Using our Stan models

Using NFIDD’s Stan tools for package models and custom code

This guide covers how to use NFIDD’s Stan tools for working with both package models and custom Stan code.

Using Stan Models

Basic Package Models

Use models included in the NFIDD package:

nfidd_stan_models()
 [1] "censored-delay-model"           "coin"                          
 [3] "estimate-inf-and-r-rw-forecast" "estimate-inf-and-r-rw"         
 [5] "estimate-inf-and-r"             "estimate-infections"           
 [7] "estimate-r"                     "gamma"                         
 [9] "joint-nowcast-with-r"           "joint-nowcast"                 
[11] "lognormal"                      "mechanistic-r"                 
[13] "simple-nowcast-rw"              "simple-nowcast"                
[15] "statistical-r"                  "truncated-delay-model"         

Create a model using a package model:

model <- nfidd_cmdstan_model("simple-nowcast")

Sample with course defaults (faster):

fit <- nfidd_sample(model, data = your_data)

Custom Stan Files

Use a custom Stan file:

model <- nfidd_cmdstan_model(model_file = "path/to/your/model.stan")

You still get access to NFIDD Stan functions:

fit <- nfidd_sample(model, data = your_data)

Custom Include Paths

Set globally using R options:

options(nfidd.stan_path = "/path/to/your/stan")
model <- nfidd_cmdstan_model("simple-nowcast")

Or override per-model:

model <- nfidd_cmdstan_model(
  model_file = "custom.stan",
  include_paths = c("/custom/path1", "/custom/path2")
)

Working with Stan Functions

Discover Available Functions

Get all function names from NFIDD:

functions <- nfidd_stan_functions()
functions
[1] "combine_obs_with_predicted_obs_rng" "condition_onsets_by_report"        
[3] "convolve_with_delay"                "geometric_diff_ar"                 
[5] "geometric_random_walk"              "observe_onsets_with_delay"         
[7] "pop_bounded_renewal"                "renewal"                           

Find which files contain specific functions:

files <- nfidd_stan_function_files(functions = c("renewal"))
files
[1] "functions/renewal.stan"

Extract Functions for Local Use

Load specific functions as a string:

renewal_code <- nfidd_load_stan_functions(
  functions = c("renewal")
)

Show first few lines:

cat(substr(renewal_code, 1, 200), "...")
// Stan functions from nfidd version 1.2.0.9000
array[] real renewal(real I0, array[] real R, array[] real gen_time) {
  // length of time series
  int n = num_elements(R);
  int max_gen_time = num_el ...

Write functions to a temporary file for demonstration:

temp_file <- file.path(tempdir(), "my_functions.stan")
nfidd_load_stan_functions(
  functions = c("renewal"),
  write_to_file = TRUE,
  output_file = temp_file,
  wrap_in_block = TRUE
)
Stan functions written to: /tmp/RtmpIqySFq/my_functions.stan
[1] "functions {\n// Stan functions from nfidd version 1.2.0.9000\narray[] real renewal(real I0, array[] real R, array[] real gen_time) {\n  // length of time series\n  int n = num_elements(R);\n  int max_gen_time = num_elements(gen_time);\n  array[n + 1] real I;\n  I[1] = I0;\n  for (i in 1:n) {\n    int first_index = max(1, i - max_gen_time + 1);\n    int len = i - first_index + 1;\n    array[len] real I_segment = I[first_index:i];\n    array[len] real gen_pmf = reverse(gen_time[1:len]);\n    I[i + 1] = dot_product(I_segment, gen_pmf) * R[i];\n  }\n  return(I[2:(n + 1)]);\n}\n}"

Verify file was created:

cat("File created at:", temp_file)
File created at: /tmp/RtmpIqySFq/my_functions.stan
cat("\nFile exists:", file.exists(temp_file))

File exists: TRUE

Load All Functions

Get all NFIDD functions:

all_functions <- nfidd_load_stan_functions()

Write all functions to file:

nfidd_load_stan_functions(
  write_to_file = TRUE,
  output_file = "nfidd_functions.stan",
  wrap_in_block = TRUE
)

Writing Package Models Locally

Sometimes you want to copy a package model to modify it locally rather than modifying the package source.

Load a package model:

model <- nfidd_cmdstan_model("simple-nowcast", compile = FALSE)

Get the Stan code from the model:

stan_code <- model$code()

Write it to a local file:

writeLines(stan_code, "local-simple-nowcast.stan")

Create functions directory:

dir.create("functions", showWarnings = FALSE)

Copy all function files individually:

stan_functions_path <- file.path(nfidd_stan_path(), "functions")
function_files <- list.files(stan_functions_path, pattern = "\\.stan$", full.names = TRUE)

for (file in function_files) {
  file.copy(file, "functions/", overwrite = TRUE)
}

Set options to use local functions:

options(nfidd.stan_path = ".")

Now you can modify the local model and it will use local functions:

modified_model <- nfidd_cmdstan_model(model_file = "local-simple-nowcast.stan")

Practical Workflows

Building Custom Models with NFIDD Functions

Extract the functions you need:

nfidd_load_stan_functions(
  functions = c("renewal", "convolve_with_delay"),
  write_to_file = TRUE,
  output_file = "my_functions.stan"
)

Create your custom model file:

#include my_functions.stan

data {
  // Your data block
}

parameters {
  // Your parameters
}

model {
  // Use NFIDD functions like renewal(), delay_pmf(), etc.
}

Compile and use:

model <- nfidd_cmdstan_model(
  model_file = "my_custom_model.stan",
  include_paths = "."
)

Development Workflow

Explore existing models:

See what models are available:

nfidd_stan_models()
 [1] "censored-delay-model"           "coin"                          
 [3] "estimate-inf-and-r-rw-forecast" "estimate-inf-and-r-rw"         
 [5] "estimate-inf-and-r"             "estimate-infections"           
 [7] "estimate-r"                     "gamma"                         
 [9] "joint-nowcast-with-r"           "joint-nowcast"                 
[11] "lognormal"                      "mechanistic-r"                 
[13] "simple-nowcast-rw"              "simple-nowcast"                
[15] "statistical-r"                  "truncated-delay-model"         

Look at model locations:

nfidd_stan_path()
[1] "/home/runner/work/_temp/Library/nfidd/stan"

Understand function dependencies:

See all available functions:

nfidd_stan_functions()

Find which files contain functions you need:

nfidd_stan_function_files(functions = c("function_name"))

Build incrementally:

Start with package model:

base_model <- nfidd_cmdstan_model("simple-nowcast")

Extend with custom functions:

custom_model <- nfidd_cmdstan_model(
  model_file = "extended_model.stan"
)

File Organisation

For projects using custom Stan code:

your_project/
├── models/
│   ├── my_model.stan
│   └── functions/
│       └── my_functions.stan

In your R code:

options(nfidd.stan_path = c("models/functions", nfidd_stan_path()))
model <- nfidd_cmdstan_model(model_file = "models/my_model.stan")

This setup gives you access to both your custom functions and all NFIDD functions.