---
title: "parallelism_in_calmr"
author: "Victor Navarro"
output: rmarkdown::html_vignette
bibliography: references.bib
csl: apa.csl
vignette: >
  %\VignetteIndexEntry{parallelism_in_calmr}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  fig.width = 7,
  collapse = TRUE,
  comment = "#>",
  message = FALSE,
  warning = FALSE
)
```

## Running experiments in parallel

With the advent of time-based models, version 0.51 of `calmr` uses the `future` package to parallelize some operations.
Thanks to the design philosophy of `future`, running things in parallel will take you a single line of code.

### Why run things in parallel?

In many situations we find ourselves having to run a model over many iterations, either
because our design contains enough kinds of trials so that order effects are a worry, or 
because we want to run the same model with different parameters.

Let's run the HeiDI model [@honey_heidi_2020] over a long, random design.
Let's also enable verbosity via `calmr_verbosity()`, which uses the `progressr` package.

```{r setup}
library(calmr)
# enables progress bars (try it on your computer)
# calmr_verbosity(TRUE)
pav_inhib <- data.frame(
  group = "group",
  phase1 = "!50(US)/50AB/50#A"
)
# set options to introduce more randomness
pars <- get_parameters(pav_inhib, model = "HDI2020")
exp <- make_experiment(pav_inhib,
  parameters = pars,
  model = "HDI2020",
  iterations = 100,
  miniblocks = FALSE
)

# time it
start <- proc.time()
pav_res <- run_experiment(exp)
end <- proc.time() - start
end
```

Let's try parallelizing now.

### Running an experiment in parallel

To run the same experiment, but in parallel, you need to enable a `future` plan.
A "plan" is one of many ways the `future` package can parallelize things 
(you should really consult their documentation).
Regardless, if you are running `calmr` on a single computer, you'll be using `plan(multisession)`

```{r, include = FALSE}
# work around for macos github runners
library(future)
if (
  nchar(Sys.getenv("GITHUB_PAT")) > 0 &&
    Sys.info()["sysname"] == "Darwin") {
  future::plan(future::sequential)
} else {
  future::plan(future::multisession(workers = 2))
}
```


```{r, eval = FALSE}
library(future)
plan(multisession, workers = 2)
```

```{r}
start <- proc.time()
pav_res <- run_experiment(exp)
end <- proc.time() - start
end

# go back to non-parallel evaluations
plan(sequential)
```

In this case, the parallel evaluation was faster (see *user* time above).

The `future` package trades off ease of use for bulkier overheads, 
but as the overheads tend to be constant, 
the parallelization will have a better payoff once you run 
more and more iterations.



