tests/testthat/setup.r

library(data.table)
library(terra)

SIG_DIGS <- 4

DESIRED_ROWS <- 5000

DAY <- seq(0, 366)
PERCENT <- seq(0, 100)
RADIANS <- seq(-360, 360, by = 0.1) * pi / 180
ZERO_OR_ONE <- list(0, 1)

ACCEL <- ZERO_OR_ONE
ASPECT <- RADIANS
BOOL <- c(TRUE, FALSE)
BUI <- seq(0, 1000, by = 0.1)
BUIEFF <- ZERO_OR_ONE
CBH <- seq(0, 200, by = 0.1)
CC <- PERCENT
CFB <- seq(-1, 2, by = 0.01)
CFL <- seq(-10, 4000, by = 0.1)
D0 <- DAY
DC <- seq(0, 1000, by = 0.1)
DMC <- seq(0, 1000, by = 0.1)
DJ <- DAY
ELV <- seq(0, 10000)
FC <- seq(-10, 20000)
FFMC <- seq(0, 101, by = 0.1)
FMC <- seq(0, 500, by = 0.1)
FRACTION <- seq(0, 1, by = 0.05)
FUELTYPE <- c(
  "NF", "WA", "C1", "C2", "C3", "C4", "C5", "C6", "C7",
  "D1", "M1", "M2", "M3", "M4", "S1", "S2",
  "S3", "O1A", "O1B"
)
GFL <- seq(0, 100)
GS <- seq(0, 200)
HR <- seq(0, 366 * 24) * 60
HOURS <- seq(0, 23)
ISI <- seq(0, 300, by = 0.1)
LAT <- seq(-90, 90, by = 0.1)
LB <- seq(-1, 1.1, by = 0.01)
# FIX: for some reason the original package just makes negatives positive
LONG <- abs(seq(-180, 360, by = 0.1))
MON <- seq(1, 12)
PC <- PERCENT
PDF <- PERCENT
PREC <- seq(-10, 300, by = 0.01)
RH <- seq(-10, 110, by = 0.01)
ROS <- seq(0, 600, by = 0.01)
SAZ <- RADIANS + pi
SAZ <- ifelse(SAZ > 2 * pi, SAZ - 2 * pi, SAZ)
SD <- unlist(append(list(-999), seq(0, 100)))
SFC <- seq(0, 20000)
SH <- seq(-10, 110)
TEMP <- seq(-30, 60, by = 0.1)
WD <- RADIANS
WS <- seq(0, 300, by = 0.1)
THETA <- seq(-360, 360, by = 0.01)
WSV <- seq(-10, 500, by = 0.1)
WAZ <- RADIANS + pi
WAZ <- ifelse(WAZ > 2 * pi, WAZ - 2 * pi, WAZ)

FBP_ARGS <- list(
  data.table(ID = 1),
  data.table(FUELTYPE = FUELTYPE),
  data.table(FFMC = FFMC),
  data.table(BUI = BUI),
  data.table(WS = WS),
  data.table(WD = WD),
  data.table(FMC = FMC),
  data.table(GS = GS),
  data.table(LAT = LAT),
  data.table(LONG = LONG),
  data.table(ELV = ELV),
  data.table(DJ = DJ),
  data.table(D0 = D0),
  data.table(SD = SD),
  data.table(SH = SH),
  data.table(HR = HR),
  data.table(PC = PC),
  data.table(PDF = PDF),
  data.table(GFL = GFL),
  data.table(CC = CC),
  data.table(THETA = THETA),
  data.table(ACCEL = ACCEL),
  data.table(ASPECT = ASPECT),
  data.table(BUIEFF = BUIEFF),
  data.table(CBH = CBH),
  data.table(CFL = CFL),
  data.table(ISI = ISI)
)

get_data_path <- function(name, suffix="csv") {
  return(test_path("data", sprintf("%s.%s", name, suffix)))
}

read_data <- function(name) {
  return(read.csv(get_data_path(name)))
}

get_raster_path <- function(name) {
  return(get_data_path(name, "tif"))
}

read_raster <- function(name) {
  return(rast(get_raster_path(name)))
}

pickRows <- function(d1, num_rows = DESIRED_ROWS) {
  d1 <- data.table(d1)
  # print(d1)
  # print(nrow(d1))
  # print(MAX_ROWS)
  old_names <- colnames(d1)
  while (nrow(d1) > num_rows) {
    # print('loop')
    # print(seq(1, nrow(d1), by=3))
    # print(d1[seq(1, nrow(d1), by=3), ])
    # print('assign')
    d1 <- data.table(d1[seq(1, nrow(d1), by = 3), ])
    # print('end loop')
    # print(nrow(d1))
    stopifnot(!is.null(nrow(d1)))
    colnames(d1) <- old_names
  }
  # print('return')
  return(d1)
}

makeInput <- function(arguments) {
  # print(arguments)
  d1 <- pickRows(arguments[[1]])
  if (1 < length(arguments)) {
    for (n in 2:length(arguments))
    {
      # print(n)
      # print(arguments[[n]])
      d2 <- pickRows(arguments[[n]], ceiling(3 * DESIRED_ROWS / nrow(d1)))
      d1 <- pickRows(merge(data.frame(d1), data.frame(d2), by = NULL))
    }
  }
  return(data.table(d1))
}

makeDataFromInput <- function(name, fct, input, split_args, with_input = FALSE) {
  if (!split_args) {
    stopifnot(is.data.table(input))
    values <- fct(input)
    input[, c(name)] <- values
    return(input)
  }
  n0 <- nrow(input)
  # input[, c(name)] <- do.call(fct, input)
  r <- list(do.call(fct, input[1, ]))
  isRow <- length(r[[1]]) > 1
  if (isRow) {
    r <- r[[1]]
    for (n in 2:nrow(input)) {
      r2 <- do.call(fct, input[n, ])
      r <- rbind(r, r2)
    }
    stopifnot(nrow(input) == n0)
    if (with_input) {
      r <- cbind(input, r)
    }
    return(r)
  } else {
    for (n in 2:nrow(input)) {
      r <- append(r, do.call(fct, input[n, ]))
    }
    input[, c(name)] <- unlist(r)
    stopifnot(nrow(input) == n0)
    return(input)
  }
}

makeData <- function(name, fct, arguments, split_args, with_input = FALSE) {
  return(makeDataFromInput(name, fct, makeInput(arguments), split_args, with_input))
}

# want to apply to each individual number
significant <- Vectorize(function(data) {
  # keep at least 2 decimal places
  return(signif(
    data,
    pmax(
      ceiling(log10(abs(data))) + 2,
      SIG_DIGS
    )
  ))
})

roundData <- function(data) {
  data <- as.data.table(data)
  for (col in names(data)) {
    # don't round integers
    if (is.numeric(data[[col]]) && !is.integer(data[[col]])) {
      data[[col]] <- significant(data[[col]])
    }
  }
  return(data)
}

roundRaster <- function(data) {
  return(signif(data, SIG_DIGS))
}

checkResults <- function(name, df1) {
  df1 <- roundData(df1)
  df2 <- as.data.table(read_data(name))
  expect_equal(df1, df2)
}

checkData <- function(name, fct, arguments, split_args = TRUE, with_input = FALSE) {
  checkResults(name, makeData(name, fct, arguments, split_args, with_input))
}

fctOnInput <- function(fct) {
  return(function(ID, FUELTYPE, FFMC, BUI, WS, WD, FMC, GS, LAT, LONG, ELV, DJ, D0,
                  SD, SH, HR, PC, PDF, GFL, CC, THETA, ACCEL, ASPECT, BUIEFF,
                  CBH, CFL, ISI) {
    input <- data.frame(
      ID = ID,
      FUELTYPE = FUELTYPE,
      FFMC = FFMC,
      BUI = BUI,
      WS = WS,
      WD = WD,
      FMC = FMC,
      GS = GS,
      LAT = LAT,
      LONG = LONG,
      ELV = ELV,
      DJ = DJ,
      D0 = D0,
      SD = SD,
      SH = SH,
      HR = HR,
      PC = PC,
      PDF = PDF,
      GFL = GFL,
      CC = CC,
      THETA = THETA,
      ACCEL = ACCEL,
      ASPECT = ASPECT,
      BUIEFF = BUIEFF,
      CBH = CBH,
      CFL = CFL,
      ISI = ISI
    )
    return(fct(input = input, output = "S"))
  })
}

test_raster <- function(name, input, fct) {
  # only comparing to significant digits specified
  actual <- roundRaster(fct(input))
  expected <- read_raster(name)

  out_cols <- setdiff(names(actual), toupper(names(input)))
  # we don't actually know the names of the columns from the file, so assign from output
  names(expected) <- names(actual)

  expect_equal(names(expected), names(actual))
  # # nc seems to prefer negative longitudes
  # ext(actual) <- ext(expected)
  m <- minmax(actual[[out_cols]] - expected[[out_cols]])
  expect_true(all(abs(m) < (10^-SIG_DIGS)))
}

Try the cffdrs package in your browser

Any scripts or data that you put into this service are public.

cffdrs documentation built on June 22, 2024, 12:25 p.m.