Package {RSYC}


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:

Other contributors:

See Also

Useful links:


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 (agb or volume) 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_id is 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: "agb" for aboveground biomass and "volume" for total volume. The default includes both.

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: "tile", "ecozone", "ecoprovince", "ecoregion", or "ecodistrict". The default includes all types.

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 strata_level. Quote ecoprovince codes such as "10.1". Values that match no published curve produce a warning. The default includes all areas.

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: "agb" for aboveground biomass or "volume" for total volume.

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: "tile", "ecozone", "ecoprovince", "ecoregion", or "ecodistrict".

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 "10.1". By default, every area with a matching published curve is included. If an area name occurs in several places, the function asks for the full sequence of area names.

output

Location of an optional GeoPackage file. When supplied, the file contains a boundary map named spatial, a yield table named curves, and a summary table named metadata.

overwrite

Replace an existing GeoPackage at output?

cache_dir

Folder in which to save the GeoPackage. By default, RSYC uses its standard user data folder, returned by tools::R_user_dir().

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

[Experimental]

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: "agb" for aboveground biomass or "volume" for total volume.

species

A species code or broad group such as "coniferous". Uppercase and lowercase letters are treated the same.

strata_level

Type of area: "tile", "ecozone", "ecoprovince", "ecoregion", or "ecodistrict".

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 rsyc_strata(). Numeric values are interpreted as codes for the selected ecological strata_level; quote ecoprovince codes such as "10.1".

obs_age

Stand ages, in years, of the local observations.

obs_response

Observed non-negative values at obs_age. Aboveground biomass in Mg/ha or total volume in m3/ha, matching response. Must be the same length as obs_age.

predict_age

One or more stand ages at which to return calibrated predictions. Defaults to the sorted unique obs_age.

apply_limits

When TRUE (the default), apply the safeguards that protect against implausible local adjustments: the random effect is constrained to random_effect_limit_sd standard deviations, an adjustment ratio above ratio_limit is discarded in favour of the bare curve, and any calibrated value above value_limit falls back to the bare curve. When FALSE, the raw shrunk BLUP adjustment is returned uncapped.

random_effect_limit_sd

Number of standard deviations of the local random-effect distribution at which the estimate is constrained. The default of 3 corresponds to the central 99.7% of that distribution. Only used when apply_limits is TRUE.

ratio_limit

Largest allowed calibration ratio before the adjustment is discarded. Only used when apply_limits is TRUE.

value_limit

Largest allowed calibrated value before the prediction falls back to the bare curve. Only used when apply_limits is TRUE.

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 age and the calibrated value at each predict_age, together with the bare-curve value_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 when apply_limits is TRUE).

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 tools::R_user_dir().

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

rsyc_boundaries()

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: "agb" for aboveground biomass or "volume" for total volume.

species

A species code or broad group such as "coniferous". Uppercase and lowercase letters are treated the same.

age

One or more stand ages in years.

strata_level

Type of area: "tile", "ecozone", "ecoprovince", "ecoregion", or "ecodistrict".

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 rsyc_strata(). Numeric values are interpreted as codes for the selected ecological strata_level; quote ecoprovince codes such as "10.1".

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: "tile", "ecozone", "ecoprovince", "ecoregion", or "ecodistrict".

cache_dir

Folder in which to save the GeoPackage. By default, RSYC uses its standard user data folder, returned by tools::R_user_dir().

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: "agb" for aboveground biomass and "volume" for total volume. The default includes both.

strata_level

One or more types of area: "tile", "ecozone", "ecoprovince", "ecoregion", or "ecodistrict". The default includes all types.

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 strata_level. Quote ecoprovince codes such as "10.1". Values that match no published curve produce a warning. The default includes all areas.

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: "agb" for aboveground biomass and "volume" for total volume. The default includes both.

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: "tile", "ecozone", "ecoprovince", "ecoregion", or "ecodistrict". The default includes all types.

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: "agb" for aboveground biomass or "volume" for total volume. By default, both are included.

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")

mirror server hosted at Truenetwork, Russian Federation.