Merge species distribution models and produce tabular summaries for score calculation

Published

2026-03-25 15:14:39

1 Overview (v4b: is_turtle = TRUE)

Merge species distribution models from multiple datasets, flag valid taxa (is_ok), and produce tabular summaries as input to calc_scores.qmd.

Data preparation steps (taxonomic ID resolution, ad-hoc species fixes, dataset ingestion) are in merge_models_prep.qmd.

v4b. For turtles, this workflow implements a “multiplicative merge” approach that integrates the SWOT+DPS ER surface with suitability surfaces from other datasets, while still allowing critical habitat cells to override via max. For non-turtles, the workflow implements a “max merge” approach that simply takes the maximum value across all datasets for each cell, with masking based on global mask priority when applicable. The max merge approach is unchanged from previous versions.

Code
librarian::shelf(
  DBI,
  dplyr,
  DT,
  duckdb,
  glue,
  here,
  knitr,
  readr,
  stringr,
  tibble,
  tidyr,
  quiet = T
)
options(readr.show_col_types = F)

source(here("libs/paths.R"))

# database connections
con_sdm <- dbConnect(duckdb(dbdir = sdm_db, read_only = F))

# section eval flags (set to TRUE to re-run) ----
do_merge_all <- T # re-merge all taxa (runs setup chunks + full iterate loop, >1 hr)
do_merge_turtles <- F # re-merge turtles only (multiplicative suitability × extinction risk)
do_merge_mammals <- T # re-merge mammals only (MMPA floor fix: all mammals are MMPA-protected)
do_merge <- do_merge_all || do_merge_turtles || do_merge_mammals
do_is_ok <- T # flag valid taxa

2 Add Merged Dataset (ms_merge)

2.1 Insert ms_merge dataset row

Code
ds_key <- "ms_merge"
row_dataset <- tibble(
  ds_key = !!ds_key,
  name_short = glue("Marine Sensitivity Merged Model, {Sys.Date()}"),
  name_original = "Marine Sensitivity merged model from multiple inputs",
  description = "This dataset is derived from others. When a given taxon has multiple distributions, the maximum value is taken. If an IUCN range exists, then that and any critical habitat (NOAA or FWS) are used to mask the other inputs so that only areas within the IUCN range are considered.",
  citation = "",
  source_broad = "BOEM",
  source_detail = "https://marinesensitivity.org/docs",
  regions = "USA",
  response_type = "mixed",
  taxa_groups = "all taxa",
  year_pub = 2025,
  date_obs_beg = NA,
  date_obs_end = NA,
  date_env_beg = NA,
  date_env_end = NA,
  link_info = "https://github.com/MarineSensitivity",
  link_download = NA,
  link_metadata = NA,
  links_other = NA,
  spatial_res_deg = 0.05,
  temporal_res = "static"
)

if (dbExistsTable(con_sdm, "dataset")) {
  dbExecute(con_sdm, glue("DELETE FROM dataset WHERE ds_key = '{ds_key}'"))
}
[1] 1
Code
dbWriteTable(con_sdm, "dataset", row_dataset, append = TRUE)
# tbl(con_sdm, "dataset")

2.2 Dataset metadata

Code
# add metadata columns to dataset table ----
for (col_def in list(
  c("name_display", "VARCHAR"),
  c("value_info", "VARCHAR"),
  c("is_mask", "BOOLEAN"),
  c("sort_order", "INTEGER"),
  c("global_mask_priority", "DECIMAL")
)) {
  tryCatch(
    dbExecute(
      con_sdm,
      glue(
        "ALTER TABLE dataset ADD COLUMN IF NOT EXISTS {col_def[1]} {col_def[2]}"
      )
    ),
    error = function(e) {
      if (!grepl("already exists", e$message, ignore.case = TRUE)) {
        stop(e)
      }
    }
  )
}

# populate metadata for each dataset
metadata <- tribble(
  ~ds_key               , ~name_display           , ~value_info                            , ~is_mask , ~sort_order , ~global_mask_priority ,
  "am_0.05"             , "AquaMaps SDM"          , NA                                     , FALSE    , 1L          , NA                    ,
  "ca_nmfs"             , "NMFS Core Area"        , "Core: 100"                            , TRUE     , 2L          , NA                    ,
  "ch_nmfs"             , "NMFS Critical Habitat" , "EN:100, TN:50"                        , TRUE     , 3L          , NA                    ,
  "ch_fws"              , "FWS Critical Habitat"  , "EN:100, TN:50"                        , TRUE     , 4L          , NA                    ,
  "rng_fws"             , "FWS Range"             , "EN:100, TN:50, LC:1"                  , TRUE     , 5L          , NA                    ,
  "bl"                  , "BirdLife Range"        , "CR:50, EN:25, VU:5, NT:2, LC:1, DD:1" , TRUE     , 6L          , 2.0                   ,
  "rng_iucn"            , "IUCN Range"            , "CR:50, EN:25, VU:5, NT:2, LC:1, DD:1" , TRUE     , 7L          , 2.0                   ,
  "rng_turtle_swot_dps" , "SWOT+DPS Turtle Range" , "EN:100, TN:50"                        , TRUE     , 8L          , 1.0                   ,
  "ms_merge"            , "Merged Model"          , NA                                     , FALSE    , 0L          , NA
)

for (i in 1:nrow(metadata)) {
  m <- metadata[i, ]
  vi <- ifelse(is.na(m$value_info), "NULL", glue("'{m$value_info}'"))
  gmp <- ifelse(is.na(m$global_mask_priority), "NULL", m$global_mask_priority)
  dbExecute(
    con_sdm,
    glue(
      "UPDATE dataset
       SET name_display         = '{m$name_display}',
           value_info           = {vi},
           is_mask              = {tolower(m$is_mask)},
           sort_order           = {m$sort_order},
           global_mask_priority = {gmp}
       WHERE ds_key = '{m$ds_key}'"
    )
  )
}

tbl(con_sdm, "dataset") |>
  select(ds_key, name_display, is_mask, sort_order) |>
  collect()
# A tibble: 9 × 4
  ds_key              name_display          is_mask sort_order
  <chr>               <chr>                 <lgl>        <int>
1 am_0.05             AquaMaps SDM          FALSE            1
2 bl                  BirdLife Range        TRUE             6
3 ca_nmfs             NMFS Core Area        TRUE             2
4 ch_fws              FWS Critical Habitat  TRUE             4
5 ch_nmfs             NMFS Critical Habitat TRUE             3
6 rng_fws             FWS Range             TRUE             5
7 rng_iucn            IUCN Range            TRUE             7
8 rng_turtle_swot_dps SWOT+DPS Turtle Range TRUE             8
9 ms_merge            Merged Model          FALSE            0

2.3 Update turtle rng_iucn values

Code
# TODO: systematically reconcile rng_iucn values with latest IUCN Red List API
#   assessments (rredlist R package). IUCN shapefile `category` can lag behind
#   the current website assessment. Known mismatches beyond turtles include:
#   - Chinook Salmon: shapefile LC(1) vs latest IUCN assessment TBD
#   - Killer Whale: shapefile DD(1) vs latest IUCN assessment TBD
#   - Beluga Whale: shapefile LC(1) vs latest IUCN assessment TBD
#   - Humpback Whale: shapefile LC(1) vs latest IUCN assessment TBD
#   - Steller Sea Lion: shapefile NT(2) vs latest IUCN assessment TBD
#   - False Killer Whale: shapefile NT(2) vs latest IUCN assessment TBD
#   - Bearded Seal: shapefile NT(2) vs latest IUCN assessment TBD
#   - Boulder Star Coral: shapefile NT(2) vs latest IUCN assessment TBD
#   - Dolly Varden: shapefile LC(1) vs latest IUCN assessment TBD

# is_turtle: override rng_iucn cell values with latest IUCN website assessments
#   for v4c, generalize this to all species using IUCN API
d_turtle_iucn <- tribble(
  ~scientific_name         , ~iucn_code ,
  "Chelonia mydas"         , "LC"       , # iucnredlist.org/species/4615/285108125
  "Eretmochelys imbricata" , "CR"       , # iucnredlist.org/species/8005/12881238
  "Lepidochelys kempii"    , "CR"       , # iucnredlist.org/species/11533/155057916
  "Dermochelys coriacea"   , "VU"       , # iucnredlist.org/species/6494/43526147
  "Caretta caretta"        , "VU"       , # iucnredlist.org/species/3897/119333622
  "Lepidochelys olivacea"  , "VU"
) # iucnredlist.org/species/11534/3292503

# get rng_iucn mdl_seq for each turtle taxon
d_turtle_mdl <- tbl(con_sdm, "taxon") |>
  filter(sp_cat == "turtle") |>
  select(taxon_id, scientific_name) |>
  inner_join(
    tbl(con_sdm, "taxon_model") |>
      filter(ds_key == "rng_iucn"),
    by = "taxon_id"
  ) |>
  collect() |>
  inner_join(d_turtle_iucn, by = "scientific_name") |>
  mutate(
    value = msens::compute_er_score(glue("IUCN:{iucn_code}"))
  )

# update rng_iucn cell values per turtle species
for (j in 1:nrow(d_turtle_mdl)) {
  r <- d_turtle_mdl[j, ]
  n <- dbExecute(
    con_sdm,
    glue(
      "UPDATE model_cell SET value = {r$value}
       WHERE mdl_seq = {r$mdl_seq}"
    )
  )
  message(glue(
    "  updated {r$scientific_name} rng_iucn (mdl_seq={r$mdl_seq}): ",
    "IUCN:{r$iucn_code} -> value={r$value} ({n} cells)"
  ))
}
  updated Caretta caretta rng_iucn (mdl_seq=19857): IUCN:VU -> value=5 (430925 cells)
  updated Chelonia mydas rng_iucn (mdl_seq=19858): IUCN:LC -> value=1 (432603 cells)
  updated Eretmochelys imbricata rng_iucn (mdl_seq=19860): IUCN:CR -> value=50 (352038 cells)
  updated Lepidochelys kempii rng_iucn (mdl_seq=19861): IUCN:CR -> value=50 (70171 cells)
  updated Dermochelys coriacea rng_iucn (mdl_seq=19859): IUCN:VU -> value=5 (420435 cells)
  updated Lepidochelys olivacea rng_iucn (mdl_seq=19862): IUCN:VU -> value=5 (137612 cells)

2.4 Iterate merge across taxa

Code
ds_key <- "ms_merge"

# cell_tif <- glue("{dir_data}/derived/r_bio-oracle_planarea.tif")
# r_cell <- rast(cell_tif)
# ext(r_cell) <- round(ext(r_cell), 3)

# determine which sp_cats to merge based on flags
if (do_merge_all) {
  merge_sp_cats <- NULL # no filter — all taxa
} else {
  merge_sp_cats <- c()
  if (do_merge_turtles) {
    merge_sp_cats <- c(merge_sp_cats, "turtle")
  }
  if (do_merge_mammals) merge_sp_cats <- c(merge_sp_cats, "mammal")
}

d_x <- tbl(con_sdm, "taxon") |>
  filter(is_ok)
if (!is.null(merge_sp_cats)) {
  d_x <- d_x |> filter(sp_cat %in% merge_sp_cats)
}
d_x <- d_x |>
  arrange(desc(n_ds), taxon_id) |>
  collect()

# removed: quick fix for turtle sp_cat — now handled by reclassify_reptiles
# chunk after taxon table creation (bind_birds_notbirds_ds)

# table(d_x$sp_cat, useNA = "ifany")
# OLD:
# bird        coral         fish invertebrate       mammal      reptile
#   49           10           12            1           12            7
# NEW (rng_iucn):
# coral         fish invertebrate       mammal        other       turtle
#   375          927          148           58            2            6

ds_keys <- tbl(con_sdm, "dataset") |>
  pull(ds_key) |>
  setdiff("ms_merge")

# datasets for extracting max value SDM
# ds_keys_sdm  <- setdiff(ds_keys, "rng_iucn")   # OLD: excluding IUCN range map except for masking
ds_keys_sdm <- ds_keys # NEW: include IUCN range map for max value SDM
# datasets that form the combined mask (IUCN range + critical habitats + national range), only when global mask exists for species
ds_keys_mask <- tbl(con_sdm, "dataset") |>
  filter(is_mask) |>
  pull(ds_key)

# datasets with global_mask_priority (lower = higher priority)
ds_global_masks <- tbl(con_sdm, "dataset") |>
  filter(!is.na(global_mask_priority)) |>
  select(ds_key, global_mask_priority) |>
  collect() |>
  arrange(global_mask_priority)

t_0 <- Sys.time()
for (i in 1:nrow(d_x)) {
  # i = 1  # which(str_detect(d_x$scientific_name, ".*ricei")) # i = 1512

  d_sp <- d_x |> slice(i)
  is_turtle <- d_sp$sp_cat == "turtle"
  # d_sp |> glimpse()
  # Rows: 1
  # Columns: 18
  # $ taxon_id         <dbl> 127186
  # $ taxon_authority  <chr> "worms"
  # $ n_ds             <int> 5
  # $ am_0.05          <int> 7466
  # $ ch_nmfs          <int> 18230
  # $ ch_fws           <int> 18309
  # $ rng_fws          <int> 18401
  # $ sp_cat           <chr> "fish"
  # $ bl               <int> NA
  # $ mdl_seq          <int> NA
  # $ scientific_name  <chr> "Salmo salar"
  # $ common_name      <chr> "silver salmon"
  # $ redlist_code     <chr> "EN"
  # $ worms_is_marine  <lgl> TRUE
  # $ worms_is_extinct <lgl> NA
  # $ worms_id         <dbl> 127186
  # $ is_ok            <lgl> TRUE
  # $ rng_iucn         <int> 19445

  # list species models by dataset from taxon_model junction table
  d_sp_l <- tbl(con_sdm, "taxon_model") |>
    filter(taxon_id == !!d_sp$taxon_id) |>
    collect() |>
    mutate(
      taxon_authority = d_sp$taxon_authority
    )
  #   taxon_id taxon_authority ds_key   mdl_seq
  #      <dbl> <chr>           <chr>      <int>
  # 1   127186 worms           am_0.05     7466
  # 2   127186 worms           ch_fws     18309
  # 3   127186 worms           ch_nmfs    18230
  # 4   127186 worms           rng_fws    18401
  # 5   127186 worms           rng_iucn   19445
  # NEW ds_key: "ms_merge"; mdl_seq: 20030

  d_r_ds <- tbl(con_sdm, "model_cell") |>
    filter(
      mdl_seq %in% d_sp_l$mdl_seq
    ) |>
    left_join(
      tbl(con_sdm, "model") |>
        select(mdl_seq, ds_key) |>
        filter(mdl_seq %in% d_sp_l$mdl_seq),
      by = "mdl_seq"
    ) |>
    group_by(ds_key) |>
    summarize(
      n_cell = n(),
      v_min = min(value, na.rm = T),
      v_max = max(value, na.rm = T),
      .groups = "drop"
    ) |>
    collect() |>
    mutate(
      ds_str = glue("{ds_key} ({n_cell} cells, {v_min} - {v_max})")
    )
  #   ds_key   n_cell v_min v_max ds_str
  #   <chr>     <dbl> <int> <int> <glue>
  # 1 rng_iucn   6245    50    50 rng_iucn (6245 cells, 50 - 50)
  # 2 ch_fws       29    90    90 ch_fws (29 cells, 90 - 90)
  # 3 am_0.05   11739     1   100 am_0.05 (11739 cells, 1 - 100)
  # 4 ch_nmfs       3    90    90 ch_nmfs (3 cells, 90 - 90)
  # 5 rng_fws     264    50    90 rng_fws (264 cells, 50 - 90)

  if (is_turtle) {
    # turtle multiplicative merge (v4b) ----
    # merged_value = pmax(1, round(er_value * suit_value / 100))
    # critical habitat cells override via max

    # suitability surface: non-mask SDM datasets (e.g., am_0.05)
    ds_suit_sp <- intersect(d_sp_l$ds_key, setdiff(ds_keys_sdm, ds_keys_mask))
    # ER surface: SWOT+DPS
    ds_er_sp <- intersect(d_sp_l$ds_key, "rng_turtle_swot_dps")
    # critical habitat datasets
    ds_ch_sp <- intersect(d_sp_l$ds_key, c("ch_nmfs", "ch_fws", "ca_nmfs"))
    # all datasets used (for description)
    ds_sdm_sp <- unique(c(ds_suit_sp, ds_er_sp, ds_ch_sp))

    if (length(ds_er_sp) > 0) {
      er_mdl_seqs <- d_sp_l |>
        filter(ds_key %in% ds_er_sp) |>
        pull(mdl_seq)
      d_er <- tbl(con_sdm, "model_cell") |>
        filter(mdl_seq %in% er_mdl_seqs) |>
        select(cell_id, er_value = value) |>
        collect()

      if (length(ds_suit_sp) > 0) {
        suit_mdl_seqs <- d_sp_l |>
          filter(ds_key %in% ds_suit_sp) |>
          pull(mdl_seq)
        d_suit <- tbl(con_sdm, "model_cell") |>
          filter(mdl_seq %in% suit_mdl_seqs) |>
          group_by(cell_id) |>
          summarize(suit_value = max(value, na.rm = T), .groups = "drop") |>
          collect()
        d_r_sp <- d_er |>
          left_join(d_suit, by = "cell_id") |>
          mutate(
            suit_value = coalesce(suit_value, 1L),
            value = pmax(
              1L,
              as.integer(round(
                er_value * suit_value / 100
              ))
            )
          ) |>
          select(cell_id, value)
      } else {
        # no suitability: suit=1 everywhere
        d_r_sp <- d_er |>
          mutate(
            value = pmax(1L, as.integer(round(er_value * 1L / 100)))
          ) |>
          select(cell_id, value)
      }
    } else {
      # no SWOT+DPS (unlikely): fall back to max of all SDMs
      sdm_mdl_seqs <- d_sp_l |>
        filter(ds_key %in% intersect(d_sp_l$ds_key, ds_keys_sdm)) |>
        pull(mdl_seq)
      d_r_sp <- tbl(con_sdm, "model_cell") |>
        filter(mdl_seq %in% sdm_mdl_seqs) |>
        group_by(cell_id) |>
        summarize(value = max(value, na.rm = T), .groups = "drop") |>
        collect()
    }

    # union critical habitat cells (override via max)
    if (length(ds_ch_sp) > 0) {
      ch_mdl_seqs <- d_sp_l |>
        filter(ds_key %in% ds_ch_sp) |>
        pull(mdl_seq)
      d_ch <- tbl(con_sdm, "model_cell") |>
        filter(mdl_seq %in% ch_mdl_seqs) |>
        group_by(cell_id) |>
        summarize(value = max(value, na.rm = T), .groups = "drop") |>
        collect()
      d_r_sp <- bind_rows(d_r_sp, d_ch) |>
        group_by(cell_id) |>
        summarize(value = max(value, na.rm = T), .groups = "drop")
    }

    has_global_mask <- FALSE
    has_other_sdm <- FALSE
  } else {
    # non-turtle max merge (v4 approach, unchanged) ----

    # datasets used for SDM
    ds_sdm_sp <- intersect(d_sp_l$ds_key, ds_keys_sdm)

    sdm_mdl_seqs <- d_sp_l |>
      filter(ds_key %in% ds_sdm_sp) |>
      pull(mdl_seq)

    # query of SDM with max value across all datasets
    q_sdm <- tbl(con_sdm, "model_cell") |>
      filter(
        mdl_seq %in% sdm_mdl_seqs
      ) |>
      group_by(cell_id) |>
      summarize(value = max(value, na.rm = T), .groups = "drop")

    # find highest-priority global mask this species has
    sp_global_masks <- d_sp_l |>
      inner_join(ds_global_masks, by = "ds_key") |>
      arrange(global_mask_priority)

    has_global_mask <- nrow(sp_global_masks) > 0

    # only mask if species has at least one SDM dataset besides the global mask
    # (avoid self-intersection, e.g. birds with only BirdLife)
    has_other_sdm <- FALSE
    if (has_global_mask) {
      best_mask_ds <- sp_global_masks$ds_key[1]
      other_sdm_ds <- setdiff(ds_sdm_sp, best_mask_ds)
      has_other_sdm <- length(other_sdm_ds) > 0
    }

    if (has_global_mask && has_other_sdm) {
      # get datasets used for mask
      # exclude lower-priority global masks from the mask union
      lower_global_masks <- sp_global_masks |>
        filter(ds_key != best_mask_ds) |>
        pull(ds_key)
      ds_mask_sp <- setdiff(
        intersect(d_sp_l$ds_key, ds_keys_mask),
        lower_global_masks
      )

      # get mdl_seqs for masking datasets
      mask_mdl_seqs <- d_sp_l |>
        filter(ds_key %in% ds_mask_sp) |>
        pull(mdl_seq)

      q_mask <- tbl(con_sdm, "model_cell") |>
        filter(mdl_seq %in% mask_mdl_seqs) |>
        distinct(cell_id) |>
        mutate(value = 1)

      # get SDM cells with mask applied
      d_r_sp <- q_sdm |>
        semi_join(
          q_mask,
          by = join_by(cell_id)
        ) |>
        collect()
    } else {
      # no global mask or no other SDM to mask — just max value of all SDMs
      d_r_sp <- collect(q_sdm)
    }
  }

  # apply MMPA/MBTA spatial minimum floors ----
  # all marine mammals are MMPA-protected (USFWS jurisdiction for walrus, polar
  # bear, sea otter, manatee, dugong; NMFS for all others)
  # derive floor values from compute_er_score to stay in sync with scoring logic
  if (d_sp$sp_cat == "mammal") {
    mmpa_floor <- msens::compute_er_score("NMFS:LC", is_mmpa = TRUE)
    d_r_sp <- d_r_sp |>
      mutate(value = pmax(value, mmpa_floor))
  }
  if (isTRUE(d_sp$is_mbta)) {
    mbta_floor <- msens::compute_er_score("NMFS:LC", is_mbta = TRUE)
    d_r_sp <- d_r_sp |>
      mutate(value = pmax(value, mbta_floor))
  }

  sp_sci <- d_sp$scientific_name
  sp_cmn <- d_sp$common_name
  sp_cat <- d_sp$sp_cat
  sp_key <- glue("{ds_key}:{d_sp$taxon_id}")

  # show message every 50 iterations or for the first 5 iterations
  if (i <= 5 || i %% 50 == 0) {
    eta <- Sys.time() + round((Sys.time() - t_0) / i * (nrow(d_x) - i))
    message(glue(
      "Processing {i}/{nrow(d_x)} [{sp_key}] ({sp_cat}): {sp_cmn} (_{sp_sci}_) ~ ETA: {eta}"
    ))
    # started ~15:00
  }

  # delete: existing merged model (must happen before zero-cells check,
  # otherwise stale merged models persist for species clipped to 0 cells) ----
  mdl_seqs <- tbl(con_sdm, "model") |>
    filter(ds_key == !!ds_key, taxa == !!sp_key) |>
    pull(mdl_seq)
  if (length(mdl_seqs) > 0) {
    dbExecute(
      con_sdm,
      glue(
        "DELETE FROM taxon_model WHERE ds_key = '{ds_key}' AND taxon_id = {d_sp$taxon_id}"
      )
    )
    dbExecute(
      con_sdm,
      glue("DELETE FROM model WHERE ds_key = '{ds_key}' AND taxa = '{sp_key}'")
    )
    dbExecute(
      con_sdm,
      glue(
        "DELETE FROM species WHERE ds_key = '{ds_key}' AND taxa = '{sp_key}'"
      )
    )
    dbExecute(
      con_sdm,
      glue(
        "DELETE FROM model_cell WHERE mdl_seq IN ({paste(mdl_seqs, collapse = ',')})"
      )
    )
    dbExecute(
      con_sdm,
      glue(
        "UPDATE taxon SET mdl_seq = NULL WHERE mdl_seq IN ({paste(mdl_seqs, collapse = ',')})"
      )
    )
  }

  n_cells <- nrow(d_r_sp)
  if (n_cells == 0) {
    message(glue("No cells for {sp_sci} ({i}/{nrow(d_x)})"))
    next()
  }

  # append: model ----
  has_mask_str <- if (has_global_mask && has_other_sdm) {
    glue(
      "; Mask applied (global mask: {best_mask_ds}) from combining datasets: {paste(ds_mask_sp, collapse = ', ')}"
    )
  } else {
    ""
  }
  d_model <- tibble(
    ds_key = ds_key,
    taxa = sp_key,
    time_period = "2025",
    region = "USA",
    mdl_type = "mixed",
    description = if (is_turtle) {
      glue(
        "Marine Sensitivity merged model with multiplicative merge ",
        "(er * suit / 100) from datasets: {paste(ds_sdm_sp, collapse = ', ')}"
      )
    } else {
      glue(
        "Marine Sensitivity merged model with max values from datasets: ",
        "{paste(ds_sdm_sp, collapse = ', ')}{has_mask_str}"
      )
    }
  )
  dbWriteTable(con_sdm, "model", d_model, append = TRUE)
  # tbl(con_sdm, "model") |> collect() |> tail()

  # get the mdl_seq that was just created
  mdl_seq <- dbGetQuery(
    con_sdm,
    glue(
      "
    SELECT mdl_seq FROM model
    WHERE
      ds_key = '{ds_key}' AND
      taxa   = '{sp_key}'
    ORDER BY mdl_seq DESC LIMIT 1 "
    )
  )$mdl_seq

  # d_sp |> glimpse()
  # Rows: 1
  # Columns: 15
  # $ taxon_id         <dbl> 127186
  # $ taxon_authority  <chr> "worms"
  # $ n_ds             <int> 4
  # $ am_0.05          <int> 7466
  # $ ch_nmfs          <int> 18230
  # $ ch_fws           <int> 18309
  # $ rng_fws          <int> 18401
  # $ sp_cat           <chr> "fish"
  # $ bl               <int> NA
  # $ mdl_seq          <int> NA
  # $ scientific_name  <chr> "Salmo salar"
  # $ common_name      <chr> "silver salmon"
  # $ redlist_code     <chr> "EN"
  # $ worms_is_marine  <lgl> TRUE
  # $ worms_is_extinct <lgl> NA

  # append: species ----
  d_species <- tibble(
    ds_key = ds_key,
    taxa = sp_key,
    sp_key = sp_key,
    worms_id = ifelse(
      d_sp$taxon_authority == "worms",
      d_sp$taxon_id,
      NA_integer_
    ),
    botw_id = ifelse(
      d_sp$taxon_authority == "botw",
      d_sp$taxon_id,
      NA_integer_
    ),
    gbif_id = NA_integer_,
    itis_id = NA_integer_,
    iucn_id = NA_integer_,
    scientific_name_dataset = sp_sci,
    common_name_dataset = sp_cmn,
    scientific_name_accepted = sp_sci,
    common_name_accepted = sp_cmn,
    redlist_code = d_sp$redlist_code,
    redlist_year = NA_integer_,
    sp_cat = sp_cat,
    worms_is_marine = d_sp$worms_is_marine,
    worms_is_extinct = d_sp$worms_is_extinct
  )
  # d_species |> glimpse()

  stopifnot(
    length(setdiff(names(d_species), dbListFields(con_sdm, "species"))) == 0
  )
  stopifnot(
    setdiff(dbListFields(con_sdm, "species"), names(d_species)) == "sp_seq"
  )
  dbWriteTable(con_sdm, "species", d_species, append = T)
  # tbl(con_sdm, "species") |> collect() |> tail()
  # tbl(con_sdm, "model")   |> collect() |> tail()
  stopifnot(
    tbl(con_sdm, "species") |> filter(is.na(sp_seq)) |> collect() |> nrow() == 0
  )

  # append: model_cell ----
  d_mdl_cell <- d_r_sp |>
    mutate(
      mdl_seq = mdl_seq
    ) |>
    arrange(cell_id)
  dbWriteTable(con_sdm, "model_cell", d_mdl_cell, append = T)

  # update taxon with mdl_seq
  dbExecute(
    con_sdm,
    glue(
      "
    UPDATE taxon
    SET   mdl_seq  = {mdl_seq}
    WHERE taxon_id = {d_sp$taxon_id}"
    )
  )

  # append ms_merge row to taxon_model junction table
  dbWriteTable(
    con_sdm,
    "taxon_model",
    tibble(
      taxon_id = d_sp$taxon_id,
      ds_key = "ms_merge",
      mdl_seq = as.integer(mdl_seq)
    ),
    append = TRUE
  )
}
Processing 1/9795 [ms_merge:137205] (turtle): Loggerhead Turtle (_Caretta caretta_) ~ ETA: 2026-03-25 18:23:32.770625
Processing 2/9795 [ms_merge:137206] (turtle): Green Turtle (_Chelonia mydas_) ~ ETA: 2026-03-25 18:16:50.066506
Processing 3/9795 [ms_merge:137207] (turtle): Hawksbill Turtle (_Eretmochelys imbricata_) ~ ETA: 2026-03-25 17:49:03.893138
Processing 4/9795 [ms_merge:137209] (turtle): Leatherback Turtle (_Dermochelys coriacea_) ~ ETA: 2026-03-25 18:26:52.986749
Processing 5/9795 [ms_merge:137208] (turtle): Kemp's Ridley Turtle (_Lepidochelys kempii_) ~ ETA: 2026-03-25 17:48:40.215049
Processing 50/9795 [ms_merge:105801] (fish): blue shark (_Prionace glauca_) ~ ETA: 2026-03-25 15:32:12.823242
Processing 100/9795 [ms_merge:126291] (fish): neckeel (_Derichthys serpentinus_) ~ ETA: 2026-03-25 15:24:55.787796
Processing 150/9795 [ms_merge:137087] (mammal): Minke Whale (_Balaenoptera acutorostrata_) ~ ETA: 2026-03-25 15:22:20.604487
Processing 200/9795 [ms_merge:158562] (fish): American eel (_Anguilla rostrata_) ~ ETA: 2026-03-25 15:21:44.27663
Processing 250/9795 [ms_merge:159243] (fish): knobbed porgy (_Calamus nodosus_) ~ ETA: 2026-03-25 15:21:39.622662
Processing 300/9795 [ms_merge:207227] (coral): hump coral (_Porites solida_) ~ ETA: 2026-03-25 15:20:52.93006
Processing 350/9795 [ms_merge:217557] (fish): Duck-billed eel (_Nettastoma parviceps_) ~ ETA: 2026-03-25 15:22:07.503129
Processing 400/9795 [ms_merge:271389] (fish): sicklefin smoothhound (_Mustelus lunulatus_) ~ ETA: 2026-03-25 15:23:22.980562
Processing 450/9795 [ms_merge:271896] (fish): Argus moray (_Muraena argus_) ~ ETA: 2026-03-25 15:23:38.164699
Processing 500/9795 [ms_merge:275443] (fish): blacktail pikeconger (_Hoplunnis diomediana_) ~ ETA: 2026-03-25 15:23:52.505774
Processing 550/9795 [ms_merge:276867] (fish): dubious conger (_Bathycongrus dubius_) ~ ETA: 2026-03-25 15:24:06.2618
Processing 600/9795 [ms_merge:280576] (fish): dwarf wrasse (_Doratonotus megalepis_) ~ ETA: 2026-03-25 15:23:17.044364
Processing 650/9795 [ms_merge:288918] (coral): hump coral (_Porites vaughani_) ~ ETA: 2026-03-25 15:22:28.190741
Processing 700/9795 [ms_merge:418734] (other): buttonwood (_Conocarpus erectus_) ~ ETA: 2026-03-25 15:21:39.087438
Processing 750/9795 [ms_merge:1460141] (fish): Clearnose skate (_Rostroraja eglanteria_) ~ ETA: 2026-03-25 15:20:49.578239
Processing 800/9795 [ms_merge:101928] (invertebrate): NA (_Ampelisca spinipes_) ~ ETA: 2026-03-25 15:19:59.03439
Processing 850/9795 [ms_merge:103638] (other): NA (_Aplidium bermudae_) ~ ETA: 2026-03-25 15:19:07.975971
Processing 900/9795 [ms_merge:104061] (other): truncated brachiopod (_Megerlia truncata_) ~ ETA: 2026-03-25 15:19:16.823844
Processing 950/9795 [ms_merge:104503] (invertebrate): NA (_Clausocalanus furcatus_) ~ ETA: 2026-03-25 15:18:25.612174
Processing 1000/9795 [ms_merge:104740] (invertebrate): NA (_Pontella securifer_) ~ ETA: 2026-03-25 15:17:34.157382
No cells for Apristurus laurussonii (1043/9795)
No cells for Hexanchus nakamurai (1044/9795)
Processing 1050/9795 [ms_merge:106215] (invertebrate): an acorn barnacle (_Balanus crenatus_) ~ ETA: 2026-03-25 15:16:42.854045
Processing 1100/9795 [ms_merge:107316] (invertebrate): NA (_Dorhynchus thomsoni_) ~ ETA: 2026-03-25 15:16:51.993659
Processing 1150/9795 [ms_merge:107649] (invertebrate): Atlantic Northern Shrimp (_Pandalus borealis_) ~ ETA: 2026-03-25 15:16:01.158601
No cells for Willemoesia leptodactyla (1162/9795)
Processing 1200/9795 [ms_merge:111411] (other): lacy crust bryozoan (_Membranipora membranacea_) ~ ETA: 2026-03-25 15:16:09.843859
Processing 1250/9795 [ms_merge:114595] (other): NA (_Mesodasys laticaudatus_) ~ ETA: 2026-03-25 15:15:18.293717
Processing 1300/9795 [ms_merge:117388] (invertebrate): knotted thread hydroid (_Obelia geniculata_) ~ ETA: 2026-03-25 15:15:27.279403
Processing 1350/9795 [ms_merge:117681] (invertebrate): NA (_Acryptolaria longitheca_) ~ ETA: 2026-03-25 15:15:36.808762
Processing 1400/9795 [ms_merge:117925] (invertebrate): NA (_Sertularia tenera_) ~ ETA: 2026-03-25 15:14:45.81589
Processing 1450/9795 [ms_merge:124048] (invertebrate): NA (_Nymphaster arenatus_) ~ ETA: 2026-03-25 15:14:54.576753
Processing 1500/9795 [ms_merge:124951] (invertebrate): Pipe-cleaner brittlestar (_Asteronyx loveni_) ~ ETA: 2026-03-25 15:14:03.349292
Processing 1550/9795 [ms_merge:126381] (fish): bandwing flyingfish (_Cheilopogon exsiliens_) ~ ETA: 2026-03-25 15:14:12.674295
No cells for Bathygadus favosus (1572/9795)
No cells for Mora moro (1587/9795)
Processing 1600/9795 [ms_merge:126538] (fish): triplewart seadevil (_Cryptopsaras couesii_) ~ ETA: 2026-03-25 15:14:22.111106
No cells for Linophryne brevibarbata (1606/9795)
No cells for Oneirodes carlsbergi (1618/9795)
No cells for Phyllorhinichthys micractis (1621/9795)
Processing 1650/9795 [ms_merge:126621] (fish): G<fc>nther<92>s lanternfish (_Lepidophanes guentheri_) ~ ETA: 2026-03-25 15:13:32.098266
No cells for Bajacalifornia calcarata (1676/9795)
Processing 1700/9795 [ms_merge:126731] (fish): brownsnout spookfish (_Dolichopteryx longipes_) ~ ETA: 2026-03-25 15:13:41.654394
No cells for Mentodus rostratus (1709/9795)
No cells for Parablennius pilicornis (1712/9795)
No cells for Epigonus telescopus (1748/9795)
Processing 1750/9795 [ms_merge:126862] (fish): snake mackerel (_Gempylus serpens_) ~ ETA: 2026-03-25 15:13:50.954935
Processing 1800/9795 [ms_merge:127232] (fish): flying gurnard (_Dactylopterus volitans_) ~ ETA: 2026-03-25 15:14:00.035304
No cells for Poromitra crassiceps (1807/9795)
No cells for Maurolicus muelleri (1834/9795)
Processing 1850/9795 [ms_merge:127332] (fish): Pawnee dragonfish (_Bathophilus pawneei_) ~ ETA: 2026-03-25 15:13:10.127003
No cells for Eustomias tetranema (1864/9795)
No cells for Leptostomias longibarba (1871/9795)
Processing 1900/9795 [ms_merge:127414] (fish): oceanic puffer (_Lagocephalus lagocephalus_) ~ ETA: 2026-03-25 15:13:19.557606
No cells for Allocyttus verrucosus (1902/9795)
No cells for Zeus faber (1905/9795)
Processing 1950/9795 [ms_merge:129043] (invertebrate): NA (_Sapphirina bicuspidata_) ~ ETA: 2026-03-25 15:13:28.539284
Processing 2000/9795 [ms_merge:130071] (other): NA (_Lysidice ninetta_) ~ ETA: 2026-03-25 15:12:37.713364
Processing 2050/9795 [ms_merge:130545] (other): NA (_Paralacydonia paradoxa_) ~ ETA: 2026-03-25 15:12:48.111662
Processing 2100/9795 [ms_merge:131121] (other): NA (_Dipolydora quadrilobata_) ~ ETA: 2026-03-25 15:12:57.536959
Processing 2150/9795 [ms_merge:131534] (other): NA (_Polycirrus plumosus_) ~ ETA: 2026-03-25 15:13:06.873314
Processing 2200/9795 [ms_merge:134654] (invertebrate): NA (_Pseudopallene brevicollis_) ~ ETA: 2026-03-25 15:13:16.36323
Processing 2250/9795 [ms_merge:135205] (coral): Marenzeller's stony coral (_Fungiacyathus (Bathyactis) marenzelleri_) ~ ETA: 2026-03-25 15:13:30.038314
Processing 2300/9795 [ms_merge:136034] (other): NA (_Aspidosiphon (Paraspidosiphon) laevis_) ~ ETA: 2026-03-25 15:12:42.231811
Processing 2350/9795 [ms_merge:138963] (invertebrate): common Atlantic slippersnail (_Crepidula fornicata_) ~ ETA: 2026-03-25 15:12:54.644993
Processing 2400/9795 [ms_merge:139472] (invertebrate): Sirvent's disc-fin squid (_Cycloteuthis sirventi_) ~ ETA: 2026-03-25 15:13:05.438615
Processing 2450/9795 [ms_merge:140226] (invertebrate): Lesueur's pteropod (_Limacina lesueurii_) ~ ETA: 2026-03-25 15:13:15.757836
Processing 2500/9795 [ms_merge:140722] (invertebrate): reticulate pteropod (_Peracle reticulata_) ~ ETA: 2026-03-25 15:13:26.154618
Processing 2550/9795 [ms_merge:141840] (invertebrate): obscure solarelle (_Solariella obscura_) ~ ETA: 2026-03-25 15:13:36.413973
Processing 2600/9795 [ms_merge:150225] (invertebrate): shredded carrot sponge (_Amphilectus fucorum_) ~ ETA: 2026-03-25 15:12:46.696323
No cells for Scomber colias (2608/9795)
Processing 2650/9795 [ms_merge:156730] (invertebrate): smooth abra (_Abra lioica_) ~ ETA: 2026-03-25 15:12:57.349222
Processing 2700/9795 [ms_merge:157145] (other): NA (_Aglaophamus circinata_) ~ ETA: 2026-03-25 15:13:07.263215
Processing 2750/9795 [ms_merge:157524] (other): NA (_Parapionosyllis longicirrata_) ~ ETA: 2026-03-25 15:13:16.895918
No cells for Narcine brasiliensis (2769/9795)
Processing 2800/9795 [ms_merge:158067] (invertebrate): heart urchin (_Moira atropos_) ~ ETA: 2026-03-25 15:13:26.441966
Processing 2850/9795 [ms_merge:158456] (invertebrate): thorned spiny crab (_Rochinia tanneri_) ~ ETA: 2026-03-25 15:13:41.20256
No cells for Gymnura micrura (2858/9795)
Processing 2900/9795 [ms_merge:158771] (fish): polka-dot cusk-eel (_Otophidium omostigma_) ~ ETA: 2026-03-25 15:13:53.399823
Processing 2950/9795 [ms_merge:158902] (fish): metallic lanternfish (_Myctophum affine_) ~ ETA: 2026-03-25 15:13:05.407979
Processing 3000/9795 [ms_merge:159219] (fish): Kriete's tonguefish (_Symphurus billykrietei_) ~ ETA: 2026-03-25 15:13:16.797923
Processing 3050/9795 [ms_merge:159399] (fish): bigeye soldierfish (_Ostichthys trachypoma_) ~ ETA: 2026-03-25 15:13:26.386296
Processing 3100/9795 [ms_merge:159571] (fish): northern searobin (_Prionotus carolinus_) ~ ETA: 2026-03-25 15:13:36.055327
Processing 3150/9795 [ms_merge:159767] (fish): naked goby (_Gobiosoma bosc_) ~ ETA: 2026-03-25 15:13:46.052865
No cells for Aphanopus intermedius (3158/9795)
Processing 3200/9795 [ms_merge:160265] (invertebrate): Cayenne keyhole limpet (_Diodora cayenensis_) ~ ETA: 2026-03-25 15:12:55.389785
Processing 3250/9795 [ms_merge:165129] (invertebrate): NA (_Hyattella pertusa_) ~ ETA: 2026-03-25 15:13:05.652416
Processing 3300/9795 [ms_merge:166814] (invertebrate): NA (_Neopetrosia subtriangularis_) ~ ETA: 2026-03-25 15:13:15.435276
Processing 3350/9795 [ms_merge:169843] (invertebrate): NA (_Jaspis stellifera_) ~ ETA: 2026-03-25 15:13:24.779623
Processing 3400/9795 [ms_merge:173577] (coral): NA (_Umbellula magniflora_) ~ ETA: 2026-03-25 15:13:35.234445
Processing 3450/9795 [ms_merge:180921] (invertebrate): needle snail (_Cerithium egenum_) ~ ETA: 2026-03-25 15:12:45.569295
Processing 3500/9795 [ms_merge:196879] (invertebrate): NA (_Clathria (Thalysias) venosa_) ~ ETA: 2026-03-25 15:12:56.255705
No cells for Plesiastrea versipora (3504/9795)
Processing 3550/9795 [ms_merge:208494] (invertebrate): cabbage jewel box (_Chama brassica_) ~ ETA: 2026-03-25 15:13:06.250527
Processing 3600/9795 [ms_merge:209021] (invertebrate): NA (_Actaea polyacantha_) ~ ETA: 2026-03-25 15:13:15.697338
Processing 3650/9795 [ms_merge:209944] (other): Christmas tree worm (_Spirobranchus giganteus_) ~ ETA: 2026-03-25 15:13:25.871701
Processing 3700/9795 [ms_merge:210544] (invertebrate): coral snapping shrimp (_Alpheus lottini_) ~ ETA: 2026-03-25 15:12:36.970542
Processing 3750/9795 [ms_merge:212899] (invertebrate): NA (_Notostomus gibbosus_) ~ ETA: 2026-03-25 15:12:47.730611
No cells for Pomacentrus tripunctatus (3754/9795)
No cells for Pterygotrigla macrorhynchus (3779/9795)
No cells for Conus betulinus (3794/9795)
No cells for Gymnura poecilura (3795/9795)
Processing 3800/9795 [ms_merge:215762] (invertebrate): vexillum rock shell (_Vexilla vexillum_) ~ ETA: 2026-03-25 15:12:57.248649
Processing 3850/9795 [ms_merge:216872] (invertebrate): Arabian cowrie (_Mauritia arabica_) ~ ETA: 2026-03-25 15:13:06.438509
No cells for Coloconger scholesi (3869/9795)
No cells for Coloconger raniceps (3870/9795)
No cells for Melanostomias niger (3873/9795)
No cells for Synodus doaki (3877/9795)
No cells for Diaphus ostenfeldi (3880/9795)
Processing 3900/9795 [ms_merge:217816] (fish): NA (_Penopus microphthalmus_) ~ ETA: 2026-03-25 15:13:16.835743
No cells for Prognichthys sealei (3912/9795)
No cells for Hoplostethus melanopterus (3917/9795)
No cells for Notopogon xenosoma (3925/9795)
No cells for Solenostomus paradoxus (3926/9795)
No cells for Halicampus boothae (3927/9795)
No cells for Phoxocampus belcheri (3928/9795)
No cells for Parascorpaena mossambica (3930/9795)
No cells for Scorpaenodes scaber (3931/9795)
No cells for Kuhlia rupestris (3938/9795)
No cells for Carangoides oblongus (3939/9795)
No cells for Scomberoides tol (3942/9795)
No cells for Cirrhitichthys aprinus (3948/9795)
No cells for Cyprinocirrhites polyactis (3949/9795)
Processing 3950/9795 [ms_merge:218934] (fish): golden-spot-hogfish (_Bodianus perditio_) ~ ETA: 2026-03-25 15:13:30.257731
No cells for Bodianus perditio (3950/9795)
No cells for Halichoeres zeylonicus (3951/9795)
No cells for Salarias sinuosus (3957/9795)
No cells for Cabillus lacertops (3958/9795)
No cells for Eviota sigillata (3961/9795)
No cells for Eviota prasina (3963/9795)
No cells for Feia nympha (3964/9795)
No cells for Luposicya lupus (3966/9795)
No cells for Pleurosicya mossambica (3968/9795)
No cells for Diademichthys lineatus (3975/9795)
No cells for Neolaeops microphthalmus (3977/9795)
No cells for Tylerius spinosissimus (3988/9795)
No cells for Barathronus maculatus (3990/9795)
Processing 4000/9795 [ms_merge:220253] (invertebrate): smooth red shrimp (_Aristeus semidentatus_) ~ ETA: 2026-03-25 15:12:41.889184
No cells for Champsodon capensis (4011/9795)
Processing 4050/9795 [ms_merge:221392] (fish): Tribute spiderfish (_Bathypterois guentheri_) ~ ETA: 2026-03-25 15:12:54.161042
No cells for Bathypterois guentheri (4050/9795)
No cells for Bathypterois atricolor (4051/9795)
No cells for Ostracoberyx dorygenys (4059/9795)
No cells for Margrethia valentinae (4061/9795)
No cells for Rhinochimaera africana (4063/9795)
No cells for Mesoplodon peruvianus (4097/9795)
Processing 4100/9795 [ms_merge:231877] (other): NA (_Branchiosyllis oculata_) ~ ETA: 2026-03-25 15:13:05.125093
No cells for Luciosudis normani (4111/9795)
Processing 4150/9795 [ms_merge:236619] (invertebrate): NA (_Hemityphis tenuimanus_) ~ ETA: 2026-03-25 15:13:14.659477
Processing 4200/9795 [ms_merge:240049] (invertebrate): NA (_Anoplodactylus monotrema_) ~ ETA: 2026-03-25 15:13:23.986986
Processing 4250/9795 [ms_merge:240848] (invertebrate): NA (_Alpheus crockeri_) ~ ETA: 2026-03-25 15:13:34.631366
Processing 4300/9795 [ms_merge:242799] (invertebrate): NA (_Amphioplus thrombodes_) ~ ETA: 2026-03-25 15:12:44.903004
Processing 4350/9795 [ms_merge:244070] (invertebrate): NA (_Ophiostigma isocanthum_) ~ ETA: 2026-03-25 15:12:54.406592
Processing 4400/9795 [ms_merge:246804] (invertebrate): NA (_Phanogenia gracilis_) ~ ETA: 2026-03-25 15:13:03.584494
Processing 4450/9795 [ms_merge:250697] (other): NA (_Herdmania pallida_) ~ ETA: 2026-03-25 15:13:13.907772
Processing 4500/9795 [ms_merge:254398] (fish): Bering poacher (_Occella dodecaedron_) ~ ETA: 2026-03-25 15:13:23.917893
Processing 4550/9795 [ms_merge:254545] (fish): whitespotted greenling (_Hexagrammos stelleri_) ~ ETA: 2026-03-25 15:12:34.210583
Processing 4600/9795 [ms_merge:255048] (invertebrate): rainbow star (_Orthasterias koehleri_) ~ ETA: 2026-03-25 15:12:43.990699
Processing 4650/9795 [ms_merge:258487] (invertebrate): NA (_Pendanthura tanaiformis_) ~ ETA: 2026-03-25 15:12:53.637608
Processing 4700/9795 [ms_merge:266603] (other): gould's sipunculid (_Phascolopsis gouldii_) ~ ETA: 2026-03-25 15:13:03.463359
No cells for Myxine garmani (4708/9795)
No cells for Myxine mccoskeri (4710/9795)
No cells for Apristurus fedorovi (4712/9795)
No cells for Sphyrna media (4713/9795)
No cells for Chimaera lignaria (4714/9795)
No cells for Hydrolagus mitsukurii (4715/9795)
No cells for Hydrolagus trolli (4716/9795)
No cells for Rhinochimaera pacifica (4717/9795)
No cells for Bathyraja diplotaenia (4720/9795)
No cells for Bathyraja isotrachys (4721/9795)
No cells for Bathyraja smirnovi (4722/9795)
No cells for Bathyraja trachouros (4723/9795)
No cells for Etmopterus evansi (4724/9795)
No cells for Gymnothorax phalarus (4725/9795)
No cells for Muraena lentiginosa (4726/9795)
No cells for Venefica multiporosa (4727/9795)
No cells for Ophichthus altipennis (4728/9795)
No cells for Chlorophthalmus albatrossis (4731/9795)
No cells for Chlorophthalmus mento (4733/9795)
No cells for Lestidiops similis (4744/9795)
No cells for Magnisudis indica (4747/9795)
Processing 4750/9795 [ms_merge:272107] (fish): NA (_Scopelarchus stephensi_) ~ ETA: 2026-03-25 15:13:12.990793
No cells for Hemiramphus saltator (4763/9795)
No cells for Hoplostethus japonicus (4772/9795)
No cells for Hoplostethus mento (4773/9795)
Processing 4800/9795 [ms_merge:272382] (fish): Nascent membranehead (_Hymenocephalus nascens_) ~ ETA: 2026-03-25 15:12:23.035071
No cells for Merluccius hernandezi (4806/9795)
No cells for Physiculus nematopus (4815/9795)
No cells for Physiculus roseus (4817/9795)
No cells for Trachipterus ishikawae (4822/9795)
No cells for Trachipterus jacksonensis (4823/9795)
No cells for Himantolophus appelii (4829/9795)
No cells for Dibranchus erinaceus (4837/9795)
No cells for Dibranchus hystrix (4838/9795)
No cells for Dibranchus japonicus (4839/9795)
No cells for Dibranchus nudivomer (4840/9795)
No cells for Dibranchus spinosus (4841/9795)
No cells for Dibranchus spongiosa (4842/9795)
No cells for Oneirodes luetkeni (4846/9795)
No cells for Oneirodes rosenblatti (4847/9795)
No cells for Oneirodes sabex (4848/9795)
Processing 4850/9795 [ms_merge:272656] (fish): dogtooth lampfish (_Ceratoscopelus townsendi_) ~ ETA: 2026-03-25 15:12:33.651497
No cells for Cataetyx simus (4876/9795)
No cells for Echiodon exsilium (4879/9795)
No cells for Bathyonus caudalis (4882/9795)
No cells for Monomitopus garmani (4884/9795)
No cells for Monomitopus kumae (4885/9795)
No cells for Monomitopus torvus (4886/9795)
Processing 4900/9795 [ms_merge:272853] (fish): Barethroat slickhead (_Asquamiceps hjorti_) ~ ETA: 2026-03-25 15:12:45.800904
No cells for Asquamiceps hjorti (4900/9795)
No cells for Glossanodon polli (4910/9795)
No cells for Maulisia acuticeps (4917/9795)
No cells for Mentodus perforatus (4918/9795)
No cells for Apogon americanus (4920/9795)
No cells for Apogon atricaudus (4921/9795)
No cells for Apogon retrosella (4932/9795)
No cells for Callanthias japonicus (4940/9795)
No cells for Trachinotus stilbe (4949/9795)
Processing 4950/9795 [ms_merge:273305] (fish): jack mackerel (_Trachurus symmetricus_) ~ ETA: 2026-03-25 15:12:56.891827
No cells for Chaetodon guentheri (4953/9795)
No cells for Chaetodon plebeius (4955/9795)
No cells for Bodianus eclancheri (4964/9795)
No cells for Mugil hospes (4965/9795)
No cells for Pholis nebulosa (4975/9795)
No cells for Chromis flavicauda (4978/9795)
No cells for Serranus huascarii (4987/9795)
Processing 5000/9795 [ms_merge:274013] (fish): North Pacific frostfish (_Benthodesmus pacificus_) ~ ETA: 2026-03-25 15:13:06.994609
No cells for Uranoscopus japonicus (5002/9795)
No cells for Arnoglossus brunneus (5026/9795)
No cells for Arnoglossus scapha (5027/9795)
No cells for Bothus constellatus (5028/9795)
No cells for Cynoglossus joyneri (5031/9795)
No cells for Cynoglossus robustus (5032/9795)
No cells for Symphurus bathyspilus (5034/9795)
No cells for Glyptocephalus stelleri (5040/9795)
No cells for Hippoglossoides dubius (5042/9795)
No cells for Microstomus achne (5046/9795)
Processing 5050/9795 [ms_merge:274374] (fish): Intermediate staghorn sculpin (_Gymnocanthus intermedius_) ~ ETA: 2026-03-25 15:13:19.649927
Processing 5100/9795 [ms_merge:274640] (fish): NA (_Peristedion imberbe_) ~ ETA: 2026-03-25 15:13:30.80222
No cells for Pontinus rhodochrous (5106/9795)
No cells for Scorpaena onaria (5115/9795)
Processing 5150/9795 [ms_merge:274812] (fish): cowcod (_Sebastes levis_) ~ ETA: 2026-03-25 15:12:42.338171
No cells for Melamphaes janae (5187/9795)
Processing 5200/9795 [ms_merge:274996] (fish): Soela hatchetfish (_Polyipnus soelae_) ~ ETA: 2026-03-25 15:12:53.155386
No cells for Polyipnus soelae (5200/9795)
No cells for Polyipnus tridentifer (5201/9795)
No cells for Polyipnus triphanos (5202/9795)
No cells for Bathophilus filifer (5211/9795)
No cells for Leptostomias bermudensis (5227/9795)
No cells for Photonectes gracilis (5233/9795)
No cells for Canthigaster ocellicincta (5245/9795)
No cells for Sphoeroides lispus (5248/9795)
Processing 5250/9795 [ms_merge:275280] (fish): southern puffer (_Sphoeroides nephelus_) ~ ETA: 2026-03-25 15:13:04.509025
No cells for Sphoeroides tyleri (5252/9795)
No cells for Pseudopleuronectes herzensteini (5256/9795)
No cells for Breviraja mouldi (5259/9795)
No cells for Moringua abbreviata (5260/9795)
No cells for Hoplunnis pacifica (5261/9795)
No cells for Myrophis plumbeus (5262/9795)
No cells for Lepophidium pardale (5284/9795)
No cells for Porogadus guentheri (5287/9795)
No cells for Opsanus dichrostomus (5289/9795)
No cells for Porichthys bathoiketes (5291/9795)
No cells for Porichthys margaritatus (5292/9795)
No cells for Porichthys pauciradiatus (5295/9795)
No cells for Porichthys porosissimus (5296/9795)
No cells for Gobiesox adustus (5297/9795)
Processing 5300/9795 [ms_merge:275678] (fish): stippled clingfish (_Gobiesox punctulatus_) ~ ETA: 2026-03-25 15:13:17.172913
No cells for Citharichthys mariajorisae (5304/9795)
No cells for Microgobius curtus (5309/9795)
No cells for Microgobius cyclolepis (5310/9795)
No cells for Microgobius tabogensis (5314/9795)
No cells for Halichoeres argus (5315/9795)
No cells for Halichoeres dimidiatus (5316/9795)
No cells for Paralichthys tropicus (5318/9795)
No cells for Poecilopsetta colorata (5323/9795)
No cells for Poecilopsetta praelonga (5324/9795)
No cells for Dicrolene longimana (5331/9795)
No cells for Dicrolene tristis (5332/9795)
No cells for Ogcocephalus notatus (5336/9795)
No cells for Hemanthias peruanus (5344/9795)
No cells for Liopropoma fasciatum (5347/9795)
No cells for Liopropoma longilepis (5348/9795)
Processing 5350/9795 [ms_merge:275951] (fish): cave basslet (_Liopropoma mowbrayi_) ~ ETA: 2026-03-25 15:13:28.989742
No cells for Rypticus bicolor (5352/9795)
No cells for Rypticus nigripinnis (5354/9795)
No cells for Trinectes microphthalmus (5364/9795)
No cells for Ancylopsetta kumperae (5367/9795)
No cells for Ancylopsetta microctenus (5368/9795)
No cells for Cyprinodon artifrons (5371/9795)
No cells for Scarus perrico (5377/9795)
No cells for Johnius grypotus (5378/9795)
No cells for Menticirrhus panamensis (5379/9795)
No cells for Stellifer microps (5380/9795)
No cells for Stellifer rastrifer (5381/9795)
No cells for Myripristis tiki (5385/9795)
No cells for Caulolatilus hubbsi (5387/9795)
No cells for Bryx veleronis (5390/9795)
No cells for Neomerinthe megalepis (5397/9795)
Processing 5400/9795 [ms_merge:276277] (fish): splitnose searobin (_Bellator xenisma_) ~ ETA: 2026-03-25 15:13:40.273427
No cells for Bellator xenisma (5400/9795)
No cells for Prionotus beanii (5401/9795)
No cells for Dorosoma petenense (5409/9795)
No cells for Hypleurochilus aequipinnis (5410/9795)
No cells for Hypsoblennius brevipinnis (5416/9795)
No cells for Oligoplites refulgens (5424/9795)
Processing 5450/9795 [ms_merge:276442] (fish): yellowhead jawfish (_Opistognathus aurifrons_) ~ ETA: 2026-03-25 15:12:50.223664
No cells for Ctenogobius manglicola (5455/9795)
No cells for Gobiosoma paradoxum (5458/9795)
No cells for Lutjanus viridis (5460/9795)
No cells for Neobythites fasciatus (5474/9795)
No cells for Neobythites longipes (5476/9795)
No cells for Neobythites monocellatus (5478/9795)
No cells for Neobythites ocellatus (5479/9795)
No cells for Neobythites stelliferoides (5480/9795)
No cells for Stegastes fuscus (5484/9795)
No cells for Priolepis dawsoni (5487/9795)
No cells for Glossogobius olivaceus (5490/9795)
No cells for Gobiodon prolixus (5493/9795)
No cells for Valenciennea immaculata (5498/9795)
No cells for Valenciennea longipinnis (5499/9795)
Processing 5500/9795 [ms_merge:277042] (fish): Swordspine gurnard (_Pterygotrigla hoplites_) ~ ETA: 2026-03-25 15:13:00.342186
No cells for Pherallodus indicus (5503/9795)
No cells for Thamnaconus tessellatus (5506/9795)
No cells for Entomacrodus textilis (5508/9795)
No cells for Enneapterygius flavoccipitis (5510/9795)
No cells for Enneapterygius philippinus (5512/9795)
No cells for Pseudanthias fasciatus (5515/9795)
No cells for Pseudanthias pictilis (5516/9795)
No cells for Asterropteryx spinosa (5518/9795)
No cells for Bathygobius andrei (5524/9795)
No cells for Bathygobius lineatus (5526/9795)
No cells for Bathygobius ramosus (5528/9795)
No cells for Siphamia tubifer (5530/9795)
No cells for Eleotris pisonis (5533/9795)
No cells for Cirrhilabrus rubrimarginatus (5535/9795)
No cells for Limnichthys fasciatus (5536/9795)
No cells for Oplegnathus insignis (5537/9795)
No cells for Stanulus talboti (5541/9795)
No cells for Oxycheilinus celebicus (5545/9795)
Processing 5550/9795 [ms_merge:278152] (fish): Indo-west Pacific pelican flounder (_Chascanopsetta prognatha_) ~ ETA: 2026-03-25 15:13:10.620744
No cells for Chascanopsetta prognatha (5550/9795)
No cells for Cryptocentrus leptocephalus (5557/9795)
No cells for Glyptophidium argenteum (5561/9795)
No cells for Glyptophidium lucidum (5562/9795)
No cells for Takifugu alboplumbeus (5563/9795)
No cells for Callorhinchus callorynchus (5564/9795)
No cells for Triphoturus oculeum (5571/9795)
No cells for Neocentropogon trimaculatus (5572/9795)
No cells for Eviota storthynx (5573/9795)
No cells for Mastigopterus imperator (5575/9795)
No cells for Fusigobius signipinnis (5580/9795)
No cells for Ostracoberyx paxtoni (5581/9795)
No cells for Halieutopsis stellifera (5583/9795)
No cells for Centropyge aurantonotus (5585/9795)
No cells for Halieutaea nigra (5591/9795)
No cells for Pseudobalistes naufragium (5592/9795)
No cells for Anampses elegans (5593/9795)
No cells for Anampses neoguinaicus (5594/9795)
No cells for Okamejei boesemani (5595/9795)
No cells for Okamejei kenojei (5596/9795)
No cells for Helcogramma ellioti (5598/9795)
Processing 5600/9795 [ms_merge:279265] (fish): Big-spined boarfish (_Pentaceros japonicus_) ~ ETA: 2026-03-25 15:13:20.069581
No cells for Pentaceros japonicus (5600/9795)
No cells for Eptatretus okinoseanus (5601/9795)
No cells for Hypomesus japonicus (5621/9795)
No cells for Acanthopsetta nadeshnyi (5631/9795)
No cells for Achirus achirus (5632/9795)
Processing 5650/9795 [ms_merge:279596] (fish): redtail surfperch (_Amphistichus rhodoterus_) ~ ETA: 2026-03-25 15:13:30.713225
No cells for Arcos erythrops (5660/9795)
No cells for Axoclinus lucillae (5679/9795)
No cells for Barbulifer pantherinus (5683/9795)
No cells for Bollmannia ocellata (5692/9795)
No cells for Bollmannia stigmatura (5693/9795)
Processing 5700/9795 [ms_merge:280006] (fish): NA (_Bufoceratias wedli_) ~ ETA: 2026-03-25 15:12:42.603044
No cells for Centropomus poeyi (5707/9795)
No cells for Centropomus viridis (5709/9795)
No cells for Chaenopsis schmitti (5715/9795)
No cells for Chiloconger dentatus (5717/9795)
No cells for Clarkichthys bilineatus (5724/9795)
No cells for Cleisthenes pinetorum (5725/9795)
No cells for Collichthys lucidus (5742/9795)
No cells for Crossosalarias macrospilus (5748/9795)
Processing 5750/9795 [ms_merge:280449] (fish): Barred snailfish (_Crystallias matsushimae_) ~ ETA: 2026-03-25 15:12:53.046046
No cells for Dactylagnus mundus (5754/9795)
No cells for Dolichosudis fuliginosa (5758/9795)
No cells for Elacatinus puncticulatus (5763/9795)
No cells for Enneanectes carminalis (5775/9795)
No cells for Fodiator acutus (5791/9795)
No cells for Gavialiceps javanicus (5794/9795)
No cells for Genyagnus monopterygius (5795/9795)
Processing 5800/9795 [ms_merge:280844] (fish): masked stargazer (_Gillellus healae_) ~ ETA: 2026-03-25 15:13:06.59909
No cells for Gillellus semicinctus (5801/9795)
No cells for Gurgesiella atlantica (5813/9795)
No cells for Halicmetus reticulatus (5815/9795)
No cells for Halicmetus ruber (5816/9795)
No cells for Hephthocara crassiceps (5818/9795)
No cells for Heteroclinus roseus (5819/9795)
No cells for Homostolus acer (5824/9795)
No cells for Hypopleuron caninum (5834/9795)
No cells for Hypoptychus dybowskii (5835/9795)
No cells for Japonoconger caribbeus (5847/9795)
Processing 5850/9795 [ms_merge:281201] (fish): shortband herring (_Jenkinsia stolifera_) ~ ETA: 2026-03-25 15:13:17.304944
No cells for Johnrandallia nigrirostris (5851/9795)
No cells for Labrisomus multiporosus (5856/9795)
No cells for Labrisomus xanti (5858/9795)
No cells for Lepidoblepharon ophthalmolepis (5859/9795)
No cells for Lepidopsetta mochigarei (5862/9795)
No cells for Lile nigrofasciata (5865/9795)
No cells for Lipogramma evides (5868/9795)
No cells for Macrocephenchelys brevirostris (5883/9795)
No cells for Macrouroides inflaticeps (5885/9795)
No cells for Malacoctenus ebisui (5889/9795)
No cells for Malacoctenus hubbsi (5892/9795)
No cells for Malacoctenus tetranemus (5894/9795)
Processing 5900/9795 [ms_merge:281558] (fish): Stripey (_Microcanthus strigatus_) ~ ETA: 2026-03-25 15:13:26.877733
No cells for Paralonchurus brasiliensis (5938/9795)
Processing 5950/9795 [ms_merge:282275] (fish): saddle stargazer (_Platygillellus rubrocinctus_) ~ ETA: 2026-03-25 15:13:37.600125
No cells for Protemblemaria bicirrus (5960/9795)
No cells for Pseudonus squamiceps (5963/9795)
No cells for Quassiremus evionthas (5966/9795)
No cells for Rhinoraja longicauda (5975/9795)
No cells for Robinsia catherinae (5982/9795)
No cells for Sciades herzbergii (5989/9795)
Processing 6000/9795 [ms_merge:282843] (fish): night smelt (_Spirinchus starksi_) ~ ETA: 2026-03-25 15:12:47.447072
No cells for Thalassophryne maculosa (6016/9795)
No cells for Thalassophryne megalops (6017/9795)
No cells for Thalassophryne nattereri (6018/9795)
No cells for Tomicodon petersii (6024/9795)
No cells for Urobatis maculatus (6029/9795)
No cells for Urotrygon aspidura (6030/9795)
No cells for Verasper moseri (6032/9795)
No cells for Xenocephalus elongatus (6038/9795)
No cells for Xenomedea rhodopyga (6039/9795)
No cells for Xenomystax congroides (6040/9795)
Processing 6050/9795 [ms_merge:283218] (fish): Flabby sculpin (_Zesticelus profundorum_) ~ ETA: 2026-03-25 15:12:56.531657
Processing 6100/9795 [ms_merge:284710] (invertebrate): NA (_Halecium bermudense_) ~ ETA: 2026-03-25 15:13:06.056319
Processing 6150/9795 [ms_merge:286401] (coral): NA (_Placogorgia mirabilis_) ~ ETA: 2026-03-25 15:13:15.3339
Processing 6200/9795 [ms_merge:287018] (coral): NA (_Flabellum (Ulocyathus) messum_) ~ ETA: 2026-03-25 15:13:24.562006
No cells for Oculina valenciennesi (6208/9795)
No cells for Montipora capricornis (6238/9795)
No cells for Porites branneri (6248/9795)
No cells for Porites colonensis (6249/9795)
Processing 6250/9795 [ms_merge:288925] (coral): Mcmurrich's anemone (_Boloceroides mcmurrichi_) ~ ETA: 2026-03-25 15:12:34.047727
Processing 6300/9795 [ms_merge:290973] (coral): NA (_Rhizosmilia gerdae_) ~ ETA: 2026-03-25 15:12:42.973081
No cells for Hyporhamphus roberti (6331/9795)
No cells for Salvelinus leucomaenis (6334/9795)
No cells for Sardinella brasiliensis (6339/9795)
Processing 6350/9795 [ms_merge:302877] (fish): white suckerfish (_Remora albescens_) ~ ETA: 2026-03-25 15:12:52.05959
No cells for Stomias colubrinus (6359/9795)
No cells for Trimma macrophthalmum (6364/9795)
No cells for Fusigobius humeralis (6365/9795)
No cells for Protosciaena bathytatos (6373/9795)
No cells for Hime japonica (6377/9795)
No cells for Ostorhinchus endekataenia (6381/9795)
No cells for Tetronarce nobiliana (6383/9795)
Processing 6400/9795 [ms_merge:327112] (other): NA (_Cirrophorus americanus_) ~ ETA: 2026-03-25 15:13:01.955523
Processing 6450/9795 [ms_merge:330841] (other): NA (_Poecilochaetus johnsoni_) ~ ETA: 2026-03-25 15:13:10.723915
Processing 6500/9795 [ms_merge:334031] (other): NA (_Mooreonuphis dangrigae_) ~ ETA: 2026-03-25 15:13:19.612982
Processing 6550/9795 [ms_merge:341849] (invertebrate): Clawed enope squid (_Abraliopsis felis_) ~ ETA: 2026-03-25 15:12:29.445682
No cells for Sotalia guianensis (6592/9795)
Processing 6600/9795 [ms_merge:344190] (invertebrate): yellow tuskshell (_Coccodentalium carduus_) ~ ETA: 2026-03-25 15:12:39.568349
Processing 6650/9795 [ms_merge:344504] (invertebrate): NA (_Graptacme acutissima_) ~ ETA: 2026-03-25 15:12:49.156986
Processing 6700/9795 [ms_merge:355182] (invertebrate): NA (_Pseudodiaptomus pelagicus_) ~ ETA: 2026-03-25 15:12:58.84387
Processing 6750/9795 [ms_merge:367285] (fish): permit (_Trachinotus falcatus_) ~ ETA: 2026-03-25 15:13:08.354932
Processing 6800/9795 [ms_merge:368083] (invertebrate): NA (_Sympagurus trispinosus_) ~ ETA: 2026-03-25 15:12:17.387698
Processing 6850/9795 [ms_merge:377558] (invertebrate): NA (_Parapenaeus americanus_) ~ ETA: 2026-03-25 15:12:26.670321
Processing 6900/9795 [ms_merge:381297] (invertebrate): frilled papercockle (_Papyridea semisulcata_) ~ ETA: 2026-03-25 15:12:36.162806
No cells for Nephropsis holthuisi (6915/9795)
No cells for Nephropsis serrata (6916/9795)
No cells for Panulirus femoristriga (6917/9795)
No cells for Pentacheles obscurus (6918/9795)
No cells for Polycheles baccatus (6919/9795)
No cells for Stereomastis auriculata (6920/9795)
No cells for Stereomastis helleri (6921/9795)
No cells for Stereomastis polita (6922/9795)
No cells for Willemoesia inornata (6923/9795)
Processing 6950/9795 [ms_merge:386416] (invertebrate): Hartweg's Chiton (_Cyanoplax hartwegii_) ~ ETA: 2026-03-25 15:12:46.413988
Processing 7000/9795 [ms_merge:392044] (invertebrate): NA (_Uroptychodes spinimarginatus_) ~ ETA: 2026-03-25 15:12:55.672159
Processing 7050/9795 [ms_merge:393708] (invertebrate): little knobbly scallop (_Caribachlamys pellucens_) ~ ETA: 2026-03-25 15:13:04.636665
No cells for Minysicya caudimaculata (7085/9795)
Processing 7100/9795 [ms_merge:397147] (invertebrate): black-striped mussel (_Mytilopsis sallei_) ~ ETA: 2026-03-25 15:12:14.151877
No cells for Apristurus australis (7104/9795)
No cells for Mustelus albipinnis (7105/9795)
No cells for Squalus edmundsi (7106/9795)
No cells for Sinobatis borneensis (7107/9795)
No cells for Chimaera macrospina (7108/9795)
No cells for Lophiodes endoi (7111/9795)
No cells for Diplobatis picta (7120/9795)
Processing 7150/9795 [ms_merge:408482] (invertebrate): pectinate cardiomya (_Cardiomya pectinata_) ~ ETA: 2026-03-25 15:12:23.285152
Processing 7200/9795 [ms_merge:413447] (invertebrate): NA (_Bayerotrochus midas_) ~ ETA: 2026-03-25 15:12:34.007304
Processing 7250/9795 [ms_merge:419374] (invertebrate): threaded rimula (_Rimula pycnonema_) ~ ETA: 2026-03-25 15:12:43.647325
Processing 7300/9795 [ms_merge:419495] (invertebrate): NA (_Parviturbo rehderi_) ~ ETA: 2026-03-25 15:12:54.086677
Processing 7350/9795 [ms_merge:419603] (invertebrate): NA (_Elachisina floridana_) ~ ETA: 2026-03-25 15:12:03.338154
Processing 7400/9795 [ms_merge:419725] (invertebrate): West Indian simnia (_Cymbovula acicularis_) ~ ETA: 2026-03-25 15:12:12.411036
Processing 7450/9795 [ms_merge:419844] (invertebrate): grooved eulima (_Melanella eulimoides_) ~ ETA: 2026-03-25 15:12:21.676277
Processing 7500/9795 [ms_merge:420004] (invertebrate): engraved dovesnail (_Nassarina glypta_) ~ ETA: 2026-03-25 15:12:31.928679
Processing 7550/9795 [ms_merge:420163] (invertebrate): NA (_Prunum pruinosum_) ~ ETA: 2026-03-25 15:12:41.094965
No cells for Conus sennottorum (7557/9795)
Processing 7600/9795 [ms_merge:420342] (invertebrate): spear mangelia (_Ithycythara lanceolata_) ~ ETA: 2026-03-25 15:12:50.472996
Processing 7650/9795 [ms_merge:420459] (invertebrate): NA (_Pseudoscilla babylonia_) ~ ETA: 2026-03-25 15:11:59.776992
Processing 7700/9795 [ms_merge:420581] (invertebrate): eyespot costasiella (_Costasiella ocellifera_) ~ ETA: 2026-03-25 15:12:09.852819
Processing 7750/9795 [ms_merge:420731] (invertebrate): comb bittersweet (_Tucetona pectinata_) ~ ETA: 2026-03-25 15:12:19.278399
Processing 7800/9795 [ms_merge:420825] (invertebrate): giant montacutid (_Orobitella floridana_) ~ ETA: 2026-03-25 15:12:30.288607
Processing 7850/9795 [ms_merge:420939] (invertebrate): waxy gouldclam (_Gouldia cerina_) ~ ETA: 2026-03-25 15:12:41.228327
Processing 7900/9795 [ms_merge:421141] (invertebrate): NA (_Amphibalanus subalbidus_) ~ ETA: 2026-03-25 15:12:50.974159
Processing 7950/9795 [ms_merge:421534] (invertebrate): NA (_Metharpinia floridana_) ~ ETA: 2026-03-25 15:12:00.710969
Processing 8000/9795 [ms_merge:421627] (invertebrate): NA (_Paratyphis maculatus_) ~ ETA: 2026-03-25 15:12:18.581321
Processing 8050/9795 [ms_merge:421753] (invertebrate): NA (_Synalpheus bousfieldi_) ~ ETA: 2026-03-25 15:12:36.236473
Processing 8100/9795 [ms_merge:421834] (invertebrate): NA (_Upogebia acanthura_) ~ ETA: 2026-03-25 15:12:49.638863
Processing 8150/9795 [ms_merge:421935] (invertebrate): pink purse crab (_Persephona crinita_) ~ ETA: 2026-03-25 15:13:05.831328
Processing 8200/9795 [ms_merge:422037] (invertebrate): rugose swimming crab (_Callinectes exasperatus_) ~ ETA: 2026-03-25 15:13:18.207623
Processing 8250/9795 [ms_merge:422134] (invertebrate): lobefront mud crab (_Micropanope lobifrons_) ~ ETA: 2026-03-25 15:12:32.337982
Processing 8300/9795 [ms_merge:422414] (other): NA (_Rhynchozoon verruculatum_) ~ ETA: 2026-03-25 15:12:44.254061
No cells for Conus archon (8346/9795)
No cells for Conus brunneus (8347/9795)
No cells for Conus capitanellus (8348/9795)
No cells for Conus fergusoni (8349/9795)
Processing 8350/9795 [ms_merge:428244] (invertebrate): NA (_Conus poormani_) ~ ETA: 2026-03-25 15:12:59.359493
No cells for Conus poormani (8350/9795)
No cells for Conus purpurascens (8351/9795)
No cells for Conus chiangi (8354/9795)
No cells for Siderastrea stellata (8360/9795)
Processing 8400/9795 [ms_merge:440471] (invertebrate): NA (_Ethusina microspina_) ~ ETA: 2026-03-25 15:13:14.139708
Processing 8450/9795 [ms_merge:444208] (invertebrate): NA (_Liomera stimpsonii_) ~ ETA: 2026-03-25 15:13:27.76263
Processing 8500/9795 [ms_merge:458663] (invertebrate): NA (_Tryphana malmii_) ~ ETA: 2026-03-25 15:13:44.753971
Processing 8550/9795 [ms_merge:476546] (invertebrate): doghead triton (_Ranularia cynocephala_) ~ ETA: 2026-03-25 15:12:56.132851
Processing 8600/9795 [ms_merge:505780] (invertebrate): horseneck clam (_Tresus nuttallii_) ~ ETA: 2026-03-25 15:13:06.457199
Processing 8650/9795 [ms_merge:506991] (invertebrate): oyster piddock (_Diplothyra curta_) ~ ETA: 2026-03-25 15:13:18.404896
Processing 8700/9795 [ms_merge:513125] (invertebrate): NA (_Arbacia stellata_) ~ ETA: 2026-03-25 15:13:31.551515
Processing 8750/9795 [ms_merge:514571] (invertebrate): NA (_Harpilius lutescens_) ~ ETA: 2026-03-25 15:13:46.075275
Processing 8800/9795 [ms_merge:523706] (invertebrate): Greenland wentletrap (_Boreoscala greenlandica_) ~ ETA: 2026-03-25 15:14:00.399869
Processing 8850/9795 [ms_merge:532643] (invertebrate): NA (_Cocculina rathbuni_) ~ ETA: 2026-03-25 15:13:13.594567
Processing 8900/9795 [ms_merge:545037] (invertebrate): NA (_Chaetoderma nanulum_) ~ ETA: 2026-03-25 15:13:29.832954
Processing 8950/9795 [ms_merge:565161] (invertebrate): NA (_Stauridiosarsia gemmifera_) ~ ETA: 2026-03-25 15:13:46.406818
No cells for Profundiconus teramachii (8982/9795)
Processing 9000/9795 [ms_merge:584793] (fish): Red-eye round herring (_Etrumeus sadina_) ~ ETA: 2026-03-25 15:13:59.311108
Processing 9050/9795 [ms_merge:706593] (invertebrate): NA (_Heliacus infundibuliformis perrieri_) ~ ETA: 2026-03-25 15:14:13.510535
No cells for Halicmetus niger (9067/9795)
No cells for Ostorhinchus cookii (9073/9795)
No cells for Paracaristius nudarcus (9075/9795)
No cells for Nicholsina collettei (9085/9795)
Processing 9100/9795 [ms_merge:723551] (invertebrate): frilly dwarf triton (_Favartia alveata_) ~ ETA: 2026-03-25 15:14:25.724478
Processing 9150/9795 [ms_merge:762295] (invertebrate): NA (_Puerulus richeri_) ~ ETA: 2026-03-25 15:13:37.882053
No cells for Chaunax reticulatus (9172/9795)
No cells for Malthopsis asperata (9173/9795)
No cells for Malthopsis parva (9174/9795)
Processing 9200/9795 [ms_merge:854493] (coral): magnificent sea anemone (_Radianthus magnifica_) ~ ETA: 2026-03-25 15:13:48.392742
Processing 9250/9795 [ms_merge:881728] (invertebrate): beaded mud crab (_Scopolius nuttingi_) ~ ETA: 2026-03-25 15:14:00.263173
No cells for Lophiodes triradiatus (9299/9795)
Processing 9300/9795 [ms_merge:1018702] (fish): Bluestriped chub (_Kyphosus ocyurus_) ~ ETA: 2026-03-25 15:14:11.953357
No cells for Scalicus investigatoris (9301/9795)
Processing 9350/9795 [ms_merge:1261644] (invertebrate): NA (_Areopaguristes oxyophthalmus_) ~ ETA: 2026-03-25 15:14:25.057772
Processing 9400/9795 [ms_merge:1415964] (invertebrate): NA (_Neoterebra alba_) ~ ETA: 2026-03-25 15:13:38.559116
Processing 9450/9795 [ms_merge:1513916] (invertebrate): NA (_Acantholobulus caribbaeus_) ~ ETA: 2026-03-25 15:13:49.558048
No cells for Deveximentum insidiator (9460/9795)
No cells for Pseudaspius brandtii (9461/9795)
No cells for Lestidiops luetkeni (9480/9795)
No cells for Rostroraja velezi (9498/9795)
Processing 9500/9795 [ms_merge:1605692] (invertebrate): NA (_Antillimunida affinis_) ~ ETA: 2026-03-25 15:14:01.568483
No cells for Rostroraja cervigoni (9549/9795)
Processing 9550/9795 [ms_merge:1668000] (fish): Spotted croaker (_Stellifer punctatissimus_) ~ ETA: 2026-03-25 15:14:12.905923
Processing 9600/9795 [ms_merge:1809212] (invertebrate): whiteleg shrimp (_Penaeus (Litopenaeus) vannamei_) ~ ETA: 2026-03-25 15:14:24.692519
Processing 9650/9795 [ms_merge:22693359] (bird): Great Knot (_Calidris tenuirostris_) ~ ETA: 2026-03-25 15:14:37.076687
Processing 9700/9795 [ms_merge:22694787] (bird): Black Tern (_Chlidonias niger_) ~ ETA: 2026-03-25 15:13:51.73034
Processing 9750/9795 [ms_merge:22698557] (bird): Black Storm-petrel (_Hydrobates melania_) ~ ETA: 2026-03-25 15:14:07.686331
Code
# Salmo salar            silver salmon

3 Set taxon.is_ok

Add is_ok: a simple logical field for flagging valid taxa, ie (so far):

  • birds:
    • redlist_code != “EX”
    • has a botw_id
    • if has worms_id:
      • worms_is_marine != F
      • worms_is_extinct != T
  • no model cells overlap with Program Areas
  • category is “reptile” but not “turtle” (handled by reclassify_reptiles)
  • not birds:
    • has a worms_id
    • worms_is_marine != F
    • worms_is_extinct != T

3.1 Flag valid taxa

Code
d <- tbl(con_sdm, "taxon") |>
  collect() # 17,561 × 16

# birds ----
# d |>
#   filter(
#     taxon_authority == "botw") |>
#   pull(redlist_code) |>
#   table(useNA = "ifany")
#  CR  DD  EN  LC  NT  TN  VU
#   3   1  58 452  45  14  41
#
# d |>
#   filter(
#     taxon_authority == "botw") |>
#   select(worms_is_marine, worms_is_extinct) |>
#   table(useNA = "ifany")
#                worms_is_extinct
# worms_is_marine <NA>
#           FALSE  118
#           TRUE   221
#           <NA>   275

d_b <- d |>
  filter(
    taxon_authority == "botw"
  ) |>
  mutate(
    is_ok = case_when(
      is.na(taxon_id) ~ F,
      is.na(mdl_seq) ~ F,
      !is.na(redlist_code) & redlist_code == "EX" ~ F, # 0
      !is.na(worms_id) & worms_is_marine == F ~ F, # 118
      !is.na(worms_id) & worms_is_extinct == T ~ F, # 0
      .default = T
    )
  )
# d_b$is_ok |> table(useNA = "ifany")
# FALSE  TRUE
#   118   496

# worms ----

# d |>
#   filter(
#     taxon_authority == "worms") |>
#   pull(redlist_code) |>
#   table(useNA = "ifany")
# CR    DD    EN    EX    LC    NT    TN    VU  <NA>
# 47   340   235     1  5574   107    11   154 10478
#
# d |>
#   filter(
#     taxon_authority == "worms") |>
#   select(worms_is_marine, worms_is_extinct) |>
#   table(useNA = "ifany")
#                worms_is_extinct
# worms_is_marine FALSE  TRUE  <NA>
#           FALSE    19     0    24
#           TRUE   4171    20 12708
#           <NA>      0     0     5

d_w <- d |>
  filter(
    taxon_authority == "worms"
  ) |>
  mutate(
    is_ok = case_when(
      is.na(taxon_id) ~ F,
      is.na(mdl_seq) ~ F,
      !is.na(redlist_code) & redlist_code == "EX" ~ F,
      !is.na(worms_id) & worms_is_marine == F ~ F,
      !is.na(worms_id) & worms_is_extinct == T ~ F,
      !is.na(worms_taxonomic_status) &
        !worms_taxonomic_status %in%
          c("accepted", "alternative representation") ~ F,
      sp_cat == "reptile" ~ F,
      sp_cat == "turtle" ~ T,
      .default = T
    )
  )
# d_w$is_ok |> table(useNA = "ifany")
# FALSE   TRUE
#    64 16,883

d2 <- bind_rows(
  d_b,
  d_w
) |>
  select(taxon_id, is_ok)

# flag taxa with no distribution inside program areas ----
# (mirrors r_mask approach in apps_2026/mapsp/app.R but with DB queries)
taxa_in_pra <- tbl(con_sdm, "taxon_model") |>
  inner_join(
    tbl(con_sdm, "model_cell") |> select(mdl_seq, cell_id),
    by = "mdl_seq"
  ) |>
  inner_join(
    tbl(con_sdm, "zone_cell") |> select(zone_seq, cell_id),
    by = "cell_id"
  ) |>
  inner_join(
    tbl(con_sdm, "zone") |>
      filter(
        fld == "programarea_key"
      ) |>
      select(zone_seq),
    by = "zone_seq"
  ) |>
  distinct(taxon_id) |>
  pull(taxon_id)

n_outside <- sum(d2$is_ok & !(d2$taxon_id %in% taxa_in_pra))
message(glue(
  "{n_outside} taxa flagged is_ok=F (no distribution in program areas)"
))
6734 taxa flagged is_ok=F (no distribution in program areas)
Code
d2 <- d2 |>
  mutate(
    is_ok = is_ok & taxon_id %in% taxa_in_pra
  )

stopifnot(sum(duplicated(d2$taxon_id)) == 0)

dbExecute(
  con_sdm,
  "ALTER TABLE taxon ADD COLUMN IF NOT EXISTS is_ok BOOLEAN"
)
[1] 0
Code
duckdb_register(con_sdm, "d2", d2)
dbExecute(
  con_sdm,
  "UPDATE taxon
    SET is_ok  = d2.is_ok
    FROM d2
    WHERE taxon.taxon_id = d2.taxon_id"
) # 17,561
[1] 17561
Code
duckdb_unregister(con_sdm, "d2")

# add is_er_spatial flag (TRUE for turtles where ER is spatially ----
# differentiated per-cell from mask datasets; FALSE for species using
# uniform species-level scalar er_score)
dbExecute(
  con_sdm,
  "ALTER TABLE taxon ADD COLUMN IF NOT EXISTS is_er_spatial BOOLEAN"
)
[1] 0
Code
dbExecute(
  con_sdm,
  "UPDATE taxon SET is_er_spatial = (sp_cat = 'turtle')"
)
[1] 17561

4 Taxon Summary

4.1 Export taxon summary

Code
taxon_csv <- here("data/taxon.csv")

# dbListFields(con_sdm, "taxon") |> paste(collapse = ", ") |> cat()
d_taxon <- tbl(con_sdm, "taxon") |>
  select(
    is_ok,
    component = sp_cat,
    common_name,
    scientific_name,
    redlist_code_max = redlist_code,
    extrisk_code,
    er_score,
    is_mmpa,
    is_mbta,
    is_bcc,
    worms_is_marine,
    worms_is_extinct,
    n_datasets = n_ds,
    taxon_authority,
    taxon_id,
    model_id = mdl_seq
  ) |>
  arrange(desc(is_ok), component, common_name) |>
  collect()

write_csv(d_taxon, taxon_csv)

5 Dataset Summary

Code
tbl(con_sdm, "dataset") |>
  select(sort_order, ds_key, name_display, value_info, is_mask) |>
  arrange(sort_order) |>
  collect() |>
  DT::datatable()
Code
tbl(con_sdm, "model") |>
  group_by(ds_key) |>
  summarize(n_models = n()) |>
  arrange(ds_key) |>
  collect() |>
  DT::datatable()

6 Species Summary

6.1 Species counts by sp_cat and ds_key

Code
tbl(con_sdm, "species") |>
  group_by(sp_cat, ds_key) |>
  summarize(n = n(), .groups = "drop") |>
  arrange(sp_cat, ds_key) |>
  collect() |>
  DT::datatable()

6.2 Taxonomic authority coverage

Code
tbl(con_sdm, "species") |>
  group_by(sp_cat, ds_key) |>
  summarize(
    n = n(),
    n_worms = sum(!is.na(worms_id), na.rm = T),
    n_itis = sum(!is.na(itis_id), na.rm = T),
    n_gbif = sum(!is.na(gbif_id), na.rm = T),
    n_allna = sum(
      is.na(worms_id) & is.na(itis_id) & is.na(gbif_id),
      na.rm = T
    ),
    .groups = "drop"
  ) |>
  mutate(
    pct_worms = round(n_worms / n * 100, 1),
    pct_itis = round(n_itis / n * 100, 1),
    pct_gbif = round(n_gbif / n * 100, 1),
    pct_allna = round(n_allna / n * 100, 1)
  ) |>
  arrange(sp_cat, ds_key) |>
  collect() |>
  DT::datatable()

6.3 WoRMS marine/extinct percentages

Code
tbl(con_sdm, "species") |>
  group_by(sp_cat) |>
  summarize(
    n = n(),
    n_worms_marine = sum(worms_is_marine, na.rm = T),
    n_worms_extinct = sum(worms_is_extinct, na.rm = T)
  ) |>
  mutate(
    pct_worms_marine = round(n_worms_marine / n * 100, 1),
    pct_worms_extinct = round(n_worms_extinct / n * 100, 1)
  ) |>
  collect() |>
  DT::datatable()

7 Taxon Table Summary

7.1 Taxon counts by sp_cat and is_ok

Code
tbl(con_sdm, "taxon") |>
  group_by(sp_cat, is_ok) |>
  summarize(n = n(), .groups = "drop") |>
  collect() |>
  pivot_wider(
    names_from = is_ok,
    values_from = n,
    names_prefix = "is_ok_"
  ) |>
  DT::datatable()

7.2 Redlist code distribution

Code
tbl(con_sdm, "taxon") |>
  filter(is_ok) |>
  group_by(sp_cat, redlist_code) |>
  summarize(n = n(), .groups = "drop") |>
  collect() |>
  pivot_wider(
    names_from = redlist_code,
    values_from = n,
    values_fill = 0
  ) |>
  DT::datatable()

7.3 Extinction risk authority summary

Code
tbl(con_sdm, "taxon") |>
  filter(is_ok) |>
  mutate(
    authority = case_when(
      str_starts(extrisk_code, "NMFS") ~ "NMFS",
      str_starts(extrisk_code, "FWS") ~ "FWS",
      str_starts(extrisk_code, "IUCN") ~ "IUCN",
      TRUE ~ "none"
    )
  ) |>
  count(authority) |>
  collect() |>
  DT::datatable()

7.4 Number of datasets per taxon

Code
tbl(con_sdm, "taxon") |>
  filter(is_ok) |>
  count(n_ds) |>
  collect() |>
  DT::datatable()

8 Taxon x Dataset Matrix

Code
tbl(con_sdm, "taxon_model") |>
  inner_join(
    tbl(con_sdm, "taxon") |>
      filter(is_ok) |>
      select(taxon_id, sp_cat),
    by = "taxon_id"
  ) |>
  group_by(sp_cat, ds_key) |>
  summarize(n = n(), .groups = "drop") |>
  collect() |>
  pivot_wider(
    names_from = ds_key,
    values_from = n,
    values_fill = 0
  ) |>
  DT::datatable()

9 Taxon Detail Table

Code
tbl(con_sdm, "taxon") |>
  filter(is_ok) |>
  select(
    sp_cat,
    scientific_name,
    common_name,
    redlist_code,
    extrisk_code,
    er_score,
    n_ds,
    taxon_id,
    taxon_authority
  ) |>
  arrange(sp_cat, scientific_name) |>
  collect() |>
  DT::datatable(
    filter = "top",
    options = list(pageLength = 25)
  )
Warning in instance$preRenderHook(instance): It seems your data is too big for
client-side DataTables. You may consider server-side processing:
https://rstudio.github.io/DT/server.html