| Title: | Remote Sensing-Derived Yield Curves for Canada |
| Version: | 0.2.0 |
| Description: | Provides published remote sensing-based yield curves for aboveground biomass and total volume across Canada, as described in Tompalski et al. (2024) <doi:10.1016/j.foreco.2024.121894> and Tompalski et al. (2025) <doi:10.1093/forestry/cpaf067>. Models are available for 150 km tiles and four levels of Canada's ecological land classification. Functions help users find curves by species and area, estimate yield at a given stand age, calibrate curves to local observations, and build spatial yield-curve datasets. |
| License: | GPL (≥ 3) |
| Encoding: | UTF-8 |
| Depends: | R (≥ 4.1.0) |
| LazyData: | true |
| Imports: | digest, glue, lifecycle, magrittr, tibble |
| Suggests: | dplyr, purrr, sf, testthat (≥ 3.0.0) |
| Config/testthat/edition: | 3 |
| URL: | https://ptompalski.github.io/RSYC/, https://github.com/ptompalski/RSYC |
| BugReports: | https://github.com/ptompalski/RSYC/issues |
| Config/Needs/website: | rmarkdown, knitr, ggplot2, DT, tidyr, jsonlite, scales, ggtext, yardstick, ptompalski/scatter |
| Config/roxygen2/version: | 8.1.1 |
| NeedsCompilation: | no |
| Packaged: | 2026-10-21 22:58:11 UTC; ptompals |
| Author: | Piotr Tompalski [aut, cre, cph], His Majesty the King in Right of Canada, as represented by the Minister of Natural Resources Canada [cph] |
| Maintainer: | Piotr Tompalski <piotr.tompalski@NRCan-RNCan.gc.ca> |
| Repository: | CRAN |
| Date/Publication: | 2026-11-03 15:50:24 UTC |
RSYC: Remote Sensing-Derived Yield Curves for Canada
Description
Provides published remote sensing-based yield curves for aboveground biomass and total volume across Canada, as described in Tompalski et al. (2024) doi:10.1016/j.foreco.2024.121894 and Tompalski et al. (2025) doi:10.1093/forestry/cpaf067. Models are available for 150 km tiles and four levels of Canada's ecological land classification. Functions help users find curves by species and area, estimate yield at a given stand age, calibrate curves to local observations, and build spatial yield-curve datasets.
Author(s)
Maintainer: Piotr Tompalski piotr.tompalski@NRCan-RNCan.gc.ca [copyright holder]
Authors:
Piotr Tompalski piotr.tompalski@NRCan-RNCan.gc.ca [copyright holder]
Other contributors:
His Majesty the King in Right of Canada, as represented by the Minister of Natural Resources Canada [copyright holder]
See Also
Useful links:
Report bugs at https://github.com/ptompalski/RSYC/issues
Pass a Result to the Next Step
Description
%>% passes the result on its left to the function on its right. See
magrittr::%>% for more examples.
Usage
lhs %>% rhs
Arguments
lhs |
The result to pass forward. |
rhs |
The next function to run. |
Value
The result from the function on the right.
Published RSYC Yield-Curve Data
Description
A table containing one row for each published remote sensing-based yield curve. It includes aboveground biomass and total-volume curves fitted across Canada and within individual regions. Curves are available for tiles and four levels of Canada's ecological land classification.
Usage
RSYC_models
Format
A table with 27,208 rows and 42 columns:
- model_id, model_version
Unique name for the curve and the RSYC release in which it was published.
- response, response_units
Forest measure (
agborvolume) and its units.- strata_type, strata_level, strata_id
Type and name of the area represented by the curve.
- ecozone_id, ecoprovince_id, ecoregion_id, ecodistrict_id
Raw identifiers for the four levels of the ecological hierarchy.
ecoprovince_idis stored as character; the other three are integers. Fields above the row's ecological level, and all four fields for tile rows, may be missing.- scale, region_id
Whether the curve was fitted across Canada or within a region, and the region name where applicable.
- species, model_group
Species code or broad species group.
- equation, age_min, age_max
Curve equation and age range. Published RSYC curves were fitted for stand ages 1 to 150 years.
- b1, b2, b3, b4
Chapman-Richards curve coefficients.
- b1_se, b2_se, b3_se, b4_se, sigma
Measures of uncertainty around the fitted curve.
- parent_b1_random_effect, parent_b1_var, local_b1_var, residual_var
-
Variance components and parent effects used by local calibration and retained for model provenance.
- has_cor_struct, has_var_struct, component_ok, component_message
-
Checks recorded while each curve was fitted.
- n_obs, n_units, converged, singular_or_boundary, fit_ok, publish_ok, model_message
Number of observations and forest units, together with checks used to decide whether the curve was suitable for publication.
Source
RSYC-Canada model products, version v20260923, upstream Git commit
c799aba24b5d99a6a7953a4dcab1dd73b0925c2c; source RDS SHA-256
193ebfc1f3279ffc278d84c917d206b4b4bcaeae95f38acf25d9c84a040bd1d5.
Examples
subset(
RSYC_models,
response == "volume" & strata_level == "ecozone" & species == "PICE.MAR"
)
RSYC Tile Grid (150 x 150 km)
Description
A model-aligned GeoPackage containing one polygon or multipolygon for each
of the 385 tile IDs used by the v20260923 national RSYC models. The path can
be obtained with system.file("extdata", "RSYC_tiles.gpkg", package = "RSYC") and read with sf::st_read().
List Published RSYC Models
Description
List the published Canada-wide curves that match a forest measure, species,
type of area, or area name. Leave a choice as NULL to include all of its
available values.
Usage
available_rsyc_models(
response = NULL,
species = NULL,
strata_level = NULL,
strata_id = NULL
)
Arguments
response |
One or both forest measures: |
species |
One or more species codes or broad groups. Uppercase and lowercase letters are treated the same. The default includes all species. Unknown species codes produce a warning. |
strata_level |
One or more types of area: |
strata_id |
One or more tile IDs, ecological area names or paths, or
ecological codes. Tile IDs, names, and paths are matched ignoring case.
Numeric values and numeric-looking character values are
interpreted as codes when no name or path matches. Code searches require
exactly one ecological |
Details
Character strata_id values are matched as names or paths before
numeric-looking values are interpreted as ecological codes. Ecozone codes
5 and 6 return both published named subdivisions. Ecozone code 10 is also
ambiguous, but currently has no published national model rows.
Value
A table with one row for each published curve that matches the
choices. strata_code is the canonical character code for ecological
rows and NA for tiles.
Examples
available_rsyc_models(
response = "volume", species = "PICE.MAR", strata_level = "tile"
)
available_rsyc_models(
response = "agb", strata_level = "ecoprovince", strata_id = "7.1"
)
Build an RSYC Spatial Yield-Curve Dataset
Description
Estimate yield for one or more species across a set of tiles or ecological areas. The boundary map is kept separate from the curve table so that each area shape is stored only once.
Usage
build_rsyc_dataset(
response,
species,
age = 1:150,
strata_level = "tile",
strata_id = NULL,
output = NULL,
overwrite = FALSE,
cache_dir = tools::R_user_dir("RSYC", "data"),
quiet = TRUE
)
Arguments
response |
Forest measure to estimate: |
species |
One or more species codes or broad groups. Uppercase and lowercase letters are treated the same. Requested species without a published curve for the selected response and areas are omitted with a warning. |
age |
One or more stand ages in years. |
strata_level |
Type of area: |
strata_id |
One or more tile IDs, ecological area names or paths, or
ecological codes. Tile IDs, names, and paths are matched ignoring case.
Numeric values and numeric-looking character values are
interpreted as codes when no name or path matches. Quote ecoprovince codes
such as |
output |
Location of an optional GeoPackage file. When supplied, the
file contains a boundary map named |
overwrite |
Replace an existing GeoPackage at |
cache_dir |
Folder in which to save the GeoPackage. By default, RSYC
uses its standard user data folder, returned by |
quiet |
Hide download progress? |
Details
The function currently uses only curves fitted across Canada. It does not
substitute a curve from another type of area or from a regional fit.
Ecological boundaries must first be downloaded with
download_rsyc_boundaries(); tile boundaries are included with RSYC.
Ecozone codes 5, 6, and 10 are ambiguous and must instead be supplied as a
subdivision name or path.
Value
Three named results: spatial, an sf boundary map; curves, a
table of yield estimates containing canonical character strata_code
values (NA for tiles); and metadata, a one-row summary of the data and
choices used. Ecological spatial results contain strata_code plus the
hierarchy names and source ID fields through the requested level. Tile
spatial results contain strata_id and geometry.
Examples
tile_dataset <- build_rsyc_dataset(
response = "agb",
species = c("PICE.MAR", "POPU.TRE"),
age = c(50, 100, 150),
strata_level = "tile",
strata_id = c("H14", "F31")
)
tile_dataset$spatial
tile_dataset$curves
Calibrate an RSYC Yield Curve with Local Observations
Description
Adjust a published RSYC curve to local field data using a best linear unbiased predictor (BLUP) of the local level. Given one or more observed values (aboveground biomass or total volume) at known stand ages, the function estimates a shrinkage-based local level adjustment and applies it as a multiplicative ratio to the selected national curve.
Usage
calibrate_rsyc(
response,
species,
strata_level,
strata_id,
obs_age,
obs_response,
predict_age = NULL,
apply_limits = TRUE,
random_effect_limit_sd = 3,
ratio_limit = 5,
value_limit = 1000
)
Arguments
response |
Forest measure to estimate: |
species |
A species code or broad group such as |
strata_level |
Type of area: |
strata_id |
Tile ID, ecological area name or path, or ecological code.
Tile IDs, names, and paths are matched ignoring case.
A single area name can be used when it occurs only once. If the name occurs
in several places, use the full sequence of area names shown by
|
obs_age |
Stand ages, in years, of the local observations. |
obs_response |
Observed non-negative values at |
predict_age |
One or more stand ages at which to return calibrated
predictions. Defaults to the sorted unique |
apply_limits |
When |
random_effect_limit_sd |
Number of standard deviations of the local
random-effect distribution at which the estimate is constrained. The
default of |
ratio_limit |
Largest allowed calibration ratio before the adjustment
is discarded. Only used when |
value_limit |
Largest allowed calibrated value before the prediction
falls back to the bare curve. Only used when |
Details
The RSYC models are nonlinear mixed-effects models in which the tile- and
pixel-level random effects act on \beta_1, the parameter associated
with the maximum biomass (or volume) potential (the asymptote parameter):
AGB_{ijk} = (\beta_1 + b_i + b_{ij})\,g(age_{ijk}) + \epsilon_{ijk}
where i indexes the tile, j the pixel nested within the tile,
k the age, and
g(age) = e^{-\beta_4 age}(1 - e^{-\beta_2 age})^{\beta_3} is the
age-related modifier. The random effects and residual errors are assumed to
be independent and normally distributed with mean zero. Hats denote
estimated values. The b1 coefficient published in RSYC_models is the
tile-level asymptote parameter, already equal to
\hat\beta_1 + \hat b_i, so the yield curve based on the tile-level
conditional prediction is \texttt{b1} \cdot \hat g(age).
Local calibration estimates the pixel-level random effect b_{ij} of
the calibration plot (assumed to coincide with pixel j within tile
i) conditional on the fitted model. Given observations y_{ijk}
at ages age_{ijk}, with m_{ijk} = \hat g(age_{ijk}),
\hat b_{ij} = \frac{\sum_k m_{ijk} (y_{ijk} - \texttt{b1} \cdot
m_{ijk})}{\sum_k m_{ijk}^2 + \hat\sigma^2_\epsilon / \hat\sigma^2_b}
where \hat\sigma^2_b is the estimated pixel-level (nested within
tile) random-effect variance and \hat\sigma^2_\epsilon is the
estimated residual variance. The
\hat\sigma^2_\epsilon / \hat\sigma^2_b term shrinks weak local
evidence toward no adjustment. The calibrated curve substitutes the adjusted
asymptote parameter into the same equation,
(\texttt{b1} + \hat b_{ij})\,\hat g(age)
which is equivalent to scaling the published curve by
(\texttt{b1} + \hat b_{ij}) / \texttt{b1}, reported as ratio_blup.
With a single observation this becomes a one-point level anchor. The result should be read as a single-observation BLUP-anchored RSYC curve, not as a local growth trajectory learned from the data.
Value
A list with the components:
- predictions
A table of
ageand the calibratedvalueat eachpredict_age, together with the bare-curvevalue_uncalibrated.- ratio_blup
The multiplicative local adjustment applied to the curve.
- b_pixel
The estimated pixel-level random effect
\hat b_{ij}(capped and shrunk whenapply_limitsisTRUE).- shrinkage_factor
The shrinkage weight in
[0, 1]; values near 0 mean weak local evidence pulled toward no adjustment.- n_obs
Number of observations used.
- random_effect_limited, ratio_limited, value_limited
Flags indicating whether each safeguard altered the result.
- model_id
Identifier of the national curve that was calibrated.
References
Tompalski, P., Hermosilla, T., Baral, S.K., Wulder, M.A., and White, J.C. (2025). National remote sensing-derived aboveground biomass yield curves for Canada. Forestry: An International Journal of Forest Research. doi:10.1093/forestry/cpaf067
Examples
# One observation for a tile model selected by tile ID.
calibrate_rsyc(
"agb", "PICE.MAR", "tile", "H14",
obs_age = 45,
obs_response = 65
)
# Two observations for an ecoregion selected by numeric code.
calibrate_rsyc(
"agb", "PICE.MAR", "ecoregion", 198,
obs_age = c(45, 70),
obs_response = c(52, 65)
)
# Four observations for an ecodistrict selected by full hierarchy path.
calibrate_rsyc(
"agb", "PICE.MAR", "ecodistrict",
paste(
"Atlantic Maritime", "Fundy Uplands", "Annapolis-Minas Lowlands",
"Windsor Lowlands", sep = "/"
),
obs_age = c(30, 50, 70, 90),
obs_response = c(22, 31, 36, 39)
)
Download RSYC Ecological Boundaries
Description
Download and save the ecological boundary maps used by RSYC. The file is not downloaded when the package is installed or loaded. It contains maps of ecozones, ecoprovinces, ecoregions, and ecodistricts, but no yield curves. Tile boundaries are already included with RSYC.
Usage
download_rsyc_boundaries(
cache_dir = tools::R_user_dir("RSYC", "data"),
overwrite = FALSE,
quiet = FALSE,
url = getOption("RSYC.ecostrat_url", .rsyc_ecostrat_url)
)
Arguments
cache_dir |
Folder in which to save the GeoPackage. By default, RSYC
uses its standard user data folder, returned by |
overwrite |
Replace a previously downloaded file? |
quiet |
Hide download progress? |
url |
Web address of the boundary file. The default points to the copy published with RSYC. Organizations may instead provide the address of an approved copy. Its contents must match the published file. |
Value
The full location of the saved GeoPackage. The function returns this location without printing it.
See Also
Examples
# Save to a temporary folder here; omit `cache_dir` to use the default.
path <- try(download_rsyc_boundaries(cache_dir = tempdir()))
Estimate Biomass or Volume from an RSYC Yield Curve
Description
Estimate aboveground biomass or total volume at one or more stand ages. The curve is selected by species and area.
Usage
predict_rsyc(response, species, age, strata_level, strata_id)
Arguments
response |
Forest measure to estimate: |
species |
A species code or broad group such as |
age |
One or more stand ages in years. |
strata_level |
Type of area: |
strata_id |
Tile ID, ecological area name or path, or ecological code.
Tile IDs, names, and paths are matched ignoring case.
A single area name can be used when it occurs only once. If the name occurs
in several places, use the full sequence of area names shown by
|
Details
This function currently uses curves fitted across Canada. The curves were
fitted for stand ages 1 through 150 years. The function warns when asked to
estimate outside this age range; age 0 is also allowed as the start of a
curve. When a full ecological area sequence is needed, use / between the
ecozone, ecoprovince, ecoregion, and ecodistrict names.
Ecological codes are resolved only within the selected strata_level.
Ecozone codes 5, 6, and 10 each identify two named package subdivisions and
therefore cannot select a single curve; use the desired subdivision name.
Value
One estimated value for each stand age. AGB is in Mg/ha and volume is in m3/ha.
Examples
# Select a tile model with its tile ID.
predict_rsyc("agb", "PICE.MAR", c(20, 60, 120), "tile", "H14")
# Select an ecozone model with its unique name.
predict_rsyc(
response = "volume",
species = "PICE.MAR",
age = c(20, 60, 120),
strata_level = "ecozone",
strata_id = "Boreal Shield East"
)
# Select an ecoregion model with its numeric ecological code.
predict_rsyc(
"agb", "PICE.MAR", c(40, 80), "ecoregion", 198
)
# A full hierarchy path is an unambiguous ecological selector.
predict_rsyc(
"agb", "PICE.MAR", 80, "ecodistrict",
paste(
"Atlantic Maritime", "Fundy Uplands", "Annapolis-Minas Lowlands",
"Windsor Lowlands", sep = "/"
)
)
Read RSYC Boundary Maps
Description
Read the tile boundaries or ecological boundaries used for the RSYC yield
curves. Tile boundaries are included with the package. Ecological boundaries
are read from the file saved by download_rsyc_boundaries(). This function
never downloads data on its own.
Usage
rsyc_boundaries(
strata_level = "tile",
cache_dir = tools::R_user_dir("RSYC", "data"),
quiet = TRUE
)
Arguments
strata_level |
Type of area: |
cache_dir |
Folder in which to save the GeoPackage. By default, RSYC
uses its standard user data folder, returned by |
quiet |
Hide messages produced while the map is read? |
Value
An sf map in the Canada Atlas Lambert projection (EPSG:3978). Tile
maps contain strata_id and geometry. Ecological maps additionally contain
canonical character strata_code and the hierarchy names and source ID
fields through the requested level.
Examples
if (requireNamespace("sf", quietly = TRUE)) {
tiles <- rsyc_boundaries("tile")
}
if (requireNamespace("sf", quietly = TRUE)) {
cache <- tempdir()
if (!inherits(try(download_rsyc_boundaries(cache_dir = cache)), "try-error")) {
districts <- rsyc_boundaries("ecodistrict", cache_dir = cache)
}
}
List Species Available in RSYC Models
Description
List Species Available in RSYC Models
Usage
rsyc_species(response = NULL, strata_level = NULL, strata_id = NULL)
Arguments
response |
One or both forest measures: |
strata_level |
One or more types of area: |
strata_id |
One or more tile IDs, ecological area names or paths, or
ecological codes. Tile IDs, names, and paths are matched ignoring case.
Numeric values and numeric-looking character values are
interpreted as codes when no name or path matches. Code searches require
exactly one ecological |
Value
A table giving each species code, common name, and broad model group.
Examples
rsyc_species(response = "agb", strata_level = "ecoregion")
List Areas Available in RSYC Models
Description
List Areas Available in RSYC Models
Usage
rsyc_strata(response = NULL, species = NULL, strata_level = NULL)
Arguments
response |
One or both forest measures: |
species |
One or more species codes or broad groups. Uppercase and lowercase letters are treated the same. The default includes all species. Unknown species codes produce a warning. |
strata_level |
One or more types of area: |
Value
A table with the short area name (strata_name), its full location
within Canada's ecological classification (strata_id), and its canonical
character strata_code. Tile rows have NA codes.
Examples
rsyc_strata(
response = "volume", species = "PICE.MAR", strata_level = "ecozone"
)
List Available Species Codes and Names
Description
List the species codes and common names represented in the published RSYC curves. Broad groups are listed first, followed by individual species.
Usage
species_codes(response = NULL, strata_level = NULL)
Arguments
response |
Forest measure to include: |
strata_level |
Type of area to include. By default, all types are included. |
Value
A table with the species code and common name.
Examples
species_codes()
species_codes(response = "volume", strata_level = "ecoregion")