ipmr: Flexible implementation of Integral Projection Models in R
'Tiffany M. Knight and Roberto Salguero-Gómez contributed equally to this work
Handling Editor: Giovanni Strona
Funding information
R.S.-G. was supported by a NERC Independent Research Fellowship (NE/M018458/1). S.C.L., A.C., S.E. and T.M.K. were funded by the Alexander von Humboldt Foundation in the framework of the Alexander von Humboldt Professorship of TM Knight endowed by the German Federal Ministry of Education and Research.
Abstract
- Integral projection models (IPMs) are an important tool for studying the dynamics of populations structured by one or more continuous traits (e.g. size, height, body mass). Researchers use IPMs to investigate questions ranging from linking drivers to population dynamics, planning conservation and management strategies, and quantifying selective pressures in natural populations. The popularity of stage-structured population models has been supported by R scripts and packages (e.g. IPMpack, popbio, popdemo, lefko3) aimed at ecologists, which have introduced a broad repertoire of functionality and outputs. However, pressing ecological, evolutionary and conservation biology topics require developing more complex IPMs, and considerably more expertise to implement them. Here, we introduce ipmr, a flexible R package for building, analysing and interpreting IPMs.
- The ipmr framework relies on the mathematical notation of the models to express them in code format. Additionally, this package decouples the model parameterization step from the model implementation step. The latter point substantially increases ipmr's flexibility to model complex life cycles and demographic processes.
- ipmr can handle a wide variety of models, including those that incorporate density dependence, discretely and continuously varying stochastic environments, and multiple continuous and/or discrete traits. ipmr can accommodate models with individuals cross-classified by age and size. Furthermore, the package provides methods for demographic analyses (e.g. asymptotic and stochastic growth rates) and visualization (e.g. kernel plotting).
- ipmr is a flexible R package for integral projection models. The package substantially reduces the amount of time required to implement general IPMs. We also provide extensive documentation with six vignettes and help files, accessible from an R session and online.
1 INTRODUCTION
Integral projection models (IPMs) are an important and widely used tool for ecologists studying structured population dynamics in discrete time. Since the paper introducing IPMs was published over two decades ago (Easterling et al., 2000), at least 255 peer-reviewed publications on at least 250 plant species and 60 animal species have used IPMs (ESM, Table S1; Figure S1). These models have addressed questions ranging from invasive species population dynamics (e.g. Crandall & Knight, 2017), effect of climate drivers on population persistence (e.g. Compagnoni et al., 2021), evolutionary stable strategies (e.g. Childs et al., 2004) and rare/endangered species conservation (e.g. Ferrer-Cervantes et al., 2012).
The IPM was introduced as alternative to matrix population models, which model populations structured by discrete traits (Caswell, 2001). Some of the advantages of using an IPM include (a) the ability to model populations structured by continuously distributed traits, (b) the ability to flexibly incorporate discrete and continuous traits in the same model (e.g. seeds in a seedbank and a height-structured plant population, Crandall & Knight, 2017, or number of females, males and age-1 recruits for fish species, Erickson et al., 2017), (c) efficient parameterization of demographic processes with familiar regression methods (Coulson, 2012), and (d) the numerical discretization of continuous kernels (see below) means that the tools available for matrix population models are usually also applicable for IPMs. Furthermore, researchers have developed methods to incorporate spatial dynamics (Jongejans et al., 2011), environmental stochasticity (Rees & Ellner, 2009) and density/frequency dependence into IPMs (Adler et al., 2010; Ellner et al., 2016). These developments were accompanied by the creation of software tools and guides to assist with IPM parameterization, implementation and analysis. These tools range from R scripts with detailed annotations (Coulson, 2012; Ellner et al., 2016; Merow et al., 2014) to R packages (Metcalf et al., 2013; Shefferson et al., 2020).
Despite the array of resources available to researchers, implementing an IPM is still not a straightforward exercise. For example, an IPM that simulates a population for 100 time steps requires the user to either write or adapt from published guides multiple functions (e.g. to summarize demographic functions into the proper format), implement the numerical approximations of the model's integrals, ensure that individuals are not accidentally sent beyond the integration bounds (‘unintentional eviction’, sensu Williams et al., 2012) and track how the population state changes over the course of a simulation. Stochastic IPMs present further implementation challenges. In addition to the aforementioned elements, users must generate the sequence of environments that the population experiences. There are multiple ways of simulating environmental stochasticity, each with their own strengths and weaknesses (Metcalf et al., 2015).
ipmr manages these key details while providing the user flexibility in their models. ipmr uses the rlang package for metaprogramming (Henry & Wickham, 2020), which enables ipmr to provide a miniature domain-specific language for implementing IPMs. ipmr aims to mimic the mathematical syntax that describes IPMs as closely as possible (Figure 1; Box 1; Tables 1 and 2). This R package can handle models with individuals classified by a mixture of any number of continuously and discretely distributed traits. Furthermore, ipmr introduces specific classes and methods to deal with both discretely and continuously varying stochastic environments, density-independent and -dependent models, as well as age-structured populations (Case Study 2). ipmr decouples the parameterization (i.e. regression model fitting) and implementation steps (i.e. converting the regression parameters into a full IPM), and does not attempt to help users with the parameterization task. This provides greater flexibility in modelling trait–demography relationships, and enables users to specify IPMs of any functional form that they desire.










Math formula | R formula | ipmr |
---|---|---|
![]() |
size_2 ~ size_1, family =gaussian() | mu_G = G_int + G_slope * z |
![]() |
G = dnorm(z_2, mu_G, sd_G) | G = dnorm(z_2, mu_G, sd_G) |
![]() |
surv ~size_1, family = binomial() | s = plogis(s_int + s_slope * z) |
![]() |
fec ~size_1, family = poisson() | r_n = exp(r_n_int + r_n_slope * z) |
![]() |
repr ~ size_1, family = binomial() | r_p = plogis(r_p_int + r_p_slope * z) |
![]() |
dnorm(z_2, mu_f_d, sigma_f_d) | r_d = dnorm(z_2, f_d_mu, f_d_sigma) |
![]() |
p_r = n_new_recruits / n_flowers | p_r = n_new / n_flowers |
![]() |
P = s * G | |
![]() |
F = r_p * r_n * r_d * p_r | |
![]() |









Math formula | R formula | ipmr |
---|---|---|
![]() |
surv ~ size_1 + age, family = binomial() | s_age = plogis(s_int + s_z * z_1 + s_a * age) |
![]() |
G = dnorm(size_2, mu_G_age, sigma_G) | G_age = dnorm(z_2, mu_G_age, sigma_G) |
![]() |
size_2 ~ size_1 + age, family = gaussian() | mu_G_age = G_int + G_z * z + G_a * age |
![]() |
repr ~size_1 + age, family = binomial() | m_p_age = plogis(m_p_int + m_p_z * z + m_p_a * age) |
![]() |
recr ~age, family = binomial() | r_p_age = plogis(r_p_int + r_p_a * age) |
![]() |
b = dnorm(size_2, mu_rc_size, sigma_rc_size) | rc_size = dnorm(z_2, mu_rc_size, sigma_rc_size) |
![]() |
rc_size_2 ~ size_1, family = gaussian() | mu_rc_size = rc_size_int + rc_size_z * z |
![]() |
P_age = s_age * g_age * d_z | |
![]() |
F_age = s_age * f_p_age * r_p_age * rc_size / 2 | |
![]() |
||
![]() |
||
![]() |
BOX 1. Code to implement a simple IPM from parameter estimates in ipmr. Because ipmr does not include functions to assist with regression modelling, this example skips the step of working with actual data and instead uses hypothetical parameter values. We see that given this set of conditions, if nothing were to change, the population would increase by ~2% each year. The case studies provide details on further use cases and analyses that are possible with ipmr.
-
library(ipmr)
-
# This section produces the result of Step 1 in Figure 1.
-
data_list <- list(
-
s_i = -0.65, # Intercept of the survival model (Logistic regression)
-
s_z = 0.75, # Slope of the survival model
-
G_i = 0.96, # Intercept of the growth model (Gaussian regression)
-
G_z = 0.66, # Slope of the growth model
-
sd_G = 0.67, # Standard deviation of residuals of growth model
-
mu_r = -0.08, # Mean of the recruit size distribution
-
sd_r = 0.76, # Standard deviation of the recruit size distribution
-
r_n_i = -1, # Intercept of recruit production model (Poisson regression)
-
r_n_z = 0.3 # Slope of recruit production model.
-
)
-
# Step 2 in Figure 1. This is how ipmr initializes a model object.
-
# All functions prefixed with define_* generate proto_ipm objects. These
-
# are converted into IPMs using the make_ipm() function in step 5.
-
example_proto_ipm <- init_ipm(sim_gen = "simple",
-
di_dd = "di",
-
det_stoch = "det")
-
# Step 3 in Figure 1. Note the link between how the model was defined
-
# mathematically and how it is defined here.
-
example_proto_ipm <- define_kernel(
-
example_proto_ipm,
-
name = "P",
-
formula = surv * Grow,
-
surv = plogis(s_i + s_z * z_1),
-
Grow = dnorm(z_2, mu_G, sd_G),
-
mu_G = G_i + G_z * z_1,
-
data_list = data_list,
-
states = list(c("z"))
-
)
-
example_proto_ipm <- define_kernel(
-
example_proto_ipm,
-
name = "F",
-
formula = recr_number * recr_size,
-
recr_number = exp(r_n_i + r_n_z * z_1),
-
recr_size = dnorm(z_2, mu_r, sd_r),
-
data_list = data_list,
-
states = list(c("z"))
-
)
-
# Step 4 in Figure 1. These next 3 functions define:
-
# 1. The numerical integration rules and how to iterate the
-
# model (define_impl).
-
# 2. The range of values the the trait "z" can take on, and the number of
-
# meshpoints to use when dividing the interval (define_domains).
-
# 3. The initial population state (define_pop_state).
-
example_proto_ipm <- define_impl(
-
example_proto_ipm,
-
list(
-
P = list(int_rule = "midpoint", state_start = "z", state_end = "z"),
-
F = list(int_rule = "midpoint", state_start = "z", state_end = "z")
-
)
-
)
-
example_proto_ipm <- define_domains(
-
example_proto_ipm,
-
z = c(-2.65, 4.5, 250) # format: c(L, U, m), m is number of meshpoints
-
)
-
example_proto_ipm <- define_pop_state(
-
example_proto_ipm,
-
n_z = rep(1/250, 250)
-
)
-
# Step 5 in Figure 1.
-
example_ipm <- make_ipm(example_proto_ipm)
-
# Step 6 in Figure 1.
-
lambda(example_ipm)
2 TERMINOLOGY AND IPM CONSTRUCTION









































Equations 1 and 2 are an example of a simple IPM. A critical aspect of ipmr's functionality is the distinction between simple IPMs and general IPMs. A simple IPM incorporates a single continuous state variable. Equations 1 and 2 represent a simple IPM because there is only one continuous state, , and no additional discrete states. A general IPM models one or more continuous state variables, and/or discrete states. General IPMs are useful for modelling species with more complex life cycles. Many species’ life cycles contain multiple life stages that are not readily described by a single state variable. Similarly, individuals with similar trait values may behave differently depending on environmental context. For example, Bruno et al. (2011) modelled aspergillosis impacts on sea fan coral Gorgonia ventalina population dynamics by creating a model where colonies were cross classified by tissue area (continuously distributed) and infection status (a discrete state with two levels—infected and uninfected). Coulson et al. (2010) constructed a model for Soay sheep where the population was structured by body weight (continuously distributed) and age (discrete state). Mixtures of multiple continuous and discrete states are also possible. Indeed, the vital rates of many species with complex life cycles are often best described with multivariate state distributions (Caswell & Salguero-Gómez, 2013). A complete definition of the simple/general distinction is given in Ellner et al. (2016, Chapter 6).
2.1 A brief worked example of a simple IPM
Box 1 shows a brief example of how ipmr converts parameter estimates into an IPM. Perhaps the most frequently used metric derived from IPMs is the asymptotic per-capita population growth rate (, Caswell, 2001). When
, the population is growing, while
indicates population decline. ipmr makes deriving estimates of
straightforward. Box 1 demonstrates how to parameterize a simple, deterministic IPM and estimate
. The example uses a hypothetical species that can survive and grow, and reproduce sexually (but not asexually, so
in Equation 2). The population is structured by size, denoted
and
, and there is no seedbank.







The code in Box 1 substitutes the actual probability density function (dnorm()) for and
, and uses inverse link functions instead of link functions. Otherwise, the math and the code should look quite similar.
2.2 Case study 1: A simple IPM
One use for IPMs is to evaluate potential performance and management of invasive species in their non-native range (e.g. Erickson et al., 2017). Calculating sensitivities and elasticities of to kernel perturbations can help identify conservation management strategies (Baxter et al., 2006; Caswell, 2001; de Kroon et al., 1986; Ellner et al., 2016). Bogdan et al. (2021) constructed a simple IPM for a Carpobrotus species growing north of Tel Aviv, Israel. The model includes four regressions, and an estimated recruit size distribution. Table 1 provides the mathematical formulae, the corresponding R model formulae and the ipmr notation for each one. The case study materials also offer an alternative implementation that uses the generic predict() function to generate the same output. The final part of the case study provides examples of functions that compute kernel sensitivity and elasticity, the per-generation growth rate, and generation time for the model, as well as how to visualize these results.
2.3 Case study 2: A general age × size IPM
We use an age- and size-structured IPM from Ellner et al. (2016) to illustrate how to create general IPMs with ipmr. This case study demonstrates the suffix syntax for vital rate and kernel expressions, which is a key feature of ipmr (highlighted in bold in the ‘ipmr’ column in Table 2). The suffixes appended to each variable name in the ipmr formulation correspond to the subscript- and/or superscript used in the mathematical formulation. ipmr internally expands the model expressions and substitutes the range of ages and/or grouping variables in for the suffixes. This allows users to specify their model in a way that closely mirrors its mathematical notation, and saves users from the potentially error-prone process of re-typing model definitions many times or using for loops over the range of discrete states. The case study then demonstrates how to compute age-specific survival and fertility from the model outputs.
3 DISCUSSION OF ADDITIONAL APPLICATIONS
We have shown above how ipmr handles a variety of model implementations that go beyond the capabilities of existing scripts and packages. The underlying implementation based on metaprogramming should be able to readily incorporate future developments in parameterization methods. Regression modelling is a field that is constantly introducing new methods. As long as these new methods have functional forms for their expected value (or a function to compute them, such as predict()), ipmr should be able to implement IPMs using them.
Finally, one particularly useful aspect of the package is the proto_ipm data structure. The proto_ipm is the common data structure used to represent every model class in ipmr and provides a concise, standardized format for representing IPMs. Furthermore, the proto_ipm object is created without any raw data, only functional forms and parameters. We are in the process of creating the PADRINO IPM database using ipmr and proto_ipms as an ‘engine’ to re-build published IPMs using only functional forms and parameter estimates. This database could act as an IPM equivalent of the popular COMPADRE and COMADRE matrix population model databases (Salguero-Gómez et al., 2016; Salguero-Gómez et al., 2014). Recent work has highlighted the power of syntheses that harness many structured population models (Adler et al., 2014; Compagnoni et al., 2021; Salguero-Gómez et al., 2016). Despite the wide variety of models that are currently published in the IPM literature, ipmr's functional approach is able to reproduce nearly all of them without requiring any raw data at all.
ACKNOWLEDGEMENTS
We thank the Associate Editor and two anonymous reviewers for comments that greatly improved this manuscript.
CONFLICTS OF INTEREST
The authors declare no conflicts of interest.
AUTHORS' CONTRIBUTIONS
All authors contributed to package design. S.C.L. implemented the package. All authors wrote the first draft of the manuscript and contributed to revisions.
Open Research
PEER REVIEW
The peer review history for this article is available at https://publons.com/publon/10.1111/2041-210X.13683.
DATA AVAILABILITY STATEMENT
The Carpobrotus dataset is included in the ipmr R package. The package is available on GitHub at https://github.com/levisc8/ipmr, CRAN at https://cran.r-project.org/web/packages/ipmr/index.html (Levin et al., 2021), and Zenodo at https://doi.org/10.5281/zenodo.5095062 (Levin, 2021). The paper and case studies do not use any other data.