| Title: | Easily Build, Simulate, and Explore Stock-and-Flow Models |
| Version: | 2.0.0 |
| Description: | Stock-and-flow models are a computational method from the field of system dynamics. They represent how systems change over time and are mathematically equivalent to ordinary differential equations. 'sdbuildR' (system dynamics builder) provides an intuitive interface for constructing stock-and-flow models without requiring extensive domain knowledge. Models can quickly be simulated and revised, supporting iterative development. 'sdbuildR' simulates models in 'R' and 'Julia', and supports computationally intensive ensemble simulations. Additionally, 'sdbuildR' can import models created in 'Insight Maker' (https://insightmaker.com/). |
| License: | GPL (≥ 3) |
| URL: | https://kcevers.github.io/sdbuildR/, https://github.com/KCEvers/sdbuildR |
| BugReports: | https://github.com/KCEvers/sdbuildR/issues |
| Depends: | R (≥ 4.2.0) |
| Imports: | cli, data.table, deSolve, DiagrammeR, igraph, jsonlite, JuliaConnectoR, plotly, rlang, stringi, stringr, textutils, withr, xml2 |
| Suggests: | DiagrammeRsvg, future, future.apply, htmlwidgets, kableExtra, knitr, qgraph, rsvg, testthat (≥ 3.0.0), this.path, webshot2 |
| Config/Needs/website: | rmarkdown, lavaan |
| Config/testthat/edition: | 3 |
| Encoding: | UTF-8 |
| RoxygenNote: | 7.3.3 |
| NeedsCompilation: | no |
| Packaged: | 2026-06-15 22:19:24 UTC; kevers1 |
| Author: | Kyra Caitlin Evers
|
| Maintainer: | Kyra Caitlin Evers <kyra.c.evers@gmail.com> |
| Repository: | CRAN |
| Date/Publication: | 2026-06-16 06:50:11 UTC |
Create data frame of simulation results
Description
Convert simulation results to a data.frame.
Usage
## S3 method for class 'simulate_stockflow'
as.data.frame(x, row.names = NULL, optional = FALSE, direction = "long", ...)
Arguments
x |
Output of |
row.names |
NULL or a character vector giving the row names for the data frame. Missing values are not allowed. |
optional |
Ignored parameter. |
direction |
Format of data frame, either "long" (default) or "wide". |
... |
Optional parameters |
Value
A data.frame with simulation results. For direction = "long" (default),
the data frame has three columns: time, variable, and value.
For direction = "wide", the data frame has columns time followed by
one column per variable.
See Also
Examples
sfm <- stockflow("SIR")
sim <- simulate(sfm)
df <- as.data.frame(sim)
head(df)
# Get results in wide format
df_wide <- as.data.frame(sim, direction = "wide")
head(df_wide)
Convert stock-and-flow model to data frame
Description
Create a data frame with properties of all model variables and functions. Specify the variable types, variable names, and/or properties to get a subset of the data frame.
Usage
## S3 method for class 'stockflow'
as.data.frame(
x,
row.names = NULL,
optional = FALSE,
name = NULL,
type = NULL,
properties = NULL,
...
)
Arguments
x |
A stock-and-flow model object of class |
row.names |
|
optional |
Ignored parameter. |
name |
Variable names to retain in the data frame. Defaults to |
type |
Variable types to retain in the data frame. Must be one or more of 'stock', 'flow', 'constant', 'aux', 'gf', or 'func'. Defaults to |
properties |
Variable properties to retain in the data frame. Defaults to |
... |
Optional arguments |
Value
A data.frame with one row per model component.
Common columns include type (component type), name (variable name),
eqn (equation), and label (descriptive label). Additional columns may include to, from,
non_negative, and others depending on variable types. The exact columns returned
depend on the type and properties arguments. Returns an empty data.frame
if no components match the filters.
Examples
as.data.frame(stockflow("SIR"))
# Only show stocks
as.data.frame(stockflow("SIR"), type = "stock")
# Only show equation and label
as.data.frame(stockflow("SIR"), properties = c("eqn", "label"))
Convert verify() results to a data frame
Description
Converts a verify_stockflow object to a data frame.
Usage
## S3 method for class 'verify_stockflow'
as.data.frame(
x,
row.names = NULL,
optional = FALSE,
which = c("tests", "sims")[1],
direction = "long",
test = NULL,
label = NULL,
ignore_case = TRUE,
status = c("pass", "fail", "error", "skip"),
condition = NULL,
...
)
Arguments
x |
A |
row.names |
|
optional |
Ignored; present for compatibility. |
which |
Character. |
direction |
Character. |
test |
Integer vector of test number(s) to display (1-based). Defaults to
|
label |
Character vector of regex patterns for partial, case-insensitive
label matching. A test is included if its label matches any pattern.
E.g., |
ignore_case |
Logical; whether |
status |
Optional character vector of statuses to include (e.g.,
|
condition |
Optional integer vector of condition numbers to filter by.
For |
... |
Additional arguments (unused). |
Details
which = "tests" (default) returns one row per unit test with columns
test, label, status, outcome, expr_str, conditions, and message.
Use test, label, and status to filter.
which = "sims" returns the underlying simulation time-series in long
format with columns test (test number(s) that used this simulation, as a
comma-separated string), conditions (specified conditions per test, if any),
time, variable, and value. Each unique condition generates one
simulation; if multiple tests share a condition their numbers are combined
in test (e.g. "1, 3"). When filtering with test, the displayed test value
shows only the requested matching test number(s) for the retained simulation
row(s). Use direction = "wide" to pivot variables into columns.
Value
A data.frame. Column set depends on which:
-
"tests":test,label,status,outcome,expr_str,condition,conditions,message. -
"sims"(long):test,condition,conditions,time,variable,value. -
"sims"(wide):test,condition,conditions,time, then one column per variable.
Examples
# Create model with 2 unit tests
sfm <- stockflow("SIR") |>
unit_test(expr = all(susceptible >= 0)) |>
# Add test with conditions
unit_test(
label = "lower infection rate",
expr = all(susceptible >= 0),
conditions = list(infection_rate = 0.1)
)
res <- verify(sfm)
# Test results (default)
as.data.frame(res)
# Simulation time-series (long format)
as.data.frame(res, which = "sims") |> head()
# Simulation time-series (wide format)
as.data.frame(res, which = "sims", direction = "wide") |> head()
# Filter to simulation for test 2 only
as.data.frame(res, which = "sims", test = 2) |> head()
# Only simulations for passing tests
as.data.frame(res, which = "sims", status = "pass") |> head()
Add or modify auxiliaries
Description
Auxiliaries are dynamic variables used for intermediate calculations in the
system. auxiliary() adds or changes an auxiliary variable. This is a convenience
wrapper around update() with type = "aux". See the Auxiliaries section
of update() for more details.
Usage
auxiliary(object, name, eqn = 0, label = name, doc = "", non_negative = FALSE)
aux(object, name, eqn = 0, label = name, doc = "", non_negative = FALSE)
Arguments
object |
Stock-and-flow model, object of class |
name |
Variable name. Accepts a bare symbol (e.g., |
eqn |
Equation (or initial value in the case of stocks). Accepts a bare expression (e.g., |
label |
Name of variable used for plotting. Defaults to the same as name. |
doc |
Description of variable. Defaults to |
non_negative |
If TRUE, variable is enforced to be non-negative (i.e., strictly 0 or positive). Defaults to |
Value
A stock-and-flow model object of class stockflow
See Also
update(), discard(), change_name()
Examples
# Create an auxiliary for an intermediate calculation
sfm <- stockflow() |>
stock(population, eqn = 100) |>
constant(carrying_capacity, eqn = 1000) |>
auxiliary(density, eqn = population / carrying_capacity, label = "Density")
Change name of variable
Description
Change the name of a variable throughout the model. This updates the data frame and all references in equations, flow connections, and labels.
Usage
change_name(object, name, new_name)
Arguments
object |
Stock-and-flow model, object of class |
name |
Variable name. Accepts a bare symbol (e.g., |
new_name |
New name. Character vector of the same length as |
Value
A stock-and-flow model object of class stockflow with the name changed throughout the model.
See Also
Examples
sfm <- stockflow("SIR")
sfm <- change_name(sfm, c(susceptible, infected, recovered),
new_name = c(S, I, R)
)
print(sfm)
# References to old names are updated
as.data.frame(sfm, type = "flow", properties = c("name", "eqn", "to", "from"))
Change variable type
Description
Change the type of a variable in a stock-and-flow model.
Usage
change_type(object, name, new_type)
Arguments
object |
Stock-and-flow model, object of class |
name |
Variable name. Accepts a bare symbol (e.g., |
new_type |
New variable type; one of |
Value
A stock-and-flow model object of class stockflow with the variable type changed throughout the model. Note that changing the type may result in changes to other properties (e.g., a flow must have "to" and/or "from" properties, so these will be added if not already present), and may require changes to the equations of connected variables.
See Also
Examples
# Start with a simple predator-prey model
sfm <- stockflow("predator_prey")
# Change the birth rate of predators from a constant to an auxiliary
sfm <- change_type(sfm, delta, new_type = "aux")
# This allows us to introduce time-dependence in the birth rate
# (e.g., seasonality with a sine function)
sfm <- sfm |>
update(delta, eqn = 0.025 + 0.01 * sin(2 * pi * t / 12))
sim <- simulate(sfm)
plot(sim)
Clean variable name(s)
Description
Clean variable name(s) to create syntactically valid, unique names for use in R and Julia.
Usage
clean_name(new, protected = NULL)
Arguments
new |
Vector of names to transform to valid names |
protected |
Optional vector of protected names, e.g., existing names in model |
Value
Vector of cleaned names
Examples
sfm <- stockflow("predator_prey")
# As the variable name "predator" is already taken, clean_name() will create
# a unique name
clean_name("predator", as.data.frame(sfm)[["name"]])
Compare two stock-and-flow models
Description
Compares the structure, equations, and simulation settings of two
stockflow models, and computes a nonlinearity score for each.
Usage
compare_models(sfm1, sfm2)
Arguments
sfm1 |
A stock-and-flow model of class |
sfm2 |
A stock-and-flow model of class |
Value
An object of class compare_stockflow (a list) containing:
labelsNames of the two model objects (captured expressions).
addedVariables present in
sfm2but notsfm1.removedVariables present in
sfm1but notsfm2.type_changedVariables with different types.
eqn_changedVariables with different equations.
sim_settings_diffSimulation settings that differ.
propertiesPer-model counts and nonlinearity scores.
See Also
Examples
sfm1 <- stockflow("SIR")
sfm2 <- stock(sfm1, "susceptible", eqn = 0.5)
compare_models(sfm1, sfm2)
Add or modify constants
Description
Constants are time-independent variables that do not change over the course
of a simulation. constant() adds or changes a constant variable. This is a
convenience wrapper around update() with type = "constant". See the
Constants section of update() for more details.
Usage
constant(object, name, eqn = 0, label = name, doc = "", non_negative = FALSE)
Arguments
object |
Stock-and-flow model, object of class |
name |
Variable name. Accepts a bare symbol (e.g., |
eqn |
Equation (or initial value in the case of stocks). Accepts a bare expression (e.g., |
label |
Name of variable used for plotting. Defaults to the same as name. |
doc |
Description of variable. Defaults to |
non_negative |
If TRUE, variable is enforced to be non-negative (i.e., strictly 0 or positive). Defaults to |
Value
A stock-and-flow model object of class stockflow
See Also
update(), discard(), change_name()
Examples
# Create constants for model parameters
sfm <- stockflow() |>
constant(growth_rate, eqn = 0.1, label = "Growth Rate") |>
constant(carrying_capacity, eqn = 1000, label = "Carrying Capacity")
Check whether value is in vector or string
Description
Equivalent of .Contains() in Insight Maker.
Usage
contains_IM(haystack, needle)
Arguments
haystack |
Vector or string to search through |
needle |
Value to search for |
Value
Logical value
Examples
contains_IM(c("a", "b", "c"), "d") # FALSE
contains_IM(c("abcdef"), "bc") # TRUE
Create or modify custom variables or functions
Description
Custom functions are user-defined functions that can be used
throughout a stock-and-flow model. custom_func() adds or changes a function. This is a convenience wrapper around update() with
type = "func".
Usage
custom_func(object, name, eqn = 0, label = name, doc = "")
Arguments
object |
Stock-and-flow model, object of class |
name |
Name of the function variable. The equation will be assigned to this name. |
eqn |
Equation of the function variable. A character vector. Defaults to |
label |
Name of variable used for plotting. Defaults to the same as name. |
doc |
Documentation. Defaults to "". |
Value
A stock-and-flow model object of class stockflow
See Also
update(), discard(), change_name()
Examples
# Simple function
sfm <- stockflow() |>
custom_func(double, eqn = "function(x) x * 2") |>
constant(a, eqn = double(2))
# Function with defaults
sfm <- stockflow() |>
custom_func(scale, eqn = "function(x, factor = 10) x * factor") |>
constant(b, eqn = scale(2))
# If the logistic() function did not exist, you could create it yourself:
sfm <- stockflow() |>
custom_func(my_logistic, eqn = "function(x, slope = 1, midpoint = .5){
1 / (1 + exp(-slope*(x-midpoint)))
}") |>
constant(c_, eqn = my_logistic(2, slope = 50))
Find dependencies
Description
Find which other variables each variable is dependent on.
Usage
dependencies(object, name = NULL, type = NULL, reverse = FALSE)
Arguments
object |
Stock-and-flow model, object of class |
name |
Variable names to find dependencies for. Defaults to |
type |
Variable types to find dependencies for. Must be one or more of 'stock', 'flow', 'constant', 'aux', 'gf', or 'func'. Defaults to |
reverse |
If FALSE, list for each variable X which variables Y it depends on for its equation definition. If TRUE, don't show dependencies but dependents. This reverses the dependencies, such that for each variable X, it lists what other variables Y depend on X. |
Value
List, with for each model variable what other variables it depends on, or if reverse = TRUE, which variables depend on it
Examples
sfm <- stockflow("SIR")
dependencies(sfm)
Remove variable(s)
Description
Remove variable(s) from a stock-and-flow model. All references in flow connections and graphical function sources are also removed. A warning will be thrown if any lingering references to the removed name remain in the model.
Usage
discard(
object,
name,
remove_references = c("to", "from", "source", "unit_test")
)
Arguments
object |
Stock-and-flow model, object of class |
name |
Name(s) to remove. Accepts bare symbols (e.g., |
remove_references |
Where to remove references to the discarded variables. By default, references to discarded variables in |
Value
A stock-and-flow model object of class stockflow
See Also
Examples
# Add stock
sfm <- stockflow() |> stock(x)
print(sfm)
# Remove stock
sfm <- discard(sfm, x)
print(sfm)
Remove a unit test from a stock-and-flow model
Description
Remove one or more unit tests by test (integer position as shown by
unit_tests()) or by label (character). Warns if a label or index is
not found. Remaining tests are renumbered sequentially after removal.
Usage
discard_unit_test(object, label, test)
Arguments
object |
Stock-and-flow model, object of class |
label |
Character label(s) of the test(s) to remove. Supports NSE
(bare symbol or string). For backward compatibility, integer values
passed via |
test |
Integer index/indices of the test(s) to remove. Corresponds to
the order shown by |
Value
The model object with the specified test(s) removed.
See Also
Examples
sfm <- stockflow("SIR") |>
unit_test(label = "susceptible is non-negative", expr = all(susceptible >= 0)) |>
unit_test(label = "recovered increases", expr = all(diff(recovered) >= 0))
# Remove by test
sfm <- discard_unit_test(sfm, test = 1)
# Remove by label
sfm <- discard_unit_test(sfm, label = "recovered increases")
Run ensemble simulations
Description
Run large-scale (i.e., ensemble) simulations of stock-and-flow models, varying initial
conditions and/or constants specified in conditions.
Usage
ensemble(
object,
n = 10,
conditions = NULL,
cross = TRUE,
quantiles = c(0.025, 0.975),
verbose = TRUE,
...
)
Arguments
object |
Stock-and-flow model, object of class |
n |
Number of simulations to run in the ensemble. When conditions is
specified, n defines the number of simulations to run per condition. If
each condition only needs to be run once, set |
conditions |
A named list specifying fixed values for ensemble conditions. Names must correspond to stocks or constants in the model. Each list element should be a numeric vector of values to test. If cross = If cross = |
cross |
If |
quantiles |
Quantiles to calculate in the summary, e.g., |
verbose |
If |
... |
Optional arguments passed to |
Details
It is strongly recommended to reduce the size of the simulation output by
saving fewer values with save_at or save_n in sim_settings().
By default, only summary statistics across simulations are returned.
To return individual simulations, set save_sims = TRUE in sim_settings() or
pass save_sims = TRUE via ... in ensemble().
Note that returning individual simulations can consume a lot of memory for large ensembles.
For simulations in Julia, the ensemble can be run in parallel using multiple threads
by setting nthreads in use_julia(). For simulations in R, use
future::plan() to control parallel execution.
To create a reproducible ensemble simulation, set a seed using sim_settings().
If you do not see any variation within a condition of the ensemble (i.e., the confidence bands are virtually non-existent), there are likely no random elements in your model. Without these, there can be no variability in the model. Try specifying a random initial condition or adding randomness to other model elements (see examples).
Value
Object of class ensemble_stockflow, which is a list
containing:
- success
If
TRUE, simulation was successful. IfFALSE, simulation failed.- error_message
If success is
FALSE, contains the error message.- df
data.frame with simulation results in long format, if save_sims is
TRUE. The iteration number is indicated by column "sim". If conditions was specified, the condition is indicated by column "condition".- summary
data.frame with summary statistics of the ensemble, including quantiles specified in quantiles. If conditions was specified, summary statistics are calculated for each condition in the ensemble.
- n
Number of simulations run in the ensemble (per condition if conditions is specified).
- n_total
Total number of simulations run in the ensemble (across all conditions if conditions is specified).
- n_conditions
Total number of conditions.
- conditions
data.frame with the conditions used in the ensemble, if conditions was specified.
- init
List with df (if save_sims = TRUE) and summary, containing data.frame with the initial values of the stocks used in the ensemble.
- constants
List with df (if save_sims = TRUE) and summary, containing data.frame with the constant parameters used in the ensemble.
- script
Script used for the ensemble simulation.
- duration
Duration of the simulation in seconds.
- ...
Other parameters passed to ensemble
See Also
update(), stockflow(), sim_settings(), use_julia(),
future::plan()
Examples
# Ensemble simulation in R (no parallelization)
# Load example
sfm <- stockflow("predator_prey")
# Set random initial conditions
sfm <- update(sfm, c(predator, prey),
eqn = runif(1, min = 20, max = 80)
)
# For ensemble simulations, it is highly recommended to reduce the
# returned output. For example, to save only 20 values per simulation:
sfm <- sim_settings(sfm, save_n = 20)
# Run ensemble simulation with a small number of simulations
sims <- ensemble(sfm, n = 3)
if (interactive()) plot(sims)
# To plot individual trajectories, rerun the ensemble with save_sims = TRUE.
# Note that this can consume a lot of memory for large simulations.
sims <- ensemble(sfm, n = 10, save_sims = TRUE)
plot(sims, which = "sims")
# Specify which trajectories to plot
plot(sims, which = "sims", sim = 1)
# Plot the median with lighter individual trajectories
plot(sims, central_tendency = "median", which = "sims", alpha = 0.1)
# For larger ensembles, we can use parallelization with future
if (requireNamespace("future", quietly = TRUE) &&
requireNamespace("future.apply", quietly = TRUE)) {
future::plan(future::multisession, workers = 4)
}
# Ensembles can also be run with exact values for the initial conditions
# and parameters. Below, we vary the initial values of the predator and the
# birth rate of the predators (delta). We generate a hundred samples per
# condition. By default, the parameters are crossed, meaning that all
# combinations of the parameters are run.
sims <- ensemble(sfm,
n = 50,
conditions = list(predator = c(10, 50), delta = c(.025, .05))
)
plot(sims)
# By default, a maximum of nine conditions is plotted.
# Plot specific conditions:
plot(sims, condition = c(1, 3), nrows = 1)
# Generate a non-crossed design, where the length of each conditions vector
# needs to be equal:
sims <- ensemble(sfm,
n = 10, cross = FALSE,
conditions = list(
predator = c(10, 20, 30),
delta = c(.020, .025, .03)
)
)
plot(sims, nrows = 3)
# Stop parallelization after use
if (requireNamespace("future", quietly = TRUE) &&
requireNamespace("future.apply", quietly = TRUE)) {
future::plan(future::sequential)
}
Expit function
Description
Inverse of the logit function
Usage
expit(x)
Arguments
x |
Numerical value |
Value
Numerical value
Examples
expit(1)
Export a stock-and-flow model
Description
Export a model of class stockflow to another format.
Usage
export_model(
object,
format = c("sdbuildR", "deSolve", "psychomodels"),
file = NULL,
title = object[["meta"]][["name"]],
description = object[["meta"]][["caption"]],
explanation = description,
publication_doi = "",
publication_citation = "",
framework = "Ordinary Differential Equations",
programming_language = "R",
psychology_discipline = "",
software_package = "",
model_variable = "",
code_repository_url = "",
data_url = "",
submission_remarks = "",
created_by = "",
updated_by = "",
published_by = "",
published_at = Sys.time(),
published_pending_moderation_at = Sys.time(),
publication_citation_fetched_at = Sys.time(),
publication_csl_fetched_at = Sys.time(),
publication_csl_json = "",
id = NA,
slug = NULL,
include_latex = TRUE,
pretty = TRUE
)
Arguments
object |
Stock-and-flow model, object of class |
format |
Export format. One of |
file |
Output file path, or |
title |
[psychomodels] Model title. Defaults to |
description |
[psychomodels] Model description.
Defaults to |
explanation |
[psychomodels] Free-text explanation. Defaults to |
publication_doi |
[psychomodels] DOI for the associated publication. |
publication_citation |
[psychomodels] Citation text. |
framework |
[psychomodels] Modeling framework.
Defaults to |
programming_language |
[psychomodels] Programming language. |
psychology_discipline |
[psychomodels] Discipline id(s), comma-separated. |
software_package |
[psychomodels] Package id(s), comma-separated. |
model_variable |
[psychomodels] Variable id(s), comma-separated. |
code_repository_url |
[psychomodels] URL to code repository. |
data_url |
[psychomodels] URL to model data. |
submission_remarks |
[psychomodels] Optional remarks. |
created_by |
[psychomodels] Identifier of creating user. |
updated_by |
[psychomodels] Identifier of last updating user. |
published_by |
[psychomodels] Identifier of publishing user. |
published_at |
[psychomodels] Publication timestamp. Defaults to current time. |
published_pending_moderation_at |
[psychomodels] Moderation timestamp. |
publication_citation_fetched_at |
[psychomodels] Citation fetch timestamp. |
publication_csl_fetched_at |
[psychomodels] CSL fetch timestamp. |
publication_csl_json |
[psychomodels] CSL JSON text. |
id |
[psychomodels] Optional record id. |
slug |
[psychomodels] Optional slug. Generated from |
include_latex |
[psychomodels] If |
pretty |
[psychomodels] If |
Details
sdbuildR format (format = "sdbuildR")
Returns R code that reconstructs the model using sdbuildR functions.
When file = NULL, returns a character string.
When file is provided, writes an .R file and returns the path invisibly.
If file has no .R extension, one is appended.
deSolve format (format = "deSolve")
Returns a standalone R script using deSolve::ode() directly — no sdbuildR
dependency required to run the output.
When file = NULL, returns a character string.
When file is provided, writes an .R file and returns the path invisibly.
If file has no .R extension, one is appended.
Requires sim_settings(language = "R") (the default).
Psychomodels format (format = "psychomodels")
Generates a JSON record for upload to
Psychomodels.
When file = NULL, returns a JSON character string.
When file is provided, writes a .json file and returns the path invisibly.
If file has no .json extension, one is appended.
Value
For file = NULL: a character string containing the exported content.
For file specified: invisibly returns the file path.
See Also
import_insightmaker(), import_desolve()
Examples
sfm <- stockflow("SIR")
# Get sdbuildR reconstruction code
cat(export_model(sfm, format = "sdbuildR"))
# Get standalone deSolve script
cat(export_model(sfm, format = "deSolve"))
# Export to Psychomodels JSON
## Not run:
json <- export_model(sfm,
format = "psychomodels",
publication_doi = "10.0000/example"
)
## End(Not run)
Save plot to a file
Description
Save a plot of a stock-and-flow diagram or a simulation to a specified file path. Note that saving plots requires additional packages to be installed (see below).
Usage
export_plot(
pl,
file,
width = 3,
height = 4,
units = "cm",
dpi = 300,
font_family = ""
)
Arguments
pl |
Plot object. Can be a |
file |
File path to save plot to, including a file extension. For plotting a stock-and-flow model, the file extension can be one of png, pdf, svg, ps, eps, webp. For plotting a simulation, the file extension can be one of png, pdf, jpg, jpeg, webp. For plotting a qgraph graph, the file extension can be one of png, pdf, svg, ps, eps, jpg, jpeg, tiff, bmp. If no file extension is specified, it will default to png. |
width |
Width of image in units. |
height |
Height of image in units. |
units |
Units in which width and height are specified. Either "cm", "in", or "px". |
dpi |
Resolution of image. Only used if units is not "px". |
font_family |
Font family used for qgraph exports. For PDF/PS/EPS exports, this is applied when the graphics device is opened. |
Value
Returns NULL invisibly, called for side effects.
Examples
# Only if dependencies are installed
if (requireNamespace("DiagrammeRsvg", quietly = TRUE) &&
requireNamespace("rsvg", quietly = TRUE)) {
sfm <- stockflow("SIR")
file <- tempfile(fileext = ".png")
export_plot(plot(sfm), file)
# Remove plot
file.remove(file)
}
## Not run:
# requires internet
# Only if suggested dependencies are installed
if (requireNamespace("htmlwidgets", quietly = TRUE) &&
requireNamespace("webshot2", quietly = TRUE)) {
# Requires Chrome to save plotly plot:
sim <- simulate(sfm)
export_plot(plot(sim), file)
# Remove plot
file.remove(file)
}
## End(Not run)
Find a named argument in a list of call arguments
Description
Searches by name; also handles positional fallback for the second argument
when the name is absent (e.g., expect_equal(x, y, tolerance = 0.01)).
Usage
find_named_arg(args, name)
Arguments
args |
List of call arguments (from |
name |
Character name of the argument to find |
Value
The argument value, or NULL if not found
Add or modify flows
Description
Flows move material and information through the system, increasing or
decreasing stocks. flow() adds or changes a flow variable. This is a
convenience wrapper around update() with type = "flow". See the
Flows section of update() for more details.
Usage
flow(
object,
name,
eqn = 0,
to = NULL,
from = NULL,
label = name,
doc = "",
non_negative = FALSE
)
Arguments
object |
Stock-and-flow model, object of class |
name |
Variable name. Accepts a bare symbol (e.g., |
eqn |
Equation (or initial value in the case of stocks). Accepts a bare expression (e.g., |
to |
Target of flow. Accepts a bare symbol or string. Must be a stock in the model. Defaults to |
from |
Source of flow. Accepts a bare symbol or string. Must be a stock in the model. Defaults to |
label |
Name of variable used for plotting. Defaults to the same as name. |
doc |
Description of variable. Defaults to |
non_negative |
If TRUE, variable is enforced to be non-negative (i.e., strictly 0 or positive). Defaults to |
Value
A stock-and-flow model object of class stockflow
See Also
update(), discard(), change_name()
Examples
# Create a flow into a stock
sfm <- stockflow() |>
stock(population, eqn = 100) |>
flow(births, eqn = population * 0.1, to = population) |>
flow(deaths, eqn = population * 0.05, from = population)
Check if user has internet
Description
Internal function
Usage
has_internet()
Value
Logical value
Examples
has_internet()
Print first rows of a simulation
Description
Print the first rows of a simulation data frame of a stock-and-flow model. This is a wrapper around head() that first converts the simulation results to a data frame using as.data.frame().
Usage
## S3 method for class 'simulate_stockflow'
head(x, n = 6L, ...)
Arguments
x |
Output of |
n |
Number of rows to print. Defaults to 6. |
... |
Other arguments passed to |
Value
A data.frame with the first rows of the simulation results.
Examples
sfm <- stockflow("SIR")
sim <- simulate(sfm)
head(sim)
Print first rows of verify results
Description
Wrapper around head() that first converts the results to a data frame using
as.data.frame.verify_stockflow().
Usage
## S3 method for class 'verify_stockflow'
head(x, n = 6L, ...)
Arguments
x |
A |
n |
Number of rows. Defaults to 6. |
... |
Other arguments passed to |
Value
A data.frame.
Examples
sfm <- stockflow("SIR") |>
unit_test(expr = all(susceptible >= 0))
res <- verify(sfm)
head(res)
Hill function
Description
Computes the Hill function with configurable slope, midpoint, and upper asymptote.
Usage
hill(x, slope = 1, midpoint = 0.5, upper = 1)
Arguments
x |
Value at which to evaluate the function |
slope |
Slope of Hill function at the midpoint. Defaults to 1. |
midpoint |
Midpoint of Hill function where the output is |
upper |
Upper asymptote (maximal value) of the Hill function. Defaults to 1. |
Details
The Hill function is a smooth S-shaped curve (when slope > 1) bounded between 0 and upper.
It transitions from near 0 to near upper around the midpoint, with the steepness
of this transition controlled by slope. See https://en.wikipedia.org/wiki/Hill_equation_%28biochemistry%29 for more details.
Value
Numeric value given by
f(x) = \frac{upper \cdot x^{slope}}{midpoint^{slope} + x^{slope}}
Examples
hill(0)
# Adjust parameters
hill(0, slope = 5, midpoint = 0.5, upper = 10)
Import a deSolve model
Description
Convert a model written for deSolve
into a stock-and-flow model of class stockflow.
Usage
import_desolve(model, params, init, times, method = "lsoda", name = NULL)
Arguments
model |
A deSolve-style ODE function with arguments |
params |
Named numeric vector of model parameters (constants). |
init |
Named numeric vector of initial state values (stocks). |
times |
Numeric vector of time points. Must be evenly spaced
(e.g., from |
method |
Integration method. Defaults to |
name |
Optional model name. Character scalar. |
Details
The model function must follow the canonical deSolve convention:
model <- function(t, state, parameters) {
with(as.list(c(state, parameters)), {
dX <- <rate expression> # d<VarName> for each state in init
list(c(dX))
})
}
State variable names are taken from names(init), parameter names from
names(params). Each d<VarName> assignment inside the with() block is
parsed as the net rate of change for stock VarName and becomes a flow in
the sfm. Any other assignments in the with() block (intermediate
calculations) are imported as auxiliary variables in the order they appear.
Value
A stock-and-flow model of class stockflow.
See Also
import_insightmaker(), export_model(), update()
Examples
logistic_model <- function(t, state, parameters) {
with(as.list(c(state, parameters)), {
dN <- r * N * (1 - N / K)
list(c(dN))
})
}
sfm <- import_desolve(
model = logistic_model,
params = c(r = 0.3, K = 100),
init = c(N = 10),
times = seq(0, 50, by = 0.1),
method = "lsoda",
name = "Logistic growth"
)
sim <- simulate(sfm)
plot(sim)
Import Insight Maker model
Description
Import a stock-and-flow model from Insight Maker. Models may be your own or another user's. Importing causal loop diagrams or agent-based models is not supported.
Usage
import_insightmaker(
url,
file,
keep_nonnegative_flow = TRUE,
keep_nonnegative_stock = FALSE
)
Arguments
url |
URL to Insight Maker model. Character. |
file |
File path to Insight Maker model. Only used if url is not specified. Needs to be a character with suffix .InsightMaker or .json. |
keep_nonnegative_flow |
If TRUE, keeps original non-negativity setting of flows. Defaults to TRUE. |
keep_nonnegative_stock |
If TRUE, keeps original non-negativity setting of stocks. Defaults to FALSE. |
Details
Insight Maker models can be imported using a URL, Insight Maker file, or ModelJSON file. Ensure the URL refers to a public (not private) model. To download a model file from Insight Maker, first clone the model if it is not your own. Then, go to "Share" (top right), "Export", and "Download Insight Maker file" or "ModelJSON File".
Value
A stock-and-flow model object of class stockflow.
See Also
Examples
# Load a model from Insight Maker
sfm <- import_insightmaker(
url =
"https://insightmaker.com/insight/43tz1nvUgbIiIOGSGtzIzj/Romeo-Juliet"
)
plot(sfm)
# Simulate the model
sim <- simulate(sfm)
plot(sim)
Find index of value in vector or string
Description
Equivalent of .IndexOf() in Insight Maker.
Usage
indexof(haystack, needle)
Arguments
haystack |
Vector or string to search through |
needle |
Value to search for |
Value
Index, integer
Examples
indexof(c("a", "b", "c"), "b") # 2
indexof("haystack", "hay") # 1
indexof("haystack", "m") # 0
Convert .InsightMaker file to .json file
Description
Import and convert a stock-and-flow model from Insight Maker to a .json file. Models may be your own or another user's. Importing causal loop diagrams or agent-based models is not supported.
Usage
insightmaker_to_json(url, file, destfile = NULL)
Arguments
url |
URL to Insight Maker model. Character. |
file |
File path to Insight Maker model. Only used if url is not specified. Needs to be a character with suffix .InsightMaker. |
destfile |
Output file path. Must have extension .json or no extension. Overwrites file if it already exists. If not provided, return model in json format. |
Details
Insight Maker models can be imported using a URL or Insight Maker file. Ensure the URL refers to a public (not private) model. To download a model file from Insight Maker, first clone the model if it is not your own. Then, go to "Share" (top right), "Export", and "Download Insight Maker file".
Value
If destfile is not provided; object of class "json". If destfile provided, invisibly returns destfile (character string).
Examples
# Convert a model from Insight Maker to json
destfile <- tempfile(fileext = ".json")
json <- insightmaker_to_json(
url =
"https://insightmaker.com/insight/43tz1nvUgbIiIOGSGtzIzj/Romeo-Juliet",
destfile = destfile
)
file.remove(destfile)
Install, update, or remove Julia environment
Description
Instantiate the Julia environment for sdbuildR to run stock-and-flow models using Julia. For more guidance, see this vignette.
Usage
install_julia_env(remove = FALSE)
Arguments
remove |
If |
Details
install_julia_env() will:
Start a Julia session
Activate a Julia environment using sdbuildR's Project.toml
Install SystemDynamicsBuildR.jl from GitHub (https://github.com/kcevers/SystemDynamicsBuildR.jl)
Install all other required Julia packages
Create Manifest.toml
Precompile packages for faster subsequent loading
Stop the Julia session
Note that this may take 10-25 minutes the first time as Julia downloads and compiles packages.
Value
Invisibly returns NULL after instantiating the Julia environment.
See Also
Examples
## Not run:
install_julia_env()
# Remove Julia environment
install_julia_env(remove = TRUE)
## End(Not run)
Recursively interpret a parsed R expression
Description
Recursively interpret a parsed R expression
Usage
interpret(e, parent_op = NULL)
Arguments
e |
A language object (from parse()) |
parent_op |
The operator of the parent call (used for precedence decisions) |
Value
A human-readable string
Length of vector or string
Description
Equivalent of .Length() in Insight Maker, which returns the number of elements when performed on a vector, but returns the number of characters when performed on a string
Usage
length_IM(x)
Arguments
x |
A vector or a string |
Value
The number of elements in x if x is a vector; the number of characters in x if x is a string
Examples
length_IM(c("a", "b", "c")) # 3
length_IM("abcdef") # 6
Logistic function
Description
Computes the logistic (i.e., sigmoid) function with configurable slope, midpoint, and upper asymptote.
Usage
logistic(x, slope = 1, midpoint = 0, upper = 1)
sigmoid(x, slope = 1, midpoint = 0, upper = 1)
Arguments
x |
Value at which to evaluate the function |
slope |
Slope of logistic function at the midpoint. Defaults to 1. |
midpoint |
Midpoint of logistic function where the output is |
upper |
Upper asymptote (maximal value) of the logistic function. Defaults to 1. |
Details
The logistic function is a smooth S-shaped curve bounded between 0 and upper.
It transitions from near 0 to near upper around the midpoint, with the steepness
of this transition controlled by slope.
Value
Numeric value given by
f(x) = \frac{upper}{1 + e^{-slope \cdot (x - midpoint)}}
Examples
logistic(0)
# equivalent:
sigmoid(0)
# Adjust parameters
logistic(0, slope = 5, midpoint = 0.5, upper = 10)
# Visualize different slopes
x <- seq(-5, 5, length.out = 1000)
plot(x, logistic(x, slope = 1), type = "l", ylab = "f(x)", ylim = c(0, 1))
lines(x, logistic(x, slope = 5), col = "blue")
lines(x, logistic(x, slope = 50), col = "red")
legend("topleft",
legend = c("slope = 1", "slope = 5", "slope = 50"),
col = c("black", "blue", "red"), lty = 1
)
Logit function
Description
Logit function
Usage
logit(p)
Arguments
p |
Probability, numerical value between 0 and 1 |
Value
Numerical value
Examples
logit(.1)
Add or modify lookup variables (graphical functions)
Description
Lookup variables define piecewise relationships using specified (x, y) points. lookup() adds or changes a lookup variable. This is a convenience wrapper around update() with type = "lookup". See the Lookup Variables section of update() for more details.
Usage
lookup(
object,
name,
xpts,
ypts,
source = NULL,
interpolation = "linear",
extrapolation = "nearest",
label = name,
doc = "",
non_negative = FALSE
)
Arguments
object |
Stock-and-flow model, object of class |
name |
Variable name. Accepts a bare symbol (e.g., |
xpts |
Only for graphical functions: vector of x-domain points. Must be of the same length as ypts. |
ypts |
Only for graphical functions: vector of y-domain points. Must be of the same length as xpts. |
source |
Only for graphical functions: name of the variable which will serve as the input to the graphical function. Accepts a bare symbol or string. Defaults to |
interpolation |
Only for graphical functions: interpolation method. Must be either "constant" or "linear". Defaults to "linear". |
extrapolation |
Only for graphical functions: extrapolation method. Must be either |
label |
Name of variable used for plotting. Defaults to the same as name. |
doc |
Description of variable. Defaults to |
non_negative |
If TRUE, variable is enforced to be non-negative (i.e., strictly 0 or positive). Defaults to |
Value
A stock-and-flow model object of class stockflow
See Also
update(), discard(), change_name()
Examples
# Create a lookup variable for a non-linear relationship
sfm <- stockflow() |>
lookup(output,
source = t,
xpts = c(0, 5, 10),
ypts = c(0, 10, 15),
interpolation = "linear"
) |>
stock(x) |>
flow(x_in, eqn = output(t), to = x)
sim <- simulate(sfm)
plot(sim)
Conditionally wrap a result string in parentheses
Description
Used by infix operators to add parens when the current operator has lower precedence than the parent context.
Usage
maybe_wrap(result, current_op, parent_op)
Arguments
result |
The human-readable string for this sub-expression |
current_op |
The current operator |
parent_op |
The parent operator (from the recursive call) |
Value
Possibly parenthesized string
Modify meta of stock-and-flow model
Description
The meta of a stock-and-flow model contains metadata about the model, such as the name, author, and version. Modify the meta of an existing model with standard or custom properties.
Usage
meta(
object,
name = "My Model",
caption = "My Model Description",
created = Sys.time(),
author = "Me",
version = "1.0",
URL = "",
doi = "",
...
)
Arguments
object |
Stock-and-flow model, object of class |
name |
Model name. Defaults to "My Model". |
caption |
Model description. Defaults to "My Model Description". |
created |
Date the model was created. Defaults to Sys.time(). |
author |
Creator of the model. Defaults to "Me". |
version |
Model version. Defaults to "1.0". |
URL |
URL associated with model. Defaults to "". |
doi |
DOI associated with the model. Defaults to "". |
... |
Optional other entries to add to the meta. |
Value
A stock-and-flow model object of class stockflow
Examples
sfm <- stockflow() |>
meta(
name = "My first model",
caption = "This is my first model",
author = "Kyra Evers",
version = "1.1"
)
Determine whether parentheses are needed to preserve meaning
Description
Parentheses are needed when the inner operator has lower precedence than the parent, because without them the human reader might misinterpret the grouping.
Usage
needs_parens(inner_op, outer_op)
Arguments
inner_op |
The operator inside the parentheses (or NULL) |
outer_op |
The operator outside (parent context, or NULL) |
Value
logical
Check whether x is less than zero
Description
Check whether x is less than zero.
Usage
nonnegative(x)
Arguments
x |
Value |
Value
x if x is greater than 0, 0 otherwise
Examples
nonnegative(NA)
nonnegative(-1)
Get the precedence level of an operator
Description
Higher number = binds tighter. Based on R's actual operator precedence.
Usage
op_precedence(op)
Plot timeseries of ensemble simulation
Description
Visualize ensemble simulation results of a stock-and-flow model. Either summary statistics or individual trajectories can be plotted. When multiple conditions j are specified, a grid of subplots is plotted. See ensemble() for examples.
Usage
## S3 method for class 'ensemble_stockflow'
plot(
x,
which = c("summary", "sims")[1],
sim = seq(1, min(c(x[["n"]], 10))),
condition = seq(1, min(c(x[["n_conditions"]], 9))),
vars = NULL,
show_constants = FALSE,
nrows = ceiling(sqrt(max(condition))),
margin = 0.05,
shareX = TRUE,
shareY = TRUE,
palette = "Dark 2",
alpha = 0.3,
colors = NULL,
font_family = "Times New Roman",
font_size = 16,
wrap_width = 25,
showlegend = TRUE,
label_subplots = TRUE,
central_tendency = c("mean", "median", FALSE)[1],
central_tendency_width = 3,
...
)
Arguments
x |
Output of |
which |
Type of plot. Either |
sim |
Indices of the individual trajectories to plot if which = |
condition |
Indices of the condition to plot. Defaults to 1:9. If only one condition is specified, the plot will not be a grid of subplots. |
vars |
Variables to plot. Defaults to NULL to plot all variables. |
show_constants |
If TRUE, include constants in plot. Defaults to FALSE. |
nrows |
Number of rows in the plot grid. Defaults to ceiling(sqrt(n_conditions)). |
margin |
Margin between subplots. Either a single numeric or a vector of length four(left, right, top, bottom). See |
shareX |
If |
shareY |
If |
palette |
Colour palette. Must be one of hcl.pals(). |
alpha |
Trajectory opacity. Defaults to |
colors |
Vector of colours. If NULL, the color palette will be used. If specified, will override palette. The number of colours must be equal to the number of variables in the simulation data frame. Defaults to NULL. |
font_family |
Font family. Defaults to "Times New Roman". |
font_size |
Font size. Defaults to 16. |
wrap_width |
Width of text wrapping for labels. Must be an integer. Defaults to 25. |
showlegend |
Whether to show legend. Must be TRUE or FALSE. Defaults to TRUE. |
label_subplots |
Whether to plot labels indicating the condition of the subplot. |
central_tendency |
Central tendency to use for the mean line. Either "mean", "median", or FALSE to not plot the central tendency. Defaults to "mean". |
central_tendency_width |
Line width of central tendency. Defaults to 3. |
... |
Optional parameters |
Value
Plotly object
See Also
Plot timeseries of simulation
Description
Visualize simulation results of a stock-and-flow model. Plot the evolution of stocks over time, with the option of also showing other model variables.
Usage
## S3 method for class 'simulate_stockflow'
plot(
x,
show_constants = FALSE,
vars = NULL,
palette = "Dark 2",
colors = NULL,
font_family = "Times New Roman",
font_size = 16,
wrap_width = 25,
showlegend = TRUE,
...
)
Arguments
x |
Output of |
show_constants |
If TRUE, include constants in plot. Defaults to FALSE. |
vars |
Variables to plot. Defaults to NULL to plot all variables. |
palette |
Colour palette. Must be one of hcl.pals(). |
colors |
Vector of colours. If NULL, the color palette will be used. If specified, will override palette. The number of colours must be equal to the number of variables in the simulation data frame. Defaults to NULL. |
font_family |
Font family. Defaults to "Times New Roman". |
font_size |
Font size. Defaults to 16. |
wrap_width |
Width of text wrapping for labels. Must be an integer. Defaults to 25. |
showlegend |
Whether to show legend. Must be TRUE or FALSE. Defaults to TRUE. |
... |
Optional parameters |
Value
Plotly object
See Also
simulate(), as.data.frame.simulate_stockflow(), plot.simulate_stockflow()
Examples
sfm <- stockflow("SIR")
sim <- simulate(sfm)
plot(sim)
# The default plot title and axis labels can be changed like so:
plot(sim, main = "Simulated trajectory", xlab = "Time", ylab = "Value")
# Add constants to the plot
plot(sim, show_constants = TRUE)
Plot stock-and-flow diagram
Description
Visualize a stock-and-flow diagram using the R package DiagrammeR. Stocks are represented as boxes. Flows are represented as arrows between stocks and/or double circles, where the latter represent what it outside of the model boundary. Thin grey edges indicate dependencies between variables. By default, constants (indicated by italic labels) are not shown. Hover over the variables to see their equations.
Usage
## S3 method for class 'stockflow'
plot(
x,
vars = NULL,
format_label = TRUE,
wrap_width = 20,
font_size = 18,
font_family = "Times New Roman",
stock_col = "#83d3d4",
flow_col = "#f48153",
dependency_col = "#999999",
show_dependencies = TRUE,
show_constants = FALSE,
show_aux = TRUE,
minlen = 2,
pad = 0.1,
nodesep = 0.3,
...
)
Arguments
x |
A stock-and-flow model object of class |
vars |
Variables to plot. Defaults to NULL to plot all variables. |
format_label |
If TRUE, apply default formatting (removing periods and underscores) to labels if labels are the same as variable names. |
wrap_width |
Width of text wrapping for labels. Must be an integer. Defaults to 20. |
font_size |
Font size. Defaults to 18. |
font_family |
Font name. Defaults to "Times New Roman". |
stock_col |
Colour of stocks. Defaults to "#83d3d4". |
flow_col |
Colour of flows. Defaults to "#f48153". |
dependency_col |
Colour of dependency arrows. Defaults to "#999999". |
show_dependencies |
If TRUE, show dependencies between variables. Defaults to TRUE. |
show_constants |
If TRUE, show constants. Defaults to FALSE. |
show_aux |
If TRUE, show auxiliary variables. Defaults to TRUE. |
minlen |
Minimum length of edges; must be an integer. Defaults to 2. |
pad |
Padding around the graph. Defaults to 0.1. |
nodesep |
Minimum distance between nodes. Defaults to 0.3. |
... |
Optional arguments |
Value
Stock-and-flow diagram
See Also
import_insightmaker(), stockflow(), plot.simulate_stockflow()
Examples
sfm <- stockflow("SIR")
plot(sfm)
# Don't show constants or auxiliaries
plot(sfm, show_constants = FALSE, show_aux = FALSE)
# Only show specific variables
plot(sfm, vars = "susceptible")
Plot verify results
Description
Visualize the simulation(s) used during verify(). Each condition j is
displayed as a subplot. Simulations are always available since verify()
unconditionally retains them.
Usage
## S3 method for class 'verify_stockflow'
plot(
x,
test = NULL,
vars = NULL,
show_constants = FALSE,
label = NULL,
ignore_case = TRUE,
status = c("pass", "fail", "error", "skip"),
condition = seq(1, min(c(x[["n_conditions"]], 9))),
nrows = ceiling(sqrt(max(condition))),
shareX = TRUE,
shareY = TRUE,
palette = "Dark 2",
colors = NULL,
font_family = "Times New Roman",
font_size = 16,
wrap_width = 25,
showlegend = TRUE,
label_subplots = TRUE,
alpha = 1,
margin = 0.05,
...
)
Arguments
x |
Output of |
test |
Integer vector of test numbers to plot.
Combines with |
vars |
Variables to plot. Defaults to NULL to plot all variables. |
show_constants |
If TRUE, include constants in plot. Defaults to FALSE. |
label |
Character vector of regex patterns for partial, case-insensitive label matching. A test is included if its label matches any pattern. |
ignore_case |
Logical; whether |
status |
Optional character vector of statuses to include (e.g.,
|
condition |
Integer vector of condition numbers to plot. Defaults to |
nrows |
Number of subplot rows. Defaults to |
shareX |
Share the x-axis across subplots. Defaults to |
shareY |
Share the y-axis across subplots. Defaults to |
palette |
Colour palette (see |
colors |
Vector of colours overriding |
font_family |
Font family. Defaults to |
font_size |
Font size. Defaults to |
wrap_width |
Label wrap width. Defaults to |
showlegend |
Whether to show the legend. Defaults to |
label_subplots |
Whether to plot labels indicating the test number of the subplot. |
alpha |
Trajectory opacity. Defaults to |
margin |
Margin between subplots. Either a single numeric or a vector of length four(left, right, top, bottom). See |
... |
Additional arguments passed to |
Value
A plotly object.
See Also
verify(), plot.simulate_stockflow(), plot.ensemble_stockflow()
Examples
sfm <- stockflow("SIR") |>
unit_test(expr = all(susceptible >= 0))
res <- verify(sfm)
plot(res)
Print comparison of two stock-and-flow models
Description
Print comparison of two stock-and-flow models
Usage
## S3 method for class 'compare_stockflow'
print(x, ...)
Arguments
x |
An object of class |
... |
Additional arguments (unused) |
Value
Invisibly returns x.
Print simulation of a stock-and-flow model
Description
Prints the first rows of the simulation results in wide format. For a statistical summary per variable use summary().
Usage
## S3 method for class 'simulate_stockflow'
print(x, ...)
Arguments
x |
A simulation result of class |
... |
Additional arguments (unused) |
Value
Invisibly returns x
See Also
simulate.stockflow(), summary.simulate_stockflow(),
plot.simulate_stockflow(), as.data.frame.simulate_stockflow()
Examples
sfm <- stockflow("SIR")
sim <- simulate(sfm)
print(sim)
Print overview of stock-and-flow model
Description
Prints a descriptive overview of the model structure, including stock-flow
topology, variable names, and simulation settings. For model diagnostics,
use summary().
Usage
## S3 method for class 'stockflow'
print(x, ...)
Arguments
x |
A stock-and-flow model object of class |
... |
Additional arguments (unused) |
Value
Invisibly returns x
See Also
summary.stockflow(), dependencies()
Examples
sfm <- stockflow("SIR")
print(sfm)
Print method for summary_stockflow
Description
Print method for summary_stockflow
Usage
## S3 method for class 'summary_stockflow'
print(x, ...)
Arguments
x |
Object of class |
... |
Ignored |
Value
x invisibly
Create pulse function
Description
Create a pulse function that jumps from zero to a specified height at a specified time, and returns to zero after a specified width. The pulse can be repeated at regular intervals.
Usage
pulse(times, start, height = 1, width = 1, repeat_interval = NULL)
Arguments
times |
Vector of simulation times |
start |
Start time of pulse in simulation time units. |
height |
Height of pulse. Defaults to 1. |
width |
Width of pulse in simulation time units. This cannot be equal to or less than 0. To indicate an instantaneous pulse, specify the simulation step size. |
repeat_interval |
Interval at which to repeat pulse. Defaults to NULL to indicate no repetition. |
Details
Equivalent of Pulse() in Insight Maker
Value
Pulse interpolation function
See Also
Examples
# Create a simple model with a pulse function
# that starts at time 5, jumps to a height of 2
# with a width of 1, and does not repeat
sfm <- stockflow() |>
update("a", "stock") |>
# Specify the global variable "times" as simulation times
update("input", "constant", eqn = "pulse(times, 5, 2, 1)") |>
update("inflow", "flow", eqn = "input(t)", to = "a")
sim <- simulate(sfm, only_stocks = FALSE)
plot(sim)
# Create a pulse that repeats every 5 time units
sfm <- update(sfm, "input", eqn = "pulse(times, 5, 2, 1, 5)")
sim <- simulate(sfm, only_stocks = FALSE)
plot(sim)
Create ramp function
Description
Create a ramp function that increases linearly from 0 to a specified height at a specified start time, and stays at this height after the specified end time.
Usage
ramp(times, start, finish, height = 1)
Arguments
times |
Vector of simulation times |
start |
Start time of ramp |
finish |
End time of ramp |
height |
End height of ramp, defaults to 1 |
Details
Equivalent of Ramp() in Insight Maker
Value
Ramp interpolation function
See Also
Examples
# Create a simple model with a ramp function
sfm <- stockflow() |>
update("a", "stock") |>
# Specify the global variable "times" as simulation times
update("input", "constant", eqn = "ramp(times, 20, 30, 3)") |>
update("inflow", "flow", eqn = "input(t)", to = "a")
sim <- simulate(sfm, only_stocks = FALSE)
plot(sim)
# To create a decreasing ramp, set the height to a negative value
sfm <- update(sfm, "input", eqn = "ramp(times, 20, 30, -3)")
sim <- simulate(sfm, only_stocks = FALSE)
plot(sim)
Generate random logical value
Description
Equivalent of RandBoolean() in Insight Maker
Usage
rbool(p)
Arguments
p |
Probability of TRUE, numerical value between 0 and 1 |
Value
Logical value
Examples
rbool(.5)
Generate random number from custom distribution
Description
Equivalent of RandDist() in Insight Maker
Usage
rdist(a, b)
Arguments
a |
Vector to draw sample from |
b |
Vector of probabilities |
Value
One sample from custom distribution
Examples
rdist(c(1, 2, 3), c(.5, .25, .25))
Remainder and modulus
Description
Remainder and modulus operators. The modulus and remainder are not the same in case either a or b is negative. If you work with negative numbers, modulus is always non-negative (it matches the sign of the divisor).
Usage
rem(a, b)
mod(a, b)
a %REM% b
Arguments
a |
Dividend |
b |
Divisor |
Value
Remainder
Examples
# Modulus and remainder are the same when a and b are positive
a <- 7
b <- 3
rem(a, b)
mod(a, b)
# Modulus and remainder are NOT when either a or b is negative
a <- -7
b <- 3
rem(a, b)
mod(a, b)
a <- 7
b <- -3
rem(a, b)
mod(a, b)
# Modulus and remainder are the same when both a and b are negative
a <- -7
b <- -3
rem(a, b)
mod(a, b)
# Alternative way of computing the remainder:
a %REM% b
Round values half-up (as in Insight Maker)
Description
R rounds .5 to 0, whereas Insight Maker rounds .5 to 1. This function is the equivalent of Insight Maker's Round() function.
Usage
round_IM(x, digits = 0)
Arguments
x |
Value |
digits |
Number of digits; optional, defaults to 0 |
Value
Rounded value
Examples
round_IM(.5) # 1
round(.5) # 0
round_IM(-0.5) # 0
round(-0.5) # 0
round_IM(1.5) # 2
round(1.5) # 2
Internal function to save data frame at specific times
Description
Internal function used to save the data frame at specific times in case save_at is not equal to dt in the simulation specifications.
Usage
saveat_func(df, time_col, new_times)
Arguments
df |
data.frame in wide format |
time_col |
Name of the time column |
new_times |
Vector of new times to save the data frame at |
Value
Interpolated data.frame. The data frame has columns time followed by
one column per variable.
Examples
# Recommended: Use save_at in sim_settings() to downsample simulations
sfm <- stockflow("SIR") |> sim_settings(dt = 0.01, save_at = 1)
sim <- simulate(sfm)
df <- as.data.frame(sim)
nrow(df) # Returns only times at intervals of 1
head(df)
# The saveat_func() is the underlying function used by simulate()
# Direct use is not recommended, but shown here for completeness:
sfm <- sfm |> sim_settings(save_at = 0.01)
sim <- simulate(sfm)
df <- as.data.frame(sim)
nrow(df) # Many more rows
# Manual downsampling (not recommended - use save_at instead)
new_times <- seq(min(df$time), max(df$time), by = 1)
df_wide <- as.data.frame(sim, direction = "wide")
df_manual <- saveat_func(df_wide, "time", new_times)
nrow(df_manual)
Create a seasonal wave function
Description
Create a seasonal wave function that oscillates between -1 and 1, with a specified period and shift. The wave peaks at the specified shift time.
Usage
seasonal(times, period = 1, shift = 0)
Arguments
times |
Vector of simulation times |
period |
Duration of wave in simulation time units. Defaults to 1. |
shift |
Timing of wave peak in simulation time units. Defaults to 0. |
Details
Equivalent of Seasonal() in Insight Maker
Value
Seasonal interpolation function
See Also
Examples
# Create a simple model with a seasonal wave
sfm <- stockflow() |>
update("a", "stock") |>
# Specify the global variable "times" as simulation times
update("input", "constant", eqn = "seasonal(times, 10, 0)") |>
update("inflow", "flow", eqn = "input(t)", to = "a")
sim <- simulate(sfm, only_stocks = FALSE)
plot(sim)
Translate between deSolve and DifferentialEquations.jl solver names
Description
Translate between deSolve and DifferentialEquations.jl solver names, or validate that a given solver name is recognized in either language. This is used internally to allow users to specify familiar R solvers when using Julia for simulation, and to provide warnings when an exact equivalent is not available.
Usage
sim_methods(method, from = NULL, to = NULL)
Arguments
method |
Solver name to validate or translate. |
from |
Source solver family, either |
to |
Target solver family when translating, either |
Value
A character scalar (validated or translated solver name), a character vector of solver
names when method is omitted, or a named list of solver names for both languages when called
with no arguments.
Examples
# List supported solvers
sim_methods()
# List supported R solvers
sim_methods(from = "R")
# List supported Julia solvers
sim_methods(from = "Julia")
# Validate or translate specific solvers
sim_methods("rk4", from = "R", to = "Julia")
Modify simulation specifications
Description
Simulation specifications are the settings that determine how the model is simulated, such as the integration method (i.e., solver), start and stop time, and timestep. Modify these specifications for an existing stock-and-flow model.
Usage
sim_settings(
object,
method = "euler",
start = 0,
stop = 100,
dt = 0.01,
save_at = 0.1,
save_n = NULL,
seed = NULL,
time_units = "seconds",
language = "R",
only_stocks = TRUE,
vars = NULL,
keep_nonnegative_stock = FALSE,
keep_nonnegative_flow = TRUE,
save_sims = FALSE
)
Arguments
object |
Stock-and-flow model, object of class |
method |
Integration method. Defaults to |
start |
Start time of simulation. Defaults to |
stop |
End time of simulation. Defaults to |
dt |
Timestep of solver; controls simulation accuracy. Smaller = more
accurate but slower. Defaults to |
save_at |
Controls which time points are saved in the output. Either:
Pass |
save_n |
Save exactly N evenly-spaced time points from |
seed |
Seed number to ensure reproducibility across runs in case of
random elements. Must be an integer. Defaults to |
time_units |
Simulation time unit. Defaults to |
language |
Coding language in which to simulate model. Either |
only_stocks |
If |
vars |
Character vector of variable names to save in simulation output.
If specified, this overrides |
keep_nonnegative_stock |
If |
keep_nonnegative_flow |
If |
save_sims |
If |
Value
A stock-and-flow model object of class stockflow
See Also
Examples
sfm <- stockflow("predator_prey") |>
sim_settings(start = 0, stop = 50, dt = 0.1)
sim <- simulate(sfm)
plot(sim)
# Change the simulation method to "rk4"
sfm <- sim_settings(sfm, method = "rk4")
# Change the time units to "years", such that one time unit is one year
sfm <- sim_settings(sfm, time_units = "years")
# Save at an interval to reduce output size without affecting accuracy
sfm <- sim_settings(sfm, save_at = 1)
sim <- simulate(sfm)
head(as.data.frame(sim))
# Save exactly 11 evenly-spaced time points (t=0, 5, 10, ..., 50)
sfm <- sim_settings(sfm, save_n = 11)
sim <- simulate(sfm)
head(as.data.frame(sim))
# Add stochastic initial condition but specify seed to obtain same result
sfm <- sim_settings(sfm, seed = 1) |>
update(c(predator, prey), eqn = runif(1, 20, 50))
Simulate stock-and-flow model
Description
Simulate a stock-and-flow model with simulation specifications defined by sim_settings(). If sim_settings(language = "julia"), the Julia environment will first be set up with use_julia(). If any problems are detected by summary(), the model cannot be simulated.
Usage
## S3 method for class 'stockflow'
simulate(object, nsim = 1, seed = NULL, ...)
Arguments
object |
Stock-and-flow model, object of class |
nsim |
Number of simulations to run (unused; see |
seed |
Seed number to ensure reproducibility across runs in case of
random elements. Must be an integer. Defaults to |
... |
Optional arguments passed to |
Value
Object of class simulate_stockflow, a list containing:
- object
Stock-and-flow model object of class
stockflow- df
Data frame: simulation results (time, variable, value)
- init
Named vector: initial stock values
- constants
Named vector: constant parameters
- script
Character: generated simulation code (R or Julia)
- duration
Numeric: simulation time in seconds
- success
Logical: TRUE if completed without errors
- error_message
NULL if completed without errors
Use as.data.frame() to extract results, plot() to visualize.
See Also
update(), stockflow(), summary(), sim_settings(), use_julia()
Examples
sfm <- stockflow("SIR")
sim <- simulate(sfm)
plot(sim)
# Obtain all model variables
sim <- simulate(sim_settings(sfm, only_stocks = FALSE))
plot(sim, show_constants = TRUE)
Create step function
Description
Create a step function that jumps from zero to a specified height at a specified time, and remains at that height until the end of the simulation time.
Usage
step(times, start, height = 1)
Arguments
times |
Vector of simulation times |
start |
Start time of step |
height |
Height of step, defaults to 1 |
Details
Equivalent of Step() in Insight Maker
Value
Step interpolation function
See Also
Examples
# Create a simple model with a step function
# that jumps at time 50 to a height of 5
sfm <- stockflow() |>
update("a", "stock") |>
# Specify the global variable "times" as simulation times
update("input", "constant", eqn = "step(times, 50, 5)") |>
update("inflow", "flow", eqn = "input(t)", to = "a")
sim <- simulate(sfm, only_stocks = FALSE)
plot(sim)
# Negative heights are also possible
sfm <- update(sfm, "input", eqn = "step(times, 50, -10)")
sim <- simulate(sfm, only_stocks = FALSE)
plot(sim)
Add or modify stocks
Description
Stocks accumulate material or information over time, defining the state of
the system. stock() adds or changes a stock variable. This is a
convenience wrapper around update() with type = "stock". See the
Stocks section of update() for more details.
Usage
stock(object, name, eqn = 0, label = name, doc = "", non_negative = FALSE)
Arguments
object |
Stock-and-flow model, object of class |
name |
Variable name. Accepts a bare symbol (e.g., |
eqn |
Equation (or initial value in the case of stocks). Accepts a bare expression (e.g., |
label |
Name of variable used for plotting. Defaults to the same as name. |
doc |
Description of variable. Defaults to |
non_negative |
If TRUE, variable is enforced to be non-negative (i.e., strictly 0 or positive). Defaults to |
Value
A stock-and-flow model object of class stockflow
See Also
update(), discard(), change_name()
Examples
# Create a stock with an initial value
sfm <- stockflow() |>
stock(population, eqn = 100, label = "Population")
# Multiple stocks
sfm <- stockflow() |>
stock(susceptible, eqn = 999, label = "susceptible") |>
stock(infected, eqn = 1, label = "infected") |>
stock(recovered, eqn = 0, label = "recovered")
Create a new stock-and-flow model
Description
Initialize a stock-and-flow model of class stockflow. You can
either create an empty stock-and-flow model or load a template from the model
library.
Usage
stockflow(template = NULL)
Arguments
template |
Name of the template to load. If
|
Details
Do not edit the object manually; this will likely lead to errors downstream.
Rather, use meta(), sim_settings(), update(), and custom_func() for safe manipulation.
Value
A stock-and-flow model object of class stockflow. Its structure is based
on XML Interchange Language for System Dynamics (XMILE). It is a nested list, containing:
- meta
Meta-information about model. A list containing arguments listed in
meta().- sim_settings
Simulation specifications. A list containing arguments listed in
sim_settings().- model
Model variables, grouped under the variable types stock, flow, aux (auxiliaries), constant, gf (graphical functions), and func (custom functions). Each variable contains arguments as listed in
update().
Use summary() to run model diagnostics, as.data.frame() to convert to a data.frame, plot() to visualize.
See Also
update(), meta(), custom_func(), sim_settings()
Examples
sfm <- stockflow()
summary(sfm)
# Load a template
sfm <- stockflow("lorenz")
sim <- simulate(sfm)
plot(sim)
Summarise simulation results
Description
Returns a data frame with per-variable summary statistics (min, mean, max, and final value) over the simulated time range.
Usage
## S3 method for class 'simulate_stockflow'
summary(object, ...)
Arguments
object |
A simulation result of class |
... |
Additional arguments (unused) |
Value
A data.frame with columns variable, min, mean, max, final.
See Also
print.simulate_stockflow(), simulate.stockflow()
Examples
sfm <- stockflow("SIR")
sim <- simulate(sfm)
summary(sim)
Run model diagnostics
Description
Check for common formulation problems in a stock-and-flow model.
Usage
## S3 method for class 'stockflow'
summary(object, ...)
Arguments
object |
Stock-and-flow model, object of class |
... |
Additional arguments (currently unused). |
Details
The following problems are detected:
An absence of stocks
Flows without a source (
from) or target (to)Flows connected to a stock that does not exist
Undefined variable references in equations
Circularity in equations
The following potential problems are detected:
Absence of flows
Stocks without inflows or outflows
Equations with a value of 0
Value
Object of class summary_stockflow. A flat named list with one
entry per check. Each entry contains a problem field ("none",
"warning", or "error") and type-specific data fields.
Examples
# No issues
sfm <- stockflow("SIR")
summary(sfm)
# Detect absence of stocks or flows
sfm <- stockflow()
summary(sfm)
# Detect stocks without inflows or outflows
sfm <- stockflow() |> update("Prey", "stock")
summary(sfm)
# Detect circularity in equation definitions
sfm <- stockflow() |>
update("Prey", "stock", eqn = "Predator") |>
update("Predator", "stock", eqn = "Prey")
summary(sfm)
Print last rows of a simulation
Description
Print the last rows of a simulation data frame of a stock-and-flow model. This is a wrapper around tail() that first converts the simulation results to a data frame using as.data.frame().
Usage
## S3 method for class 'simulate_stockflow'
tail(x, n = 6L, ...)
Arguments
x |
Output of |
n |
Number of rows to print. Defaults to 6. |
... |
Other arguments passed to |
Value
A data.frame with the last rows of the simulation results.
Examples
sfm <- stockflow("SIR")
sim <- simulate(sfm)
tail(sim)
Print last rows of verify results
Description
Wrapper around tail() that first converts the results to a data frame using
as.data.frame.verify_stockflow().
Usage
## S3 method for class 'verify_stockflow'
tail(x, n = 6L, ...)
Arguments
x |
A |
n |
Number of rows. Defaults to 6. |
... |
Other arguments passed to |
Value
A data.frame.
Examples
sfm <- stockflow("SIR") |>
unit_test(expr = all(susceptible >= 0))
res <- verify(sfm)
tail(res)
Add or modify unit tests
Description
Unit tests are assertions about model behavior that can be evaluated against
simulation results. For example, you might assert that a stock remains
non-negative, or that a certain variable reaches a threshold by the end of
the simulation. Unit tests can be added to a model such that they can be
evaluated with verify(). All unit tests can be displayed with
unit_tests().
Usage
unit_test(object, test, expr, label, conditions = list(), active = TRUE)
Arguments
object |
Stock-and-flow model, object of class |
test |
Integer number of the test to modify. Must be a positive integer
(a warning is issued and the value rounded when a non-integer is
supplied). When |
expr |
An expression to evaluate against simulation results. Variable names in the expression refer to model variables; each resolves to a numeric vector of time-series values. Required when adding a new test; optional when modifying (keeps the current expression if omitted). |
label |
A descriptive label for the test. If omitted when adding,
auto-generated from |
conditions |
A named list of constant or initial stock overrides used
when evaluating this test. If non-empty, |
active |
If |
Details
The expr argument accepts a plain logical expression:
-
Logical:
all(S >= 0),cor(D, C) < -.5.
When label is omitted, a human-readable label is generated automatically
by parsing the expression (e.g., all(S >= 0) →
"S is at least 0 (for all values)").
Value
The model object with the unit test added or modified, invisibly.
Adding vs. modifying
-
Add a new test: omit
test(and provide alabelthat does not match any existing test, or omitlabelto auto-generate one). -
Modify an existing test by number: supply
test(integer). -
Modify an existing test by label: supply a
labelthat matches an existing test (without specifyingtest).
When modifying, only the arguments you explicitly supply are changed; all other fields keep their current value.
Uniqueness
Labels must be unique across all unit tests. An error is thrown if a new
or modified label would create a duplicate. Expressions must also be unique;
an error is thrown if an identical expr already exists on another test.
See Also
verify(), unit_tests(), discard_unit_test()
Examples
sfm <- stockflow("SIR") |>
unit_test(expr = all(susceptible >= 0))
# Run unit tests
verify(sfm)
# Add test with label
sfm <- unit_test(sfm,
label = "recovered increases",
expr = all(diff(recovered) >= 0)
)
verify(sfm)
# Add test with conditions
sfm <- unit_test(sfm,
expr = all(infected == infected[1]),
label = "When infection_rate is zero, no one gets infected",
conditions = list(infection_rate = 0)
)
verify(sfm)
# View all tests
unit_tests(sfm)
# Deactivate test test 1
sfm <- unit_test(sfm, test = 1, active = FALSE)
verify(sfm)
# Modify test by label, e.g., to change the expression
sfm <- unit_test(sfm,
label = "recovered increases over time",
expr = all(diff(recovered) > -1)
)
verify(sfm)
Display unit tests defined on a stock-and-flow model
Description
Returns an overview of all unit tests attached to the model. The result
has a print() method.
Usage
unit_tests(object, test = NULL, label = NULL, ignore_case = TRUE)
Arguments
object |
Stock-and-flow model, object of class |
test |
Integer vector of test number(s) to display (1-based). Defaults to
|
label |
Character vector of regex patterns for partial, case-insensitive
label matching. A test is included if its label matches any pattern.
E.g., |
ignore_case |
Logical; whether |
Value
An object of class unit_tests_stockflow, printed automatically.
See Also
Examples
sfm <- stockflow("SIR") |>
unit_test(expr = all(susceptible >= 0)) |>
unit_test(
label = "recovered increases over time",
expr = all(diff(recovered) >= 0)
)
unit_tests(sfm)
unit_tests(sfm, test = 1L)
unit_tests(sfm, label = "increases")
Create or modify variables
Description
Add or change variables in a stock-and-flow model. Variables may be stocks, flows, constants, auxiliaries, or graphical functions. When creating new variables, only "name", "type", and "eqn" (initial value for stocks) are required. When modifying existing variables, only "name" is required to identify the variable to modify, and any other properties can be updated by including the corresponding arguments.
Usage
## S3 method for class 'stockflow'
update(
object,
name,
type = NULL,
eqn = 0,
label = name,
doc = "",
to = NULL,
from = NULL,
non_negative = FALSE,
xpts = NULL,
ypts = NULL,
source = NULL,
interpolation = "linear",
extrapolation = "nearest",
df = NULL,
...
)
Arguments
object |
Stock-and-flow model, object of class |
name |
Variable name. Accepts a bare symbol (e.g., |
type |
Type of building block(s); accepts a bare symbol or string. One of |
eqn |
Equation (or initial value in the case of stocks). Accepts a bare expression (e.g., |
label |
Name of variable used for plotting. Defaults to the same as name. |
doc |
Description of variable. Defaults to |
to |
Target of flow. Accepts a bare symbol or string. Must be a stock in the model. Defaults to |
from |
Source of flow. Accepts a bare symbol or string. Must be a stock in the model. Defaults to |
non_negative |
If TRUE, variable is enforced to be non-negative (i.e., strictly 0 or positive). Defaults to |
xpts |
Only for graphical functions: vector of x-domain points. Must be of the same length as ypts. |
ypts |
Only for graphical functions: vector of y-domain points. Must be of the same length as xpts. |
source |
Only for graphical functions: name of the variable which will serve as the input to the graphical function. Accepts a bare symbol or string. Defaults to |
interpolation |
Only for graphical functions: interpolation method. Must be either "constant" or "linear". Defaults to "linear". |
extrapolation |
Only for graphical functions: extrapolation method. Must be either |
df |
A data.frame with variable properties to add and/or modify. Each row represents one variable to update. Required columns depend on the variable type being created:
Optional columns for all types: 'label', 'doc', 'non_negative' Optional columns for graphical functions: 'source', 'interpolation', 'extrapolation' Columns not applicable to a variable type should be set to NA. See Examples for a complete demonstration. |
... |
Additional arguments (currently unused). |
Value
A stock-and-flow model object of class stockflow
Stocks
Stocks define the state of the system. They accumulate material or information over time, such as people, products, or beliefs, which creates memory and inertia in the system. As such, stocks need not be tangible. Stocks are variables that can increase and decrease, and can be measured at a single moment in time. The value of a stock is increased or decreased by flows. A stock may have multiple inflows and multiple outflows. The net change in a stock is the sum of its inflows minus the sum of its outflows.
The obligatory properties of a stock are "name", "type", and "eqn". Optional additional properties are "label", "doc", "non_negative".
Flows
Flows move material and information through the system. Stocks can only decrease or increase through flows. A flow must flow from and/or flow to a stock. If a flow is not flowing from a stock, the source of the flow is outside of the model boundary. Similarly, if a flow is not flowing to a stock, the destination of the flow is outside the model boundary. Flows are defined in units of material or information moved over time, such as birth rates, revenue, and sales.
The obligatory properties of a flow are "name", "type", "eqn", and either "from", "to", or both. Optional additional properties are "label", "doc", "non_negative".
Constants
Constants are variables that do not change over the course of the simulation - they are time-independent. These may be numbers, but also functions. They can depend only on other constants.
The obligatory properties of a constant are "name", "type", and "eqn". Optional additional properties are "label", "doc", "non_negative".
Auxiliaries
Auxiliaries are dynamic variables that change over time. They are used for intermediate calculations in the system, and can depend on other flows, auxiliaries, constants, and stocks.
The obligatory properties of an auxiliary are "name", "type", and "eqn". Optional additional properties are "label", "doc", "non_negative".
Graphical functions
Graphical functions, also known as table or lookup functions, are interpolation functions used to define the desired output (y) for a specified input (x). They are defined by a set of x- and y-domain points, which are used to create a piecewise linear function. The interpolation method defines the behavior of the graphical function between x-points ("constant" to return the value of the previous x-point, "linear" to linearly interpolate between defined x-points), and the extrapolation method defines the behavior outside of the x-points ("NA" to return NA values outside of defined x-points, "nearest" to return the value of the closest x-point).
The obligatory properties of a graphical function are "name", "type", "xpts", and "ypts". "xpts" and "ypts" must be of the same length. Optional additional properties are "label", "doc", "source", "interpolation", "extrapolation".
Non-standard evaluation (NSE)
The name, type, eqn, to, from, and source arguments
support non-standard evaluation. This means you can pass bare symbols and
expressions instead of quoted strings:
# These are equivalent: stock(sfm, "population", eqn = "birth_rate * 0.1") stock(sfm, population, eqn = birth_rate * 0.1)
To inject the value of a variable (rather than its name), use the
!! (bang-bang) operator from rlang:
my_name <- "population" stock(sfm, !!my_name, eqn = 100)
The label, doc, non_negative, xpts, ypts,
interpolation, and extrapolation arguments are not affected by NSE
and are evaluated normally.
See Also
stockflow() to initialize a model, simulate() to simulate a model, and summary() to run model diagnostics. Variable-specific helper functions stock(), flow(), constant(), aux(), and lookup() are also available as wrappers around update() that set the "type" argument for convenience. Further helper functions for modifying models are change_name() to rename a variable, change_type() to change a variable's type, and discard() to remove a variable.
Examples
# First initialize an empty model
sfm <- stockflow()
print(sfm)
# Add two stocks. Specify their initial values in the "eqn" property
# and their plotting label.
sfm <- stock(sfm, predator, eqn = 10, label = "Predator") |>
stock(prey, eqn = 50, label = "Prey")
# Add four flows: the births and deaths of both the predators and prey. The
# "eqn" property of flows represents the rate of the flow. In addition, we
# specify which stock the flow is coming from ("from") or flowing to ("to").
sfm <- flow(sfm, predator_births,
eqn = delta * prey * predator,
label = "Predator Births", to = predator
) |>
flow(predator_deaths,
eqn = gamma * predator,
label = "Predator Deaths", from = predator
) |>
flow(prey_births,
eqn = alpha * prey,
label = "Prey Births", to = prey
) |>
flow(prey_deaths,
eqn = beta * prey * predator,
label = "Prey Deaths", from = prey
)
plot(sfm)
# The flows make use of four other variables: "delta", "gamma", "alpha", and
# "beta". Define these as constants in a vectorized manner for efficiency.
sfm <- constant(sfm, c(delta, gamma, alpha, beta),
eqn = c(.025, .5, .5, .05),
label = c("Delta", "Gamma", "Alpha", "Beta"),
doc = c(
"Birth rate of predators", "Death rate of predators",
"Birth rate of prey", "Death rate of prey by predators"
)
)
# We now have a complete predator-prey model which is ready to be simulated.
sim <- simulate(sfm)
plot(sim)
# Modify a variable - note that we no longer need to specify type
sfm <- update(sfm, delta, eqn = .03, label = "DELTA")
# To add and/or modify variables more quickly, pass a data.frame.
# The data.frame is processed per row.
# For instance, to create a logistic population growth model:
df <- data.frame(
type = c("stock", "flow", "flow", "constant", "constant"),
name = c("X", "inflow", "outflow", "r", "K"),
eqn = c(.01, "r * X", "r * X^2 / K", 0.1, 1),
label = c(
"Population size", "Births", "Deaths", "Growth rate",
"Carrying capacity"
),
to = c(NA, "X", NA, NA, NA),
from = c(NA, NA, "X", NA, NA)
)
sfm <- update(stockflow(), df = df)
# Run model diagnostics
summary(sfm)
# --- Programmatic usage ---
# To inject the value of an R variable, use !! (bang-bang)
my_name <- "growth"
sfm <- constant(sfm, !!my_name, eqn = 0.1)
# Strings also work
sfm <- constant(sfm, "growth", eqn = 0.2)
Extract Insight Maker model from URL
Description
Create XML string from Insight Maker URL. For internal use; use import_insightmaker() to import an Insight Maker model.
Usage
url_to_insightmaker(url, file = NULL)
Arguments
url |
String with URL to an Insight Maker model |
file |
If specified, file path to save Insight Maker model to. If NULL, do not save model. |
Value
XML string with Insight Maker model
See Also
Examples
url <- "https://insightmaker.com/insight/43tz1nvUgbIiIOGSGtzIzj/Romeo-Juliet"
xml <- url_to_insightmaker(url)
# Save model to file
file <- tempfile(fileext = ".InsightMaker")
xml <- url_to_insightmaker(url, file = file)
file.remove(file)
Start Julia and activate environment
Description
Start Julia session and activate Julia environment to simulate stock-and-flow models. To do so, Julia needs to be installed (see https://julialang.org/install/) and findable from within R. See this vignette for guidance. In addition, the Julia environment specifically for sdbuildR needs to have been instantiated. This can be set up with install_julia_env().
Usage
use_julia(stop = FALSE, restart = FALSE, nthreads = NULL)
Arguments
stop |
If |
restart |
If |
nthreads |
If not |
Details
In every R session, use_julia() needs to be run once (which is done automatically in simulate()), which can take around 30-60 seconds.
Value
Returns NULL invisibly, used for side effects
See Also
Examples
# Start a Julia session and activate the Julia environment for sdbuildR
use_julia()
# Start Julia with 2 threads (only works if threading is supported)
use_julia(nthreads = 2)
# Restart Julia session (in case of issues)
use_julia(restart = TRUE)
# Stop Julia session
use_julia(stop = TRUE)
Verify model behavior with unit tests
Description
Verify model behavior with unit tests
Usage
verify(object, ...)
Arguments
object |
A model object to verify. |
... |
Additional arguments passed to specific methods. |
Verify unit tests against simulation results
Description
Run all active unit tests defined on a stock-and-flow model. Use
unit_test() to define tests; use unit_tests() to display them.
Usage
## S3 method for class 'stockflow'
verify(object, test = NULL, ...)
Arguments
object |
An |
test |
Integer vector of test number(s) to run (numbers-based, as shown by |
... |
Additional arguments passed to |
Details
Calling verify() on a stockflow model will first simulate the model, then
run all tests — including those that require re-simulation under alternative
conditions. Simulations are always retained in the returned
object so that plot.verify_stockflow() works without any extra arguments.
For repeated-run robustness testing use ensemble() instead.
Value
An object of class verify_stockflow, returned invisibly. Use
as.data.frame() to extract results as a data frame and plot() to
visualize the simulations used. The object contains:
- results
List of test result entries, one per test (including inactive tests, which appear with
status = "skip"). Each entry haslabel,expr_str,conditions,status,error_type,message, andoutcome.- object
The
stockflowmodel the tests were run against.- sims
Nested list of
simulate_stockflowobjects used internally byplot.verify_stockflow(). Always present (neverNULL).- j
Named integer vector mapping each test label to its condition index. Used internally by
plot.verify_stockflow().- n
Number of simulations run per condition.
- n_conditions
Number of unique simulation conditions.
- test_indices
Integer vector of the original 1-based test numbers that were run (as shown by
unit_tests()). Equal toseq_along(results)whentest = NULL(all tests run).
See Also
unit_test(), unit_tests(), simulate.stockflow(),
as.data.frame.verify_stockflow(), plot.verify_stockflow()
Examples
sfm <- stockflow("SIR") |>
unit_test(expr = all(susceptible >= 0)) |>
unit_test(
label = "recovered increases over time",
expr = all(diff(recovered) >= 0)
)
verify(sfm)