Ingest Seabird Vulnerabilities to Offshore Wind Energy Development

1 Process

Goal: Summarize and compare seabird vulnerabilities to offshore wind energy development in the Atlantic and Pacific Oceans.

  1. Import data from “sensitivity” or “vulnerability” studies

    A species’ vulnerability is based on a combination of its sensitivity and exposure. Exposure is determined by the overlap of the species’ current distribution and the magnitude of the expected climate change.
    (Morrison et al. 2016)

  2. Match taxonomy (sp_id)

    • Use GBIF since comprehensive (includes OBIS)

    • WoRMS missing 8 seabirds from Willmott et al. (2013)).

    • Map occurrences using GBIF’s Maps API.

    • Use taxadb R package for copy of local taxa database and fast matching:

      sp_id = taxadb::get_ids(
        names    = "Chen caerulescens", 
        provider = "gbif", 
        format   = "prefix")
      # "GBIF:2498165"
  3. Match species with mapped distributions

    • Q: What to do with species sensitivities but no maps or maps but no sensitivities?
  4. Calculate population-weighted sensitivities

    • Normalize for combining species layers, using:

      base::scale(x, center = TRUE, scale = TRUE)

      based on mean (\(\bar{x}\)) and standard deviation (\(\sigma\)): \[ x_{normalized} = \frac{x - \bar{x}}{\sigma} \]

Code
librarian::shelf(
  dplyr, DT, janitor, glue, here, leaflet, 
  purrr, readxl, readr, scales, stringr, taxadb, terra, tidyr,
  quiet = T)
options(readr.show_col_types = F)

knitr::opts_chunk$set(
  message = F)

willmott2013_xls <- "/Users/bbest/My Drive/projects/msens/data/raw/studies/willmott2013/Willmott et al. - 2013 - The relative vulnerability of migratory bird speci.xlsx"

winship2018_xls <- "/Users/bbest/My Drive/projects/_archive/offhab/data/raw/ncei.noaa.gov - seabirds, atlantic/0176682/1.1/data/0-data/NCCOS-Atlantic-Birds_ArchiveDataPackage/Documentation/atl_spp.xlsx"

dir_atl_raw    <- here("data/sdm/raw/nc_atl_birds_dens")
dir_atl_out    <- here("data/sdm/derived/nc_atl_birds_dens")
atl_mw_csv     <- glue("{dir_atl_out}/mw.csv")
atl_mw_spp_csv <- glue("{dir_atl_out}/mw_spp.csv")

2 Atlantic

2.1 Species Vulnerability (Willmott, Forcey, and Kent 2013)

  • Species Vulnerability Data: (Willmott, Forcey, and Kent 2013)

  • asdf (Willmott, Forcey, and Kent 2013)

  • Manual PDF table extraction. Exported to tables from PDF to XLSX with Adobe Acrobat. Copied individual tables into dedicated sheets and for each: unmerged columns, removed duplicate headers and empty columns.

Code
# install the taxanomic database locally
taxadb::td_create("gbif")

# get all data from study
d <- read_excel(willmott2013_xls, sheet = "TableA-2") |> 
  left_join(
    read_excel(willmott2013_xls, sheet = "Table5"), 
    by = "Common Name") |> 
  left_join(
    read_excel(willmott2013_xls, sheet = "Table8"), 
    by = "Common Name") |> 
  left_join(
    read_excel(willmott2013_xls, sheet = "Table11"), 
    by = "Common Name") |> 
  janitor::clean_names() |> 
  mutate(
    sp_id = taxadb::get_ids(
      scientific_name, "gbif", "prefix")) |> 
  rename(
    sp_scientific = scientific_name, 
    sp_common     = common_name) |> 
  mutate(
    study = "willmott2013") |> 
  relocate(study, sp_id)
stopifnot(sum(is.na(d$sp_id))      == 0)
stopifnot(sum(duplicated(d$sp_id)) == 0)

# [d]ata frame of species [spp]
d_w_spp <- d |> 
  select(study, sp_id, sp_scientific, sp_common)

# show d_w_spp
d_w_spp |> 
  DT::datatable(
    caption = "Atlantic seabird species with vulnerabilities (Willmott et al. 2013)")
Code
# [d]ata frame of sensitivity [w]eights
d_w <- d |>
  select(study, sp_id, where(is.double)) |>
  pivot_longer(
    cols      = -c(study, sp_id),
    names_to  = "parameter",
    values_to = "value_dbl") |> 
  bind_rows(
    d |>
      select(sp_id, where(is.character)) |>
      pivot_longer(
        cols      = -sp_id,
        names_to  = "parameter",
        values_to = "value_chr") ) |> 
  filter(!(is.na(value_dbl) & is.na(value_chr)))
params <- setdiff(unique(d_w$parameter), names(d_w_spp))
params
 [1] "lower_final_population_sensitivity"               
 [2] "best_estimate_final_population_sensitivity"       
 [3] "upper_final_population_sensitivity"               
 [4] "lower_final_collision_sensitivity_rank"           
 [5] "best_estimate_final_collision_sensitivity_rank"   
 [6] "upper_final_collision_sensitivity_rank"           
 [7] "lower_final_displacement_sensitivity_rank"        
 [8] "best_estimate_final_displacement_sensitivity_rank"
 [9] "upper_final_displacement_sensitivity_rank"        
[10] "collision_sensitivity_qualitative_ranking"        
[11] "displacement_sensitivity_qualitative_value"       
Code
d_w |> 
  DT::datatable(
    caption = "Atlantic seabird sensitivity parameters (Willmott et al. 2013)")

2.2 Species Distributions (Winship et al. 2018)

Code
# [d]ata frame of species [m]aps
d_m <- read_excel(winship2018_xls) |> 
  janitor::clean_names() |> 
  rename(
    sp_code       = species_code,
    sp_scientific = scientific_name,
    sp_common     = common_name) |> 
  mutate(
    study         = "winship2018",
    sp_common     = str_replace_all(sp_common,     "\r\n", " "),
    sp_scientific = str_replace_all(sp_scientific, "\r\n", " "),
    sp_id         = taxadb::get_ids(
      sp_scientific, "gbif", "prefix")) |> 
  relocate(study, sp_id)
stopifnot(sum(is.na(d_m$sp_id)) == 0)

d_m_seasons <- d_m |> 
  select(study, sp_code, sp_id, spring, summer, fall, winter) |> 
  pivot_longer(
    cols      = -c(study, sp_code, sp_id),
    names_to  = "season",
    values_to = "season_bln") |> 
  filter(!is.na(season_bln)) |> 
  select(study, season, sp_code, sp_id) |> 
  mutate(
    tif = glue("{sp_code}_{season}.tif") ) |> 
  arrange(study, season, sp_code)

d_m_spp <- d_m |> 
  select(-spring, -summer, -fall, -winter)

d_m |> 
  DT::datatable(
    caption = "Atlantic seabird species with map distributions (Winship et al. 2018)")
Code
# knitr::opts_chunk$set(
#   eval = F)

2.3 Species Vulnerability x Distribution

Code
# [d]ata frame of species [spp] with both distribution [m]aps and sensitivity [w]eights
d_mw_spp <- d_m_spp |> 
  rename(study_map = study) |>
  inner_join(
    d_w_spp |> 
      rename(study_param = study) |> 
      select(study_param, sp_id), 
    by = "sp_id")

# add taxa info to d_mw_spp ----
d_mw_spp <- d_mw_spp |> 
  mutate(
    d_sp = map(sp_id, taxadb::filter_id, provider = "gbif")) |> 
  unnest(d_sp)
write_csv(d_mw_spp, atl_mw_spp_csv)
      
d_w_spp_notm <- d_w_spp |> 
  anti_join(
    d_mw_spp, by = "sp_id") # nrow: 130
d_m_spp_notw <- d_m_spp |> 
  anti_join(
    d_mw_spp, by = "sp_id") # nrow:   0
stopifnot(
  0 %in% c(
    nrow(d_w_spp_notm), 
    nrow(d_m_spp_notw)))

# [d]ata frame of both distribution [m]aps and sensitivity [w]eights
d_mw <- d_m_seasons |> # nrow: 140
  select(-study, -sp_code) |> 
  inner_join(
    d_mw_spp,                   # nrow:  47
    by = "sp_id") |>            # nrow: 140
  relocate(study_map, season, sp_code, sp_id) |> 
  arrange(study_map, season, sp_code) |> 
  left_join(
    d_w |> 
      filter(!is.na(value_dbl)) |> 
      select(-study, -value_chr) |>
      pivot_wider(
        names_from  = parameter,
        values_from = value_dbl),
    by = "sp_id")

write_csv(d_mw, atl_mw_csv)

d_mw |> 
  datatable(
    caption = "Atlantic seabird species and seasons with both map distributions (Winship et al. 2018) and vulnerability parameters (Willmott et al. 2013)")

2.3.1 Rasters

Code
writeCOG <- function(r, tif, method = "BILINEAR", ...){
  # TODO: move to oceanmetrics/leaftiles

  tmp <- tempfile(fileext = ".tif")

  terra::writeRaster(r, tmp, ...)

  gdalUtilities::gdal_translate(
    src_dataset = tmp,
    dst_dataset = tif,
    co = matrix(c(
      "COMPRESS=DEFLATE",
      paste0("RESAMPLING=", method),
      paste0("OVERVIEW_RESAMPLING=", method),
      "PREDICTOR=2",
      "BIGTIFF=IF_NEEDED"), ncol = 1),
    of = "COG")

  unlink(tmp)
}
Code
d_mw <- read_csv(atl_mw_csv) |>
  mutate(
    path_tif = glue("{dir_atl_raw}/{tif}"),
    r        = map(path_tif, rast, lyrs = "n_per_km2") )
d_mw_spp <- read_csv(atl_mw_spp_csv)

# TODO: Shiny app
# - [ ] sel_spp: https://dreamrs.github.io/shinyWidgets/#tree
# - [ ] txt_eqn_raster_presum & txt_eqn_values_postsum: 
#       NOTE: experimental and not to be used in production 
#             for security concerns.
# - [ ] 

rgn_default <- "Atlantic"
ssn_default <- "fall"
spp_default <- d_mw |> 
  filter(season == ssn_default) |> 
  pull(sp_id)
input <- list(
  sel_rgn = rgn_default,
  sel_ssn = ssn_default,
  sel_spp = spp_default,
  txt_eqn_raster_presum = "terra::scale(r) * (
    best_estimate_final_population_sensitivity +
    best_estimate_final_collision_sensitivity_rank +
    best_estimate_final_displacement_sensitivity_rank )",
  txt_eqn_values_postsum = "scales::rescale(v, c(0, 100))")

ssn = "fall"

d_mws <- d_mw |> 
  filter(season == ssn)

librarian::shelf(skimr)
d_mws |> 
  select(any_of(params)) |> 
  skimr::skim() |> 
  select(-n_missing, -complete_rate) |> 
  yank("numeric")

Variable type: numeric

skim_variable mean sd p0 p25 p50 p75 p100 hist
lower_final_population_sensitivity 1.89 0.56 1.13 1.50 1.69 2.03 3.65 ▇▅▂▁▁
best_estimate_final_population_sensitivity 2.56 0.67 1.50 2.12 2.50 2.75 4.50 ▆▇▆▁▂
upper_final_population_sensitivity 2.99 0.68 1.78 2.53 2.88 3.25 4.88 ▃▇▆▂▂
lower_final_collision_sensitivity_rank 7.00 1.82 0.47 6.88 7.33 7.89 9.00 ▁▁▁▆▇
best_estimate_final_collision_sensitivity_rank 8.02 1.63 2.05 7.47 8.39 9.09 9.81 ▁▁▁▅▇
upper_final_collision_sensitivity_rank 8.72 1.32 4.56 8.14 9.13 9.65 10.00 ▁▁▁▃▇
lower_final_displacement_sensitivity_rank 3.73 2.66 0.00 1.69 2.63 6.04 9.13 ▇▆▂▆▂
best_estimate_final_displacement_sensitivity_rank 5.45 2.94 0.00 3.20 5.50 8.34 9.80 ▂▆▆▂▇
upper_final_displacement_sensitivity_rank 6.34 2.88 0.00 4.70 6.60 8.99 9.95 ▂▂▆▆▇
Code
# TODO: Shiny add tab of summary with tab of full table

equn_r <- input$txt_eqn_raster_presum
equn_v <- input$txt_eqn_values_postsum

d_mws <- d_mws %>% 
  mutate(
    r_e = pmap(., function(...) {
      with(list(...), {
        eval(parse(text = equn_r)) } ) } ) )
res_m <- res(d_mws$r[[1]])
r_sum <- sum(rast(d_mws$r_e)) |> 
  terra::project("epsg:3857", method="bilinear", res=res_m)
if (equn_v > ""){
  v <- values(r_sum)
  values(r_sum) <- eval(parse(text = equn_v))
}

plot(r_sum)

Code
pal <- colorNumeric("Spectral", values(r_sum),
  na.color = "transparent", reverse = T)

leaflet() |> 
  addProviderTiles("Esri.OceanBasemap") |> 
  addRasterImage(
    r_sum, 
    project = F,
    colors  = pal, 
    opacity = 0.9) |>  # TODO: shiny input$opacity
  addLegend(
    pal = pal, 
    values = values(r_sum),
    title  = "Species<br>Vulnerability<br>x Density")

3 Pacific

Code
dir_study <- "/Users/bbest/My Drive/projects/msens/data/raw/studies/adams2016"

# collision vulnerability
cv_csv <- glue("{dir_study}/Collisionvulner/CCS_vulnerability_FINAL_VERSION_v10_CV.csv")
# displacement vulnerability
dv_csv <- glue("{dir_study}/Displacementvul/CCS_vulnerability_FINAL_VERSION_v10_DV.csv")
# population vulnerability
pv_csv <- glue("{dir_study}/Populationvulne/CCS_vulnerability_FINAL_VERSION_v9_PV.csv")

flds_spp <- c("TaxNumCl", "Taxonomy", "AlphaCode", "Common_Name", "Scientific_Name")

d_pv <- read_csv(pv_csv)
d_cv <- read_csv(cv_csv)
d_dv <- read_csv(dv_csv)
# names(d_cv)
d_spp <- d_cv |> 
  select(all_of(flds_spp)) |> 
  mutate(
    Scientific_Name = case_match(
      Scientific_Name,
      "Oceanodroma furcatus" ~ "Oceanodroma furcata",
      "Pterodroma ultina"    ~ "Pterodroma ultima",
      .default = Scientific_Name), 
    sp_id = taxadb::get_ids(
      Scientific_Name, "gbif", format = "prefix") )
stopifnot(sum(is.na(d_spp$sp_id)) == 0)
stopifnot(sum(duplicated(d_spp$sp_id)) == 0)

d_spp |> 
  datatable()

Other:

4 Frameworks

5 Next Steps

TODO:

6 References

Adams, Josh, Emily C. Kelsey, Jonathan J. Felis, and David M. Pereksta. 2016a. “Collision and Displacement Vulnerability Among Marine Birds of the California Current System Associated with Offshore Wind Energy Infrastructure.” https://doi.org/10.3133/ofr20161154.
———. 2016b. “Data for Calculating Population, Collision and Displacement Vulnerability Among Marine Birds of the California Current System Associated with Offshore Wind Energy Infrastructure (Ver. 2.0, June 2017).” U.S. Geological Survey. https://doi.org/10.5066/F79C6VJ0.
Best, Benjamin D., and Patrick N. Halpin. 2019. “Minimizing Wildlife Impacts for Offshore Wind Energy Development: Winning Tradeoffs for Seabirds in Space and Cetaceans in Time.” PLOS ONE 14 (5): e0215722. https://doi.org/10.1371/journal.pone.0215722.
Bradbury, Gareth, Mark Trinder, Bob Furness, Alex N. Banks, Richard W. G. Caldow, and Duncan Hume. 2014. “Mapping Seabird Sensitivity to Offshore Wind Farms.” PLoS ONE 9 (9): e106366. https://doi.org/10.1371/journal.pone.0106366.
Croll, Donald A., Aspen A. Ellis, Josh Adams, Aonghais S. C. P. Cook, Stefan Garthe, Morgan Wing Goodale, C. Scott Hall, et al. 2022. “Framework for Assessing and Mitigating the Impacts of Offshore Wind Energy Development on Marine Birds.” Biological Conservation 276 (December): 109795. https://doi.org/10.1016/j.biocon.2022.109795.
Fauchald, Per, Victoria Marja Sofia Ollus, Manuel Ballesteros, Arild Breistøl, Signe Christensen-Dalsgaard, Sindre Molværsmyr, Arnaud Tarroux, Geir Helge Systad, and Børge Moe. 2024. “Mapping Seabird Vulnerability to Offshore Wind Farms in Norwegian Waters.” Frontiers in Marine Science 11 (March). https://doi.org/10.3389/fmars.2024.1335224.
Furness, Robert W., Helen M. Wade, and Elizabeth A. Masden. 2013. “Assessing Vulnerability of Marine Bird Populations to Offshore Wind Farms.” Journal of Environmental Management 119 (April): 56–66. https://doi.org/10.1016/j.jenvman.2013.01.025.
Galparsoro, Ibon, Iratxe Menchaca, Joxe Mikel Garmendia, Ángel Borja, Ana D. Maldonado, Gregorio Iglesias, and Juan Bald. 2022. “Reviewing the Ecological Impacts of Offshore Wind Farms.” Npj Ocean Sustainability 1 (1): 1–8. https://doi.org/10.1038/s44183-022-00003-5.
Garthe, Stefan, and Ommo Hüppop. 2004. “Scaling Possible Adverse Effects of Marine Wind Farms on Seabirds: Developing and Applying a Vulnerability Index.” Journal of Applied Ecology 41 (4): 724–34. https://doi.org/10.1111/j.0021-8901.2004.00918.x.
Goodale, M. Wing, Anita Milman, and Curtice R. Griffin. 2019. “Assessing the Cumulative Adverse Effects of Offshore Wind Energy Development on Seabird Foraging Guilds Along the East Coast of the United States.” Environmental Research Letters 14 (7): 074018. https://doi.org/10.1088/1748-9326/ab205b.
Goodale, M., and Iain Stenhouse. 2016. “A Conceptual Model to Determine Vulnerability of Wildlife Populations to Offshore Wind Energy Development.” HumanWildlife Interactions 10 (1). https://digitalcommons.usu.edu/hwi/vol10/iss1/7.
Grover, Whitney. 2023. “Offshore Wind Energy and Seabird Collision Vulnerability in California.” Master’s Projects and Capstones, May. https://repository.usfca.edu/capstone/1508.
Halpern, Benjamin S., and Rod Fujita. 2013. “Assumptions, Challenges, and Future Directions in Cumulative Impact Analysis.” Ecosphere 4 (10): art131. https://doi.org/10.1890/ES13-00181.1.
Kelsey, Emma C., Jonathan J. Felis, Max Czapanskiy, David M. Pereksta, and Josh Adams. 2018. “Collision and Displacement Vulnerability to Offshore Wind Energy Infrastructure Among Marine Birds of the Pacific Outer Continental Shelf.” Journal of Environmental Management 227 (December): 229–47. https://doi.org/10.1016/j.jenvman.2018.08.051.
Morrison, Wendy E., Mark W. Nelson, Roger B. Griffis, and Jonathan A. Hare. 2016. “Methodology for Assessing the Vulnerability of Marine and Anadromous Fish Stocks in a Changing Climate.” Fisheries 41 (7): 407409. https://doi.org/10.1080/03632415.2016.1182507.
Serratosa, J., and T. Allinson. 2022. “AVISTEP: The Avian Sensitivity Tool for Energy Planning. Technical Manual.”
Willmott, Julia Robinson, G. Forcey, and A. Kent. 2013. “The Relative Vulnerability of Migratory Bird Species to Offshore Wind Energy Projects on the Atlantic Outer Continental Shelf: An Assessment Method and Database.”
Winship, Arliss J., Brian Patrick Kinlan, Timothy Paul White, Jeffrey Leirness, and John Christensen. 2018. “Modeling at-Sea Density of Marine Birds to Support Atlantic Marine Renewable Energy Planning.”