We use github issues for feature requests, bug reports and developer coordination.
We use the Gitflow workflow. This means we have two main branches:
master
) for stable releasesdevelop
) where all development takes placeWe 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.
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 filesattributes
: 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
attributeroxygen
: Compiles the documentation for Rtest
Run the test suitecheck
: Checks plant for common problemsclean
: Deletes *.o
and *.so
files that were produced when compiling the packagevignettes
: Builds the vignetteswebsite
: Makes the website using pkgdownplant
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.
The code is organised as follows. This structure reflects structure generally used for R packages including C++ source.
├── docker # Docker files
│ └── plant-test
├── inst
│ ├── RcppR6_classes.yml # Used by RCppR6 to generate the interface for Rcpp (C++ classes)
│ ├── RcppR6_functions.yml # Used by RCppR6 to generate the interface for Rcpp (C++ function)
│ ├── include
│ │ ├── plant.h # THE main header file for package - sources other headers
│ │ ├── plant # header (.h) files for different components, many including implementation
│ │ └── tk # simple cubic spline interpolation library
│ ├── reference_plant_ff16 # Reference plant physiology ff16
│ ├── docs # Files for building the documentation
│ ├── scripts # Tools used in package management
│ └── website # Reference plant physiology ff16
├── man # R Documentation files (*.Rd)
├── R # R functions
├── scripts # R scripts
├── src # C++ files with implementation where not included in headers
├── tests # Tests
└── vignettes # Empty until the documentation is built
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:
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:
plant_runner.h plant_tools.h scm_utils.h
stochastic_patch_runner.h stochastic_patch.h stochastic_species.h stochastic_utils.h
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
.
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 test
to 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.
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)