Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed BirdFlowAPI.tar.gz
Binary file not shown.
1 change: 0 additions & 1 deletion NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,3 @@ export(load_models)
export(range_rescale)
export(save_json_palette)
export(symbolize_raster_data)
import(BirdFlowR)
46 changes: 22 additions & 24 deletions R/flow.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ get_s3_config <- function() {

#' Null coalescing operator for config values
`%||%` <- function(a, b) if (!is.null(a) && !is.na(a) && nzchar(a)) a else b
#' @import BirdFlowR

if(FALSE) {
# Manually set function arguments for dev and debugging
Expand All @@ -35,12 +34,6 @@ if(FALSE) {
# the other files are correct


# Load required libraries
library(BirdFlowR)
library(jsonlite)
library(terra)
library(aws.s3)

# Load globals and helpers
original_wd <- getwd()
if(!grepl("api$", getwd()))
Expand Down Expand Up @@ -99,6 +92,11 @@ save_local_path <- "config/save_local.flag"
#' `type`
#' @export
flow <- function(loc, week, taxa, n, direction = "forward", save_local = FALSE) {
# TODO:
# utils::data("species", package = "BirdFlowAPI", envir = environment())

# load_models()

s3_cfg <- get_s3_config()
s3_enabled <- !is.na(s3_cfg$bucket) && nzchar(s3_cfg$bucket)

Expand Down Expand Up @@ -139,24 +137,24 @@ flow <- function(loc, week, taxa, n, direction = "forward", save_local = FALSE)

# Snap lat/lon to cell center using the first model (all models use same grid)
bf <- models[[ifelse(taxa == "total", species$species[1], taxa)]]
xy <- latlon_to_xy(lat_lon$lat, lat_lon$lon, bf = bf)
col <- x_to_col(xy$x, bf = bf)
row <- y_to_row(xy$y, bf = bf)
x <- col_to_x(col, bf = bf)
y <- row_to_y(row, bf = bf)
snapped_latlon <- xy_to_latlon(x, y, bf = bf)
xy <- BirdFlowR::latlon_to_xy(lat_lon$lat, lat_lon$lon, bf = bf)
col <- BirdFlowR::x_to_col(xy$x, bf = bf)
row <- BirdFlowR::y_to_row(xy$y, bf = bf)
x <- BirdFlowR::col_to_x(col, bf = bf)
y <- BirdFlowR::row_to_y(row, bf = bf)
snapped_latlon <- BirdFlowR::xy_to_latlon(x, y, bf = bf)
snapped_latlon$lat <- round(snapped_latlon$lat, 2)
snapped_latlon$lon <- round(snapped_latlon$lon, 2)
lat_lon <- snapped_latlon

# Re-compute snapped xy for later use
xy <- latlon_to_xy(lat_lon$lat, lat_lon$lon, bf = bf)
xy <- BirdFlowR::latlon_to_xy(lat_lon$lat, lat_lon$lon, bf = bf)

# Form file names and S3 keys using snapped lat/lon
snapped_lat <- paste(lat_lon$lat, collapse = "_")
snapped_lon <- paste(lat_lon$lon, collapse = "_")
cache_prefix <- paste0(direction, "/", taxa, "_", week, "_", snapped_lat, "_", snapped_lon, "/")
pred_weeks <- lookup_timestep_sequence(bf, start = week, n = n, direction = direction)
pred_weeks <- BirdFlowR::lookup_timestep_sequence(bf, start = week, n = n, direction = direction)
png_files <- paste0(flow_type, "_", taxa, "_", pred_weeks, ".png")
symbology_files <- paste0(flow_type, "_", taxa, "_", pred_weeks, ".json")
png_bucket_paths <- paste0(s3_flow_path, cache_prefix, png_files)
Expand All @@ -169,14 +167,14 @@ flow <- function(loc, week, taxa, n, direction = "forward", save_local = FALSE)
cache_hit <- TRUE
if (!save_local && s3_enabled) {
for (i in seq_along(pred_weeks)) {
png_exists <- object_exists(object = png_bucket_paths[i], bucket = s3_cfg$bucket)
json_exists <- object_exists(object = symbology_bucket_paths[i], bucket = s3_cfg$bucket)
png_exists <- aws.s3::object_exists(object = png_bucket_paths[i], bucket = s3_cfg$bucket)
json_exists <- aws.s3::object_exists(object = symbology_bucket_paths[i], bucket = s3_cfg$bucket)
if (!png_exists || !json_exists) {
cache_hit <- FALSE
break
}
}
tiff_exists <- object_exists(object = tiff_bucket_path, bucket = s3_cfg$bucket)
tiff_exists <- aws.s3::object_exists(object = tiff_bucket_path, bucket = s3_cfg$bucket)
if (!tiff_exists) cache_hit <- FALSE
} else {
# Local cache: check if all files exist in localtmp
Expand Down Expand Up @@ -231,23 +229,23 @@ flow <- function(loc, week, taxa, n, direction = "forward", save_local = FALSE)
for (i in seq_along(target_species)) {
sp <- target_species[i]
bf <- models[[sp]]
valid <- is_location_valid(bf, timestep = week, x = xy$x, y = xy$y)
valid <- BirdFlowR::is_location_valid(bf, timestep = week, x = xy$x, y = xy$y)
if (!all(valid)) {
next
}
any_valid <- TRUE
start_distr <- as_distr(xy, bf)
start_distr <- BirdFlowR::as_distr(xy, bf)
if (nrow(lat_lon) > 1) {
start_distr <- apply(start_distr, 1, sum)
start_distr <- start_distr / sum(start_distr)
}
log_progress(paste("Starting prediction for", sp))
pred <- predict(bf, start_distr, start = week, n = n, direction = direction)
location_i <- xy_to_i(xy, bf = bf)
initial_population_distr <- get_distr(bf, which = week)
location_i <- BirdFlowR::xy_to_i(xy, bf = bf)
initial_population_distr <- BirdFlowR::get_distr(bf, which = week)
start_proportion <- sum(initial_population_distr[location_i]) / 1
abundance <- pred * species$population[species$species == sp] / prod(res(bf) / 1000) * start_proportion
this_raster <- rasterize_distr(abundance, bf = bf, format = "terra")
abundance <- pred * species$population[species$species == sp] / prod(terra::res(bf) / 1000) * start_proportion
this_raster <- BirdFlowR::rasterize_distr(abundance, bf = bf, format = "terra")
if (is.null(combined)) {
combined <- this_raster
} else {
Expand Down
16 changes: 10 additions & 6 deletions R/load_models.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#'
#' @export
load_models <- function() {
# utils::data("species", package = "BirdFlowAPI", envir = environment())

# Load BirdFlow models
BirdFlowR::birdflow_options(collection_url = "https://birdflow-science.s3.amazonaws.com/sparse_avian_flu/")
index <- BirdFlowR::load_collection_index()
Expand All @@ -23,14 +25,16 @@ load_models <- function() {
stop("Expected BirdFlow models:", paste(miss, collapse = ", "), " are missing from the model collection." )
}

# This is slow so skipping if it's already done - useful when developing to
# avoid having to wait to reload.
if(!exists("models") || !is.environment(models) || !all(species$species %in% names(models))) {
models <<- new.env(parent = globalenv())
print(paste("Loading", length(species$species), "models from https://birdflow-science.s3.amazonaws.com/avian_flu/"))
# This is slow so skipping if it's already done - useful when developing to
# avoid having to wait to reload.
if(!all(species$species %in% names(models))) {
print(paste("Loading", length(species$species), "models from https://birdflow-science.s3.amazonaws.com/sparse_avian_flu/"))
for (sp in species$species) {
print(paste0("Loading model for species: ", sp))
models[[sp]] <- BirdFlowR::load_model(model = sp)
}
}
}
else {
print("Models already loaded.")
}
}
1 change: 1 addition & 0 deletions R/models.R
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
models <- new.env()
6 changes: 0 additions & 6 deletions R/zzz.R
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
.onLoad <- function(libname, pkgname) {
utils::data("species", package = "BirdFlowAPI", envir = parent.env(environment()))
utils::data("flow_colors", package = "BirdFlowAPI", envir = parent.env(environment()))
load_models()
}

.ignore_unused_imports <- function() {
plumber::plumb
}
13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,21 @@ BirdFlowAPI is an R package containing the API and backend code for the Avian In

You can build and install BirdFlowAPI locally or from GitHub.

**Build locally:**
```sh
R CMD build .
```
This will create a source tarball (e.g., `BirdFlowAPI_x.y.z.tar.gz`).

**Install from local tarball:**
**Install from local cloned repository:**
```r
install.packages("path/to/BirdFlowAPI_x.y.z.tar.gz", repos = NULL, type = "source")
devtools::install()
```

**Install from GitHub:**
```r
devtools::install_github("UMassCDS/BirdFlowAPI")
```

## Configure API

The `load_models.R` file defines a function `load_models` that loads the the models of all species. The `load_models` function must be explicitly called while configuring the API. This is done by running `load_models()`.

## Testing

Run the full test suite:
Expand Down
3 changes: 1 addition & 2 deletions inst/plumber/flow/endpoints/predict.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
library(BirdFlowR)
birdflow_options(collection_url = "https://birdflow-science.s3.amazonaws.com/avian_flu/")

#* Test and generate a plot from a BirdFlow model
Expand Down Expand Up @@ -27,4 +26,4 @@ function(model_name = "ambduc") {
file_exists = file_exists,
file_size = file_size
)
}
}
5 changes: 3 additions & 2 deletions man/flow.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions man/get_s3_config.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions man/grapes-or-or-grapes.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions man/set_s3_config.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions tests/testthat/setup.R
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
load_models()
Loading