Skip to contents

Larger-than-RAM methods

The sheer size of the FIA Database can present a serious challenge for many users interested in performing regional studies (requiring a large subset of the database). Recent updates to rFIA are intended to reduce these barriers.

Namely, we’ve implemented “larger-than-RAM” methods for all rFIA estimator functions. In short, behind the scenes we read the necessary tables for individual states into RAM one at a time and summarize to the estimation unit level (always sub-state and mutually exclusive populations, hence additive properties apply). We save the estimation unit level results for each state in RAM, and combine them into the final output once we’ve iterated over all states. This may sound complicated, but fortunately these “larger-than-RAM” methods use the exact same syntax as normal “in-memory” operations.

To get started, we simply have to set up a Remote.FIA.Database in place of our regular in-memory FIA.Database by setting inMemory=FALSE in our call to readFIA():

library(rFIA)
# Download data for two small states
getFIA(c('RI', 'CT'), dir = 'path/to/save/', load = FALSE)

# Now set up a Remote.FIA.Database with readFIA by setting inMemory = FALSE
# Instead of reading in the data now, readFIA will simply save a pointer
# and allow the estimator functions to read/process the data state-by-state
fia <- readFIA('path/to/save/', inMemory = FALSE)
class(fia)
## [1] "Remote.FIA.Database"

Once set up, our Remote.FIA.Database will work exactly the same as we are used to. That is, we can use the same syntax we have been using for normal, in-memory operations. For example, to estimate biomass using our Remote.FIA.Database:

# Estimate biomass with Remote.FIA.Database
biomass(db = fia)
## # A tibble: 21 × 5
##     YEAR BIO_ACRE BIO_ACRE_SE nPlots_TREE nPlots_AREA
##    <dbl>    <dbl>       <dbl>       <int>       <int>
##  1  2005     70.6        3.19         219         223
##  2  2006     71.1        2.65         325         331
##  3  2007     71.0        2.26         436         442
##  4  2008     71.8        2.21         425         430
##  5  2009     73.6        2.24         419         425
##  6  2010     75.1        2.21         422         426
##  7  2011     76.1        2.18         435         441
##  8  2012     77.1        2.15         441         446
##  9  2013     77.3        2.12         438         443
## 10  2014     77.8        2.12         439         444
## # ℹ 11 more rows
# All the extra goodies work the same:
# By species
biomass(fia, bySpecies = TRUE)
## # A tibble: 1,373 × 8
##     YEAR  SPCD COMMON_NAME      SCIENTIFIC_NAME BIO_ACRE BIO_ACRE_SE nPlots_TREE
##    <dbl> <dbl> <chr>            <chr>              <dbl>       <dbl>       <int>
##  1  2005    10 fir spp.         Abies spp.      0.000761       100.            1
##  2  2005    43 Atlantic white-… Chamaecyparis … 0.00398         99.9           1
##  3  2005    68 eastern redcedar Juniperus virg… 0.517           29.4          20
##  4  2005    91 Norway spruce    Picea abies     0.00445        100.            1
##  5  2005    97 red spruce       Picea rubens    0.0155         100.            1
##  6  2005   125 red pine         Pinus resinosa  0.0300         100.            1
##  7  2005   126 pitch pine       Pinus rigida    0.417           58.4           6
##  8  2005   129 eastern white p… Pinus strobus   3.78            20.3          59
##  9  2005   261 eastern hemlock  Tsuga canadens… 2.58            22.9          37
## 10  2005   315 striped maple    Acer pensylvan… 0.00956         77.1           3
## # ℹ 1,363 more rows
## # ℹ 1 more variable: nPlots_AREA <int>
# Alternative estimators (linear moving average)
biomass(fia, method = 'LMA')
## # A tibble: 21 × 5
##     YEAR BIO_ACRE BIO_ACRE_SE nPlots_TREE nPlots_AREA
##    <dbl>    <dbl>       <dbl>       <int>       <int>
##  1  2005     70.8        2.97         219         223
##  2  2006     71.5        2.52         320         326
##  3  2007     72.3        2.20         435         441
##  4  2008     73.6        2.38         412         417
##  5  2009     74.3        2.45         417         423
##  6  2010     76.2        2.29         421         425
##  7  2011     76.0        2.45         435         441
##  8  2012     77.6        2.52         441         446
##  9  2013     77.2        2.49         438         443
## 10  2014     78.6        2.50         439         444
## # ℹ 11 more rows
# Grouping variables
biomass(fia, grpBy = c(STDORGCD, SITECLCD))
## # A tibble: 162 × 7
##     YEAR STDORGCD SITECLCD BIO_ACRE BIO_ACRE_SE nPlots_TREE nPlots_AREA
##    <dbl>    <int>    <int>    <dbl>       <dbl>       <int>       <int>
##  1  2005        0        3    105.        12.4            4           4
##  2  2005        0        4     86.5        7.52          39          39
##  3  2005        0        5     72.9        3.45         121         124
##  4  2005        0        6     55.5        7.37          63          65
##  5  2005        0        7     45.6        9.93           3           3
##  6  2005        1        3     84.7        0              1           1
##  7  2005        1        6     10.2        6.25           2           2
##  8  2006        0        3    103.        11.4            5           5
##  9  2006        0        4     80.9        6.96          51          51
## 10  2006        0        5     75.3        2.89         186         191
## # ℹ 152 more rows

In addition, you can still specify spatial-temporal subsets on Remote.FIA.Database objects using clipFIA():

# A most recent subset with the Remote.FIA.Database
fiaMR <- clipFIA(fia)

# Biomass in most recent inventory
biomass(fiaMR)
## # A tibble: 1 × 5
##    YEAR BIO_ACRE BIO_ACRE_SE nPlots_TREE nPlots_AREA
##   <dbl>    <dbl>       <dbl>       <int>       <int>
## 1  2025     83.2        2.32         435         443

In practice, rFIA's larger-than-RAM methods make it possible for nearly anyone to work with very large subsets of FIA Database. In our testing, we have run tpa(), biomass(), dwm(), and carbon() for the entire continental US on a machine with just 16 GB of RAM (where the FIA data total ~ 50GB).

The only challenge that the Remote.FIA.Database presents is that it becomes difficult for users to modify variables in FIA tables (e.g., make tree size classes). However, it is possible to read in, modify, and save tables of interest prior to setting up a Remote.FIA.Database. For example, we can extend our example above to produce estimates of live tree biomass grouped by stand age classes, where stand age classes can be computed with makeClasses().

# Rather than read all tables into memory, just read those of interest
# In this case, we just need the COND table
modTables <- readFIA(dir = 'path/to/save/', tables = 'COND', 
                     states = c('RI', 'CT'), inMemory = TRUE)

# Now we can modify the COND table in any way we like
# Here we just add a variable that we will want to group by later
modTables$COND$STANDAGEGROUP <- makeClasses(modTables$COND$STDAGE, interval = 50)

# Now we can save our changes to the modified tables on disk with writeFIA
# This will overwrite the COND tables previously stored in our target directory
# And allow us to use our new variables in a subsequent 'Remote.FIA.Database'
writeFIA(modTables, dir = 'path/to/save/', byState = TRUE)


# Now set up the Remote database again
fia <- readFIA('path/to/save/', inMemory = FALSE)

# And produce estimates grouped by our new variable
biomass(fia, grpBy = STANDAGEGROUP)
##   [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
##  [16] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
##  [31] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
##  [46] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
##  [61] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
##  [76] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
##  [91] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [106] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [121] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [136] TRUE
## # A tibble: 88 × 6
##     YEAR STANDAGEGROUP BIO_ACRE BIO_ACRE_SE nPlots_TREE nPlots_AREA
##    <dbl> <chr>            <dbl>       <dbl>       <int>       <int>
##  1  2005 [-49,1)          12.4        80.2            3           5
##  2  2005 [1,51)           33.6        14.2           35          36
##  3  2005 [101,151)        83.2         7.39          18          19
##  4  2005 [51,101)         74.7         3.19         178         179
##  5  2006 [-49,1)          12.9        67.9            3           7
##  6  2006 [1,51)           35.7        10.5           57          59
##  7  2006 [101,151)        79.9         6.64          23          25
##  8  2006 [51,101)         76.4         2.65         261         262
##  9  2007 [-49,1)           6.19       91.0            3           9
## 10  2007 [1,51)           35.5         9.45          74          76
## # ℹ 78 more rows

Simple, easy parallelization

All rFIA estimator functions (as well as readFIA() and getFIA()) can be implemented in parallel, using the nCores argument. By default, processing is implemented serially with nCores = 1, although users may find substantial increases in efficiency by increasing nCores.

Parallelization is implemented with the parallel package. Parallel implementation is achieved using a snow type cluster on any Windows OS, and with multicore forking on any Unix OS (Linux, Mac). Implementing parallel processing may substantially decrease free memory during processing, particularly on Windows OS. Thus, users should be cautious when running in parallel, and consider implementing serial processing for this task if computational resources are limited (nCores = 1).

# Check the number of cores available on your machine 
# Requires the parallel package
parallel::detectCores()
## [1] 16
# On our machine, we have a fun 16 cores to play with. 
# To speed processing, we will split the workload 
# across 3 of these cores using nCores = 3
tpaRI_par <- tpa(fiaRI, nCores = 3)