Skip to contents

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 stockflow.

name

Variable name. Accepts a bare symbol (e.g., population), a string ("population"), or a vector via c() (e.g., c(a, b) or c("a", "b")). Use !! to inject from a variable.

type

Type of building block(s); accepts a bare symbol or string. One of stock, flow, constant, aux, lookup, or func. Does not need to be specified to modify an existing variable.

eqn

Equation (or initial value in the case of stocks). Accepts a bare expression (e.g., a * b + 1), a string ("a * b + 1"), or a numeric value. Use !! to inject from a variable. Defaults to 0.

label

Name of variable used for plotting. Defaults to the same as name.

doc

Description of variable. Defaults to "" (no description).

to

Target of flow. Accepts a bare symbol or string. Must be a stock in the model. Defaults to NULL to indicate no target.

from

Source of flow. Accepts a bare symbol or string. Must be a stock in the model. Defaults to NULL to indicate no source.

non_negative

If TRUE, variable is enforced to be non-negative (i.e., strictly 0 or positive). Defaults to FALSE.

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 NULL.

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 "nearest" or "NA". Defaults to "nearest".

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:

  • All types require: 'type', 'name'

  • Stocks require: 'eqn' (initial value)

  • Flows require: 'eqn', and at least one of 'from' or 'to'

  • Constants require: 'eqn'

  • Auxiliaries require: 'eqn'

  • Graphical functions require: 'xpts', 'ypts'

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)
#> 
#> ── Stock-and-Flow Model ────────────────────────────────────────────────────────
#>  Empty model without any variables.
#> 
#> ── Simulation Settings ──
#> 
#> Time: 0 to 100 seconds (dt = 0.01) • euler • R

# 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) #> #> ── Stock-and-Flow Model Diagnostics ──────────────────────────────────────────── #> No problems detected! # --- 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)