Skip to content
Daniel Wagner edited this page Jul 3, 2023 · 5 revisions

rFVS R Package

Introduction

This Wiki page discusses the use of FVS within the R System for Statistical Computing. As stated in the discussion of the FVS Application Program Interface, using FVS as a shared library requires that the library be loaded and called from a parent program -- here, the parent is R.

What follows is a description of each of several R functions that are in the rFVS portion of the open-fvs repository. This Wiki page serves as the documentation to that collection of functions.

This is experimental work that is subject to change, particularly with respect to adding functions.

NOTE: The source code for rFVS is contained within the Forest Vegetation Simulator - Interface Repository

Getting Started

Notation Used Below

  • The code blocks specify commands entered into R.
  • The notation <open-fvs-interface>/ defines the directory where the open-fvs interface code is stored on your system. Modify this string so that the path name to the files can be found.

DLL Architecture and SQLite Data Format

The FVS DLLs distributed by the FVS staff are 64 bit, and require that you use the 64-bit version of R 4.0.0 or newer. These DLLs (installed to ../FVS/FVSbin) are also "SQLite-direct", meaning that your input data must be in SQLite format ( .db). The new FVS interface converts valid non-SQLite databases types into the required .db format. Once uploaded and installed you can download the database needed for your rFVS runs. The general process is to:

  1. Upload and install the database by going to Upload Data > Upload inventory data and perform Steps 1 & 2.
  2. Download the converted input database by going to Tools > Downloads > Click the “Input data base (all data)” button.

DLL provenance

rFVS is able to make use of DLLs created with the rTools (BuildProcess Rtools) tool chain or the tool chains based on Cmake: MinGW and Unix-alike. Note that the FVS staff generally uses the make utility with Rtools and therefore they are well maintained.

So far, it has not been possible to use rFVS with DLLs created with the Visual Studio 2010 tool chain. The low level incompatibility is related to differences in the way API references are stored by different compilers: upper-case for VS2010 and lower-case for all others. Another possible incompatibility may be differences in the location of underscore decorations in the binaries. In any case, it is simple for Visual Studio developers to create deployable components with MinGW or Unix tools after developing with VS2010.

Whichever valid tool chain you use, rFVS must be able to locate and load and run the .dlls associated with the tool chain. Please see the relevant wiki page to locate the names of the FVS DLLs created by your tool chain. As well, you will need to load the names of any compiler-specific redistributable DLLs which may be needed. These are documented under the "Redistributable" heading for each tool chain. As rFVS is developed further, some of these loading steps will likely become more automated.

Start up

The first step is to start R and load the the rFVS package. The "unpackaged" rFVS functions found in <open-fvs-interface>/rFVS/R. Remember to replace the string <open-fvs-interface> with the pathname of where you have stored your copy of FVS. If you have the rFVS package you would simply load it using the R library("rFVS") command.

sdir = "<open-fvs-interface>/rFVS/R"
for (rf in dir (sdir)) source (paste(sdir,rf,sep="/"))

The second step is to load the FVS shared library. A function has been provided to accomplish this task.

fvsLoad("FVSie")

The preceding command assumes that program FVSie has been built as a shared library using the rTools tool chain.

As an alternative way to load the shared libraries, the relative or complete path name of the bin can be specified. This step may be important if you are working within R Studio, which might define the working directory differently from the <open-fvs-interface>/rFVS/R path. Documentation for this function is provided below.

fvsLoad("FVSie", bin="<open-fvs>/trunk/bin")

rFVS Function Reference

The following is a list of the R functions that call FVS API member functions as needed; consult the API for more information on the functions used.

fvsAddActivity(year,activity,parms=NULL)

fvsAddActivity(year,activity,parms=NULL)

Add an an FVS Activity to the activity schedule.

Arguments:

Argument Name Description
year Year the activity is scheduled to be accomplished
activity Can be either an FVS activity code (which is a number recognized by the FVS activity processing code) or a character string corresponding the FVS keyword used to schedule the activity. If a keyword is specified, this function translates it to the necessary numeric code. Not all of the possible keyword/code pairs are programmed, but those that control the harvesting logic plus the establishment model PLANT and NATURAL keywords are.
parms Numeric vector of parameters (if any are needed) associated with the keyword. These must be in order and have values FVS can use. Error checking is not done as is the case when keywords are entered into FVS via the keyword file.

Return value:

An integer flag with the value 0 if the activity was added and 1 if there was some error.

fvsAddTrees(newtrees)

fvsAddTrees(newtrees)

Add new tree records to an existing simulation. Designed to be used to simulate regeneration establishment.

Argument:

A dataframe that has values defined for the following attributes of new trees.

Name Description
dbh Diameter breast height (inches)
species FVS numeric species code
ht Height (feet)
cratio Crown ratio (proportion of height in live crown)
plot FVS numeric plot index
tpa Trees per acre

Return value:

A scalar integer with the return code from FVS where 0 signals trees were added and 1 signals an error.

fvsCompositeSum(sumList)

fvsCompositeSum(sumList)

Argument:

A list of summary statistics tables as returned by fvsGetSummary().

Return value:

A named list of 4 matrices. Each matrix contains entries only for the years that are in common to all of the summary tables in sumList. The matrices are as follows:

Name Description
sumTable The weighted average of the individual summary tables, with the same column headings
ForType The column headings are the unique forest type codes found in the data and the data are the sum of the corresponding sampling weights.
SizeCls The column headings are the unique size classes found in the data and the data are the sum of the corresponding sampling weights.
StkCls The column headings are the unique stocking classes found in the data and the data are the sum of the corresponding sampling weights.

Also see: fvsSetupSummary(sumTable)

fvsGetDims()

fvsGetDims()

Return value:

A named vector of integers as follows: ntrees, ncycles, nplots, maxtrees, maxspecies, maxplots, maxcycles.

fvsGetSVSDims()

fvsGetSVSDims()

Return value:

A named vector of integers as follows: nsvsobjs, ndeadobjs, ncwdobjs, mxsvsobjs, mxdeadobjs, mxcwdobjs.

fvsGetEventMonitorVariables(vars)

fvsGetEventMonitorVariables(vars)

Argument:

A scalar or vector of strings whereby each string names an FVS Event Monitor for which the value will be returned.

Return value:

A named vector of values. The values will be NA if they were not defined.

Also see: fvsSetEventMonitorVariables(vars)

fvsGetRestartcode()

fvsGetRestartcode()

Provides an R interface to Fortran function fvsGetRestartcode.

Return value:

The FVS restart codes (integer).

fvsGetSpeciesCodes()

fvsGetSpeciesCodes()

Return value:

A matrix of character strings with one row for each species and three columns. The column names fvs, fia, plant correspond to the three kinds of species codes used in FVS. The order is exactly as presented in the FVS variant which means, for example, that row 1 corresponds to the internal FVS species index number 1, row 2 for species 2 and so on.

fvsGetStandIDs()

fvsGetStandIDs()

Return value:

A named vector of three strings with names standid, standcn, and mgmtid.

fvsGetSummary()

fvsGetSummary()

Return value:

A matrix of integer values with one row for each completed FVS cycle. The columns are named as documented in the FVS Summary Statistics.

Also see: fvsSetupSummary(sumTable) and fvsCompositeSum(sumList)

fvsGetSpeciesAttrs(vars)

fvsGetSpeciesAttrs(vars)

Argument:

A vector of strings whereby each string names an attribute to be returned. The names can be one or more of the following:

Attribute Name Description
spccf CCF for each species, recomputed in FVS so setting will likely have no effect
spsdi SDI maximums for each species
spsiteindx Species site indices

Return value:

A dataframe of numeric values with one row for each species and a column for each attribute.

Also see: fvsSetSpeciesAttrs(vars)

fvsGetTreeAttrs(vars)

fvsGetTreeAttrs(vars)

Argument:

A vector of strings whereby each string names an attribute to be returned. The names can be one or more of the following:

Attribute Name Description
id Tree identification number (may not be unique)
species FVS numeric species code
tpa Trees per acre
mort Trees per acre predicted to die
dbh Diameter breast height (inches)
dg Diameter growth scaled to cycle length (inches)
ht Height (feet)
htg Height growth scaled to cycle length (feet)
crwdth Crown width (feet)
cratio Crown ratio (proportion of height in live crown)
age Tree age
plot FVS numeric plot index
tcuft Total cubic volume
mcuft Merch cubic volume
bdft Board foot volume
ptbal Point basal area in larger trees (sq ft/acre)
bapctile Percentile in the distribution of tree basal area
defect Defect coded as 11223344 as described below
mgmtcd Tree value class or management code (1, 2, or 3)
plotsize Size of plot tree was sampled from
crownwt0 Weight of foliage (pounds)
crownwt1 Weight of 0-.25 inch crown material (pounds)
crownwt2 Weight of .25-1 inch crown material (pounds)
crownwt3 Weight of 1-3 inch crown material (pounds)
crownwt4 Weight of 3-6 inch crown material (pounds)
crownwt5 Weight of 06-12 inch crown material (pounds)

Return value:

A dataframe of numeric values with one row for each tree and a column for each attribute.

The defect value is an 8-digit code comprised of four 2-digit code segments strung together. Each 2-digit segment represents a different defect, as described below.

defect code segment Definition
first and second digits input merchantable cubic volume defect percent
third and fourth digits input board foot defect percent
fifth and sixth digits applied merchantable cubic volume defect percent
seventh and eighth digits applied board foot defect percent

Also see: fvsSetTreeAttrs(vars)

fvsInteractRun (...)

fvsInteractRun (...)

This function is used to provide for functional interaction between R and FVS. Most of the arguments (all those listed in the table below), when specified, refer to names of stop points; each provides R code that is run when the stop point is reached. One additional optional argument may be added that that is trace=[TRUE|FALSE]. When trace=TRUE is specified, informative messages are output during the function call. Setting trace=FALSE has the same effect as not specifying it at all.

Argument Name Definition
BeforeEM1 R code to run at the stop point just before the first call to the Event Monitor
AfterEM1 R code to run at the stop point just after the first call to the Event Monitor
BeforeEM2 R code to run at the stop point just before the second call to the Event Monitor
AfterEM2 R code to run at the stop point just after the second call to the Event Monitor
BeforeAdd R code to run at the stop point after growth and mortality has been computed, but prior to applying them
BeforeEstab R code to run at the stop point just before the Regeneration Establishment Model is called
SimEnd R code to run at the stop point at the end of one stand's simulaton and prior to the beginning of the next

The value of arguments can be either:

  1. a quoted character string containing a valid R expression (more than one can be specified if separated by semicolons (;), or
  2. an R function with no arguments. The expression is evaluated (or the function is called) when the corresponding stop point is reached.

Note that using fvsInteractRun() without arguments is functionally equivalent to using fvsRun() without arguments.

Return value:

A named list where the names are automatically generated using the standid, mgmtid, and year. In the case where the return value corresponds to the end of the simulation, the string SimEnd is used in place of year.

The objects in this returned list are also a named lists. Each contains the values of the expressions (or functions) when they are computed. The values are named using the argument names.

Example 2 provides a simple example of using this function.

Also see: fvsRun()

fvsLoad(fvsProgram,bin="../../trunk/bin")

fvsLoad(fvsProgram,bin="../../trunk/bin")

This function loads the FVS dynamic library specified in the first argument. It has the side effect of creating an object in the R global environment called .FVSLOADEDLIBRARY that contains the names of the libraries loaded by the call. If .FVSLOADEDLIBRARY exists when this function is called, the libraries that are already loaded are unloaded prior to the specified libraries being loaded.

Return value:

A copy of .FVSLOADEDLIBRARY is invisibly returned.

fvsRun()

fvsRun(stopPointCode=NA,stopPointYear=NA)

Arguments:

Note: If one of these arguments is left as NA (the default), then both are ignored. That is, you must code both or neither.

Argument Name Description
stopPointCode The value of the next stop point, see Stop Points for a list of valid codes.
stopPointYear The simulation year the stop point is requested. Code -1 to signal the that the stop point should be immediate.

Return value:

A return code from FVS, see Return code state.

If the return code is zero, then it is often very useful to use fvsGetRestartcode() to fetch the restart code that resulted in FVS returning. When fvsRun() is called again, it will continue processing where it left off. Repeating the call to fvsRun() until it is non-zero is how to create a simple simulation.

fvsSetCmdLine(cl = NULL)

fvsSetCmdLine(cl = NULL)

Sets the command line to the values listed of the FVS Command Line and opens files for input as indicted by the values found. This routine can result in the FVS return code state to be reset.

Argument:

A character string that contains the command line arguments. If NULL (the default), the function attempts to fetch the arguments as they may be specified on the command that starts R. This is done by calling the R function commandArgs(trailingOnly = TRUE), see R documentation for details.

Return value:

The passed argument is returned.

fvsSetEventMonitorVariables(vars)

fvsSetEventMonitorVariables(vars)

This function sets the values of Event Monitor variables. Generally, however, many of the variables are reset to by FVS when the Event Monitor is called each cycle (before and after simulated harvests). This is especially true of those automatic variables defined during the first and second calls to the Event Monitor (consult FVS documentation). Therefore setting the value of these variables may be in effective in meeting useful goals.

One use of this function is to set user-defined variables (those traditionally defined using the FVS Compute keyword). If a Event Monitor variable that has the name given in the names attribute of the vars argument is not found, one is created. If a user-defined variable has already been defined, it is given a new value when this function is called.

Argument:

A vector of named numeric values where the names are FVS Event Monitor variable names that will take on the corresponding values.

Return value:

A named vector of values. The values will be NA if they were not defined.

Also see: fvsGetEventMonitorVariables(vars)

fvsSetSpeciesAttrs(vars)

fvsSetSpeciesAttrs(vars)

Argument:

A named list of vectors (or a dataframe) where each vector (or column) is:

  1. of numeric type
  2. has no NAs
  3. has as many entries as there are defined species (variable maxspecies from fvsGetDims()). Use the variable names listed for fvsGetSpeciesAttrs(vars). Vectors or columns that have other names are skipped.

Return value:

A scalar integer return code where 0 signals OK and 1 signals an error).

Also see: fvsGetSpeciesAttrs(vars)

fvsSetTreeAttrs(vars)

fvsSetTreeAttrs(vars)

Argument:

A named list of vectors (or a dataframe) where each vector (or column) is:

  1. of numeric type
  2. has no NAs
  3. has as many entries as there are defined trees (variable ntrees from fvsGetDims()). Use the listed for fvsGetTreeAttrs(vars). Vectors or columns that have other names are skipped.

Return value:

A scalar integer return code where 0 signals OK and 1 signals an error (or warnings).

Also see: fvsGetTreeAttrs(vars)

fvsSetupSummary(sumTable)

fvsSetupSummary(sumTable)

Adds extra data to the summary statistics table returned by function fvsGetSummary(). The extra data include new columns showing total production of trees and volume plus new rows so that years with removals have two data points, one for before and the after the harvest.

Argument: A matrix as returned by fvsGetSummary() or the summary table returned by fvsCompositeSum(sumList).

Return value:

A matrix with additional columns and rows (if there were harvests in the run).

fvsUnitConversion(name)

fvsUnitConversion(name)

Argument:

A case sensitive character string naming a conversion factor to be returned. See Return Unit Conversions for a list of valid codes.

Return value:

A scalar numeric value; NA if the name is not valid.

Run Examples

Example code is like a photograph: a few lines of working code are worth a 1,000 words of explanation. Note that these examples are all run with program FVSie, it is left as an exercise to adapt them to your situation.

Example 1 Simple run

Here is a simple run of one stand simulated with three different prescriptions. The keyword file and tree data for this run are in the <open-fvs>/rFVS/tests/ directory. That directory is set as the working directory prior to any other commands being entered. This run is the same as that found in <open-fvs>/trunk/tests/FVSie, but in that case the run is done using the FVSie program rather than the shared library.

:::R
setwd ("<open-fvs>/rFVS/tests")  # Note: edit <open-fvs> to reflect your system. This directory string should be wherever 
# your keyword file and input data are loacted

# load the R functions using this method (if you don't have the rFVS package)
sdir = "../R"        # Note: this directory string should be wherever the rFVS functions are located
for (rf in dir (sdir)) source (paste(sdir,rf,sep="/"))

# or, if the rFVS package is installed, then just enter
library(rFVS)

# load the FVS library
fvsLoad("FVSie", bin="<open-fvs>/trunk/bin")    # Note: edit <open-fvs> to reflect your system. This directory string should 
# be wherever your FVS shared libraries are located

# specify the keyword file
fvsSetCmdLine("--keywordfile=iet01.key")

# Run the simulation as would be done using FVS as a program
fvsRun()

Example 2 R-FVS Interaction with Graphics

The simple run in Example 1 is revisited to illustrate how to interact with FVS during the simulation. Here, the function fvsInteractRun() is used in place of fvsRun() because it provides a simple-to-use scheme for including interaction between FVS and R.

The goal of the run is to capture two types of data from FVS so that it can be used for plotting after the simulation is completed. The first type is a set of six data frames containing tree heights, diameters, and species codes. There is one of these data frames for each of the 3 management alternatives captured at 2 points in time (2020 and 2070). The second set includes the summary statistics tables captured at the end of the simulations.

The tree-by-tree data are captured using a function we specify (as shown in the example code).

The R code below assumes that the same set up steps used in Example 1 are used up to the fvsSetCmdLine() command.

:::R
# specify the keyword file

fvsSetCmdLine("--keywordfile=iet01.key")

# define a function that will be called after the first call to the Event
# Monitor. This function returns a data frame that contains the dbh, ht, and
# species of each tree. It takes one argument which is a vector of years
# corresponding to the years the data frame is desired. NULL is returned
# in all other years.

fetchTrees <- function (captureYears)
{
  curYear <- fvsGetEventMonitorVariables("year")
  if (is.na(match(curYear,captureYears))) NULL else
      fvsGetTreeAttrs(c("dbh","ht","species"))
}

# run the simulation and capture the data. Note that the first argument
# is a string of R code that is evaluated at each stop point and the
# second is a function that contains no arguments.

output <- fvsInteractRun(AfterEM1="fetchTrees(c(2020,2070))",
                         SimEnd=fvsGetSummary)

Here, the captured output is used to create plots. The first set is a panel of six height/diameter scatter plots corresponding to the three management alternatives and two points in time captured in the output data frame.

Here are the commands to make the scatter plots:

:::R
# separate the tree list information from the summary statistics so that
# the following code is easier to follow.

treeLists    <- output[-grep("SimEnd",names(output))]
summaryStats <- output[ grep("SimEnd",names(output))]

# find global values for axes limits. Note that the default name
# given to the value returned from  is "AfterEM1"
xlim <- range(unlist(lapply(treeLists,function (x) range(x[["AfterEM1"]][,"dbh"]))))
ylim <- range(unlist(lapply(treeLists,function (x) range(x[["AfterEM1"]][,"ht"]))))

# there are 6 plots, arrange them in 3 rows, 2 cols
# for saving plot: png(file="rFVS_ex2A.png",pointsize=8,height=3.5,width=2.5,units="in",res=200)
X11(height=3.5,width=2.5,pointsize=8)
par(mar=c(3,3.8,3,1)+.1)
layout(mat=matrix(1:6,3,2,byrow=TRUE))

for (caseID in names(treeLists))
{
  atts <- treeLists[[caseID]][["AfterEM1"]]
  plot(atts[,c("dbh","ht")],col=atts[,"species"],xlim=xlim,ylim=ylim,main=caseID,
       xlab="D.B.H. (inches)",ylab="Height (feet)")
}
#for saving plot: dev.off()

The second plots show standing cubic volume and total production of total cubic volume over time. There are three plots, one for each alternative. The plots share the same scaling; also note that not all of the simulations are the same length.

The summary statistics table provided by FVS is not set up for simple plotting. The function fvsSetupSummary() (described above) is used to compute a matrix of values suitable for plotting.

:::R
# set up the summary statistics tables for plotting
sumToPlot <- lapply(summaryStats,fvsSetupSummary)

# find global range
yrRange    <- range(unlist(lapply(sumToPlot,function (x) range(x[,"Year"]))))
tcuftRange <- range(unlist(lapply(sumToPlot,function (x) range(x[,"TPrdTCuFt"]))))

# for saving plot: png(file="rFVS_ex2B.png",pointsize=8,height=1.5,width=4,units="in",res=200)
X11(height=1.5,width=4,pointsize=8)
par(mar=c(3,3.8,3,1)+.1,mfcol=c(1,3))

for (caseID in names(sumToPlot))
{
  mainLab <- sub(":SimEnd","",caseID) #remove SimEnd for a plot title.
  plot(TPrdTCuFt ~ Year, data=sumToPlot[[caseID]], xlim=yrRange, ylim=tcuftRange,
       type="b",main=mainLab,col="green",ylab="Total cubic volume per acre")
  lines(TCuFt    ~ Year, data=sumToPlot[[caseID]], xlim=yrRange, ylim=tcuftRange,
       type="b",col="red")
}
#for saving plot: dev.off()
Clone this wiki locally