diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index c446e47..ede6f76 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -25,7 +25,7 @@ jobs: - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} - {os: ubuntu-latest, r: 'release'} - {os: ubuntu-latest, r: 'oldrel-1'} - - {os: ubuntu-latest, r: '4.0.0'} + - {os: ubuntu-latest, r: '4.1.0'} env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} diff --git a/DESCRIPTION b/DESCRIPTION index 51c1172..6e23259 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,5 +1,5 @@ Package: BioCroField -Version: 0.3.0 +Version: 0.4.0 Title: Tools for BioCro Field Data Description: A collection of tools for processing field data related to BioCro crop growth simulations. @@ -12,9 +12,10 @@ Authors@R: c( License: MIT + file LICENSE Encoding: UTF-8 LazyData: true -Depends: R (>= 4.0.0) +Depends: R (>= 4.1.0) Imports: - rmarkdown + rmarkdown, + BioCro Suggests: knitr, testthat (>= 3.0.0), diff --git a/NEWS.md b/NEWS.md index b611e1d..eb3b5f6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,7 +8,7 @@ major.minor.patch structure of semantic versioning. When applicable, entries should include direct links to the relevant pull requests. Then, when a new release is made, "# Unreleased" should be replaced by a heading -with the new version number, such as "# CHANGES IN BioCroField VERSION 2.0.0." +with the new version number, such as "# BioCroField version 2.0.0." This section will combine all of the release notes from all of the pull requests merged in since the previous release. @@ -16,7 +16,16 @@ Subsequent commits will then include a new "Unreleased" section in preparation for the next release. --> -# BioCroField VERSION 0.3.0 +# BioCroField version 0.4.0 + +- It is now possible to specify extra columns to be returned in the output from + `biomass_table`. +- Values of `time` are now calculated using `BioCro::add_time_to_weather_data` + to ensure they are always consistent with BioCro's time definition. +- Values of partitioned leaf mass can be set to `NA` when creating a + `harvest_point`, which is treated as if the leaf mass had not been provided. + +# BioCroField version 0.3.0 - LMA is now included in the output from `biomass_table`. - New crop-specific guides to harvesting and weighing are now available, along @@ -26,7 +35,7 @@ for the next release. - A new vignette has been added (`images_from_the_field`) that illustrates parts of the harvesting and weighing process using pictures from the field. -# BioCroField VERSION 0.2.0 +# BioCroField version 0.2.0 - Two new methods for estimating LAI were added to `process`: `LAI_from_planting_density` and `LAI_from_measured_population`. The original @@ -45,7 +54,7 @@ for the next release. - https://github.com/biocro/BioCroField/pull/4 - https://github.com/biocro/BioCroField/pull/5 -# BioCroField VERSION 0.1.1 +# BioCroField version 0.1.1 - A bug related to partial name matching for partitioning components was detected and fixed. In short, if a value of `leaf` mass was not supplied but @@ -57,7 +66,7 @@ for the next release. - PRs related to creating this version: - https://github.com/biocro/BioCroField/pull/2 -# BioCroField VERSION 0.1.0 +# BioCroField version 0.1.0 - This is the first version of BioCroField. At this point, the package is in a state of rapid development, and not all changes will be described here. diff --git a/R/add_seed_biomass.R b/R/add_seed_biomass.R index ae1aedb..f11f986 100644 --- a/R/add_seed_biomass.R +++ b/R/add_seed_biomass.R @@ -157,8 +157,10 @@ add_seed_biomass <- function( initial_biomass[['year']] <- year initial_biomass[['doy']] <- doy initial_biomass[['hour']] <- hour - initial_biomass[['time']] <- - initial_biomass[['doy']] + initial_biomass[['hour']] / 24.0 + + time_list <- list(doy = doy, hour = hour) + time_list <- BioCro::add_time_to_weather_data(time_list) + initial_biomass[['time']] <- time_list[['time']] # Reset certain columns to zero; there is no leaf area when the plant is a # seed, so also make sure to set all LAI estimates to zero diff --git a/R/biomass_table.R b/R/biomass_table.R index 92ebef7..17b4f25 100644 --- a/R/biomass_table.R +++ b/R/biomass_table.R @@ -1,4 +1,17 @@ -biomass_table <- function(..., zero_when_missing = character()) { +biomass_table <- function( + ..., + zero_when_missing = character(), + other_columns = c( + 'leaf_area_per_plant', + 'LAI_from_planting_density', + 'LAI_from_measured_population', + 'agb_per_area', + 'agb_per_plant_row', + 'agb_per_plant_partitioning', + 'measured_population' + ) +) +{ x <- list(...) types <- lapply(x, class) @@ -9,12 +22,26 @@ biomass_table <- function(..., zero_when_missing = character()) { UseMethod('biomass_table', x[[1]]) } -biomass_table.harvest_point <- function(..., zero_when_missing = character()) { +biomass_table.harvest_point <- function( + ..., + zero_when_missing = character(), + other_columns = c( + 'leaf_area_per_plant', + 'LAI_from_planting_density', + 'LAI_from_measured_population', + 'agb_per_area', + 'agb_per_plant_row', + 'agb_per_plant_partitioning', + 'measured_population' + ) +) +{ x <- list(...) # a list of harvest_point objects # Make sure certain inputs are character should_be_c <- list( - zero_when_missing = zero_when_missing + zero_when_missing = zero_when_missing, + other_columns = other_columns ) c_bad <- sapply(should_be_c, function(x) {!is.character(x)}) @@ -48,18 +75,13 @@ biomass_table.harvest_point <- function(..., zero_when_missing = character()) { 'SLA', 'LMA', 'LAI_from_LMA', - 'LAI_from_planting_density', - 'LAI_from_measured_population', - 'agb_per_plant_row', - 'agb_per_plant_partitioning', - 'measured_population', 'row_spacing', 'plant_spacing', 'planting_density' ) cnames <- - c(initial_columns, all_components, final_columns, additional_arguments) + c(initial_columns, all_components, final_columns, other_columns, additional_arguments) # Form a data frame biomass <- stats::setNames( @@ -75,7 +97,7 @@ biomass_table.harvest_point <- function(..., zero_when_missing = character()) { for (i in seq_along(x)) { hpp <- x[[i]] - for (name in c(initial_columns, final_columns)) { + for (name in c(initial_columns, final_columns, other_columns)) { if (name %in% names(hpp)) { biomass[i, name] <- hpp[[name]] } diff --git a/R/harvest_point.R b/R/harvest_point.R index 29f50fa..823d50a 100644 --- a/R/harvest_point.R +++ b/R/harvest_point.R @@ -190,6 +190,7 @@ harvest_point <- function( # Do not allow a leaf with zero area but nonzero mass if (!is.na(partitioning_leaf_area) && partitioning_leaf_area == 0 && !is.null(partitioning_component_weights[['leaf']]) && + !is.na(partitioning_component_weights[['leaf']]) && partitioning_component_weights[['leaf']] > 0) { stop("It is not possible for a leaf with zero area to have a nonzero mass") } @@ -197,6 +198,7 @@ harvest_point <- function( # Do not allow a leaf with zero mass but nonzero area if (!is.na(partitioning_leaf_area) && partitioning_leaf_area > 0 && !is.null(partitioning_component_weights[['leaf']]) && + !is.na(partitioning_component_weights[['leaf']]) && partitioning_component_weights[['leaf']] == 0) { stop("It is not possible for a leaf with zero mass to have a nonzero area") } diff --git a/R/process.R b/R/process.R index 607bdf6..4e39325 100644 --- a/R/process.R +++ b/R/process.R @@ -12,7 +12,9 @@ process.harvest_point <- function(x, leaf_name = 'leaf', ...) { # that we can handle incomplete information in the inputs. # The time (as specified in BioCro) - time <- x[['doy']] + x[['hour']] / 24.0 + time_list <- list(doy = x[['doy']], hour = x[['hour']]) + time_list <- BioCro::add_time_to_weather_data(time_list) + time <- time_list[['time']] # Above-ground biomass from the plants that were partitioned (in g) partitioning_agb_weight <- if (length(x[['agb_components']]) > 0) { diff --git a/man/biomass_table.Rd b/man/biomass_table.Rd index 37dc953..04f8496 100644 --- a/man/biomass_table.Rd +++ b/man/biomass_table.Rd @@ -11,9 +11,33 @@ } \usage{ - biomass_table(\dots, zero_when_missing = character()) - - \method{biomass_table}{harvest_point}(\dots, zero_when_missing = character()) + biomass_table( + \dots, + zero_when_missing = character(), + other_columns = c( + 'leaf_area_per_plant', + 'LAI_from_planting_density', + 'LAI_from_measured_population', + 'agb_per_area', + 'agb_per_plant_row', + 'agb_per_plant_partitioning', + 'measured_population' + ) + ) + + \method{biomass_table}{harvest_point}( + \dots, + zero_when_missing = character(), + other_columns = c( + 'leaf_area_per_plant', + 'LAI_from_planting_density', + 'LAI_from_measured_population', + 'agb_per_area', + 'agb_per_plant_row', + 'agb_per_plant_partitioning', + 'measured_population' + ) + ) } \arguments{ @@ -26,6 +50,11 @@ \code{pod} would be set to \code{NA} for these points, but it would make more sense to set it to 0. } + + \item{other_columns}{ + The names of variables to include as columns in addition to the default + columns (see below). + } } \details{ @@ -55,16 +84,6 @@ \item \code{LAI_from_LMA} - \item \code{LAI_from_planting_density} - - \item \code{LAI_from_measured_population} - - \item \code{agb_per_plant_row} - - \item \code{agb_per_plant_partitioning} - - \item \code{measured_population} - \item \code{row_spacing} \item \code{plant_spacing} @@ -76,6 +95,9 @@ \item Any additional arguments (such as comments) that were passed to \code{\link{harvest_point}} when creating the data points + + \item Any additional variables specified in the \code{other_columns} input + argument } See \code{\link{harvest_point}} and \code{\link{process}} for more information diff --git a/man/generate_crop_guide.Rd b/man/generate_crop_guide.Rd index e8d6672..836f6c3 100644 --- a/man/generate_crop_guide.Rd +++ b/man/generate_crop_guide.Rd @@ -88,7 +88,7 @@ LaTeX installation, you may need to use the \code{TinyTex} package. To do this, make sure the package is installed and then run \code{tinytex::install_tinytex()}. \code{TinyTex} can be installed from CRAN - by typing code{install.packages('TinyTex')}. + by typing \code{install.packages('TinyTex')}. } \value{ diff --git a/man/process.Rd b/man/process.Rd index a99d330..0e06026 100644 --- a/man/process.Rd +++ b/man/process.Rd @@ -38,8 +38,8 @@ The detailed calculations are as follows: \itemize{ - \item \code{time}: In BioCro, the time is specified as a fractional day of - the year calculated by \code{time = doy + hour / 24.0}. + \item \code{time}: The time as determined from the \code{doy} and + \code{hour} using \code{\link[BioCro]{add_time_to_weather_data}}. \item \code{measured_population}: The number of plants per unit ground area (in \code{plants / acre} can be estimated from the row spacing and the diff --git a/tests/testthat/test-add_seed_biomass.R b/tests/testthat/test-add_seed_biomass.R index 25b4d20..1c717ce 100644 --- a/tests/testthat/test-add_seed_biomass.R +++ b/tests/testthat/test-add_seed_biomass.R @@ -50,3 +50,19 @@ test_that("Seed biomass is properly added to tables", { 2.47 ) }) + +test_that("Time is calculated the same was as in `process`", { + doy = 12 + hour = 3 + + biomass_df <- add_seed_biomass( + biomass_table(process(harvest_point(doy = doy, hour = hour))), + doy = doy, + hour = hour + ) + + expect_equal( + biomass_df$time[1], + biomass_df$time[2] + ) +}) diff --git a/tests/testthat/test-biomass_table.R b/tests/testthat/test-biomass_table.R index dd9e68f..1bd0870 100644 --- a/tests/testthat/test-biomass_table.R +++ b/tests/testthat/test-biomass_table.R @@ -24,3 +24,55 @@ test_that("Additional harvest_point arguments are included in the final table", expect_identical(biomass$stem_comment, c('blah', NA)) }) + +test_that("Some table columns are specified by the user", { + essential_columns <- c( + 'crop', + 'variety', + 'location', + 'plot', + 'year', + 'doy', + 'hour', + 'time', + 'SLA', + 'LMA', + 'LAI_from_LMA', + 'row_spacing', + 'plant_spacing', + 'planting_density' + ) + + optional_columns <- c( + 'LAI_from_planting_density', + 'LAI_from_measured_population', + 'agb_per_area', + 'agb_per_plant_row', + 'agb_per_plant_partitioning', + 'measured_population' + ) + + hp <- process(harvest_point()) + + # Use default arguments + biomass_table_1 <- biomass_table(hp) + + expect_true( + all(essential_columns %in% colnames(biomass_table_1)) + ) + + expect_true( + all(optional_columns %in% colnames(biomass_table_1)) + ) + + # Don't include any extra columns + biomass_table_2 <- biomass_table(hp, other_columns = character()) + + expect_true( + all(essential_columns %in% colnames(biomass_table_2)) + ) + + expect_true( + all(!optional_columns %in% colnames(biomass_table_2)) + ) +}) diff --git a/tests/testthat/test-harvest_point.R b/tests/testthat/test-harvest_point.R index 4294c06..4629837 100644 --- a/tests/testthat/test-harvest_point.R +++ b/tests/testthat/test-harvest_point.R @@ -156,12 +156,12 @@ test_that("Missing density parameters are automatically calculated", { harvest_point(row_spacing = 0.75, plant_spacing = 0.2)$planting_density, 26980 ) - + expect_equal( harvest_point(row_spacing = 0.75, planting_density = 26980)$plant_spacing, 0.2 ) - + expect_equal( harvest_point(plant_spacing = 0.2, planting_density = 26980)$row_spacing, 0.75 @@ -218,3 +218,9 @@ test_that("Additional arguments must have length 1 and be numeric, character, or "The following inputs should have length 1, but do not: construct" ) }) + +test_that("Partitioned leaf mass can be NA when leaf area is numeric", { + expect_no_error( + harvest_point(partitioning_component_weights = list(leaf = NA), partitioning_leaf_area = 1) + ) +}) diff --git a/tests/testthat/test-process.R b/tests/testthat/test-process.R index 4a6cb82..7cdd549 100644 --- a/tests/testthat/test-process.R +++ b/tests/testthat/test-process.R @@ -16,7 +16,7 @@ test_that("time is calculated only when possible", { expect_equal( process(harvest_point(doy = 1, hour = 12))$time, - 1.5 + BioCro::add_time_to_weather_data(list(doy = 1, hour = 12))$time ) }) @@ -122,6 +122,8 @@ test_that("LMA is calculated only when possible", { expect_na(hpp$LMA) expect_na(process(harvest_point(partitioning_leaf_area = 1))$LMA) + + expect_na(process(harvest_point(partitioning_component_weights = list(leaf = NA), partitioning_leaf_area = 1))$LMA) expect_na(process(harvest_point(partitioning_component_weights = list(leaf = 1)))$LMA) diff --git a/vignettes/handling_biomass_measurements.Rmd b/vignettes/handling_biomass_measurements.Rmd index 0f4a8ae..16e8389 100644 --- a/vignettes/handling_biomass_measurements.Rmd +++ b/vignettes/handling_biomass_measurements.Rmd @@ -204,7 +204,7 @@ access_sheet('harvest') ``` The sheet is also available via the `BioCroField` -[GitHub website](https://github.com/biocro/BioCroField/blob/main/inst/sheets/). +[GitHub website](https://github.com/biocro/BioCroField/tree/main/inst/sheets/). When using this sheet, it is recommended to electronically fill out any fields whose values are known beforehand (such as location, year, row spacing, name, @@ -226,7 +226,7 @@ access_sheet('soybean_guide') ``` They are also available via the `BioCroField` -[GitHub website](https://github.com/biocro/BioCroField/blob/main/inst/sheets/). +[GitHub website](https://github.com/biocro/BioCroField/tree/main/inst/sheets/). When using these sheets, it is recommended to print out one copy of each relevant crop guide so you can keep it on hand for reference while harvesting.