context("Simplification of fragment data (from NASIS)") ## related issues # https://github.com/ncss-tech/soilDB/issues/57 ## some complex data from NASIS phfrags table d.single.hz <- structure( list( phiid = c(1202607L, 1202607L, 1202607L, 1202607L, 1202607L), fragvol = c(5, 30, 10, 30, 5), fragsize_l = c(2L, 76L, 76L, 2L, 251L), fragsize_r = c( NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_ ), fragsize_h = c(75L, 250L, 250L, 75L, 600L), fragshp = structure( c( NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_ ), .Label = c("flat", "nonflat"), class = "factor" ), fraghard = structure( c(10L, 2L, 10L, 2L, 2L), .Label = c( "noncemented", "indurated", "moderately cemented", "strongly cemented", "weakly cemented", "extremely weakly", "very weakly", "very strongly", "weakly", "moderately", "strongly", "extremely strong", "H", "S" ), class = "factor" ) ), .Names = c( "phiid", "fragvol", "fragsize_l", "fragsize_r", "fragsize_h", "fragshp", "fraghard" ), row.names = 306:310, class = "data.frame" ) ## data from NASIS phfrags with NA fragvol d.missing.fragvol <- structure( list( phiid = c(1386592L, 1386592L, 1386592L, 1386592L, 1386592L, 1386592L), fragvol = c(10, 10, 20, 20, 10, NA), fragsize_l = c(2L, 2L, 75L, 75L, 380L, NA), fragsize_r = c( NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_ ), fragsize_h = c(75L, 75L, 380L, 380L, 600L, NA), fragshp = structure( c(1L, 1L, 1L, 1L, 1L, NA), .Label = c("flat", "nonflat"), class = "factor" ), fraghard = structure( c(11L, 9L, 11L, 9L, 11L, NA), .Label = c( "noncemented", "indurated", "moderately cemented", "strongly cemented", "weakly cemented", "extremely weakly", "very weakly", "very strongly", "weakly", "moderately", "strongly", "extremely strong", "H", "S" ), class = "factor" ) ), .Names = c( "phiid", "fragvol", "fragsize_l", "fragsize_r", "fragsize_h", "fragshp", "fraghard" ), row.names = 1044:1049, class = "data.frame" ) # all records are missing data d.all.NA.fragvol <- d.missing.fragvol[6, ] # no fragment size data, some records are NULL d.missing.size <- structure( list( phiid = c( 541527L, 541528L, 541529L, 541530L, 541543L, 541544L, 541545L, 541546L, 541547L, 541548L, 541549L, 541550L ), fragvol = c(20, 30, 20, 8, 2, 2, 3, 5, 4, 4, NA, NA), fragsize_l = c( NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_ ), fragsize_r = c( NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_ ), fragsize_h = c( NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_ ), fragshp = structure( c( NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_ ), .Label = c("flat", "nonflat"), class = "factor" ), fraghard = structure( c( NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_ ), .Label = c( "noncemented", "indurated", "moderately cemented", "strongly cemented", "weakly cemented", "extremely weakly", "very weakly", "very strongly", "weakly", "moderately", "strongly", "extremely strong", "H", "S" ), class = "factor" ) ), .Names = c( "phiid", "fragvol", "fragsize_l", "fragsize_r", "fragsize_h", "fragshp", "fraghard" ), row.names = c(NA, 12L), class = "data.frame" ) test_that(".seive correctly skips / pads NA", { expect_equal(soilDB:::.sieve(diameter = c(NA, 55)), c(NA, 'gravel')) }) test_that(".seive returns correct size class, nonflat, fragments", { expect_equal(soilDB:::.sieve(diameter = 4, flat = FALSE, para = FALSE), 'fine_gravel') expect_equal(soilDB:::.sieve(diameter = 6, flat = FALSE, para = FALSE), 'gravel') expect_equal(soilDB:::.sieve(diameter = 65, flat = FALSE, para = FALSE), 'gravel') expect_equal(soilDB:::.sieve(diameter = 74, flat = FALSE, para = FALSE), 'gravel') expect_equal(soilDB:::.sieve(diameter = 77, flat = FALSE, para = FALSE), 'cobbles') expect_equal(soilDB:::.sieve(diameter = 200, flat = FALSE, para = FALSE), 'cobbles') expect_equal(soilDB:::.sieve(diameter = 250, flat = FALSE, para = FALSE), 'stones') expect_equal(soilDB:::.sieve(diameter = 251, flat = FALSE, para = FALSE), 'stones') expect_equal(soilDB:::.sieve(diameter = 600, flat = FALSE, para = FALSE), 'boulders') expect_equal(soilDB:::.sieve(diameter = 601, flat = FALSE, para = FALSE), 'boulders') expect_equal(soilDB:::.sieve(diameter = 900, flat = FALSE, para = FALSE), 'boulders') expect_equal(soilDB:::.sieve(diameter = 1000, flat = FALSE, para = FALSE), 'boulders') }) test_that("seive returns correct size class, flat, fragments", { expect_equal(soilDB:::.sieve(diameter = 4, flat = TRUE, para = FALSE), 'channers') expect_equal(soilDB:::.sieve(diameter = 149, flat = TRUE, para = FALSE), 'channers') expect_equal(soilDB:::.sieve(diameter = 151, flat = TRUE, para = FALSE), 'flagstones') expect_equal(soilDB:::.sieve(diameter = 300, flat = TRUE, para = FALSE), 'flagstones') expect_equal(soilDB:::.sieve(diameter = 379, flat = TRUE, para = FALSE), 'flagstones') expect_equal(soilDB:::.sieve(diameter = 381, flat = TRUE, para = FALSE), 'stones') expect_equal(soilDB:::.sieve(diameter = 599, flat = TRUE, para = FALSE), 'stones') expect_equal(soilDB:::.sieve(diameter = 601, flat = TRUE, para = FALSE), 'boulders') expect_equal(soilDB:::.sieve(diameter = 601, flat = TRUE, para = FALSE), 'boulders') expect_equal(soilDB:::.sieve(diameter = 900, flat = TRUE, para = FALSE), 'boulders') }) test_that("seive returns correct size class, nonflat, parafragments", { expect_equal(soilDB:::.sieve(diameter = 4, flat = FALSE, para = TRUE), 'parafine_gravel') expect_equal(soilDB:::.sieve(diameter = 6, flat = FALSE, para = TRUE), 'paragravel') expect_equal(soilDB:::.sieve(diameter = 65, flat = FALSE, para = TRUE), 'paragravel') expect_equal(soilDB:::.sieve(diameter = 77, flat = FALSE, para = TRUE), 'paracobbles') expect_equal(soilDB:::.sieve(diameter = 200, flat = FALSE, para = TRUE), 'paracobbles') expect_equal(soilDB:::.sieve(diameter = 249, flat = FALSE, para = TRUE), 'paracobbles') expect_equal(soilDB:::.sieve(diameter = 251, flat = FALSE, para = TRUE), 'parastones') expect_equal(soilDB:::.sieve(diameter = 599, flat = FALSE, para = TRUE), 'parastones') expect_equal(soilDB:::.sieve(diameter = 601, flat = FALSE, para = TRUE), 'paraboulders') expect_equal(soilDB:::.sieve(diameter = 900, flat = FALSE, para = TRUE), 'paraboulders') expect_equal(soilDB:::.sieve(diameter = 1000, flat = FALSE, para = TRUE), 'paraboulders') }) test_that("seive returns correct size class, flat, parafragments", { expect_equal(soilDB:::.sieve(diameter = 4, flat = TRUE, para = TRUE), 'parachanners') expect_equal(soilDB:::.sieve(diameter = 149, flat = TRUE, para = TRUE), 'parachanners') expect_equal(soilDB:::.sieve(diameter = 151, flat = TRUE, para = TRUE), 'paraflagstones') expect_equal(soilDB:::.sieve(diameter = 300, flat = TRUE, para = TRUE), 'paraflagstones') expect_equal(soilDB:::.sieve(diameter = 379, flat = TRUE, para = TRUE), 'paraflagstones') expect_equal(soilDB:::.sieve(diameter = 381, flat = TRUE, para = TRUE), 'parastones') expect_equal(soilDB:::.sieve(diameter = 599, flat = TRUE, para = TRUE), 'parastones') expect_equal(soilDB:::.sieve(diameter = 601, flat = TRUE, para = TRUE), 'paraboulders') expect_equal(soilDB:::.sieve(diameter = 601, flat = TRUE, para = TRUE), 'paraboulders') expect_equal(soilDB:::.sieve(diameter = 900, flat = TRUE, para = TRUE), 'paraboulders') }) ## new tests for rockFragmentSieve: missing frag sizes / unspecified class test_that("rockFragmentSieve puts fragments without fragsize into 'unspecified' class", { d <- data.frame(fragvol=25, fragsize_l=NA, fragsize_r=NA, fragsize_h=NA, fragshp=NA, fraghard=NA) res <- soilDB:::.rockFragmentSieve(d) expect_equal(res$class, 'unspecified') }) test_that("rockFragmentSieve assumptions are applied, results correct", { d <- data.frame(fragvol=NA, fragsize_l=NA, fragsize_r=50, fragsize_h=NA, fragshp=NA, fraghard=NA) res <- soilDB:::.rockFragmentSieve(d) # assumptions in the absence of fragment shape / hardness expect_equal(res$fragshp, 'nonflat') expect_equal(res$fraghard, 'strongly cemented') # correct class in the absence of fragment shape / hardness expect_equal(res$class, 'gravel') # one more try d <- data.frame(fragvol=NA, fragsize_l=NA, fragsize_r=200, fragsize_h=NA, fragshp=NA, fraghard=NA) res <- soilDB:::.rockFragmentSieve(d) # assumptions in the absence of fragment shape / hardness expect_equal(res$fragshp, 'nonflat') expect_equal(res$fraghard, 'strongly cemented') # correct class in the absence of fragment shape / hardness expect_equal(res$class, 'cobbles') }) test_that("rockFragmentSieve assumptions are applied when all NA", { d <- data.frame(fragvol=NA, fragsize_l=NA, fragsize_r=NA, fragsize_h=NA, fragshp=NA, fraghard=NA) res <- soilDB:::.rockFragmentSieve(d) # assumptions in the absence of fragment shape / hardness expect_equal(res$fragshp, 'nonflat') expect_equal(res$fraghard, 'strongly cemented') # class should be NA expect_true(is.na(res$class)) }) test_that("rockFragmentSieve always uses the RV, computed when missing", { # full specification d <- data.frame(fragvol=10, fragsize_l=15, fragsize_r=50, fragsize_h=75, fragshp='nonflat', fraghard='strongly cemented') res <- soilDB:::.rockFragmentSieve(d) # assumptions in the absence of fragment shape / hardness expect_equal(res$fragshp, 'nonflat') expect_equal(res$fraghard, 'strongly cemented') # correct class in the absence of fragment shape / hardness expect_equal(res$class, 'gravel') # only RV available d <- data.frame(fragvol=10, fragsize_l=NA, fragsize_r=50, fragsize_h=NA, fragshp='nonflat', fraghard='strongly cemented') res <- soilDB:::.rockFragmentSieve(d) # assumptions in the absence of fragment shape / hardness expect_equal(res$fragshp, 'nonflat') expect_equal(res$fraghard, 'strongly cemented') # correct class in the absence of fragment shape / hardness expect_equal(res$class, 'gravel') # L/H available d <- data.frame(fragvol=10, fragsize_l=5, fragsize_r=NA, fragsize_h=74, fragshp='nonflat', fraghard='strongly cemented') res <- soilDB:::.rockFragmentSieve(d) # assumptions in the absence of fragment shape / hardness expect_equal(res$fragshp, 'nonflat') expect_equal(res$fraghard, 'strongly cemented') # correct class in the absence of fragment shape / hardness expect_equal(res$class, 'gravel') }) test_that("rockFragmentSieve complex sample data from NASIS, single horizon", { # pretty common, many fragments specified for a single horizon res <- soilDB:::.rockFragmentSieve(d.single.hz) # correct classes expect_equal(res$class, c('cobbles', 'gravel', 'stones', 'paragravel', 'paracobbles')) }) test_that("simplifyFragmentData complex sample data from NASIS, single horizon", { # pretty common, many fragments specified for a single horizon res <- soilDB::simplifyFragmentData(d.single.hz, id.var = 'phiid', nullFragsAreZero = TRUE) # correct class totals expect_equal(res$fine_gravel, 0) expect_equal(res$gravel, 30) expect_equal(res$cobbles, 30) expect_equal(res$stones, 5) expect_equal(res$paragravel, 5) expect_equal(res$paracobbles, 10) # correct total without parafrags expect_equal(res$total_frags_pct_nopf, 65) # correct total with parafrags expect_equal(res$total_frags_pct, 80) }) test_that("simplifyFragmentData when missing fragment sizes, low/rv/high", { # all fragments are collated into the unspecified column # totals should be correct # some horizons have no fragment records expect_silent( { res <- simplifyFragmentData(d.missing.size, id.var = 'phiid', nullFragsAreZero = TRUE) } ) # rows missing fragvol should be removed from the simplified result expect_true(nrow(d.missing.size) == 12) expect_true(nrow(res) == 10) # unspecified total should match RF sums expect_equal(res$unspecified, res$total_frags_pct_nopf) expect_equal(res$unspecified, res$total_frags_pct) }) test_that("simplifyFragmentData warning generated when NA in fragvol", { expect_silent(simplifyFragmentData(d.missing.fragvol, id.var = 'phiid', nullFragsAreZero = TRUE)) }) test_that("simplifyFragmentData warning generated when all fragvol are NA", { expect_message(simplifyFragmentData(d.all.NA.fragvol, id.var = 'phiid', nullFragsAreZero = TRUE), regexp = 'all records are missing rock fragment volume') }) test_that("simplifyFragmentData nullFragsAreZero works as expected", { expect_silent( { a <- simplifyFragmentData(d.missing.fragvol, id.var = 'phiid', nullFragsAreZero = FALSE) } ) expect_silent( { b <- simplifyFragmentData(d.missing.fragvol, id.var = 'phiid', nullFragsAreZero = TRUE) } ) expect_equal(as.logical(is.na(a)), c(FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE)) expect_true(all(!is.na(b))) })