Development

Issues

We use github issues for feature requests, bug reports and developer coordination.

Gitflow workflow

We use the Gitflow workflow. This means we have two main branches:

  1. a master branch (master) for stable releases
  2. a development branch (develop) where all development takes place

We also use feature branches which branch from the development branch where we can then introduce new features and then pull them back into the development branch.

Compiling

The makefile defines multiple targets in the package build process. These are called by running

make target_name

where target_name is the target to build. Targets are as follows:

  • all: Compiles the package and builds the function documentation to /man
  • install: Installs this package (R CMD INSTALL .)
  • build: Builds plant (R CMD build --no-build-vignettes)
  • RcppR6: Update or install RcppR6 files
  • attributes: Scans the source files for attributes and generate code as required. Generates the bindings required to call C++ functions from R for functions labelled with the Rcpp::export attribute
  • roxygen: Compiles the documentation for R
  • test Run the test suite
  • check: Checks plant for common problems
  • clean: Deletes *.o and *.so files that were produced when compiling the package
  • vignettes: Builds the vignettes
  • website: Makes the website using pkgdown

Design & Structure

plant is build as an R package using C++ code, linked via Rcpp. Rcpp provides “provides R functions as well as C++ classes which offer a seamless integration of R and C++.”

Two common challenges with using Rcpp are 1) that there is a lot of interface code (or “boilerplate”) needed, 2) Rcpp “modules” can be slow to load. To overcome these we use the package RcppR6 to generate the interface. The RcppR6 package aims to provide a simple way of generating boilerplate code for exposing C++ classes to R. It is similar in many ways to Rcpp “modules” but without the slow load time. RcppR6 creates an interface using Rcpp’s “attributes” facilities to build the actual R/C++ glue. The R6 R package is the reference class that we use for wrapping the generated class. To achieve the link, class definitions are written into a YAML file.

Templating

We use templating to enable plant to work with multiple strategies and lets us write code that is strategy generic. The templated class definitions are found in inst/include/plant and their function implementations are found either in the .h files or in /src.

We then use the RcppR6 package combined with the .h files and class definitions (found in inst/RcppR6_classes.yml) into Rcpp which we can then be used in the .R files (in /R) or exported.

Templating Resources:

Classes and their functions

The main c++ header files (i.e. *.h) are stored within the directory inst/include/plant/. In many cases, the implementations is written directly into the header files. Otherwise, the corresponding source file (i.e. *.cpp) is stored within the folder src.

The role of these different files is as follows.

strategies: ff16_strategy.h

plant.h

cohort.h

species.h

patch.h

SCM.h

Helpers:

  • parameters.h
  • cohort_schedule.h
  • control.h
  • disturbance.h
  • environment.h

plant_runner.h plant_tools.h scm_utils.h

stochastic_patch_runner.h stochastic_patch.h stochastic_species.h stochastic_utils.h

Utilities

adaptive_interpolator.h get_state.h gradient.h interpolator.h lorenz.h ode_control.h ode_interface.h ode_r.h ode_runner.h ode_solver.h ode_step.h qag_internals.h qag.h qk_rules.h qk.h

RcppR6_post.hpp RcppR6_pre.hpp RcppR6_support.hpp uniroot.h util_post_rcpp.h util.h

Strategies

The foundation of the plant package are sub-models for an individual species’ physiological strategy. The FF16 strategy is the default strategy. However, the plant package has been written to enable new physiological strategies to be added, and then use the same machinery for modelling size-structured population dynamics, we do this by using templating in C++11 (see Templating).

Adding a new physiological strategy requires some changes to be made throughout the code and then the code recompiled. To achieve this, you’ll need to download the package code from Github (new strategies cannot be added using an installed R package) and follow the instructions below.

As a naming convention, strategies are named using two initials r (eg. the first two authors) followed by a year, e.g. FF16. A single letter suffix can be added to indicate a minor modification of an existing strategy, e.g. FF16r.

Installing new strategies

Let’s assume you want to add a new strategy called XX99. To add this strategy, the following changes are required. First, some new files need to be created:

  • inst/include/plant/XX99_strategy.h (C++ header file, describing strategy)
  • src/XX99_strategy.cpp (C++ source file, describing strategy)
  • R/XX99.R (R wrapper functions for the new strategy, plus hyperparameter function)
  • tests/testthat/test-strategy-XX99.R (Tests of the new strategy)

In addition, the following files must be modified to include appropriate details for the new strategy (use the examples for FF16 as a guide):

  • inst/include/RccpR6_classes.yml
  • inst/include/plant.h
  • src/plant_plus.cpp
  • src/plant_tools.cpp
  • tests/testthat/helper-plant.R
  • R/scm_support.R (Currently uses the FF16 hyperpar and make_hyperpar)

Rather than making the above modifications by hand, you can use the scaffolder found in inst/scripts/new_strategy_scaffolder.R to create a suitable template. The scaffolder is set up to add code at appropriate points.

Before trying to install a new strategy, make sure your project is at a state where you are happy to go back to if you decide to, ie: do this in a new branch or fork. There is no easy way to undo the changes so you will have to do git reset --hard HEAD if you want to go back. You will still have to delete the new and untracked files listed above.

To install a new strategy using the scaffolder, run the following code from an R session at the project root:

source('inst/scripts/new_strategy_scaffolder.R')
create_strategy_scaffold("XX99", "FF16")

where XX99 is the name of your new strategy and FF16 is the strategy that you want to copy from. If run without FF16, the scaffolder copies from the FF16 strategy by default.

This will create the code-base for a new template. Then run make clean; make; make testto recompile and run the test suite with your new strategy template.

If that works you can then modify the files src/XX99_strategy.cpp and inst/include/plant/XX99_strategy.h to reflect any changes in biology you desire for the new strategy. If you make changes to your new strategies parameters you will have to update the files: * inst/include/RccpR6_classes.yml - see top-level section under the new strategy name, describing your parameters. * tests/testthat/test-strategy-XX99.R with suitable tests for your new strategy.

Then recompile and test as above.

After the project compiles, you will notices even more files that have changed, for example in files like NAMESPACE, R/RcppExports.R etc. These files are auto-generated and therefore modifications are triggered from files listed above.

Website

Building the website:

To build and push the website to the gh-pages branch run make website. This first builds the vignettes from /inst/docs then builds the site with pkgdown. The site is then pushed to the gh-pages branch. (https://traitecoevo.github.io/plant)