diff --git a/..Rcheck/00check.log b/..Rcheck/00check.log new file mode 100644 index 0000000..461524d --- /dev/null +++ b/..Rcheck/00check.log @@ -0,0 +1,14 @@ +* using log directory ‘/Users/jason/GitHub/zoomss/..Rcheck’ +* using R version 4.5.0 (2025-04-11) +* using platform: aarch64-apple-darwin20 +* R was compiled by + Apple clang version 14.0.0 (clang-1400.0.29.202) + GNU Fortran (GCC) 14.2.0 +* running under: macOS 26.0 +* using session charset: UTF-8 +* using options ‘--no-examples --no-tests --no-vignettes’ +* checking for file ‘./DESCRIPTION’ ... ERROR +Required fields missing or empty: + ‘Author’ ‘Maintainer’ +* DONE +Status: 1 ERROR diff --git a/.Rbuildignore b/.Rbuildignore new file mode 100644 index 0000000..8ee7eaa --- /dev/null +++ b/.Rbuildignore @@ -0,0 +1,11 @@ +^zoomss\.Rproj$ +^\.Rproj\.user$ +^LICENSE\.md$ +^data-raw$ +^README\.Rmd$ +^_pkgdown\.yml$ +^docs$ +^pkgdown$ +^\.github$ +^doc$ +^Meta$ diff --git a/.github/.gitignore b/.github/.gitignore new file mode 100644 index 0000000..2d19fc7 --- /dev/null +++ b/.github/.gitignore @@ -0,0 +1 @@ +*.html diff --git a/.github/workflows/Linux.yaml b/.github/workflows/Linux.yaml new file mode 100644 index 0000000..f326ccf --- /dev/null +++ b/.github/workflows/Linux.yaml @@ -0,0 +1,49 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: [main, master] + pull_request: + +name: Linux + +permissions: read-all + +jobs: + R-CMD-check: + runs-on: ${{ matrix.config.os }} + + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) + + strategy: + fail-fast: false + matrix: + config: + - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} + - {os: ubuntu-latest, r: 'release'} + - {os: ubuntu-latest, r: 'oldrel-1'} + + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + R_KEEP_PKG_SOURCE: yes + + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-pandoc@v2 + + - uses: r-lib/actions/setup-r@v2 + with: + r-version: ${{ matrix.config.r }} + http-user-agent: ${{ matrix.config.http-user-agent }} + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::rcmdcheck + needs: check + + - uses: r-lib/actions/check-r-package@v2 + with: + upload-snapshots: true + build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' diff --git a/.github/workflows/MacOS.yaml b/.github/workflows/MacOS.yaml new file mode 100644 index 0000000..233f777 --- /dev/null +++ b/.github/workflows/MacOS.yaml @@ -0,0 +1,47 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: [main, master] + pull_request: + +name: MacOS + +permissions: read-all + +jobs: + R-CMD-check: + runs-on: ${{ matrix.config.os }} + + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) + + strategy: + fail-fast: false + matrix: + config: + - {os: macos-latest, r: 'release'} + + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + R_KEEP_PKG_SOURCE: yes + + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-pandoc@v2 + + - uses: r-lib/actions/setup-r@v2 + with: + r-version: ${{ matrix.config.r }} + http-user-agent: ${{ matrix.config.http-user-agent }} + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::rcmdcheck + needs: check + + - uses: r-lib/actions/check-r-package@v2 + with: + upload-snapshots: true + build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' diff --git a/.github/workflows/Windows.yaml b/.github/workflows/Windows.yaml new file mode 100644 index 0000000..081de96 --- /dev/null +++ b/.github/workflows/Windows.yaml @@ -0,0 +1,47 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: [main, master] + pull_request: + +name: Windows + +permissions: read-all + +jobs: + R-CMD-check: + runs-on: ${{ matrix.config.os }} + + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) + + strategy: + fail-fast: false + matrix: + config: + - {os: windows-latest, r: 'release'} + + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + R_KEEP_PKG_SOURCE: yes + + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-pandoc@v2 + + - uses: r-lib/actions/setup-r@v2 + with: + r-version: ${{ matrix.config.r }} + http-user-agent: ${{ matrix.config.http-user-agent }} + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::rcmdcheck + needs: check + + - uses: r-lib/actions/check-r-package@v2 + with: + upload-snapshots: true + build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml new file mode 100644 index 0000000..0ab748d --- /dev/null +++ b/.github/workflows/test-coverage.yaml @@ -0,0 +1,62 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: [main, master] + pull_request: + +name: test-coverage.yaml + +permissions: read-all + +jobs: + test-coverage: + runs-on: ubuntu-latest + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-r@v2 + with: + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::covr, any::xml2 + needs: coverage + + - name: Test coverage + run: | + cov <- covr::package_coverage( + quiet = FALSE, + clean = FALSE, + install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") + ) + print(cov) + covr::to_cobertura(cov) + shell: Rscript {0} + + - uses: codecov/codecov-action@v5 + with: + # Fail if error if not on PR, or if on PR and token is given + fail_ci_if_error: ${{ github.event_name != 'pull_request' || secrets.CODECOV_TOKEN }} + files: ./cobertura.xml + plugins: noop + disable_search: true + token: ${{ secrets.CODECOV_TOKEN }} + + - name: Show testthat output + if: always() + run: | + ## -------------------------------------------------------------------- + find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true + shell: bash + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v4 + with: + name: coverage-test-failures + path: ${{ runner.temp }}/package diff --git a/.gitignore b/.gitignore index 44c3878..a18df5a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,7 @@ Ancillary/EnvironmentalData/CreateEnviro/Data/GEBCO_2014_2D.nc RawOutput/* Ancillary/* +inst/doc +docs +/doc/ +/Meta/ diff --git a/Ancillary/TODO_FoodWebs_0a_Functions.R b/Ancillary/TODO_FoodWebs_0a_Functions.R deleted file mode 100644 index 2ccab43..0000000 --- a/Ancillary/TODO_FoodWebs_0a_Functions.R +++ /dev/null @@ -1,592 +0,0 @@ -## Calculates average trophic level of each group in each grid square, returns a matrix where -## rows correspond to grid squares, columns to each group - -Extract_ZooMSS_Species <- function(N, TestGroups, w){ - species <- N %>% - reduce(`+`) # Elementwise summing of the model abundance - species <- species/length(N) - - rownames(species) <- TestGroups$species - out <- as_tibble(t(species)) - out <- out %>% - add_column("Weight" = w) -} - -# Return Abundance/Biomass by weight class - -Extract_ZooMSS <- function(N, w){ - - Abundance <- matrix(NA, nrow = length(N), ncol = length(w)) # Preallocate - Biomass <- matrix(NA, nrow = length(N), ncol = length(w)) # Preallocate - - # Loop through and extract the model output. - for (i in 1:length(N)) { - Biomass[i,] <- apply(sweep(N[[i]], 2, w, '*'), 2, sum) # Use sweep to multiply by the weights - Abundance[i,] <- apply(N[[i]], 2, sum) - } - out <- tibble("Biomass" = Biomass, "Abundance" = Abundance) - -} - - -NBSS_data <- function(LOPC, Bins, chl_lims){ - LOPC2 <- LOPC %>% - dplyr::filter(Chl >= chl_lims[1] & Chl <= chl_lims[2]) %>% - dplyr::select(starts_with("NB_"), Chl) %>% - pivot_longer(cols = starts_with("NB_")) %>% - mutate(name = str_remove(name,"NB_"), - name = as.numeric(name)) - - Bins2 <- Bins[LOPC2$name,] - colnames(Bins2) <- "Bins" - LOPC2 <- bind_cols(LOPC2, Bins2) - LOPC2 <- LOPC2 %>% - drop_na(value) %>% - dplyr::filter(value > 0) %>% - dplyr::rename(NB = value) - - NBSS <- LOPC2 %>% - group_by(name) %>% - summarise(NB = mean(NB, na.rm = T), - Bins = Bins[1], - n = n()) - - rm(Bins, Bins2) - out <- list() - out[[1]] <- NBSS - out[[2]] <- LOPC2 - return(out) - - # return(NBSS) -} - - - -NBSS_ZooMSS <- function(res, chl_lims, enviro_data, w, plot_params){ - - w_mg <- w *1e3 # Convert weight to mg (as is normal for zooplankton NBSS) - subs_mdl <- enviro_data$chlo >= chl_lims[1] & enviro_data$chlo <= chl_lims[2] # What cells are within the chl range? - limits = 10^ c(log10(w_mg[1])-plot_params$dx/2, log10(w_mg) + plot_params$dx/2) # Set limits of each bin - - model_out <- Extract_ZooMSS(res[subs_mdl], w_mg) - - model_NBSS <- tibble("Bins" = w*1000) - - model_NBSS <- model_NBSS %>% - mutate( - Biomass = colSums(model_out$Biomass) / length(res), # Get average of all biomass rows - Abundance = colSums(model_out$Abundance) / length(res), # Get average of all abundance rows - BinLower = limits[1:length(limits)-1], # Lower limit of the bins - BinUpper = limits[2:length(limits)], # Upper limit of the bins - BinWidth = BinUpper - BinLower, - NB = Biomass/BinWidth) %>% - filter(log10(BinUpper) <= plot_params$MaxSize & log10(BinLower) > plot_params$MinSize) %>% - filter(Biomass > 0) - - rm(subs_mdl, model_out) - # return(model_NBSS) - - out <- list() - out[[1]] <- model_NBSS - out[[2]] <- model_out - - return(out) -} - - - - -TrophicLevel_Calc <- function(diets, TestGroups){ - - ################### TROPHIC LEVEL - stor = matrix(0, nrow = length(diets), ncol = 12) # Output storage, I have 12 groups, so 12 columns and 1 row for each grid square - colnames(stor) <- TestGroups$species - - starter_tl = c(1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2)### Starting trophic levels, phyto is 1, for all other 12 groups is 2 - - for(i in 1:length(diets)){ # Loop over number of grid squares - start_tl = starter_tl # Initialise trophic level vector - diet = diets[[i]] # Pull out diet matrix for current grid square - - ### You only need these two lines if diet matrix has a column for small, medium and large phytoplankton - diet[,3] = rowSums(diet[,c(1:3)]) - diet = diet[,-c(1,2)] - - diet_prop = round((diet/rowSums(diet)), 3) # Calculate diet composition, round to 3 decimal places - - for(k in 1:100){ # Gauss-Siedel iterative loop to calculate trophic levels - for(j in 1:dim(diet_prop)[1]){ # Loop over each group - curr_tl = sum(start_tl*diet_prop[j,], na.rm = TRUE) # Calculate trophic level of group j - start_tl[j+1] = curr_tl + 1 # Update trophic level - } - } - stor[i,] = start_tl[2:13] # Save non phyto trophic levels - - } # Close enviro grid square loop - - return(stor) -} - - -biom_ratios <- function(res, TestGroups, enviro_data){ - - biom_store = matrix(0, nrow = length(res), ncol = 3) - colnames(biom_store) = c('Phyto', 'Zoo', 'Fish') - ratio_store = matrix(0, nrow = length(res), ncol = 3) - colnames(ratio_store) = c('ZooPhyto', 'FishZoo', 'FishPhyto') - - for(i in 1:length(res)){ - - ### CALCULATE PHYTO BIOMASS - # w0_phyto = -14.5 # minimum phytoplankton size class (1um) - wMax_phyto = min(enviro_data$phyto_max[i]) - wMax_phyto = min(-8, wMax_phyto) - w_phyto = 10^(seq(-14.5, wMax_phyto,0.1)) - a = enviro_data$a[i] - b = enviro_data$b[i] - biom_store[i,1] = sum((10^a)*(w_phyto^(b+1))) - - ### CALCULATE ZOO AND FISH BIOMASS - w0 = min(TestGroups$W0) - wMax = max(TestGroups$Wmax) - w = 10^seq(w0, wMax, 0.1) # Vector of body sizes - w[w > 1e5] = 0 # Cut off large fish values (heavy senescence mortality on these size classes - model artifact) - - curr_abund = res[[i]] - curr_biom = rowSums(sweep(curr_abund, 2, w, '*')) # Calculate biomass from abundance and sum across each group - - zoo_groups = which(is.na(TestGroups$prop) == FALSE) # Which rows are zooplankton - fish_groups = which(is.na(TestGroups$prop) == TRUE) # Which rows are fish - - biom_store[i,2] = sum(curr_biom[zoo_groups]) # Sum biomass over all zoo groups - biom_store[i,3] = sum(curr_biom[fish_groups]) # Sum biomass over all fish groups - - ratio_store[i,1] = biom_store[i,2]/biom_store[i,1] # Calculate zoo to phyto biom ratio - ratio_store[i,2] = biom_store[i,3]/biom_store[i,2] # Calculate fish to zoo biom ratio - ratio_store[i,3] = biom_store[i,3]/biom_store[i,1] # Calculate fish to phyto biom ratio - } - - return(ratio_store) - -} - -Biomass_Change = function(model_abunds, control_abunds, w) { - model_fish_bioms <- 0 # vector(nrow = length(model_abunds), dim(enviro_data)[1]) # Preallocate Fish Biomass - control_fish_bioms <- 0 # vector(nrow = length(control_abunds), dim(enviro_data)[1]) # Preallocate Fish Proportions - - # fish_groups <- 10:12 # Which rows are fish - control_fish_groups <- ((dim(control_abunds[[1]])[1])-2):dim(control_abunds[[1]])[1] - model_fish_groups <- ((dim(model_abunds[[1]])[1])-2):dim(model_abunds[[1]])[1] - - for(j in 1:length(model_abunds)){ - control_fish_bioms[j] = sum(apply(sweep(control_abunds[[j]], 2, w, '*'), 1, sum)[control_fish_groups]) # Get the reference/control data - model_fish_bioms[j] = sum(apply(sweep(model_abunds[[j]], 2, w, '*'), 1, sum)[model_fish_groups]) # The run we are comparing to - } - - # fish_props = (model_fish_bioms/control_fish_bioms)*100-100 - fish_props = ((model_fish_bioms-control_fish_bioms)/control_fish_bioms)*100 - return(fish_props) -} - -Pie_Preparation = function(bdf){ - bdf <- bdf %>% - dplyr::select(-c(Fish_Small, Fish_Med, Fish_Large, SST, Chl, x, y)) - - ZS <- bdf %>% - mutate(ZoopSum = dplyr::select(., Larvaceans:Jellyfish) %>% - apply(1, sum, na.rm=TRUE)) - - bdf <- bdf/ZS$ZoopSum - bdf <- bdf %>% - pivot_longer(names_to = "Taxa", values_to = "Biomass", cols = everything()) %>% - group_by(Taxa) %>% - summarise(Mean = round(mean(Biomass,na.rm = TRUE), digits = 2)) %>% - ungroup %>% - mutate(Taxa = factor(Taxa)) - rm(ZS) - - bdf <- left_join(x = bdf, y = TestGroups[ , c("species", "Colour", "Feeding")], by = c("Taxa"="species"), all.x=TRUE) - bdf <- bdf %>% - arrange(Feeding) %>% # Group feeding types together - mutate(Taxa = factor(Taxa, levels = Taxa), # Fix factor levels to this order too - ) -} - -Biomass_Proportion = function(){ - biomass_brick <- readRDS("../GlobalZoopAbundModels/ModelOutput/GlobalLayers/Num_Brick_Biomass.rds") - - bdf <- as.data.frame(biomass_brick, xy = TRUE) - - bdf <- bdf %>% - dplyr::select(-c(Fish_Small, Fish_Med, Fish_Large)) %>% - mutate(Chl = replace(Chl, Chl > 0.5, 0.5)) # Setting Chl to max log10(0.5) - - bdf2 <- pivot_longer(bdf, names_to = "Taxa", values_to = "Biomass", - cols = c("Larvaceans", "OmniCopepods","CarnCopepods", "Euphausiids", "Chaetognaths", "Salps", "Jellyfish")) - - bdf3 <- bdf2 %>% - filter(!is.na(Chl) & !is.na(SST)) %>% - mutate(Chl = round(Chl,1), # Round to 2 decimal places - Chl = as.factor(Chl)) %>% - dplyr::group_by(Chl) - - bdf4 <- bdf3 %>% - summarise(TotalBio = sum(Biomass,na.rm = T), - Larvaceans = sum(Biomass[Taxa == "Larvaceans"],na.rm = T)/TotalBio, - OmniCopepods = sum(Biomass[Taxa == "OmniCopepods"],na.rm = T)/TotalBio, - CarnCopepods = sum(Biomass[Taxa == "CarnCopepods"],na.rm = T)/TotalBio, - Euphausiids = sum(Biomass[Taxa == "Euphausiids"],na.rm = T)/TotalBio, - Chaetognaths = sum(Biomass[Taxa == "Chaetognaths"],na.rm = T)/TotalBio, - Salps = sum(Biomass[Taxa == "Salps"],na.rm = T)/TotalBio, - Jellyfish = sum(Biomass[Taxa == "Jellyfish"],na.rm = T)/TotalBio) %>% - ungroup() - - bdf5 <- gather(bdf4, key = "Taxa", value = "Proportion", -c(TotalBio, Chl)) %>% - mutate(Chl = as.numeric(as.character(Chl)), - Taxa = as.factor(Taxa), - Taxa = factor(Taxa, levels = c("OmniCopepods", "Euphausiids", "Jellyfish", "Chaetognaths", "CarnCopepods", "Salps", "Larvaceans"))) -} - - -PhytoBio_Proportion = function(){ - biomass_brick <- readRDS("../GlobalZoopAbundModels/ModelOutput/GlobalLayers/Num_Brick_Biomass.rds") - - source("../ZooMSS/Ancillary/Supplementary/EnvironmentalData/fZooMSS_CalculatePhytoParam.R") - - bdf <- as.data.frame(biomass_brick, xy = TRUE) - - phyto <- fZooMSS_CalculatePhytoParam(10^bdf$Chl) - bdf <- bind_cols(bdf, phyto) - - bdf <- bdf %>% - dplyr::select(c(Flagellates, Ciliates, Chl, SST, pico_biom, nano_biom, micro_biom)) %>% - rename("PicoPhytoplankton" = pico_biom, "NanoPhytoplankton" = nano_biom, "MicroPhytoplankton" = micro_biom) %>% - mutate(Chl = replace(Chl, Chl > 0.5, 0.5)) # Setting Chl to max log10(0.5) - - bdf2 <- pivot_longer(bdf, names_to = "Taxa", values_to = "Biomass", - cols = c(Flagellates, Ciliates, PicoPhytoplankton, NanoPhytoplankton, MicroPhytoplankton)) - - bdf3 <- bdf2 %>% - filter(!is.na(Chl) & !is.na(SST)) %>% - mutate(Chl = round(Chl,1), # Round to 2 decimal places - Chl = as.factor(Chl)) %>% - dplyr::group_by(Chl) - - bdf4 <- bdf3 %>% - summarise(TotalBio = sum(Biomass,na.rm = T), - Flagellates = sum(Biomass[Taxa == "Flagellates"],na.rm = T)/TotalBio, - Ciliates = sum(Biomass[Taxa == "Ciliates"],na.rm = T)/TotalBio, - PicoPhytoplankton = sum(Biomass[Taxa == "PicoPhytoplankton"],na.rm = T)/TotalBio, - NanoPhytoplankton = sum(Biomass[Taxa == "NanoPhytoplankton"],na.rm = T)/TotalBio, - MicroPhytoplankton = sum(Biomass[Taxa == "MicroPhytoplankton"],na.rm = T)/TotalBio) %>% - ungroup() - - bdf5 <- gather(bdf4, key = "Taxa", value = "Proportion", -c(TotalBio, Chl)) %>% - mutate(Chl = as.numeric(as.character(Chl)), - Taxa = as.factor(Taxa), - Taxa = factor(Taxa, levels = c("PicoPhytoplankton", "NanoPhytoplankton", "MicroPhytoplankton", "Flagellates", "Ciliates"))) -} - - - - -Diet_Prepare = function(diets, enviros){ - - diets <- diets[enviros] - - ### These lines create diet matrices for subset (oligo, eutro etc). The matrices rows are predators, columns are prey. - ### The first 3 columns are phytoplankton broken into pico, nano and microphytoplankton - diets_mat <- apply(array(unlist(diets), dim = c(nrow(diets[[1]]), ncol(diets[[1]]), length(diets))), c(1,2), mean) - - ### Add together pico, nano, microphytoplankton, append to diet matrices and remove pico, nano and microphytoplankton columns - diets_mat <- cbind(rowSums(diets_mat[,c(1:3)]), diets_mat[,-c(1:3)]) - - ### Add dummy row for phytoplankton predation (all zero) - diets_mat <- rbind(rep(0, 13), diets_mat) - - ### Flip matrices, so rows are prey and columns are predators - diets_mat = t(diets_mat) - - namess <- c("Phytoplankton", "Flagellates", "Ciliates", "Larvaceans", "OmniCopepods", - "CarnCopepods", "Euphausiids", "Chaetognaths", "Salps", "Jellyfish", - "PlanktivorousFish", "Fish_Med", "Fish_Large") - colnames(diets_mat) <- namess - rownames(diets_mat) <- namess - - return(diets_mat) -} - - -Chord_Prepare = function(diets, enviros, TestGroups) { - - diets <- diets[enviros] - - ### These lines create diet matrices for subset (oligo, eutro etc). The matrices rows are predators, columns are prey. - ### The first 3 columns are phytoplankton broken into pico, nano and microphytoplankton - diets_mat <- apply(array(unlist(diets), dim = c(nrow(diets[[1]]), ncol(diets[[1]]), length(diets))), c(1,2), mean) - - ### Add together pico, nano, microphytoplankton, append to diet matrices and remove pico, nano and microphytoplankton columns - diets_mat <- cbind(rowSums(diets_mat[,c(1:3)]), diets_mat[,-c(1:3)]) - - ### Add dummy row for phytoplankton predation (all zero) - diets_mat <- rbind(rep(0, 13), diets_mat) - - ### Flip matrices, so rows are prey and columns are predators, then add together fish groups to get total fish diet - diets_mat = t(diets_mat) - diets_mat[,11] = rowSums(diets_mat[,c(11:13)]) - diets_mat[11,] = colSums(diets_mat[c(11:13),]) - diets_mat = diets_mat[1:11, 1:11] ### Remove seperated fish groups - - namess <- c("Phytoplankton", TestGroups$species[1:9], "Fish") - colnames(diets_mat) <- namess - rownames(diets_mat) <- namess - - return(diets_mat) -} - -PPMR_plot = function(TestGroups, res, enviros){ - - min_size = min(TestGroups$W0) # smallest size class - max_size = max(TestGroups$Wmax) # largest size class - w = 10^(seq(from = min_size, to = max_size, 0.1)) # all size classes - - # Calculate PPMR (beta) table, where dim1 = group, dim2 = body size with - # value being PPMR for that body size (this is not realised PPMR - not - # emergent from diet but calculated from m-values and Wirtz, 2012 equation) - D.z = 2*(3*(w)*1e12/(4*pi))^(1/3) # convert body mass g to ESD (um) - zoo_m = TestGroups$m # pull out m-values from parameter table - betas = log10(t(sapply(zoo_m, function(x){(exp(0.02*log(D.z)^2 - x + 1.832))^3}))) # Convert m to betas, using Wirtz 2012 equation - betas = betas[-which(is.na(TestGroups$m)),] # remove fish rows - - ## Modify beta matrix for larvaceans and salps - all size classes for these groups feed on same prey, so log10PPMR increases by 0.1 for each 0.1 log10 size interval - betas[3,45:75] <- betas[3,44] + seq(0.1,3.1,0.1) # Larvaceans (index 44 in w vector is smallest size class, 75 is maximum size class) - betas[8,61:121] <- betas[8,61] + seq(0.1,6.1,0.1) # Salps (index 61 in w vector is smallest size class, 121 is maximum size class - - # Calculate ave abundances across oligo/eutro grid squares, then calculate ave - # biomass and proportion of total zoo biomass that is from each group size class - abunds = res[enviros] - ave = matrix(0, nrow = dim(TestGroups)[1], ncol = length(w)) - for(i in 1:length(abunds)){ - ave = ave + abunds[[i]]/length(abunds) - } - ave_biom = sweep(ave, 2, w, "*") # Calculate oligo biomass for zoo groups - ave_biom = ave_biom[-which(is.na(TestGroups$m)),] # remove rows for fish - beta_props = ave_biom/sum(ave_biom) # Calculate fraction of zoo biomass in each group, in each size class - - out <- list() - out[[1]] <- betas - out[[2]] <- beta_props - names(out) <- c("betas", "beta_props") - - temp <- density(betas, weights = beta_props) - - out <- tibble("x" = temp$x, "y" = temp$y, "mn_beta" = sum(beta_props*betas)) - - spbeta_props = ave_biom/rowSums(ave_biom) # Species specific proportions - spPPMR <- tibble("Species" = TestGroups$species[-which(is.na(TestGroups$m))], "Betas" = rowSums(spbeta_props*betas), "y" = NA) # Get species-specific PPMR - - for (s in 1:length(spPPMR$Species)){ - spPPMR$y[s] <- out$y[which.min(abs(out$x - spPPMR$Betas[s]))] - } - out2 <- list() - out2[[1]] <- out - out2[[2]] <- spPPMR - - return(out2) -} - - -### BIOM DATAFRAME -biom_mat_zoo <- function(N, groups, cut_point1, cut_point2){ - zoo_groups = which(is.na(groups$prop) == FALSE)[-c(1,2)] # Which rows are zooplankton (excluding flag and cils) - num_zoo = length(zoo_groups) - - biom_mat <- matrix(0, nrow = length(N), ncol = num_zoo) - - - for(i in 1:length(N)){ - N_ave = N[[i]] - B_ave = N_ave*matrix(w, nrow = dim(N_ave)[1], ncol = dim(N_ave)[2], byrow = TRUE) - weight_cut = which(round(log10(w),2) >= cut_point1 & round(log10(w),2) <= cut_point2) - zoo_bioms = rowSums(B_ave[zoo_groups, weight_cut]) - zoo_props = zoo_bioms - biom_mat[i,] <- zoo_props - } - - colnames(biom_mat) = as.character(groups$species)[3:9] - biom_mat = as.data.frame(biom_mat) - biom_mat -} - -# ### BIOM DATAFRAME - Flagellates and Ciliates -# biom_mat_hetero <- function(res, model, TestGroups, cut_point1, cut_point2){ -# zoo_groups = which(is.na(TestGroups$prop) == FALSE)[c(1,2)] # Which rows are flagellates and ciliates -# num_zoo = length(zoo_groups)+1 # Add one column for the phytoplankton -# -# biom_mat <- matrix(0, nrow = dim(enviro_data)[1], ncol = num_zoo) -# -# for(i in 1:dim(enviro_data)[1]){ -# # Calculate flag and cil biomass -# N_ave = res[[i]] -# B_ave = N_ave*matrix(model$w, nrow = dim(N_ave)[1], ncol = dim(N_ave)[2], byrow = TRUE) -# weight_cut = which(round(log10(model$w),2) >= cut_point1 & round(log10(model$w),2) <= cut_point2) -# zoo_bioms = rowSums(B_ave[zoo_groups, weight_cut]) -# -# # Calculate phytoplankton biomass -# w0_phyto = -14.5 # minimum phytoplankton size class (1um) -# wMax_phyto = min(enviro_data$phyto_max[i]) -# w_phyto = 10^(seq(-14.5, wMax_phyto,0.1)) -# a = enviro_data$a[i] -# b = enviro_data$b[i] -# phyto_biom = sum((10^a)*(w_phyto^(b+1))) -# -# # Concatenate and save -# all_bioms = c(phyto_biom,zoo_bioms) -# biom_mat[i,] <- all_bioms -# } -# -# colnames(biom_mat) = c('Phyto',as.character(TestGroups$species)[1:2]) -# biom_mat = as.data.frame(biom_mat) -# } - -### RATIO OF ZOO TO PHYTO, FISH TO ZOO AND FISH TO PHYTO -ratio_frame <- function(N, groups, enviro, cut_point1, cut_point2){ - enviro_data = enviro - chlo <- enviro_data$chlo - c_chl <- ((chlo^0.89)*(10^1.79))/chlo # chlo:carbon ratio (0.02 Chl:C) - phyto_carb <- c_chl*chlo/1000 # (convert to grams carbon) - # phyto_ww <- phyto_carb*0.1 - - - zoo_groups = which(is.na(groups$prop) == FALSE)[-c(1:2)] # Which rows are zooplankton - num_zoo = length(zoo_groups) - - biom_mat <- matrix(0, nrow = dim(enviro_data)[1], ncol = num_zoo) - - for(i in 1:dim(enviro_data)[1]){ - N_ave = N[[i]] - weight_cut = which(round(log10(model$w),2) >= cut_point1 & round(log10(model$w),2) <= cut_point2) - B_ave = N_ave*matrix(model$w, nrow = dim(N_ave)[1], ncol = dim(N_ave)[2], byrow = TRUE) - zoo_bioms = rowSums(B_ave[zoo_groups, weight_cut]) - zoo_props = zoo_bioms - biom_mat[i,] <- zoo_props - } - - colnames(biom_mat) = as.character(groups$species)[3:9] - biom_mat = as.data.frame(biom_mat) - zoo_ww = rowSums(biom_mat) - zoo_carb = rowSums(sweep(biom_mat, 2, groups$carbon[3:9], "*")) - - fish_groups = which(is.na(groups$prop) == TRUE) # Which rows are fish - num_fish = length(fish_groups) - - biom_matf <- matrix(0, nrow = dim(enviro_data)[1], ncol = num_fish) - - for(i in 1:dim(enviro_data)[1]){ - N_ave = N[[i]] - B_ave = N_ave*matrix(model$w, nrow = dim(N_ave)[1], ncol = dim(N_ave)[2], byrow = TRUE) - fish_bioms = rowSums(B_ave[fish_groups,]) - fish_props = fish_bioms - biom_matf[i,] <- fish_props - } - - colnames(biom_matf) = as.character(groups$species)[10:12] - biom_matf = as.data.frame(biom_matf) - fish_ww = rowSums(biom_matf) - fish_carb = rowSums(sweep(biom_matf, 2, groups$carbon[10:12], "*")) - - ratio_frame = data.frame("ZP" = zoo_carb/phyto_carb, "FZ" = fish_carb/zoo_carb, "FP" = fish_carb/phyto_carb) - ratio_frame - -} - -## CALCULATE SLOPES OF PHYTO, ZOO AND FISH -slope_frame <- function(N, groups, start, finish){ - ########## RESULTS TABLES - slopes <- matrix(0, dim(enviro_data)[1],3) - fish_groups = which(is.na(groups$prop) == TRUE) # Which rows are fish - zoo_groups = which(is.na(groups$prop) == FALSE) # Which rows are zooplankton - num_zoo = length(zoo_groups) - num_fish = length(fish_groups) - - for(i in 1:dim(enviro_data)[1]){ - N_ave = N[[i]] - enviro <- enviro_data[i,] - tot_zoo = colSums(N_ave[zoo_groups,]) - tot_fish = N_ave[fish_groups,] - - if(num_fish > 1){ - tot_fish = colSums(N_ave[fish_groups,]) - } - tot_anim = tot_zoo + tot_fish - # Average Slope - fish_start = which(round(log10(model$w), digits = 2) == (param$groups$W0[dim(groups)[1]])) - fish_finish = which(round(log10(model$w), digits = 2) == (param$groups$Wmat[dim(groups)[1]])) - max_phyto = round(log10(param$wMax_phyto), digits = 2) - zoo_start = which(round(log10(model$w), digits = 2) == start) - zoo_finish = which(round(log10(model$w), digits = 2) == finish) - zoo_slope2 = lm(log10(tot_anim[zoo_start:zoo_finish])~log10(model$w[zoo_start:zoo_finish]))$ - coefficients[2] - #zoo_slope2 = round((log10(tot_zoo[zoo_finish]) - log10(tot_zoo[zoo_start]))/ - # (log10(model$w[zoo_finish]) - log10(model$w[zoo_start])), digits = 2) - fish_slope2 = round(lm(log10(tot_fish[fish_start:fish_finish])~log10(model$w[fish_start:fish_finish]))$ - coefficients[2], digits = 2) - #fish_slope2 = round((log10(N_ave[dim(N_ave)[1],fish_finish]) - log10(N_ave[dim(N_ave)[1],fish_start]))/ - # (log10(model$w[fish_finish]) - log10(model$w[fish_start])), digits = 2) - phyto_slope = enviro$b - - slopes[i,1] <- phyto_slope - slopes[i,2] <- zoo_slope2 - slopes[i,3] <- fish_slope2 - } - - colnames(slopes) <- c('Phyto_Slope', 'Zoo_Slope', 'Fish_Slope') - slopes -} - -### CALCULATE TOTAL FISH BIOMASS IN EACH GRID SQUARE -biom_mat_fish = function(res){ - l_res = length(res) - fish_biom = rep(0, l_res) - - for(i in 1:l_res){ - N = res[[i]] - fish = N[c(10:12),c(1:168)] - w_fish = w[1:168] - fish_biom[i] = sum(sweep(fish, 2, w_fish, "*")) - } - fish_biom -} - -#first, take out the by-species total abundances for each grid square -summary_by_species <- function(N, Groups, enviro_data){ - #setup matrix with a row per square, and enough columns for the enviro data and species abundance/biomass - res_summary <- matrix(nrow=dim(enviro_data)[1],ncol=(dim(enviro_data)[2]+2*dim(Groups)[1])) - colnames(res_summary) <- c(colnames(enviro_data),paste0(as.character(Groups$species),"_abund"),paste0(as.character(Groups$species),"_biom")) - #paste in the environment data - for (i in 1:dim(enviro_data)[1]) { - for (j in 1:dim(enviro_data)[2]) { - res_summary[i,j]=enviro_data[i,j] - } - } - #abundance - for (j in 1:dim(Groups)[1]) { - for (i in 1:dim(enviro_data)[1]) { - res_summary[i,dim(enviro_data)[2]+j]<-sum(N[[i]][j,]) - } - } - #biomass - dx = 0.1 # log10 weight step - w0 = 10^(min(Groups$W0)) # minimum dynamic size class - wMax = 10^(max(Groups$Wmax))# maximum dynamic size class - w = 10^(seq(from = log10(w0), to = log10(wMax), dx)) - for (i in 1:dim(enviro_data)[1]) { - res_summary[i,dim(enviro_data)[2]+dim(Groups)[1]+1:dim(Groups)[1]]<-apply(sweep(N[[i]], 2, w, '*'),1,sum) - } - - - #Biomass <- apply(sweep(N[[i]], 2, model$w, '*'),c(1,2),sum) - - res_summary <- as_tibble(res_summary) - return(res_summary) -} diff --git a/Ancillary/TODO_FoodWebs_0b_Initialise.R b/Ancillary/TODO_FoodWebs_0b_Initialise.R deleted file mode 100644 index 3f5158b..0000000 --- a/Ancillary/TODO_FoodWebs_0b_Initialise.R +++ /dev/null @@ -1,62 +0,0 @@ -# Loads the required model data - -### Get the environmental data -# enviro_data <- read_rds(paste0(data_dir,"enviro200_20200209.RDS")) # Load in environmental data -TestGroups <- read_csv("~/Nextcloud/MME2Work/ZooMSS/_LatestModel/20200212_Control_Full_UNSW/TestGroups.csv") # Load in functional group information - -# Lets add these colours to TestGroup -TestGroups <- TestGroups %>% - mutate(Colour = case_when(species == "Flagellates" ~ "seagreen3", - species == "Ciliates" ~ "seagreen4", - species == "Larvaceans" ~ "lightgoldenrod4", - species == "OmniCopepods" ~ "cornflowerblue", - species == "CarnCopepods" ~ "darkred", - species == "Euphausiids" ~ "darkblue", - species == "Chaetognaths" ~ "firebrick1", - species == "Salps" ~ "lightgoldenrod3", - species == "Jellyfish" ~ "orange", - species == "Fish_Small" ~ "lightcoral", - species == "Fish_Med" ~ "coral3", - species == "Fish_Large" ~ "coral4"), - CommonName = species, - CommonName = case_when(species == "Euphausids" ~ "Krill", - species != "Euphausids" ~ species), - Abbrev = case_when(species == "Flagellates" ~ "Het. Flag.", - species == "Ciliates" ~ "Het. Cil.", - species == "Larvaceans" ~ "Larv.", - species == "OmniCopepods" ~ "Omni.Cop.", - species == "CarnCopepods" ~ "Carn.Cop.", - species == "Euphausiids" ~ "Euph.", - species == "Chaetognaths" ~ "Chaet.", - species == "Salps" ~ "Salps", - species == "Jellyfish" ~ "Jelly.", - species == "Fish_Small" ~ "Fish_Small", - species == "Fish_Med" ~ "Fish_Med", - species == "Fish_Large" ~ "Fish_Large"), - Feeding = case_when(species == "Flagellates" ~ "Heterotroph", - species == "Ciliates" ~ "Heterotroph", - species == "Larvaceans" ~ "FilterFeeder", - species == "OmniCopepods" ~ "Omnivore", - species == "CarnCopepods" ~ "Carnivore", - species == "Euphausiids" ~ "Omnivore", - species == "Chaetognaths" ~ "Carnivore", - species == "Salps" ~ "FilterFeeder", - species == "Jellyfish" ~ "Carnivore", - species == "Fish_Small" ~ "Fish", - species == "Fish_Med" ~ "Fish", - species == "Fish_Large" ~ "Fish" - ), - FeedingNo = case_when(species == "Flagellates" ~ 0, - species == "Ciliates" ~ 0, - species == "Larvaceans" ~ 1, - species == "OmniCopepods" ~ 2, - species == "CarnCopepods" ~ 3, - species == "Euphausiids" ~ 2, - species == "Chaetognaths" ~ 3, - species == "Salps" ~ 1, - species == "Jellyfish" ~ 3, - species == "Fish_Small" ~ 4, - species == "Fish_Med" ~ 4, - species == "Fish_Large" ~ 4 - ) - ) diff --git a/Ancillary/TODO_FoodWebs_1_ZoopSlopes.R b/Ancillary/TODO_FoodWebs_1_ZoopSlopes.R deleted file mode 100644 index 04ad7b3..0000000 --- a/Ancillary/TODO_FoodWebs_1_ZoopSlopes.R +++ /dev/null @@ -1,278 +0,0 @@ -## script to take the outputs and produce summaries of abundance and biomass by species and weight class - -library(tidyverse) -library(patchwork) -library(rnaturalearth) -library(rnaturalearthdata) -library(sf) -library(raster) - -source("FoodWebs_0a_Functions.R") -source("FoodWebs_0b_Initialise.R") - -enviro_data <- read_rds("~/Nextcloud/MME2Work/ZooMSS/_LatestModel/20200221_OneZoo_Full_UNSW/envirofull_20200312.RDS") # Load in environmental data -res <- read_rds("~/Nextcloud/MME2Work/ZooMSS/_LatestModel/20200212_Control_Full_UNSW/Output/res_20200212_Control_Full_UNSW.RDS") - -txt_size <- 4.5 - -# Original -oligo <- c(0,0.1) -eutro <- c(1,100) - -Bins <- read_csv("~/Dropbox/MissingLink/Output/LOPC_Bins_250.csv", col_names = FALSE) -Limits <- read_csv("~/Dropbox/MissingLink/Output/LOPC_Limits_250.csv", col_names = FALSE) - -### Plot data -plot_params <- tibble(dx = 0.1, # log10 weight step - w0 = 10^(min(TestGroups$W0)), # minimum dynamic size class - wMax = 10^(max(TestGroups$Wmax)), # maximum dynamic size class - MinSize = log10(Limits$X1[1]), # Min zoo size - MaxSize = log10(Limits$X1[length(Limits$X1)]), # Max zoo size - XMin = -2.5, # Plot x-min - XMax = 2.7, # Plot x-max - YMin = -4,#-1.2, # Plot y-min - YMax = 4) # Plot y-max -# Set weight bins -w = 10^(seq(from = log10(plot_params$w0), to = log10(plot_params$wMax), plot_params$dx)) - -### Load OPC Data -LOPC <- read_csv("~/Dropbox/MissingLink/Output/MasterDatabase_v20200308.csv", - col_types = cols(Voyage = "f", VolMethod = "f", User = "f", Unit = "f", - Season = "f",Model = "f", Region = "f", LonghurstBiome = "f", - LonghurstProvince = "f",OceanName = "f", Orientation = "f")) - -LOPC <- LOPC %>% - filter(is.na(Chl)==0) %>% - filter(Depth < 200) - - -## NOW DO MODEL VS OBSERVATIONS # - -## Data fits -NBSSdata_list_oligo <- NBSS_data(LOPC, Bins, oligo) -NBSSdata_oligo <- NBSSdata_list_oligo[[1]] -NBSSdata_full_oligo <- NBSSdata_list_oligo[[2]] -NBSSdata_full_oligo$Enviro <- "Oligotrophic" - -NBSSdata_list_eutro <- NBSS_data(LOPC, Bins, eutro) -NBSSdata_eutro <- NBSSdata_list_eutro[[1]] -NBSSdata_full_eutro <- NBSSdata_list_eutro[[2]] -NBSSdata_full_eutro$Enviro <- "Eutrophic" - -NBSSdata_all <- bind_rows(NBSSdata_full_eutro, NBSSdata_full_oligo) -NBSSdata_all$Enviro <- as.factor(NBSSdata_all$Enviro) - -modelfit_LOPC <- lm(log10(NB) ~ log10(Bins) + Enviro, data = NBSSdata_all) # No interactions -summary(modelfit_LOPC) - -modelfit_LOPC_int <- lm(log10(NB) ~ log10(Bins) * Enviro, data = NBSSdata_all) # Add in the interaction -summary(modelfit_LOPC_int) -anova(modelfit_LOPC_int, modelfit_LOPC) - -plot(modelfit_LOPC_int) - - -m1<- glm(NB ~ log10(Bins) + Enviro, family = Gamma(link = "log"), data = NBSSdata_all) # Add in the interaction -m2 <- glm(NB ~ log10(Bins) * Enviro, family = Gamma(link = "log"), data = NBSSdata_all) # Add in the interaction -anova(m1, m2, test = "F") -plot(m2) - - - -## ZooMSS fits - -NBSS_ZooMSS_oligo <- NBSS_ZooMSS(res, oligo, enviro_data, w, plot_params) # Compile Oligotrophic Model Output -modelfit_ZooMSS_oligo <- lm(log10(NB) ~ log10(Bins), data = NBSS_ZooMSS_oligo) # Do NBSS Fit - -NBSS_ZooMSS_eutro <- NBSS_ZooMSS(res, eutro, enviro_data, w, plot_params) # Compile Eutrophic Model Output -modelfit_ZooMSS_eutro <- lm(log10(NB) ~ log10(Bins), data = NBSS_ZooMSS_eutro) # Do NBSS Fit - -NBSS_ZooMSS_oligo$Enviro <- "Oligotrophic" # Add factor for bound df below. -NBSS_ZooMSS_eutro$Enviro <- "Eutrophic" - -NBSS_ZooMSS_all <- bind_rows(NBSS_ZooMSS_eutro, NBSS_ZooMSS_oligo) -NBSS_ZooMSS_all$Enviro <- as.factor(NBSS_ZooMSS_all$Enviro) - -## -gg_dat <- ggplot() + - scale_x_continuous(limits = c(plot_params$XMin, plot_params$XMax), expand = c(0, 0)) + - # scale_y_continuous(limits = c(plot_params$YMin, plot_params$YMax), expand = c(0, 0)) + - geom_point(data = NBSSdata_oligo, mapping = aes(x = log10(Bins), y = log10(NB)), colour = "red3") + - annotate("segment", x = plot_params$MinSize, xend = plot_params$MaxSize, - y = modelfit_LOPC_oligo$coefficients[1] + modelfit_LOPC_oligo$coefficients[2]*plot_params$MinSize, - yend = modelfit_LOPC_oligo$coefficients[1] + modelfit_LOPC_oligo$coefficients[2]*plot_params$MaxSize, - colour = "red3", size = 1.5) + - ylab(expression(paste("log"[10], "(Normalised biomass (" * m^-3 * "))"))) + - xlab(expression(paste("log"[10], "(Zooplankton size class (mg))"))) + - annotate("text", x = -1, y = 0.5, - label = "Oligotrophic", - colour = "red3", size = txt_size, hjust = "centre") + - annotate("text", x = -1, y = 0, - label = paste("Slope == ",sprintf("%.2f", modelfit_LOPC_oligo$coefficients[2])), - parse = TRUE, colour = "red3", size = txt_size, hjust = "centre") + - geom_point(data = NBSSdata_eutro, mapping = aes(x = log10(Bins), y = log10(NB)), colour = "blue3") + - annotate("segment", x = plot_params$MinSize, xend = plot_params$MaxSize, - y = modelfit_LOPC_eutro$coefficients[1] + modelfit_LOPC_eutro$coefficients[2]*plot_params$MinSize, - yend = modelfit_LOPC_eutro$coefficients[1] + modelfit_LOPC_eutro$coefficients[2]*plot_params$MaxSize, - colour = "blue3", size = 1.5) + - annotate("text", x = 0.5, y = 3.5, - label = "Eutrophic", - colour = "blue3", size = txt_size, hjust = "centre") + - annotate("text", x = 0.5, y = 3, - label = paste("Slope == ",deparse(sprintf("%.2f", round(modelfit_LOPC_eutro$coefficients[2], digits = 2)))), - parse = TRUE, colour = "blue3", size = txt_size, hjust = "centre") + - theme_bw() + - ggtitle(label = "",subtitle = "D) Data") + - theme(plot.title = element_text(size = 18), - plot.margin = unit(c(0,0,0,0), "mm")) - -gg_mod <- ggplot() + - scale_x_continuous(limits = c(plot_params$XMin, plot_params$XMax), expand = c(0, 0)) + - # scale_y_continuous(limits = c(plot_params$YMin, plot_params$YMax), expand = c(0, 0)) + - geom_point(data = NBSS_ZooMSS_oligo, mapping = aes(x = log10(Bins), y = log10(NB)), colour = "red3") + - annotate("segment", x = plot_params$MinSize, xend = plot_params$MaxSize, - y = modelfit_ZooMSS_oligo$coefficients[1] + modelfit_ZooMSS_oligo$coefficients[2]*plot_params$MinSize, - yend = modelfit_ZooMSS_oligo$coefficients[1] + modelfit_ZooMSS_oligo$coefficients[2]*plot_params$MaxSize, - colour = "red3", size = 1.5) + - ylab(expression(paste("log"[10], "(Normalised biomass (" * m^-3 * "))"))) + - xlab(expression(paste("log"[10], "(Zooplankton size class (mg))"))) + - annotate("text", x = -0.5, y = -0.5, - label = "Oligotrophic", - colour = "red3", size = txt_size, hjust = "centre") + - annotate("text", x = -0.5, y = -1, - label = paste("Slope == ",sprintf("%.2f", round(modelfit_ZooMSS_oligo$coefficients[2], digits = 2))), - parse = TRUE, colour = "red3", size = txt_size, hjust = "centre") + - geom_point(data = NBSS_ZooMSS_eutro, mapping = aes(x = log10(Bins), y = log10(NB)), colour = "blue3") + - annotate("segment", x = plot_params$MinSize, xend = plot_params$MaxSize, - y = modelfit_ZooMSS_eutro$coefficients[1] + modelfit_ZooMSS_eutro$coefficients[2]*plot_params$MinSize, - yend = modelfit_ZooMSS_eutro$coefficients[1] + modelfit_ZooMSS_eutro$coefficients[2]*plot_params$MaxSize, - colour = "blue3", size = 1.5) + - annotate("text", x = 0.5, y = 2.5, - label = "Eutrophic", - colour = "blue3", size = txt_size, hjust = "centre") + - annotate("text", x = 0.5, y = 2, - label = paste("Slope == ",sprintf("%.2f", round(modelfit_ZooMSS_eutro$coefficients[2], digits = 2))), - parse = TRUE, colour = "blue3", size = txt_size, hjust = "centre") + - theme_bw() + - ggtitle(label = "",subtitle = "E) Model") + - theme(plot.title = element_text(size = 18), - plot.margin = unit(c(0,0,0,0), "mm")) - - -world <- ne_countries(scale = "medium", returnclass = "sf") -world_sf <- st_transform(world, crs = 54009) # Convert to Mollweide - -theme_opts <- list(theme( - # panel.grid.minor = element_blank(), - # panel.grid.major = element_blank(), - panel.background = element_blank(), - # panel.border = element_blank(), - # plot.background = element_rect(fill = NA), - plot.margin = unit(c(0,0,0,0), "mm"), - # axis.line = element_blank(), - # axis.text.x = element_blank(), - # axis.text.y = element_blank(), - # axis.ticks = element_blank(), - # axis.title.x = element_blank(), - # axis.title.y = element_blank(), - # legend.title = element_text(size = 6), - # legend.text = element_text(size = 6), - # legend.position = "right", - # legend.direction = "horizontal", - # legend.background = element_rect(fill = NA), - # legend.key.height = unit(9, "mm"), - # legend.key.width = unit(4, "mm"), - # legend.position = c(0.5, -0.05), -)) - -dat <- LOPC %>% - dplyr::select(c(Lon, Lat)) -sub_sf <- st_as_sf(dat, coords = c('Lon', 'Lat'), crs = 4326) # Convert to sf -sub_sf <- st_transform(sub_sf, crs = 54009) # Alter the CRS -# -# nb <- readRDS("../GlobalZoopAbundModels/ModelOutput/GlobalLayers/Num_Brick_Biomass.rds") -# Chl_poly <- rasterToPolygons(nb$Chl, fun=NULL, n=4, na.rm=TRUE, digits=12, dissolve=FALSE) # Convert to polygon which is better for plotting -# Chl <- st_as_sf(Chl_poly, coords = c("x", "y")) -# st_crs(Chl) <- CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs") -# Chl <- st_transform(Chl, crs = 54009) # Alter the CRS - -enviro_data <- read_rds("~/GitHub/ZooMSS/envirofull_20200317.RDS") -Chl_data <- enviro_data %>% - dplyr::select(Lon, Lat, chlo) %>% - rename("Lon" = Lon, "Lat" = Lat, "Chl" = chlo) - -Chl_raster <- rasterFromXYZ(Chl_data) #Convert first two columns as lon-lat and third as value -crs(Chl_raster) <- CRS('+init=EPSG:4326') -Chl_poly <- rasterToPolygons(Chl_raster, fun=NULL, n=4, na.rm=TRUE, digits=12, dissolve=FALSE) # Convert to polygon which is better for plotting -Chl_sf <- st_as_sf(Chl_poly, crs = 4326) # Convert to sf -st_crs(Chl_sf) <- 4326 # Set base projection -Chl_sf_moll <- st_transform(Chl_sf, crs = 54009) # Alter the CRS to mollweide - - -gg_map <- ggplot() + - geom_sf(data = Chl_sf_moll, mapping = aes(fill = log10(Chl)), colour = NA) + - geom_sf(data = sub_sf, size = 0.4, colour = "purple", fill = "purple", inherit.aes = T) + - geom_sf(data = world_sf, size = 0.05, fill = "grey50") + - ggtitle("C) Data Distribution") + - scale_fill_gradient(name = element_blank(), - limits = c(-1, 0.5), - low = "#e5f5e0", #"#c7e9c0", - high = "#00441b", - na.value = "grey50", - guide = guide_colourbar(title = expression(paste("log"[10], "(Chlorophyll ",italic(a),"\n mg m"^-3, ")")), - title.position = "right", - title.vjust = 0.5, - title.hjust = 0.5, - title.theme = element_text(angle = 270, size = 10), - barheight = 10), - aesthetics = "fill", - oob = scales::squish) + - theme(plot.background = element_rect(fill = NA), - panel.grid.major = element_line(colour = "grey50", size = 0.2), - panel.grid.minor = element_blank(), - panel.background = element_blank(), - panel.border = element_blank(), - plot.margin = unit(c(0,0,0,0), "mm")) - -graphics.off() -x11(height = 7, width = 8) - -layout <- " -AA -AA -AA -AA -BC -BC -BC -" - -gg_map + gg_dat + gg_mod + plot_layout(design = layout) -ggsave("Figures/FoodWebs_1_Slopes.png", dpi = 400) - - - -## Do the statistics - -load("NBSS_Data.RData") - -modelfit_LOPC <- lm(log10(NB) ~ log10(Bins) + Enviro, data = NBSSdata_all) # No interactions -summary(modelfit_LOPC) - -modelfit_LOPC_int <- lm(log10(NB) ~ log10(Bins) * Enviro, data = NBSSdata_all) # Add in the interaction -summary(modelfit_LOPC_int) - -anova(modelfit_LOPC_int) # ? ANCOVA - - -modelfit_ZooMSS <- lm(log10(NB) ~ log10(Bins) + Enviro, data = NBSS_ZooMSS_all) # No interaction -summary(modelfit_ZooMSS) - -modelfit_ZooMSS_int <- lm(log10(NB) ~ log10(Bins) * Enviro, data = NBSS_ZooMSS_all) # With interaction -summary(modelfit_ZooMSS_int) - -anova(modelfit_ZooMSS_int) # ? ANCOVA - - - - diff --git a/Ancillary/TODO_FoodWebs_3a_ZooplanktonTaxa.R b/Ancillary/TODO_FoodWebs_3a_ZooplanktonTaxa.R deleted file mode 100644 index 2d8b13c..0000000 --- a/Ancillary/TODO_FoodWebs_3a_ZooplanktonTaxa.R +++ /dev/null @@ -1,417 +0,0 @@ -library(tidyverse) -library(patchwork) -library(raster) -library(ggplotify) -library(circlize) - -source("FoodWebs_0a_Functions.R") -source("FoodWebs_0b_Initialise.R") - -data_dir <- "~/Nextcloud/MME2Work/ZooMSS/_LatestModel/20200212_Control_Full_UNSW/" -diets <- read_rds(paste0(data_dir, "Output/diets_20200212_Control_Full_UNSW.RDS")) -res <- read_rds(paste0(data_dir, "Output/res_20200212_Control_Full_UNSW.RDS")) -model <- read_rds(paste0(data_dir, "Output/ModelParameters.RDS")) -enviro_data <- read_rds(paste0(data_dir, "envirofull_20200312.RDS")) - -# data_dir <- "~/Nextcloud/MME2Work/ZooMSS/_LatestModel/20200428_NoDiffusion/" -# diets <- read_rds(paste0(data_dir, "Output/diets_20200428_NoDiffusion.RDS")) -# res <- read_rds(paste0(data_dir, "Output/res_20200428_NoDiffusion.RDS")) -# model <- read_rds(paste0(data_dir, "Output/ModelParameters.RDS")) -# enviro_data <- read_rds(paste0(data_dir, "envirofull_20200317.RDS")) - -enviros_oligo = which(enviro_data$chlo <= 0.1) # Oligo grid squares are where chlo is <= 0.1 mg m-3 -enviros_eutro = which(enviro_data$chlo >= 1) # Eutro grid squares are where chlo is > 1 mg m-3 - -low_Chl <- "#e5f5f9" # "#bcdcbc"# "#E5FFCC" -high_Chl <- "#99d8c9" # "#228b22" #"#4ea24e"# "#2e8b57"# "#009900" - -#### CHORD DIAGRAMS #### -colr <- TestGroups$Colour[c(3,8,4,6,5,7,9,10)] -model_color <- c("darkgreen", colr) # Add green for phytoplankton -txt <- 0.9 - -diets_mat_oligo = Chord_Prepare(diets, enviros_oligo, TestGroups) -diets_mat_oligo <- diets_mat_oligo[-c(2:3), -c(2:3)] -diets_mat_oligo <- diets_mat_oligo[c(1,2,7,3,5,4,6,8,9),c(1,2,7,3,5,4,6,8,9)] - -diets_mat_eutro = Chord_Prepare(diets, enviros_eutro, TestGroups) -diets_mat_eutro <- diets_mat_eutro[-c(2:3), -c(2:3)] -diets_mat_eutro <- diets_mat_eutro[c(1,2,7,3,5,4,6,8,9),c(1,2,7,3,5,4,6,8,9)] - -## ## bottom, left, top and right margins -gg_fw <- as.ggplot(function(){ - circos.clear() - par(mar = c(0, 1, 0, 2), xpd = NA, mfrow = c(1,2)) #oma = c(0,0,0,0) - # circos.par(start.degree = 90) - chordDiagram(diets_mat_oligo, - directional = 1, - grid.col = model_color, - direction.type = c("diffHeight"), - link.arr.type = "triangle", - diffHeight = -uh(2, "mm"), - annotationTrack = c("grid"), - annotationTrackHeight = c(0.1, 0.01), - transparency = 0.2, - # preAllocateTracks = 1 - ) - text(0.9, -1, "Phytoplankton", cex = txt) - text(-1.3, 0.3, "Larvaceans", cex = txt) - text(-0.6, 0.98, "Salps", cex = txt) - text(0, 1.3, "Omnivorous\n Copepods", cex = txt) - text(0.7, 1, "Euphausiids", cex = txt) - text(1.5, 0.57, "Carnivorous\n Copepods", cex = txt, adj = c(1,0)) - text(1.3, 0.6, "Chaetognaths", cex = txt) - text(1.2, 0.6, "Jellyfish", cex = txt) - text(1.1, 0.25, "Fish", cex = txt) - # text(-1,1,"E)",cex = 1.2) - # }) + - # labs(tag = "E)") + - # theme(plot.tag.position = c(-0.01, 1), - # plot.tag = element_text(size = 14, face = "bold")) - # - # gg_fw_eutro <- as.ggplot(function(){ - # par(mar = c(0, 0, 0, 0), oma = c(0,0,0,0), xpd = TRUE) - chordDiagram(diets_mat_eutro, - directional = 1, - grid.col = model_color, - direction.type = c("diffHeight"), - link.arr.type = "triangle", - diffHeight = -uh(2, "mm"), - annotationTrack = c("grid"), - annotationTrackHeight = c(0.1, 0.01), - transparency = 0.2, - # preAllocateTracks = 1 - ) - text(0.6, -1.1, "Phytoplankton", cex = txt) - text(-1.8, 0.9, "Omnivorous\n Copepods", cex = txt, adj = c(-1,0)) - text(0.45, 1, "Euphausiids", cex = txt) - text(1.2, 0.3, "Fish", cex = txt) - arrows(x0 = -0.85, y0 = -0.4, x1 = -0.7, y1 = -0.4, length = 0, lwd = 2) - text(-1.2, -0.25, "Larvaceans\n Salps", cex = txt, pos = 1) - arrows(x0 = 0.7, y0 = 0.55, x1 = 0.6, y1 =0.5, length = 0, lwd = 2) - text(1.5, 1, "Carnivorous Copepods\n Chaetognaths\n Jellyfish", cex = txt, pos = 2) - # text(-1,1,"F)", cex = 1.2) -}) - -# + -# labs(tag = "F)") + -# theme(plot.tag.position = c(-0.01, 1), -# plot.tag = element_text(size = 14, face = "bold")) - - - -gg_fw_eutro <- as.ggplot(function(){ - par(mar = c(0, 0, 0, 0), oma = c(0,0,0,0), xpd = TRUE) - chordDiagram(diets_mat_eutro, - directional = 1, - grid.col = model_color, - direction.type = c("diffHeight"), - link.arr.type = "triangle", - diffHeight = -uh(2, "mm"), - annotationTrack = c("grid"), - annotationTrackHeight = c(0.1, 0.01), - transparency = 0.2)} -) + - labs(tag = "F)") + - theme(plot.tag.position = c(-0.01, 1), - plot.tag = element_text(size = 14, face = "bold")) - - - - - - -#### PHYTO BIOMASS PROPORTION #### -PhytoBioProp <- PhytoBio_Proportion() # Get the Biomass Proportion Data - -gg_numPbio <- ggplot(PhytoBioProp, aes(x = Chl, y = Proportion, fill = Taxa)) + - scale_x_continuous(limits = c(-1.3001, 0.5001), expand = c(0, 0)) + - scale_y_continuous(limits = c(-0.001,1.001), expand = c(0, 0)) + - labs(fill = "Taxa") + - ylab("Biomass Proportion") + - geom_area(alpha = 0.8) + - scale_fill_manual(values = c("PicoPhytoplankton" = "#c7e9c0", - "NanoPhytoplankton" = "#a1d99b", - "MicroPhytoplankton" = "#74c476", - "Flagellates" = "#238b45", - "Ciliates" = "#00441b")) + # Greens: #e5f5e0 #c7e9c0 #a1d99b #74c476 #41ab5d #238b45 #006d2c #00441b - theme_bw(base_size = 12) + - theme(axis.title.x = element_blank(), - axis.text.x = element_blank(), - legend.title = element_blank(), - # plot.margin = margin(0,0,1,10), - legend.key.size = unit(5, "mm"), - panel.grid = element_line(color = "darkgrey")) + - # annotate("text", x = -1.3, y = 0.9, label = "A)") + - labs(tag = "A)") + - theme(plot.tag.position = c(0, 1), - plot.tag = element_text(size = 14, face = "bold")) - - -#### MESOZOOP BIOMASS PROPORTION #### -BiomassProp <- Biomass_Proportion() # Get the Biomass Proportion Data - -gg_numbio <- ggplot(BiomassProp, aes(x = Chl, y = Proportion, fill = Taxa)) + - scale_x_continuous(limits = c(-1.3001, 0.5001), expand = c(0, 0)) + - scale_y_continuous(limits = c(-0.001,1.001), expand = c(0, 0)) + - labs(fill = "Taxa") + - ylab("Biomass Proportion") + - xlab(expression(paste("log"[10], "(Chlorophyll ",italic(a)," mg m"^-3, ")"))) + - geom_area(alpha = 0.8) + - scale_fill_manual(values = c("Larvaceans" = TestGroups$Colour[TestGroups$species=="Larvaceans"], - "Salps" = TestGroups$Colour[TestGroups$species=="Salps"], - "Jellyfish" = TestGroups$Colour[TestGroups$species=="Jellyfish"], - "CarnCopepods" = TestGroups$Colour[TestGroups$species=="CarnCopepods"], - "Chaetognaths" = TestGroups$Colour[TestGroups$species=="Chaetognaths"], - "Euphausiids" = TestGroups$Colour[TestGroups$species=="Euphausiids"], - "OmniCopepods" = TestGroups$Colour[TestGroups$species=="OmniCopepods"])) + - theme_bw(base_size = 12) + - theme(legend.title = element_blank(), - plot.margin=grid::unit(c(0,0,1,0), "mm"), - legend.key.size = unit(5, "mm"), - # panel.background = element_rect(fill = NA), - # panel.ontop = TRUE, - panel.grid = element_line(color = "darkgrey")) + - labs(tag = "B)") + - theme(plot.tag.position = c(0, 1), - plot.tag = element_text(size = 14, face = "bold")) - - -#### FISH DIET #### -diet_df <- tibble(Diet = numeric(), Chl = numeric(), Taxa = character()) -Chl <- log10(enviro_data$chlo) -bins <- seq(-1.3, 0.5, by = 0.1) - -for (j in bins){ - m <- (Chl > j-0.05 & Chl <= j+0.05) - diets_mat <- Diet_Prepare(diets, m) - temp <- tibble(Diet = as.vector(diets_mat[c(1,4,5,6,7,8,9,10,11),"PlanktivorousFish"]), Chl = j, Taxa = rownames(diets_mat[c(1, 4:11),])) - diet_df <- bind_rows(diet_df, temp) -} - -sum_diet_df <- diet_df %>% - group_by(Chl) %>% - summarise(SumDiet = sum(Diet, na.rm=T)) %>% - ungroup() - -diet_df <- left_join(diet_df, sum_diet_df, by = "Chl") - -diet_df <- diet_df %>% - mutate(DietProp = Diet/SumDiet, - Taxa = as.factor(Taxa), - Taxa = factor(Taxa, levels = c("Phytoplankton", "OmniCopepods", "Euphausiids", "Jellyfish", "Chaetognaths", "CarnCopepods", "Salps", "Larvaceans", "PlanktivorousFish"))) - -gg_diet <- ggplot(diet_df, aes(x = Chl, y = DietProp, fill = Taxa)) + - scale_x_continuous(limits = c(-1.3001, 0.5001), expand = c(0, 0)) + - scale_y_continuous(limits = c(-0.001,1.001), expand = c(0, 0)) + - # labs(subtitle = "Diet Proportion") + - labs(fill = "Taxa") + - ylab("Planktivorous Fish\n Diet") + - geom_area(alpha = 0.8) + - theme_bw(base_size = 12) + - theme(axis.title.x = element_blank(), - axis.text.x = element_blank(), - legend.title = element_blank(), - plot.margin=grid::unit(c(0,0,1,0), "mm"), - legend.key.size = unit(5, "mm"), - # panel.background = element_rect(fill = NA), - # panel.ontop = TRUE, - panel.grid = element_line(color = "darkgrey")) + - scale_fill_manual(values = c("Phytoplankton" = "darkgreen", - "Larvaceans" = TestGroups$Colour[TestGroups$species=="Larvaceans"], - "Salps" = TestGroups$Colour[TestGroups$species=="Salps"], - "Jellyfish" = TestGroups$Colour[TestGroups$species=="Jellyfish"], - "CarnCopepods" = TestGroups$Colour[TestGroups$species=="CarnCopepods"], - "Chaetognaths" = TestGroups$Colour[TestGroups$species=="Chaetognaths"], - "Euphausiids" = TestGroups$Colour[TestGroups$species=="Euphausiids"], - "OmniCopepods" = TestGroups$Colour[TestGroups$species=="OmniCopepods"], - "PlanktivorousFish" = TestGroups$Colour[TestGroups$species=="Fish_Small"])) + - labs(tag = "G)") + - theme(plot.tag.position = c(0.0, 1), - plot.tag = element_text(size = 14, face = "bold")) - - - - -#### TROPHIC LEVEL #### -TrophLev <- as.data.frame(TrophicLevel_Calc(diets, TestGroups)) -TrophLev$Chl <- enviro_data$chlo - -gg_troph <- ggplot() + - geom_rect(aes(xmin = -Inf, xmax = -1, ymin = 2, ymax = 4.6), fill = low_Chl, alpha = 0.5) + - geom_rect(aes(xmin = 0.1, xmax = Inf, ymin = 2, ymax = 4.6), fill = high_Chl, alpha = 0.5) + - geom_point(data = TrophLev, aes(x = log10(Chl), y = Fish_Small), alpha = 1, size = 1, colour = "black", show.legend = FALSE) + - geom_smooth(data = TrophLev, aes(x = log10(Chl), y = Fish_Small), colour = "blue", fill = "black", method = "loess", span = 1, se = TRUE, show.legend = TRUE) + - # labs(subtitle = "Planktivorous Fish Trophic Level") + - xlab(expression(paste("log"[10], "(Chlorophyll ",italic(a)," mg m"^-3, ")"))) + - ylab("Food Chain Length") + - scale_x_continuous(limits = c(-1.3001, 0.5001), expand = c(0, 0)) + - scale_y_continuous(limits = c(2, 4.6), expand = c(0, 0)) + - theme_bw(base_size = 12) + - theme( - # panel.ontop = TRUE, - # panel.background = element_blank(), - # panel.grid.major = element_line(colour = "black"), - # axis.title.x = element_blank(), - # axis.text.x = element_blank(), - legend.key.size = unit(5, "mm"), - plot.margin=grid::unit(c(0,0,0,0), "mm")) + - labs(tag = "H)") + - theme(plot.tag.position = c(0.0, 1), - plot.tag = element_text(size = 14, face = "bold")) - - -# #### FISH:PHYTO RATIOS #### -# BiomassRat <- as.data.frame(biom_ratios(res, TestGroups, enviro_data)) -# BiomassRat$Chl <- enviro_data$chlo -# -# gg_ratio <- ggplot(data = BiomassRat, aes(x = log10(Chl), y = BiomassRat$FishPhyto)) + -# geom_point(alpha = 1, size = 1, colour = "black", show.legend = FALSE) + -# geom_smooth(colour = "blue", fill = "black", method = "loess", span = 1, se = TRUE, show.legend = TRUE) + -# xlab("log10(Chlorophyll)") + -# ylab("Fish:Phyto") + -# scale_x_continuous(limits = c(-1.3001, 0.5001), expand = c(0, 0)) + -# theme_bw(base_size = 12) - - -#### PPMR PLOTS #### -out_list_oligo <- PPMR_plot(TestGroups, res, enviros_oligo) -out_PPMR_oligo <- out_list_oligo[[1]] -sp_PPMR_oligo <- out_list_oligo[[2]] -sp_PPMR_oligo <- sp_PPMR_oligo %>% - mutate(Species = as.factor(Species), - Species = factor(Species, levels = c("Flagellates", "Ciliates", "OmniCopepods", "Euphausiids", "Jellyfish", "Chaetognaths", "CarnCopepods", "Salps", "Larvaceans"))) - -spPPMR2 <- sp_PPMR_oligo -spPPMR2$y <- spPPMR2$y * 0 -sp_PPMR_oligo <- bind_rows(sp_PPMR_oligo, spPPMR2) - - -out_list_eutro <- PPMR_plot(TestGroups, res, enviros_eutro) -out_PPMR_eutro <- out_list_eutro[[1]] -sp_PPMR_eutro <- out_list_eutro[[2]] -sp_PPMR_eutro <- sp_PPMR_eutro %>% - mutate(Species = as.factor(Species), - Species = factor(Species, levels = c("Flagellates", "Ciliates", "OmniCopepods", "Euphausiids", "Jellyfish", "Chaetognaths", "CarnCopepods", "Salps", "Larvaceans"))) - -spPPMR2 <- sp_PPMR_eutro -spPPMR2$y <- spPPMR2$y * 0 -sp_PPMR_eutro <- bind_rows(sp_PPMR_eutro, spPPMR2) - - -x1 <- -1.5 -x2 <- 14 -y1 <- -0.001 -y2 <- 0.31 - -gg_ppmr_o <- ggplot() + - geom_rect(aes(xmin = x1, xmax = x2, ymin = y1, ymax = y2), fill = low_Chl, alpha = 0.5) + - geom_line(data = sp_PPMR_oligo, mapping = aes(x = Betas, y = y, colour = Species), size = 1) + - geom_line(data = out_PPMR_oligo, mapping = aes(x = x, y = y), size = 1.2) + - theme_bw() + - theme(plot.margin=grid::unit(c(0,0,0,0), "mm")) + - scale_x_continuous(limits = c(x1, x2), expand = c(0, 0)) + - scale_y_continuous(limits = c(y1, y2), expand = c(0, 0)) + - labs(x = expression('log' [10] * PPMR), - y = "Biomass Proportion") + - geom_vline(data = out_PPMR_oligo, mapping = aes(xintercept = mn_beta), colour = 'black') + - theme_bw(base_size = 12) + - geom_text(data = data.frame(x = x2-0.5, y = 0.29, label = "Oligotrophic"), aes(x = x, y = y, label = label), fontface = "bold", hjust = "right") + - labs(tag = "C)") + - theme(plot.tag.position = c(0.0, 1.03), - plot.tag = element_text(size = 14, face = "bold"), - legend.position = "none") + - scale_colour_manual(values = c("Flagellates" = TestGroups$Colour[TestGroups$species=="Flagellates"], - "Ciliates" = TestGroups$Colour[TestGroups$species=="Ciliates"], - "Larvaceans" = TestGroups$Colour[TestGroups$species=="Larvaceans"], - "Salps" = TestGroups$Colour[TestGroups$species=="Salps"], - "Jellyfish" = TestGroups$Colour[TestGroups$species=="Jellyfish"], - "CarnCopepods" = TestGroups$Colour[TestGroups$species=="CarnCopepods"], - "Chaetognaths" = TestGroups$Colour[TestGroups$species=="Chaetognaths"], - "Euphausiids" = TestGroups$Colour[TestGroups$species=="Euphausiids"], - "OmniCopepods" = TestGroups$Colour[TestGroups$species=="OmniCopepods"])) - -gg_ppmr_e <- ggplot() + - geom_rect(aes(xmin = x1, xmax = x2, ymin = y1, ymax = y2), fill = high_Chl, alpha = 0.5) + - geom_line(data = sp_PPMR_eutro, mapping = aes(x = Betas, y = y, colour = Species), size = 1) + - geom_line(data = out_PPMR_eutro, mapping = aes(x = x, y = y), size = 1.2) + - theme_bw() + - theme(plot.margin=grid::unit(c(0,0,0,0), "mm"), - axis.text.y = element_blank(), - legend.title = element_blank()) + - scale_x_continuous(limits = c(x1, x2), expand = c(0, 0)) + - scale_y_continuous(limits = c(y1, y2), expand = c(0, 0)) + - geom_text(data = data.frame(x = x2-0.5, y = 0.29, label = "Eutrophic"), aes(x = x, y = y, label = label), fontface = "bold", hjust = "right") + - labs(x = expression('log' [10] * PPMR), y = element_blank()) + - geom_vline(data = out_PPMR_eutro, mapping = aes(xintercept = mn_beta), colour = 'black') + - # theme_bw(base_size = 12) + - labs(tag = "D)") + - theme(plot.tag.position = c(0, 1.03), - plot.tag = element_text(size = 14, face = "bold")) + - scale_colour_manual(values = c("Flagellates" = TestGroups$Colour[TestGroups$species=="Flagellates"], - "Ciliates" = TestGroups$Colour[TestGroups$species=="Ciliates"], - "Larvaceans" = TestGroups$Colour[TestGroups$species=="Larvaceans"], - "Salps" = TestGroups$Colour[TestGroups$species=="Salps"], - "Jellyfish" = TestGroups$Colour[TestGroups$species=="Jellyfish"], - "CarnCopepods" = TestGroups$Colour[TestGroups$species=="CarnCopepods"], - "Chaetognaths" = TestGroups$Colour[TestGroups$species=="Chaetognaths"], - "Euphausiids" = TestGroups$Colour[TestGroups$species=="Euphausiids"], - "OmniCopepods" = TestGroups$Colour[TestGroups$species=="OmniCopepods"]), - guide = guide_legend(keyheight = grid::unit(5, "mm"))) - - -#### Do PPMR/Biomass plots -graphics.off() -x11(height = 14, width = 8) -layout <- " -AA -AA -BB -BB -CC -CC -DD -DD -DD -DD -EE -EE -FF -FF -" -gg_numPbio + gg_numbio + (gg_ppmr_o + gg_ppmr_e + plot_layout(guides = 'collect')) + plot_spacer() + - gg_diet + gg_troph + plot_layout(design = layout) -# gg_numPbio + gg_numbio + gg_ppmr_o + gg_ppmr_e + -# ((wrap_elements(panel = gg_fw_oligo, clip = FALSE) + wrap_elements(panel = gg_fw_eutro, clip = TRUE)) / -# gg_diet + plot_layout(guides = 'collect')) + gg_troph + plot_layout(design = layout) -ggsave("Figures/FoodWebs_3.png", dpi = 400) - - - - -print( - paste("Mean PPMR for oligo is: ",round((10^out_PPMR_oligo$mn_beta[1])/1e3,3), "thousand") -) -print( - paste("Mean PPMR for eutro is: ",round((10^out_PPMR_eutro$mn_beta[1])/1e3,3), "thousand") -) - -print( - paste("Mean TL for oligo is: ",mean(TrophLev$Fish_Small[enviros_oligo])) -) - -print( - paste("Mean TL for eutro is: ",mean(TrophLev$Fish_Small[enviros_eutro])) -) - - -diets <- read_rds("~/Nextcloud/MME2Work/ZooMSS/_LatestModel/20200304_GroupExperiments_Full_UNSW/NoLarvaceans/Output/diets_NoLarvaceans.RDS") -TrophLevNoLarv <- as.data.frame(TrophicLevel_Calc(diets, TestGroups)) -TrophLevNoLarv$Chl <- enviro_data$chlo - -print( - paste("Mean TL for No Larvaceans in oligo is: ",mean(TrophLevNoLarv$Fish_Small[enviros_oligo])) -) - - - diff --git a/Ancillary/TODO_FoodWebs_3b_ChordDiagrams.R b/Ancillary/TODO_FoodWebs_3b_ChordDiagrams.R deleted file mode 100644 index 106a27a..0000000 --- a/Ancillary/TODO_FoodWebs_3b_ChordDiagrams.R +++ /dev/null @@ -1,183 +0,0 @@ -library(circlize) -library(tidyverse) - -source("FoodWebs_0a_Functions.R") -source("FoodWebs_0b_Initialise.R") - -# data_dir <- "~/Nextcloud/MME2Work/ZooMSS/_LatestModel/20200212_Control_Full_UNSW/" -# diets <- read_rds(paste0(data_dir, "Output/diets_20200212_Control_Full_UNSW.RDS")) -# res <- read_rds(paste0(data_dir, "Output/res_20200212_Control_Full_UNSW.RDS")) -# model <- read_rds(paste0(data_dir, "Output/ModelParameters.RDS")) -# enviro_data <- read_rds(paste0(data_dir, "envirofull_20200312.RDS")) - -data_dir <- "~/Nextcloud/MME2Work/ZooMSS/_LatestModel/20200428_NoDiffusion/" -diets <- read_rds(paste0(data_dir, "Output/diets_20200428_NoDiffusion.RDS")) -res <- read_rds(paste0(data_dir, "Output/res_20200428_NoDiffusion.RDS")) -model <- read_rds(paste0(data_dir, "Output/ModelParameters.RDS")) -enviro_data <- read_rds(paste0(data_dir, "envirofull_20200317.RDS")) - - -enviros_oligo = which(enviro_data$chlo <= 0.1) # Oligo grid squares are where chlo is <= 0.1 mg m-3 -enviros_eutro = which(enviro_data$chlo >= 1) # Eutro grid squares are where chlo is > 1 mg m-3 - -#### CHORD DIARGRAMS #### - -### DO Chords without Hetero -diets_mat_oligo = Chord_Prepare(diets, enviros_oligo, TestGroups) -diets_mat_oligo <- diets_mat_oligo[-c(2:3), -c(2:3)] -diets_mat_oligo <- diets_mat_oligo[c(1,2,7,3,5,4,6,8,9),c(1,2,7,3,5,4,6,8,9)] - -diets_mat_eutro = Chord_Prepare(diets, enviros_eutro, TestGroups) -diets_mat_eutro <- diets_mat_eutro[-c(2:3), -c(2:3)] -diets_mat_eutro <- diets_mat_eutro[c(1,2,7,3,5,4,6,8,9),c(1,2,7,3,5,4,6,8,9)] - -enviros_new <- 1429:1638 -diets_mat_new = Chord_Prepare(diets, enviros_new, TestGroups) -diets_mat_new <- diets_mat_new[-c(2:3), -c(2:3)] -diets_mat_new <- diets_mat_new[c(1,2,7,3,5,4,6,8,9),c(1,2,7,3,5,4,6,8,9)] - -colr <- TestGroups$Colour[c(3,8,4,6,5,7,9,10)] - -model_color = c("darkgreen", colr) # Add green for phytoplankton - -x11(width = 11, height = 5) - ## bottom, left, top and right margins -par(mar = c(0, 3, 0, 3), mfrow = c(1,2), xpd = NA) - -### OLIGOTROPHIC FOOD WEB -chordDiagram(diets_mat_oligo, - directional = 1, - grid.col = model_color, - direction.type = c("diffHeight"), - link.arr.type = "triangle", - diffHeight = -uh(2, "mm"), - annotationTrack = c("grid"), - annotationTrackHeight = c(0.1, 0.01), - transparency = 0.2) - -txt <- 0.9 -text(0.6, -1, "Phytoplankton", cex = txt) -text(-1.1, 0.45, "Larvaceans", cex = txt) -text(-0.55, 0.95, "Salps", cex = txt) -text(0, 1.1, "Omnivorous\n Copepods", cex = txt) -text(0.5, 1, "Euphausiids", cex = txt) -text(1.02, 0.76, "Carnivorous\n Copepods", cex = txt, adj = c(1,0)) -text(1.01, 0.68, "Chaetognaths", cex = txt) -text(0.98, 0.6, "Jellyfish", cex = txt) -text(1.2, 0.25, "Planktivorous\n Fish", cex = txt) - -text(-1,1,"E)",cex = 1.5, font = 2) - -### EUTROPHIC FOOD WEB -# circos.par(gap.after = c(rep(5, nrow(diets_mat_eutro)))) -chordDiagram(diets_mat_eutro, - directional = 1, - grid.col = model_color, - direction.type = c("diffHeight"), - link.arr.type = "triangle", - diffHeight = -uh(2, "mm"), - annotationTrack = c("grid"), - annotationTrackHeight = c(0.1, 0.01), - transparency = 0.2) - - -text(0.6, -1, "Phytoplankton", cex = txt) -text(-1.4, 0.75, "Omnivorous\n Copepods", cex = txt, adj = c(-1,0)) -text(0.45, 1, "Euphausiids", cex = txt) -text(1.15, 0.35, "Planktivorous\n Fish", cex = txt) - -arrows(x0 = -1.1, y0 = -0.6, x1 = -0.9, y1 = -0.5, length = 0, lwd = 2) -text(-1.2, -0.6, "Larvaceans\n Salps", cex = txt, pos = 1) - -arrows(x0 = 0.79, y0 = 0.65, x1 = 0.85, y1 = 0.7, length = 0, lwd = 2) -text(0.98, 0.9, "Carnivorous Copepods\n Chaetognaths\n Jellyfish", cex = txt, pos = 1) - -text(-1,1,"F)",cex = 1.5, font = 2) - -dev.print(pdf,'Figures/FoodWebs_3ef_ChordDiagram.pdf') -circos.clear() - - -# -# -# -# -# -# -# -# -# -# ### Do Chords with Hetero -# diets_mat_oligo = Chord_Prepare(diets, enviros_oligo, TestGroups) -# diets_mat_eutro = Chord_Prepare(diets, enviros_eutro, TestGroups) -# -# model_color = c("darkgreen", TestGroups$Colour[c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)]) # Add green for phytoplankton -# -# x11(width = 10, height = 5) -# par(mfrow = c(1,2)) -# -# ### OLIGOTROPHIC FOOD WEB -# chordDiagram(diets_mat_oligo, -# directional = 1, -# grid.col = model_color, -# direction.type = c("diffHeight"), -# link.arr.type = "triangle", -# diffHeight = uh(0.8, "mm"), -# annotationTrack = c("grid"), -# annotationTrackHeight = c(0.1, 0.01), -# transparency = 0.1, -# preAllocateTracks = 1) -# -# for(si in get.all.sector.index()) { -# if(get.cell.meta.data("xlim", sector.index = si)[2] > 0.02){ -# if (get.cell.meta.data("xlim", sector.index = si)[2] > 0.05) { -# prop <- seq(0,1,0.2)} else{prop <- seq(0,1,0.5)} -# circos.axis(h = "top", -# labels.cex = 0.5, -# sector.index = si, -# track.index = 2, -# labels.facing = "outside", -# major.at = (get.cell.meta.data("xlim", sector.index = si)[2] *prop), -# labels = (get.cell.meta.data("xlim", sector.index = si)[2] *prop)/(get.cell.meta.data("xlim", sector.index = si)[2])*100) -# -# xlim = get.cell.meta.data("xlim", sector.index = si, track.index = 2) -# ylim = get.cell.meta.data("ylim", sector.index = si, track.index = 2) -# circos.text(mean(xlim), mean(ylim), si, sector.index = si, track.index = 2, -# facing = "bending.inside", niceFacing = TRUE, col = "white", cex = 0.8) -# } -# } -# -# ### EUTROPHIC FOOD WEB -# chordDiagram(diets_mat_eutro, -# directional = 1, -# grid.col = model_color, -# direction.type = c("diffHeight"), -# link.arr.type = "triangle", -# diffHeight = uh(0.8, "mm"), -# annotationTrack = c("grid"), -# annotationTrackHeight = c(0.1, 0.01), -# transparency = 0.1, -# preAllocateTracks = 1) -# -# for(si in get.all.sector.index()) { -# if(get.cell.meta.data("xlim", sector.index = si)[2] > 5){ -# if (get.cell.meta.data("xlim", sector.index = si)[2] > 2) { -# prop <- seq(0,1,0.2)} else{prop <- seq(0,1,0.5)} -# circos.axis(h = "top", -# labels.cex = 0.5, -# sector.index = si, -# track.index = 2, -# labels.facing = "outside", -# major.at = (get.cell.meta.data("xlim", sector.index = si)[2] *prop), -# labels = (get.cell.meta.data("xlim", sector.index = si)[2] *prop)/(get.cell.meta.data("xlim", sector.index = si)[2])*100) -# -# xlim = get.cell.meta.data("xlim", sector.index = si, track.index = 2) -# ylim = get.cell.meta.data("ylim", sector.index = si, track.index = 2) -# circos.text(mean(xlim), mean(ylim), si, sector.index = si, track.index = 2, -# facing = "bending.inside", niceFacing = TRUE, col = "white", cex = 0.8) -# } -# } -# -# dev.print(pdf,'Figures/FoodWebs_Supp_ChordDiagram.pdf') -# circos.clear() -# diff --git a/Ancillary/TODO_FoodWebs_5_Supp+Stats.R b/Ancillary/TODO_FoodWebs_5_Supp+Stats.R deleted file mode 100644 index d0e5a42..0000000 --- a/Ancillary/TODO_FoodWebs_5_Supp+Stats.R +++ /dev/null @@ -1,61 +0,0 @@ -library(tidyverse) -library(patchwork) - - -source("FoodWebs_0a_Functions.R") -source("FoodWebs_0b_Initialise.R") - -# diets <- read_rds("/Users/jason/Dropbox/Multi-Zoo Size Spectrum Model/_LatestModel/20200212_Control_Full_UNSW/Output/diets_20200212_Control_Full_UNSW.RDS") -# res <- read_rds("/Users/jason/Dropbox/Multi-Zoo Size Spectrum Model/_LatestModel/20200212_Control_Full_UNSW/Output/res_20200212_Control_Full_UNSW.RDS") -# model <- read_rds("/Users/jason/Dropbox/Multi-Zoo Size Spectrum Model/_LatestModel/20200212_Control_Full_UNSW/Output/ModelParameters.RDS") -# enviro_data <- read_rds("/Users/jason/Dropbox/Multi-Zoo Size Spectrum Model/_LatestModel/20200212_Control_Full_UNSW/envirofull_20200209.RDS") - -#### TROPHIC LEVEL #### -# TrophLev <- as.data.frame(TrophicLevel_Calc(diets, TestGroups)) -# TrophLev$Chl <- enviro_data$chlo - -enviro200 <- read_rds("/Users/jason/Dropbox/Multi-Zoo Size Spectrum Model/_LatestModel/20200209_GroupExperiments_UNSW/NoLarvaceans/enviro200_20200209.RDS") - -diets_noLarv <- read_rds("/Users/jason/Dropbox/Multi-Zoo Size Spectrum Model/_LatestModel/20200209_GroupExperiments_UNSW/NoLarvaceans/Output/diets_NoLarvaceans.RDS") -TrophLev_noLarv <- as.data.frame(TrophicLevel_Calc(diets_noLarv, TestGroups)) -TrophLev_noLarv$Chl <- enviro200$chlo - -diets_noSalps <- read_rds("/Users/jason/Dropbox/Multi-Zoo Size Spectrum Model/_LatestModel/20200209_GroupExperiments_UNSW/NoSalps/Output/diets_NoSalps.RDS") -TrophLev_noSalps <- as.data.frame(TrophicLevel_Calc(diets_noSalps, TestGroups)) -TrophLev_noSalps$Chl <- enviro200$chlo - -diets_all <- read_rds("/Users/jason/Dropbox/Multi-Zoo Size Spectrum Model/_LatestModel/20200204_Control_200cells_UNSW/Output/diets_20200204_Control_200cells_UNSW.RDS") -TrophLev_all <- as.data.frame(TrophicLevel_Calc(diets_all, TestGroups)) -TrophLev_all$Chl <- enviro200$chlo - -## I need to do a delta plot of the TL change. Wait for my full model runs to finish. - -larv_diff = TrophLev_all$Fish_Small - TrophLev_noLarv$Fish_Small -salps_diff = TrophLev_all$Fish_Small - TrophLev_noSalps$Fish_Small -# fish_props = ((fish_bioms-control_fish_bioms)/control_fish_bioms)*100 - -TrophLev <- tibble(Chl = enviro200$chlo, diff_NoLarv = larv_diff, diff_NoSalps = salps_diff) - -gg_troph <- ggplot(data = TrophLev, aes(x = log10(Chl), y = diff_NoLarv)) + - geom_point(alpha = 1, size = 1, colour = TestGroups$Colour[TestGroups$species=="Larvaceans"], show.legend = FALSE) + - geom_smooth(colour = TestGroups$Colour[TestGroups$species=="Larvaceans"], fill = TestGroups$Colour[TestGroups$species=="Larvaceans"], method = "loess", span = 1, se = TRUE, show.legend = TRUE) + - geom_point(data = TrophLev, aes(x = log10(Chl), y = diff_NoSalps), - alpha = 1, size = 1, colour = TestGroups$Colour[TestGroups$species=="Salps"], show.legend = FALSE) + - geom_smooth(data = TrophLev, aes(x = log10(Chl), y = diff_NoSalps), - colour = TestGroups$Colour[TestGroups$species=="Salps"], fill = TestGroups$Colour[TestGroups$species=="Salps"], method = "loess", span = 1, se = TRUE, show.legend = TRUE) + - ylab("Trophic Level") + - scale_fill_manual(values = TestGroups$Colour[TestGroups$Feeding=="FilterFeeder"], - labels = TestGroups$CommonName[TestGroups$Feeding=="FilterFeeder"], - name = element_blank()) + - scale_x_continuous(limits = c(-1.3001, 0.5001), expand = c(0, 0)) + - theme_bw(base_size = 14) + - theme(plot.margin=grid::unit(c(0,0,0,0), "mm"), - legend.position="right") + - xlab("log10(Chlorophyll)") + - ylab("Planktivorous Fish Trophic Level") - -graphics.off() -x11(width = 10, height = 5) -gg_troph -ggsave(filename="Figures/FoodWebs_Supp_TrophicLevel_Gelatinous.png", dpi = 400) - diff --git a/Ancillary/TODO_ZooMSS_Plot_GlobalFeedGroups.R b/Ancillary/TODO_ZooMSS_Plot_GlobalFeedGroups.R deleted file mode 100644 index 3fead99..0000000 --- a/Ancillary/TODO_ZooMSS_Plot_GlobalFeedGroups.R +++ /dev/null @@ -1,144 +0,0 @@ -library(tidyverse) -library(patchwork) -library(raster) -library(rnaturalearth) -library(rnaturalearthdata) -library(sf) - -df_raster <- rasterFromXYZ(df) #Convert first two columns as lon-lat and third as value -df_poly <- rasterToPolygons(df_raster, fun=NULL, n=4, na.rm=TRUE, digits=12, dissolve=FALSE) # Convert to polyg - -biomass_brick <- readRDS("../GlobalZoopAbundModels/ModelOutput/GlobalLayers/Num_Brick_Biomass.rds") -BB <- dropLayer(biomass_brick, c("Fish_Small", "Fish_Med", "Fish_Large", "SST", "Chl")) - -BB_sum <- calc(BB, fun = sum) # Sum the data for the proportion -names(BB_sum) <- "ZoopSum" - -BBProp <- BB/BB_sum # Calculate Proportion -names(BBProp) <- names(BB) # Copy layer names across - -BBPropPoly <- rasterToPolygons(BBProp, fun=NULL, n=4, na.rm=TRUE, digits=12, dissolve=FALSE) # Convert to polygon which is better for plotting -BBProp_sf <- st_as_sf(BBPropPoly, crs = 4326) # Convert to sf - -st_crs(BBProp_sf) <- 4326 # Set base projection -BBProp_sf_moll <- st_transform(BBProp_sf, crs = 54009) # Alter the CRS to mollweide -BBProp_sf_moll <- BBProp_sf_moll %>% - dplyr::select(c("Larvaceans", "CarnCopepods", - "Salps", "Chaetognaths", - "OmniCopepods", "Jellyfish", - "Euphausiids", "geometry" )) - -BB_Group_sum <- BB_sum -BB_Group_sum <- addLayer(BB_Group_sum, BB$Larvaceans + BB$Salps) -BB_Group_sum <- addLayer(BB_Group_sum, BB$CarnCopepods + BB$Jellyfish + BB$Chaetognaths) -BB_Group_sum <- addLayer(BB_Group_sum, BB$OmniCopepods + BB$Euphausiids) -names(BB_Group_sum) <- c("ZoopSum", "FilterFeeders", "Carnivores", "Omnivores") -BB_GroupProp <- BB_Group_sum/BB_Group_sum$ZoopSum # Calculate Proportion -names(BB_GroupProp) <- names(BB_Group_sum) # Copy layer names across - -BB_GroupPropPoly <- rasterToPolygons(BB_GroupProp, fun=NULL, n=4, na.rm=TRUE, digits=12, dissolve=FALSE) # Convert to polygon which is better for plotting -BB_GroupProp_sf <- st_as_sf(BB_GroupPropPoly, crs = 4326) # Convert to sf - -st_crs(BB_GroupProp_sf) <- 4326 # Set base projection -BB_GroupProp_sf_moll <- st_transform(BB_GroupProp_sf, crs = 54009) # Alter the CRS to mollweide - -rm(biomass_brick, BB, BB_sum, BBProp, BBPropPoly, BBProp_sf) - -world <- ne_countries(scale = "medium", returnclass = "sf") -world_sf <- st_transform(world, crs = 54009) # Convert to Mollweide - -theme_opts <- list(theme(panel.grid.minor = element_blank(), - panel.grid.major = element_line(colour = "grey50", size = 0.2), - panel.background = element_blank(), - panel.border = element_blank(), - plot.background = element_rect(fill = NA), - plot.title = element_text(hjust = 0.5), - plot.margin = unit(c(0,0,0,0), "mm"), - axis.line = element_blank(), - axis.text.x = element_blank(), - axis.text.y = element_blank(), - axis.ticks = element_blank(), - axis.title.x = element_blank(), - axis.title.y = element_blank(), - # legend.title = element_text(size = 6), - # legend.text = element_text(size = 6), - legend.position = "right", - # legend.direction = "horizontal", - # legend.background = element_rect(fill = NA), - legend.key.height = unit(9, "mm"), - legend.key.width = unit(4, "mm"), - # legend.position = c(0.5, -0.05), -)) - -colr <- list() -colr[[1]] <- c("#eff3ff", "#c6dbef", "#9ecae1", "#6baed6", "#3182bd", "#08519c") # Blues -colr[[2]] <- c("#fee5d9", "#fcbba1", "#fc9272", "#fb6a4a", "#de2d26", "#a50f15") # Reds -colr[[3]] <- c("#f5f5f5", "#f6e8c3", "#dfc27d", "#bf812d", "#8c510a", "#543005") # Browns -#c("#edf8fb", "#ccece6", "#99d8c9", "#66c2a4", "#2ca25f", "#006d2c") # Greens - -myplots <- list() -for(j in names(BBProp_sf_moll)){ - if(j != "geometry"){ - myplots[[j]] <- ggplot() + - geom_sf(data = BBProp_sf_moll, aes_string(fill = j), color = NA) + - geom_sf(data = world_sf, size = 0.05, fill = "grey20") + - scale_fill_gradient2(limits = c(as.numeric(quantile(as.vector(dplyr::select(as_tibble(BBProp_sf_moll), !! j)[[1]]), 0.05)), - as.numeric(quantile(as.vector(dplyr::select(as_tibble(BBProp_sf_moll), !! j)[[1]]), 0.95))), - low = "white", - high = TestGroups$Colour[TestGroups$species==j], - space = "Lab", - na.value = "grey50", - aesthetics = "fill", - oob = scales::squish, - guide = guide_colourbar(title = "Proportion of\nMesozooplankton", - title.position = "right", - title.hjust = 0.5, - title.theme = element_text(angle = 270, size = 10))) + - theme_opts + - scale_alpha(range = c(-0, 0.5)) + - (if(j=="OmniCopepods"){ggtitle("Omnivorous Copepods")} - else{if(j=="CarnCopepods"){ggtitle("Carnivorous Copepods")} - else{if(j=="Euphausiids"){ggtitle("Krill")} - ggtitle(j)}}) - } -} - -x11(height = 10, width = 10) -wrap_plots(myplots) + plot_layout(ncol = 2) + plot_annotation(tag_levels = "A", tag_suffix = ")") -ggsave("Figures/FoodWebs_Supp_BiomassProp.png", dpi = 500) - -# Now plot by feeding group - -BB_GroupProp_sf_moll <- BB_GroupProp_sf_moll %>% - dplyr::select(Omnivores, Carnivores, FilterFeeders, everything()) # Reorder - -jj <- 0 - -myplots <- list() -for(j in names(BB_GroupProp_sf_moll)){ - if(j != "geometry" & j != "ZoopSum"){ - jj <- jj + 1 - myplots[[j]] <- ggplot() + - geom_sf(data = BB_GroupProp_sf_moll, aes_string(fill = j), color = NA) + - geom_sf(data = world_sf, size = 0.05, fill = "grey20") + - scale_fill_gradientn(name = "Proportion", - colours = colr[[jj]], # BuGn from RColorBRewer - limits = c(as.numeric(quantile(as.vector(dplyr::select(as_tibble(BB_GroupProp_sf_moll), !! j)[[1]]), 0.05)), - as.numeric(quantile(as.vector(dplyr::select(as_tibble(BB_GroupProp_sf_moll), !! j)[[1]]), 0.95)) - ), - oob = scales::squish, - guide = guide_colourbar(title = "Proportion of\nMesozooplankton", - title.position = "right", - title.hjust = 0.5, - title.theme = element_text(angle = 270, size = 10))) + - theme_opts + - scale_alpha(range = c(-0, 0.5)) + - (if(j=="FilterFeeders"){ggtitle("Filter Feeders")} else{ggtitle(j)}) - } -} - -x11(height = 7, width = 5) -wrap_plots(myplots) + plot_layout(ncol = 1) + plot_annotation(tag_levels = "A", tag_suffix = ")") -ggsave("Figures/FoodWebs_2_BiomassProp_ByGroup.png", dpi = 500) - - diff --git a/Ancillary/ZooMSS_Plotting.R b/Ancillary/ZooMSS_Plotting.R deleted file mode 100644 index d6453c3..0000000 --- a/Ancillary/ZooMSS_Plotting.R +++ /dev/null @@ -1,101 +0,0 @@ -library(tidyverse) - -res <- readRDS("Output/res_Control_20200131.RDS") -Groups <- read_csv("TestGroups.csv") - -enviro_data <- readRDS("enviro200.RDS") -## ACTUAL BIOMASS -biom_act <- function(N, groups, cut_point1, cut_point2, enviro_data, en){ - - w <- 10^(seq(from = -10.7, to = 7, 0.1)) # Size bins of whole model - - zoo_groups = which(is.na(groups$prop) == FALSE)[-c(1,2)] # Which rows are zooplankton - num_zoo = length(zoo_groups) - - abund_mat <- matrix(0, nrow = dim(enviro_data)[1], ncol = num_zoo) - - - for(i in 1:dim(enviro_data)[1]){ - N_ave = N[[i]] - B_ave = N_ave*matrix(w, nrow = dim(N_ave)[1], ncol = dim(N_ave)[2], byrow = TRUE) - weight_cut = which(round(log10(w),2) >= cut_point1 & round(log10(w),2) <= cut_point2) - zoo_abunds = rowSums(B_ave[zoo_groups, weight_cut]) - zoo_props = zoo_abunds - abund_mat[i,] <- zoo_props - } - - if(en == "chlo"){ - par(mfrow = c(4,2)) - for( i in 1:num_zoo){ - plot(log10(enviro_data$chlo), abund_mat[,i], main = groups$species[i+2], xlab = "log10(Chlo)", ylab = expression(paste("Biomass (g m"^-3, ")"))) - } - } - - if(en == "sst"){ - par(mfrow = c(4,2)) - for( i in 1:num_zoo){ - plot((enviro_data$sst), abund_mat[,i], main = groups$species[i+2], xlab = "SST", ylab = expression(paste("Biomass (# m"^-3, ")"))) - } - } - par(mfrow = c(1,1)) - - -} - -####### PROPORTIONS OF BIOMASS -biom_props <- function(N, groups, cut_point1, cut_point2, enviro_data, en){ - - w <- 10^(seq(from = -10.7, to = 7, 0.1)) # Size bins of whole model - zoo_groups = which(is.na(groups$prop) == FALSE)[-c(1,2)] # Which rows are zooplankton - num_zoo = length(zoo_groups) - - abund_mat <- matrix(0, nrow = dim(enviro_data)[1], ncol = num_zoo) - - - for(i in 1:dim(enviro_data)[1]){ - N_ave = N[[i]] - B_ave = N_ave*matrix(w, nrow = dim(N_ave)[1], ncol = dim(N_ave)[2], byrow = TRUE) - weight_cut = which(round(log10(w),2) >= cut_point1 & round(log10(w),2) <= cut_point2) - zoo_abunds = rowSums(B_ave[zoo_groups, weight_cut]) - zoo_props = zoo_abunds/sum(zoo_abunds) - abund_mat[i,] <- zoo_props - } - - if(en == "chlo"){ - par(mfrow = c(4,2)) - for( i in 1:num_zoo){ - plot(log10(enviro_data$chlo), abund_mat[,i], main = groups$species[i+2], xlab = "log10(Chlo)", ylab = "Biom Prop") - } - } - - if(en == "sst"){ - par(mfrow = c(4,2)) - for( i in 1:num_zoo){ - plot((enviro_data$sst), abund_mat[,i], main = groups$species[i+2], xlab = "SST", ylab = "Biom Prop") - } - } - par(mfrow = c(1,1)) - - -} - - -filename = "BiomProps_Chlo.pdf" -pdf(filename, width = 5.8, height = 8.3) -biom_props(res, groups = Groups, -10.7, 3, enviro_data, en = "chlo") -dev.off() - -filename = "BiomProps_SST.pdf" -pdf(filename, width = 5.8, height = 8.3) -biom_props(res, groups = Groups, -10.7, 3, enviro_data, en = "sst") -dev.off() - -filename = "BiomAct_Chlo.pdf" -pdf(filename, width = 5.8, height = 8.3) -biom_act(res, groups = Groups, -10.7, 3, enviro_data, en = "chlo") -dev.off() - -filename = "BiomAct_SST.pdf" -pdf(filename, width = 5.8, height = 8.3) -biom_act(res, groups = Groups, -10.7, 3, enviro_data, en = "sst") -dev.off() diff --git a/Ancillary/ZooplanktonDatabase_2_Devel_AddEnviro2csv.R b/Ancillary/ZooplanktonDatabase_2_Devel_AddEnviro2csv.R deleted file mode 100644 index 774b753..0000000 --- a/Ancillary/ZooplanktonDatabase_2_Devel_AddEnviro2csv.R +++ /dev/null @@ -1,86 +0,0 @@ -library(tidyverse) -library(ncdf4) -library(yaImpute) -library(lubridate) - -EnviroDir <- "Data/EnvironmentalData" - -########### IMPORT BATHYMETRY ########### -bathy_files <- "GEBCO_BATHY_2002-01-01_rgb_360x180.csv" -bathy_raw <- read.csv(paste0(EnviroDir,"/",bathy_files), header = FALSE) -bathy_vector <- as.vector(t(as.matrix(bathy_raw))) # Convert to vector - -# create a grid of lat/lon, add headers, and convert to data frame -bathy_matrix = matrix(NA, nrow = length(bathy_vector), ncol = 3) -bathy_matrix[,c(1,2)] = as.matrix(expand.grid("Long" = seq(-179.5, 179.5, 1), "Lat" = seq(89.5, -89.5, -1))) -bathy_matrix[,3] <- bathy_vector -colnames(bathy_matrix) <- c("Long", "Lat", "BATHY") -bathy_matrix <- as.data.frame(bathy_matrix) -bathy_matrix[c(bathy_matrix$BATHY > 0), "BATHY"] <- NA -bathy_matrix <- bathy_matrix[!is.na(bathy_matrix$BATHY),] # Remove all the land so the nearest neighbbour below always finds a value -########### END BATHYMETRY ########### - -########### Import CHLOROPHYLL AND SST ########### -SST_files <- list.files(path = EnviroDir, pattern = "MC_SST", recursive = TRUE, full.names = TRUE) -Chl_files <- list.files(path = EnviroDir, pattern = "MC_CHL", recursive = TRUE, full.names = TRUE) - -# Rearrange to get January first up. -SST_files <- SST_files[c(7:12, 1:6)] -Chl_files <- Chl_files[c(7:12, 1:6)] - -# IMPORT NETCDF AND EXTRACT GEOGRAPHIC REFERENCES -nc.SST <- nc_open(SST_files[1]) - -SST_lat <- ncvar_get(nc.SST, "lat") -SST_lon <- ncvar_get(nc.SST, "lon") -SST_var <- t(ncvar_get(nc.SST, "sst4")) - -# Create a matrix of data -SST_store <- Chl_store <- matrix(NA, nrow = length(SST_lat)*length(SST_lon), ncol = 14) -SST_store[,c(1,2)] <- Chl_store[,c(1,2)] <- as.matrix(expand.grid(lon = SST_lon, lat = SST_lat)) - -### OPEN NETCDFS -SST_nc_all <- lapply(SST_files, nc_open) -Chl_nc_all <- lapply(Chl_files, nc_open) - -## EXTRACT SST AND CHLOROPHYLL, THESE SST AND CHLO CLIMATOLOGIES ARE 9KM MODIS AQUA -SST_nc_vall <- lapply(SST_nc_all, ncvar_get, varid = "sst4") -Chl_nc_vall <- lapply(Chl_nc_all, ncvar_get, varid = "chlor_a") - - -## PUT MONTHLY SST AND CHLO IN RESPECTIVE MATRICES, LABEL COLUMNS AND CONVERT TO DATA FRAME, -for(i in 1:12){ - SST_store[,c(i+2)] <- as.vector((unlist(SST_nc_vall[[i]]))) - Chl_store[,c(i+2)] <- as.vector((unlist(Chl_nc_vall[[i]]))) -} -colnames(SST_store) <- colnames(Chl_store) <- c("Long","Lat","January", "February", "March", "April", "May", - "June", "July", "August", "September", "October", "November", "December") -SST_store <- as.data.frame(SST_store) -Chl_store <- as.data.frame(Chl_store) -########### End CHLOROPHYLL AND SST ########### - - -########### IMPORT ZOOPLANKTON DATA ########### -dat <- readRDS("LatestDatabaseOuput_Final.rds") -dat$Day[is.na(dat$Day)] <- 15 # Make all missing days to the middle of the month -dat <- dat[!is.na(dat$Month),] # Remove rows with no complete date - -dat$Month2 <- month(dat$Month,label = TRUE, abbr = FALSE) - -dat$SST = NA -dat$Chl = NA -dat$Bathy = NA -nvsc <- ann(as.matrix(SST_store[,c("Long", "Lat")]), - as.matrix(dat[,c("Longitude", "Latitude")]), - k = 1, verbose = FALSE)$knnIndexDist[,1] -nvb <- ann(as.matrix(bathy_matrix[,c("Long", "Lat")]), as.matrix(dat[,c("Longitude", "Latitude")]), k = 1, verbose = FALSE)$knnIndexDist[,1] - -pb <- txtProgressBar(min = 0, max = dim(dat)[1], style = 3) -for(j in 1:dim(dat)[1]){ - setTxtProgressBar(pb, j) - dat$SST[j] <- SST_store[nvsc[j], dat$Month2[j]] - dat$Chl[j] <- Chl_store[nvsc[j], dat$Month2[j]] - dat$Bathy[j] <- bathy_matrix[nvb[j],"BATHY"] -} - -saveRDS(dat, file = "LatestDatabaseOuput_Final_Enviro.rds") diff --git a/Ancillary/fZooMSS_CheckIdent.R b/Ancillary/fZooMSS_CheckIdent.R deleted file mode 100644 index ba3f5d9..0000000 --- a/Ancillary/fZooMSS_CheckIdent.R +++ /dev/null @@ -1,26 +0,0 @@ -# This function checks the model output against a previous run to see where any differences are. - -fZooMSS_CheckIdent <- function(out,out_old){ - nm <- names(out_old$model$param) - for(a in 1:length(nm)){ - b <- eval(parse(text = paste0("identical(out_old$model$param$",nm[a],",out$model$param$",nm[a],")"))) - if (b == FALSE & - eval(parse(text = paste0("!is.null(out_old$model$param$",nm[a],")"))) & - eval(parse(text = paste0("!is.null(out$model$param$",nm[a],")"))) - ){ - print(paste0("Param ",nm[a]," is different.")) - }#else{print(paste0("Param ",nm[a]," is equal."))} - } - - nm2 <- names(out_old$model) - for(a in 1:length(nm2)){ - b <- eval(parse(text = paste0("identical(out_old$model$",nm2[a],",out$model$",nm2[a],")"))) - if (b == FALSE & - eval(parse(text = paste0("!is.null(out_old$model$",nm2[a],")"))) & - eval(parse(text = paste0("!is.null(out$model$",nm2[a],")"))) - ){ - print(paste0("Model ",nm2[a]," is different.")) - }#else{print(paste0("Model Setup ",nm2[a]," is equal."))} - } - -} \ No newline at end of file diff --git a/Ancillary/fZooMSS_ReduceFullRunto200Cells.R b/Ancillary/fZooMSS_ReduceFullRunto200Cells.R deleted file mode 100644 index 5812600..0000000 --- a/Ancillary/fZooMSS_ReduceFullRunto200Cells.R +++ /dev/null @@ -1,17 +0,0 @@ -fZooMSS_ReduceFullRunto200Cells = function(){ - library(tidyverse) - - envirofull <- read_rds("/Users/jason/Dropbox/Multi-Zoo Size Spectrum Model/_LatestModel/envirofull_20200317.RDS") - enviro200 <- read_rds("/Users/jason/Dropbox/Multi-Zoo Size Spectrum Model/_LatestModel/enviro200_20200317.RDS") - - fi <- NA - for (f in 1:nrow(enviro200)){ - fii <- which(envirofull$chlo==enviro200$chlo[f] & envirofull$sst==enviro200$sst[f]) - if(length(fii)>1){ - print(fii) - } - fi[f] <- fii - } - - return(fi) -} \ No newline at end of file diff --git a/DESCRIPTION b/DESCRIPTION new file mode 100644 index 0000000..0ad0b2e --- /dev/null +++ b/DESCRIPTION @@ -0,0 +1,70 @@ +Package: zoomss +Title: Zooplankton Model of Size Spectra +Version: 0.1.0 +Authors@R: + c( + person( + given = "Jason D.", + family = "Everett", + role = c("aut", "cre"), + email = "DrJasonEverett@gmail.com", + comment = c(ORCID = "0000-0002-6681-8054") + ), + person( + given = "Ryan F.", + family = "Heneghan", + role = c("aut"), + email = "r.heneghan@griffith.edu.au", + comment = c(ORCID = "0000-0001-7626-1248") + ), + person( + given = "Kieran", + family = "Murphy", + role = c("aut"), + email = "kieran.murphy@uq.edu.au", + comment = c(ORCID = "0000-0002-9697-2458") + ), + person( + given = "Anthony J.", + family = "Richardson", + role = c("aut"), + email = "a.richardson1@uq.edu.au", + comment = c(ORCID = "0000-0002-9289-7366") + )) +Description: A functional size-spectrum model of the marine ecosystem that resolves + phytoplankton, nine zooplankton functional groups (heterotrophic flagellates and + ciliates, omnivorous and carnivorous copepods, larvaceans, euphausiids, salps, + chaetognaths and jellyfish) and three size-based fish groups. The model supports + both constant and time-varying environmental conditions, enabling studies of + seasonal cycles, climate change scenarios, and ecosystem responses to environmental + variability. ZooMSS uses the functional size-spectrum framework to resolve + body size ranges, size-based feeding characteristics and carbon content of marine + functional groups. +License: MIT + file LICENSE +URL: https://github.com/MathMarEcol/zoomss +BugReports: https://github.com/MathMarEcol/zoomss/issues +Encoding: UTF-8 +Roxygen: list(markdown = TRUE) +RoxygenNote: 7.3.2 +Suggests: + knitr, + rmarkdown, + testthat (>= 3.0.0) +VignetteBuilder: knitr +Imports: + assertthat, + dplyr, + ggplot2, + magrittr, + patchwork, + progress, + readr, + rlang, + stringr, + tibble, + tidyr, + tidyselect +Depends: + R (>= 3.5) +LazyData: true +Config/testthat/edition: 3 diff --git a/EnviroData_oneDeg_20210728.rds b/EnviroData_oneDeg_20210728.rds deleted file mode 100644 index c51ea88..0000000 Binary files a/EnviroData_oneDeg_20210728.rds and /dev/null differ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a4fb109 --- /dev/null +++ b/LICENSE @@ -0,0 +1,2 @@ +YEAR: 2025 +COPYRIGHT HOLDER: zoomss authors diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..5d80687 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2025 zoomss authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/NAMESPACE b/NAMESPACE new file mode 100644 index 0000000..e2a8914 --- /dev/null +++ b/NAMESPACE @@ -0,0 +1,24 @@ +# Generated by roxygen2: do not edit by hand + +export("%>%") +export(averageTimeSeries) +export(calculatePhytoParam) +export(createEnviroData) +export(createInputParams) +export(extractPPMR) +export(extractSizeRange) +export(extractTrophicLevels) +export(getBiomass) +export(getGroups) +export(plotEnvironment) +export(plotPPMR) +export(plotSizeSpectra) +export(plotTimeSeries) +export(reduceAll) +export(reduceSize) +export(reduceSpecies) +export(validateGroups) +export(zoomss_model) +importFrom(magrittr,"%>%") +importFrom(rlang,":=") +importFrom(rlang,.data) diff --git a/R/data.R b/R/data.R new file mode 100644 index 0000000..aec72b3 --- /dev/null +++ b/R/data.R @@ -0,0 +1,56 @@ +#' ZooMSS Functional Groups Data +#' +#' @title Default functional groups for the ZooMSS model +#' @description A dataset containing the biological parameters for different +#' functional groups used in the ZooMSS size-structured marine ecosystem model. +#' These represent various taxa from flagellates to large fish, each defined +#' by their feeding behavior, size ranges, and physiological parameters. +#' +#' @format A data frame with 12 rows (functional groups) and 19 columns: +#' \describe{ +#' \item{Species}{Character. Name of the functional group/taxa} +#' \item{Type}{Character. Broad category (Zooplankton or Fish)} +#' \item{FeedType}{Character. Feeding strategy (Heterotroph, FilterFeeder, Omnivore, Carnivore)} +#' \item{Prop}{Numeric. Initial proportion of total biomass} +#' \item{W0}{Numeric. Log10 minimum body weight (g) for the group} +#' \item{Wmax}{Numeric. Log10 maximum body weight (g) for the group} +#' \item{Wmat}{Numeric. Log10 maturation body weight (g)} +#' \item{SearchCoef}{Numeric. Search coefficient for predation interactions} +#' \item{SearchExp}{Numeric. Search exponent for predation scaling} +#' \item{PPMRscale}{Numeric. Predator-prey mass ratio scaling parameter} +#' \item{PPMR}{Numeric. Predator-prey mass ratio (for fish groups)} +#' \item{FeedWidth}{Numeric. Feeding kernel width parameter} +#' \item{GrossGEscale}{Numeric. Gross growth efficiency scaling} +#' \item{Carbon}{Numeric. Carbon content proportion} +#' \item{Repro}{Numeric. Reproduction parameter} +#' \item{Fmort}{Numeric. Fishing mortality rate} +#' \item{Fmort_W0}{Numeric. Log10 minimum weight for fishing mortality} +#' \item{Fmort_Wmax}{Numeric. Log10 maximum weight for fishing mortality} +#' \item{PlotColour}{Character. Color code for plotting the functional group} +#' } +#' +#' @details The GroupInputs dataset defines 12 functional groups spanning from +#' small microzooplankton (flagellates, ciliates) through various mesozooplankton +#' groups (copepods, euphausiids, chaetognaths) to gelatinous zooplankton (salps, jellyfish) +#' and three fish size classes (small, medium, large). Each group is characterized by: +#' +#' - **Size ranges**: W0 to Wmax define the body size spectrum +#' - **Feeding behavior**: Different strategies for resource acquisition +#' - **Interaction parameters**: Search rates and predator-prey relationships +#' - **Physiological rates**: Growth efficiency and carbon content +#' +#' These parameters are based on marine ecological literature and represent +#' typical values for temperate marine ecosystems. +#' +#' @source Marine ecological literature and ZooMSS model development +#' @family ZooMSS-data +#' @examples +#' data(GroupInputs) +#' head(GroupInputs) +#' +#' # View size ranges across groups +#' plot(GroupInputs$W0, GroupInputs$Wmax, +#' col = GroupInputs$PlotColour, +#' xlab = "Log10 Min Weight", ylab = "Log10 Max Weight") +#' text(GroupInputs$W0, GroupInputs$Wmax, GroupInputs$Species, pos = 3, cex = 0.7) +"GroupInputs" diff --git a/R/utils.R b/R/utils.R new file mode 100644 index 0000000..3333def --- /dev/null +++ b/R/utils.R @@ -0,0 +1,680 @@ +#' Sum ZooMSS Output Across Size Bins +#' +#' @title Aggregate ZooMSS abundances across all size classes +#' @description Sums abundance values across all size classes for each functional group, +#' providing total abundance per group. +#' @details This function collapses the size dimension of ZooMSS output by summing +#' across all size classes. Useful for analyzing total abundance patterns without +#' size structure detail. +#' @param x 3D array outptut from ZooMSS model +#' @param method Character string specifying aggregation method: "sum" (default) or "mean". +#' @return List of vectors with total abundance per functional group +#' @export +#' +#' @examples +#' \dontrun{ +#' # After running ZooMSS model +#' results <- zoomss_model(input_params, Groups) +#' total_abundances <- reduceSize(results$abundances) +#' } +#' +reduceSize = function(x, method = "sum") { + + assertthat::assert_that(is.array(x)) + assertthat::assert_that(method %in% c("sum", "mean")) + + apply(x, c(1, 2), match.fun(method)) # Sum or mean ZooMSS output across the size bins +} + + +#' Aggregate ZooMSS abundances across all species +#' +#' @title Aggregate ZooMSS abundances across all species +#' @description Aggregates abundance values across all species bins for each functional group and size class using the specified method. +#' @details This function collapses the species dimension by applying the specified method (sum or mean) across all species bins. +#' @param x 3D array outptut from ZooMSS model +#' @param method Character string specifying aggregation method: "sum" (default) or "mean". +#' @return Array with species dimension reduced using the specified method +#' @export +reduceSpecies = function(x, method = "sum") { + assertthat::assert_that(is.array(x)) + assertthat::assert_that(method %in% c("sum", "mean")) + + apply(x, c(1, 3), match.fun(method)) +} + + +#' Aggregate abundances across all groups and size classes +#' +#' @title Aggregate abundances across all groups and size classes +#' @description Calculates total abundance across all functional groups and size classes using the specified method. +#' @details This function provides the most aggregated view of ZooMSS output by applying the method across both functional groups and size classes. +#' @param x 3D array outptut from ZooMSS model +#' @param method Character string specifying aggregation method: "sum" (default) or "mean". +#' @return Vector of total abundance values (one per spatial cell) +#' @export +reduceAll = function(x, method = "sum") { + assertthat::assert_that(is.array(x)) + assertthat::assert_that(method %in% c("sum", "mean")) + + apply(x, 1, match.fun(method)) +} + +#' Convert Abundance to Biomass +#' +#' @title Convert ZooMSS abundance matrices to biomass by multiplying by body weights +#' @description Converts abundance data to wet weight biomass by multiplying abundances +#' by the corresponding body weights for each size class. Optionally converts to carbon biomass. +#' @details This function transforms abundance matrices to biomass by applying the +#' weight vector across size classes. Essential for analyses requiring biomass +#' units rather than abundance counts. Works with 3D arrays (time, groups, size_classes). +#' Can convert to either wet weight or carbon biomass units. +#' +#' @param mdl ZooMSS model object containing abundance array (N) and weight vector (param$w) +#' @param units Character string specifying biomass units: "ww" for wet weight (default) or "carbon" for carbon biomass +#' +#' @return 3D array of biomass values with same dimensions as N. Units depend on the units parameter: +#' \itemize{ +#' \item "ww": grams wet weight +#' \item "carbon": grams carbon +#' } +#' @export +#' +#' @examples +#' \dontrun{ +#' # Run ZooMSS model +#' results <- zoomss_model(input_params, Groups) +#' +#' # Convert abundances to wet weight biomass +#' biomass_ww <- getBiomass(results, units = "ww") +#' +#' # Convert abundances to carbon biomass +#' biomass_carbon <- getBiomass(results, units = "carbon") +#' } +#' +getBiomass <- function(mdl, units = "ww") { + + # Validate units parameter + if (!units %in% c("ww", "carbon")) { + stop("units must be either 'ww' (wet weight) or 'carbon'") + } + + # Check that N exists in the model + if (!"abundance" %in% names(mdl)) { + stop("Abundance array 'N' not found in model output") + } + + # Check that weights exist in model parameters + if (is.null(mdl$param$w)) { + stop("Weight vector 'w' not found in mdl$param$w") + } + + # Get abundance array and weights + N <- mdl$abundance + w <- mdl$param$w + + # Check dimensions match + if (dim(N)[3] != length(w)) { + stop("Size dimension of abundance (", dim(N)[3], ") does not match length of weight vector (", length(w), ")") + } + + # Convert abundance to wet weight biomass by multiplying by weights across size dimension (3rd dimension) + Biomass <- sweep(N, 3, w, '*') # Multiply each size class by its corresponding weight + + # Convert to carbon biomass if requested + if (units == "carbon") { + # Check that carbon content factors exist + if (is.null(mdl$param$Groups$Carbon)) { + stop("Carbon content factors 'Groups$Carbon' not found in mdl$param$Groups$Carbon") + } + + # Check dimensions match + if (dim(N)[2] != length(mdl$param$Groups$Carbon)) { + stop("Group dimension of N (", dim(N)[2], ") does not match length of carbon vector (", length(mdl$param$Groups$Carbon), ")") + } + + # Convert to carbon biomass by multiplying by carbon content across group dimension (2nd dimension) + Biomass <- sweep(Biomass, 2, mdl$param$Groups$Carbon, '*') + } + + return(Biomass) +} + + +#' Extract Size Range from ZooMSS Output +#' +#' @title Extract specific size class range from model variable +#' @description Subsets ZooMSS model output to include only specified size range, +#' useful for focusing analysis on particular size ranges. +#' @details This function extracts a subset of size classes from the specified +#' ZooMSS model variable. Useful for analyzing specific size ranges +#' (e.g., microzooplankton, mesozooplankton) or excluding boundary effects +#' from model analysis. The function converts log10 size values to size class +#' indices automatically. +#' +#' @param mdl ZooMSS model results object containing model parameters and output arrays +#' @param var Character string specifying which variable to extract (e.g., "N", "Z", "Growth") +#' @param min_size Minimum size (log10 grams) to extract +#' @param max_size Maximum size (log10 grams) to extract +#' +#' @return Array with same dimensions as original variable but subsetted size range +#' @export +#' +#' @examples +#' \dontrun{ +#' # Run ZooMSS model +#' results <- zoomss_model(input_params, Groups) +#' +#' # Extract mesozooplankton size range from abundance data +#' meso_abundance <- extractSizeRange(results, "N", min_size = -8, max_size = -5) +#' +#' # Extract microzooplankton size range from growth data +#' micro_growth <- extractSizeRange(results, "Growth", min_size = -10, max_size = -8) +#' } +#' +extractSizeRange = function(mdl, var, min_size, max_size) { + + # Extract the specified variable from model output + if (!var %in% names(mdl)) { + stop("Variable '", var, "' not found in model output. Available variables: ", + paste(names(mdl), collapse = ", ")) + } + x <- mdl[[var]] + + # Get size grid from model parameters + if (is.null(mdl$param$w_log10)) { + stop("Cannot find size grid (w_log10) in mdl$param$w_log10") + } + w_log10 <- mdl$param$w_log10 + + # Find indices corresponding to size range + min_idx <- which.min(abs(w_log10 - min_size)) + max_idx <- which.min(abs(w_log10 - max_size)) + + # Ensure min_idx <= max_idx + if (min_idx > max_idx) { + temp <- min_idx + min_idx <- max_idx + max_idx <- temp + } + + # Validate indices are within bounds + n_size_classes <- length(w_log10) + min_idx <- max(1, min_idx) + max_idx <- min(n_size_classes, max_idx) + + # Provide feedback about the extraction + actual_min_size <- w_log10[min_idx] + actual_max_size <- w_log10[max_idx] + n_extracted <- max_idx - min_idx + 1 + cat("Extracting size range", actual_min_size, "to", actual_max_size, + "log10(g) (", n_extracted, "size classes) from variable", var, "\n") + + # Extract the size range from the variable + # Handle different array dimensions + if (length(dim(x)) == 2) { + # 2D array: (groups, size_classes) + out <- x[, min_idx:max_idx, drop = FALSE] + } else if (length(dim(x)) == 3) { + # 3D array: (time, groups, size_classes) + out <- x[, , min_idx:max_idx, drop = FALSE] + } else { + stop("Variable '", var, "' must be a 2D or 3D array") + } + + return(out) +} + + +#' Calculate Average Output from Model Time Series +#' +#' @title Calculate mean of final portion of ZooMSS time series +#' @description Calculates the mean of the final n years of a time series +#' to obtain equilibrium values after model spin-up period. +#' @details This function removes the initial transient period from time series data +#' and calculates the mean of the final n years, providing representative +#' steady-state values. Essential for obtaining equilibrium abundances, growth rates, +#' and other model outputs after the model has reached dynamic equilibrium. +#' +#' @param mdl ZooMSS model results object containing model parameters and output arrays +#' @param var Character string specifying which variable to extract and average (e.g., "N", "Growth", "Mort") +#' @param n_years Number of years from the end of the time series to average (default: 10) +#' +#' @return 2D array with averaged values (groups x size_classes) +#' @export +#' +#' @examples +#' \dontrun{ +#' # Run ZooMSS model +#' results <- zoomss_model(input_params, Groups) +#' +#' # Average final 3 years of abundance data +#' avg_abundance <- averageTimeSeries(results, "N", n_years = 3) +#' +#' # Average final 10 years of growth data (default) +#' avg_growth <- averageTimeSeries(results, "gg") +#' } +#' +averageTimeSeries = function(mdl, var, n_years = 10){ + + # Extract dt from model parameters + if (is.null(mdl$param$dt)) { + stop("Cannot find dt (time step) in mdl$param$dt") + } + dt <- mdl$param$dt + + # Extract isave parameter (how often results were saved) + if (is.null(mdl$param$isave)) { + stop("Cannot find isave (save interval) in mdl$param$isave") + } + isave <- mdl$param$isave + + # Extract the specified variable from model output + if (!var %in% names(mdl)) { + stop("Variable '", var, "' not found in model output. Available variables: ", + "N", "Z", "gg") + } + x <- mdl[[var]] + + # Check that we have a 3D array + if (length(dim(x)) != 3) { + stop("Variable '", var, "' must be a 3D array with dimensions (time, groups, size_classes)") + } + + # Calculate number of saved time steps corresponding to n_years + # Each saved time step represents isave * dt years + dt_saved <- isave * dt # Years represented by each saved time step + n_time_steps <- round(n_years / dt_saved) + + # Get total number of time steps in the array + total_time_steps <- dim(x)[1] + + # Ensure we don't try to average more time steps than available + n_time_steps <- min(n_time_steps, total_time_steps) + + # Calculate start index for averaging (from end) + start_idx <- max(1, total_time_steps - n_time_steps + 1) + + # Provide helpful feedback about what's being averaged + actual_years <- n_time_steps * dt_saved + cat("Averaging final ", actual_years, " years (", n_time_steps, " saved time steps with isave = ", isave, ") of ", + var, " from ", total_time_steps, " total saved time steps.\n", sep = "") + + # Calculate the average + ave_x <- colMeans(x[start_idx:total_time_steps,,], dims = 1) + return(ave_x) +} + +#' Remove Tibble Attributes +#' +#' @title Convert tibble to data frame for efficiency +#' @description Removes tibble attributes and converts to a plain data frame +#' for improved speed and memory efficiency in computational workflows. +#' @details This utility function strips tibble-specific attributes that can +#' slow down operations in tight computational loops. Used internally by +#' ZooMSS for performance optimization when working with large datasets. +#' +#' @param tibble A tibble or data frame object to convert +#' +#' @return Plain data frame without tibble attributes +#' +untibble <- function (tibble) { + data.frame(unclass(tibble), check.names = FALSE, stringsAsFactors = FALSE) +} ## escape the nonsense + + + + +#' Calculate PPMR Data for Plotting +#' +#' @title Calculate predator-prey mass ratio data for visualization +#' @description Calculates predator-prey mass ratio (PPMR) values and biomass weightings +#' for creating PPMR distribution plots in ZooMSS analysis. +#' @details This function computes theoretical and realized PPMR patterns by: +#' - Calculating size-dependent PPMR values using Wirtz 2012 equations +#' - Weighting by biomass to show community-level patterns +#' - Computing species-specific PPMR values +#' - Handling special cases for filter feeders (larvaceans, salps) +#' - Processing either time-averaged abundances (2D) or full time series (3D) +#' +#' The function dynamically determines size class ranges for larvaceans and salps +#' based on their W0 and Wmax values. For 3D abundance arrays, it calculates +#' PPMR for each time step separately. +#' +#' This is a helper function primarily used by plotPPMR for visualization. +#' PPMR analysis provides insights into food web structure and predation patterns. +#' +#' @param mdl ZooMSS results object containing abundance data (N) and model parameters +#' +#' @return For 2D input: List containing PPMR density data and species-specific values for plotting +#' For 3D input: Array where first dimension is time, containing PPMR results for each timestep +#' @export +#' +extractPPMR = function(mdl){ + + # min_size = min(mdl$param$Groups$W0) # smallest size class + # max_size = max(mdl$param$Groups$Wmax) # largest size class + + w = mdl$param$w # all size classes + w_log10 = log10(mdl$param$w) # log10 size classes + + # Calculate PPMR (beta) table, where dim1 = group, dim2 = body size with + # value being PPMR for that body size (this is not realised PPMR - not + # emergent from diet but calculated from m-values and Wirtz, 2012 equation) + D.z = 2*(3*(w)*1e12/(4*pi))^(1/3) # convert body mass g to ESD (um) + zoo_m = mdl$param$Groups$PPMRscale # pull out PPMR scaling values from parameter table + betas = log10(t(sapply(zoo_m, function(x){(exp(0.02*log(D.z)^2 - x + 1.832))^3}))) # Convert m to betas, using Wirtz 2012 equation + betas = betas[-which(is.na(mdl$param$Groups$PPMRscale)),] # remove fish rows + + ## Dynamically determine size class indices for special groups + # Find larvaceans indices + larv_idx <- which(mdl$param$Groups$Species=="Larvaceans") + if(length(larv_idx) > 0 && !is.na(mdl$param$Groups$PPMRscale[larv_idx])) { + larv_w0 <- mdl$param$Groups$W0[larv_idx] + larv_wmax <- mdl$param$Groups$Wmax[larv_idx] + larv_start_idx <- which.min(abs(w_log10 - larv_w0)) + larv_end_idx <- which.min(abs(w_log10 - larv_wmax)) + larv_beta_idx <- which(mdl$param$Groups$Species[-which(is.na(mdl$param$Groups$PPMRscale))]=="Larvaceans") + + if(length(larv_beta_idx) > 0 && larv_start_idx <= larv_end_idx) { + # Set PPMR increases by 0.1 for each 0.1 log10 size interval + n_larv_sizes <- larv_end_idx - larv_start_idx + 1 + betas[larv_beta_idx, larv_start_idx:larv_end_idx] <- betas[larv_beta_idx, larv_start_idx] + + seq(0, (n_larv_sizes-1)*0.1, 0.1) + } + } + + # Find salps indices + salp_idx <- which(mdl$param$Groups$Species=="Salps") + if(length(salp_idx) > 0 && !is.na(mdl$param$Groups$PPMRscale[salp_idx])) { + salp_w0 <- mdl$param$Groups$W0[salp_idx] + salp_wmax <- mdl$param$Groups$Wmax[salp_idx] + salp_start_idx <- which.min(abs(w_log10 - salp_w0)) + salp_end_idx <- which.min(abs(w_log10 - salp_wmax)) + salp_beta_idx <- which(mdl$param$Groups$Species[-which(is.na(mdl$param$Groups$PPMRscale))]=="Salps") + + if(length(salp_beta_idx) > 0 && salp_start_idx <= salp_end_idx) { + # Set PPMR increases by 0.1 for each 0.1 log10 size interval + n_salp_sizes <- salp_end_idx - salp_start_idx + 1 + betas[salp_beta_idx, salp_start_idx:salp_end_idx] <- betas[salp_beta_idx, salp_start_idx] + + seq(0, (n_salp_sizes-1)*0.1, 0.1) + } + } + + # Handle 3D abundance array (time, groups, size_classes) + n_timesteps <- dim(mdl$abundance)[1] + + # Initialize output array + results_array <- array(list(), dim = c(n_timesteps)) + + for(t in 1:n_timesteps) { + # Extract abundance for this timestep + N_t <- mdl$abundance[t, , ] + + # Calculate biomass for this timestep + ave_biom = sweep(N_t, 2, w, "*") # Calculate biomass for each group and size + ave_biom = ave_biom[-which(is.na(mdl$param$Groups$PPMRscale)),] # remove rows for fish + + # Check for non-finite values and handle edge cases + total_biom = sum(ave_biom) + if (!is.finite(total_biom) || total_biom == 0) { + # If total biomass is zero or non-finite, create uniform weights + beta_props = matrix(1/length(ave_biom), nrow = nrow(ave_biom), ncol = ncol(ave_biom)) + warning("Non-finite or zero total biomass detected at timestep ", t, ". Using uniform weights for density calculation.") + } else { + beta_props = ave_biom/total_biom # Calculate fraction of zoo biomass in each group, in each size class + } + + # Ensure beta_props values are finite for density function + beta_props[!is.finite(beta_props)] <- 0 + + # Calculate density with bandwidth selection using weights + betas_vec <- as.vector(betas) + beta_props_vec <- as.vector(beta_props) + non_zero_weights <- beta_props_vec > 0 + unique_betas <- unique(betas_vec[non_zero_weights]) + + if (length(unique_betas) < 2) { + # Not enough unique values for automatic bandwidth selection + bw <- if (length(unique_betas) == 1) 0.1 else diff(range(unique_betas))/10 + temp <- suppressWarnings(stats::density(betas_vec, weights = beta_props_vec, bw = bw)) + } else { + temp <- suppressWarnings(stats::density(betas_vec, weights = beta_props_vec)) + } + out <- tibble::tibble("x" = temp$x, "y" = temp$y, "mn_beta" = sum(beta_props*betas)) + + # Calculate species-specific proportions with safety checks + row_sums <- rowSums(ave_biom) + spbeta_props = ave_biom + for(i in seq_len(nrow(ave_biom))) { + if(is.finite(row_sums[i]) && row_sums[i] > 0) { + spbeta_props[i,] = ave_biom[i,] / row_sums[i] + } else { + spbeta_props[i,] = 1/ncol(ave_biom) # uniform distribution if row sum is invalid + } + } + spbeta_props[!is.finite(spbeta_props)] <- 0 # ensure all values are finite + spPPMR <- tibble::tibble("Species" = as.factor(mdl$param$Groups$Species[-which(is.na(mdl$param$Groups$PPMRscale))]), "Betas" = rowSums(spbeta_props*betas), "y" = NA) # Get species-specific PPMR + + for (s in seq_along(spPPMR$Species)){ + spPPMR$y[s] <- out$y[which.min(abs(out$x - spPPMR$Betas[s]))] + } + + spPPMR <- spPPMR %>% + dplyr::mutate(y = .data$y * 0) %>% + dplyr::bind_rows(spPPMR) + + # Store results for this timestep + results_array[[t]] <- list("ppmr_density" = out, "species_ppmr" = spPPMR) + } + + return(results_array) +} + + +#' Calculate Phytoplankton Size Spectrum Parameters +#' +#' @title Calculate phytoplankton abundance spectrum from chlorophyll data +#' @description Converts chlorophyll concentration data to phytoplankton size spectrum +#' parameters (slope, intercept, maximum size) using established oceanographic relationships. +#' @details This function implements the Brewin et al. (2015) algorithm to partition +#' chlorophyll among picophytoplankton, nanophytoplankton, and microphytoplankton size +#' classes, then calculates: +#' - Size spectrum slope and intercept parameters +#' - Maximum phytoplankton size based on micro proportion +#' - Biomass estimates for each size class +#' +#' These parameters drive the dynamic phytoplankton spectrum in ZooMSS that serves +#' as the base of the food web. The function can work with either chlorophyll-only +#' data (using empirical relationships) or direct phytoplankton biomass measurements. +#' +#' @param dat Data frame containing chlorophyll data (chl column in mg/m^3) and +#' optionally phytoplankton biomass (phy column in g/m^3) +#' +#' @return Data frame with added columns: +#' \itemize{ +#' \item phyto_slope: Power law slope for phytoplankton size spectrum +#' \item phyto_int: Log10 intercept for phytoplankton abundance +#' \item phyto_max: Maximum phytoplankton size (log10 grams) +#' \item pico_biom, nano_biom, micro_biom: Biomass in each size class +#' } +#' @export +#' +#' @references +#' Brewin, R.J.W., et al. (2015). A three-component model of phytoplankton size class +#' for the Atlantic Ocean. Ecological Modelling, 306, 90-101. +#' +#' Maranon, E., et al. (2014). Resource supply overrides temperature as a controlling +#' factor of marine phytoplankton growth. PLoS ONE, 9(6), e99312. +#' +calculatePhytoParam <- function(dat){ + + ## Calculate pico, nano, micro phytoplankton proportions of total chlorophyll + ## BREWIN ET AL., 2015 + pico <- (0.13*(1-exp(-0.8/0.13*dat$chl)))/dat$chl + nano <- (0.77*(1-exp(-0.94/0.77*dat$chl)))/dat$chl - pico + micro <- (dat$chl - 0.77*(1-exp(-0.94/0.77*dat$chl)))/dat$chl + + if("phy" %in% colnames(dat)){ + tot_biom <- dat$phy + } else { + ## Convert total chlorophyll to g m^-3 total wet weight - biomass + ## Allocate total chlorophyll to the three size classes + c_chl <- ((dat$chl^0.89)*(10^1.79))/dat$chl # chl:carbon ratio, from Maranon et al. 2014 + tot_biom_c <- c_chl*dat$chl/1000 # (convert to grams carbon) + tot_biom <- tot_biom_c*(1/0.1) # convert to grams wet weight, assuming 0.1 C:ww + } + + # Break up total biom into pico, nano and micro + dat$pico_biom <- pico*tot_biom + dat$nano_biom <- nano*tot_biom + dat$micro_biom <- micro*tot_biom + + ## Find abundances at boundaries of pico, nano size ranges, by analytically + ## solving integral of N = aw^b + + w_0 <- -14.5 # log minimum size of picophytoplankton + w_1 <- -11.5 # log minimum size of nanophytoplankton (max size of pico also) + w_2 <- -8.5 # log minimum size of macrophytoplankton (max size of nano also) + + dat$phyto_slope <- (log10(dat$pico_biom) - log10(dat$nano_biom) - w_1 + w_2)/(w_1 - w_2) # Calculate slope + dat$phyto_int <- log10(dat$pico_biom*(dat$phyto_slope+1)/((10^(w_1))^(dat$phyto_slope+1) - (10^(w_0))^(dat$phyto_slope+1))) # Calculate intercept + + ## Calculate maximum size + dat$phyto_max <- 0.1*round((-8.4 + 2*micro)/0.1) # Maximum size depends on the proportion of micro + max_phyto <- rep(-7, length(dat$chl)) # Set -7 to be the max possible size for phyto + dat$phyto_max <- pmin(max_phyto, dat$phyto_max) + + return(dat) +} + + +#' Calculate Trophic Levels from Diet Matrix +#' +#' @title Compute trophic levels for functional groups using diet composition +#' @description Calculates trophic levels for each functional group based on their +#' diet composition using an iterative Gauss-Seidel algorithm. +#' @details This function computes trophic levels by: +#' - Starting with phytoplankton at trophic level 1.0 +#' - Initializing all other groups at trophic level 2.0 +#' - Iteratively updating trophic levels based on weighted diet composition +#' - Continuing until convergence (difference < 0.01) or maximum iterations (100) +#' - Processing 3D diet arrays with time series data +#' +#' Trophic level calculation follows: TL = 1 + sum(diet_fraction_i * TL_prey_i) +#' +#' The function calculates trophic levels for each time step separately and +#' dynamically determines the number of groups from the diet matrix dimensions. +#' +#' This provides a quantitative measure of each group's position in the food web +#' and is useful for analyzing ecosystem structure and energy transfer efficiency. +#' +#' @param mdl ZooMSS model results object containing 3D diet data (mdl$diet). +#' Dimensions are time, groups, prey_items where columns 1:3 are always +#' phytoplankton size classes and remaining columns are zooplankton/fish groups. +#' +#' @return Matrix where rows are time steps and columns are functional groups +#' @export +#' +#' @examples +#' \dontrun{ +#' # After running ZooMSS model with 3D time series +#' results <- zoomss_model(input_params, Groups) +#' trophic_levels <- extractTrophicLevels(results) # Returns matrix (time x groups) +#' +#' # View trophic levels by group for final time step +#' final_tl <- trophic_levels[nrow(trophic_levels), ] +#' names(final_tl) <- results$param$Groups$Species +#' print(final_tl) +#' } +#' +extractTrophicLevels <- function(mdl){ + + phyto_tl <- 1 # Phyto TL is 1 + + # Extract 3D diet array (time, groups, prey) + if(!"diet" %in% names(mdl)) { + stop("Diet data (mdl$diet) not found in model output") + } + + diet_array <- mdl$diet + + if(length(dim(diet_array)) != 3) { + stop("Diet array must be 3D with dimensions [time, groups, prey_items]") + } + + n_timesteps <- dim(diet_array)[1] + n_groups <- dim(diet_array)[2] + n_prey_items <- dim(diet_array)[3] + + # Dynamically determine number of zooplankton/fish groups + n_dynamic_groups <- n_prey_items - 3 # Subtract 3 phytoplankton columns + + # Initialize output matrix (time x groups) + trophic_levels <- matrix(NA, nrow = n_timesteps, ncol = n_groups) + + for(t in 1:n_timesteps) { + # Extract diet matrix for this timestep + diet_matrix <- diet_array[t,,] + + # Calculate trophic levels for this timestep + start_dynam_tl <- rep(2, n_groups) # Start TL at 2 for all zoo and fish groups + + # Current phyto diet (columns 1:3) + curr_phyto_diet <- rowSums(diet_matrix[,1:3]) + + # Current heterotroph diet (columns 4 onwards) + if(n_dynamic_groups > 0) { + curr_dynam_diet <- diet_matrix[,4:(3+n_dynamic_groups)] + if(n_dynamic_groups == 1) { + # Handle case where there's only one dynamic group (ensure it's a matrix) + curr_dynam_diet <- matrix(curr_dynam_diet, ncol = 1) + } + } else { + # If no dynamic groups, create empty matrix + curr_dynam_diet <- matrix(0, nrow = n_groups, ncol = 0) + } + + # Calculate total diet + total_diet <- curr_phyto_diet + rowSums(curr_dynam_diet) + + # Avoid division by zero + valid_diet <- total_diet > 0 + + if(any(valid_diet)) { + # Calculate diet fractions only for groups with valid diets + curr_phyto_frac <- rep(0, n_groups) + curr_phyto_frac[valid_diet] <- curr_phyto_diet[valid_diet] / total_diet[valid_diet] + + if(n_dynamic_groups > 0) { + curr_dynam_frac <- matrix(0, nrow = n_groups, ncol = n_dynamic_groups) + curr_dynam_frac[valid_diet,] <- sweep(curr_dynam_diet[valid_diet,, drop = FALSE], 1, total_diet[valid_diet], '/') + } else { + curr_dynam_frac <- matrix(0, nrow = n_groups, ncol = 0) + } + + # Gauss-Seidel iterative loop + n_iter <- 1 + eps_diff <- 1 + + while(eps_diff > 0.01 && n_iter < 100) { + n_iter <- n_iter + 1 + eps <- start_dynam_tl[min(n_groups, 10)] # Use a representative group for convergence check + + if(n_dynamic_groups > 0) { + calc_dynam_tl <- sweep(curr_dynam_frac, 2, start_dynam_tl[1:min(n_dynamic_groups, n_groups)], '*') + calc_dynam_tl[is.nan(calc_dynam_tl)] <- 0 # Remove NaNs + start_dynam_tl <- 1 + phyto_tl * curr_phyto_frac + rowSums(calc_dynam_tl) + } else { + start_dynam_tl <- 1 + phyto_tl * curr_phyto_frac + } + + eps_diff <- abs(eps - start_dynam_tl[min(n_groups, 10)]) + } + } + + trophic_levels[t,] <- start_dynam_tl + } + + return(trophic_levels) +} diff --git a/R/utils_enviro.R b/R/utils_enviro.R new file mode 100644 index 0000000..a6e1169 --- /dev/null +++ b/R/utils_enviro.R @@ -0,0 +1,211 @@ +#' Create ZooMSS Input Parameters Object +#' +#' @title Create input parameters data frame for ZooMSS model runs +#' @description Creates a properly formatted input parameters data frame for ZooMSS model +#' simulations, combining temporal parameters with environmental time series data. +#' @details This function combines environmental time series (SST and chlorophyll) with +#' time data to create the input_params object required by zoomss_model(). +#' The function performs validation checks using assertthat to ensure: +#' - All input vectors are numeric and of equal length +#' - SST values are within reasonable ocean range (-2 to 35 deg C) +#' - Chlorophyll values are positive and within typical range (0 to 50 mg/m^3) +#' - Time values are increasing and reasonable +#' +#' +#' @param time Numeric vector of time values in years (must be increasing and uniform, can start at any value) +#' @param sst Numeric vector of sea surface temperature values in deg C +#' @param chl Numeric vector of chlorophyll concentration values in mg/m^3 +#' @param cellID Optional numeric vector of cell identifiers for spatial data (default: NULL) +#' +#' @return Data frame with columns: time, time_step, sst, chl, and cellID (if provided) +#' @export +#' +#' @examples +#' \dontrun{ +#' # Create simple environmental time series +#' time_vec <- seq(0, 10, 0.01) # 10 years with 0.01 year time steps +#' sst_vec <- 15 + 3*sin(2*pi*time_vec/1) # annual cycle +#' chl_vec <- 0.5 + 0.2*cos(2*pi*time_vec/1) # annual cycle +#' +#' # Create input parameters object +#' input_params <- createInputParams(time_vec, sst_vec, chl_vec) +#' +#' # Use with ZooMSS model +#' results <- zoomss_model(input_params, Groups, isave = 50) +#' } +#' +createInputParams <- function(time, + sst, + chl, + cellID = NULL) { + + # Load assertthat package for validation + if (!requireNamespace("assertthat", quietly = TRUE)) { + stop("assertthat package required for input validation") + } + + # Validate input data types and structure + assertthat::assert_that(is.numeric(time), msg = "time must be numeric") + assertthat::assert_that(is.numeric(sst), msg = "sst must be numeric") + assertthat::assert_that(is.numeric(chl), msg = "chl must be numeric") + + # Validate equal lengths if length of sst and chl > 1 + if (length(sst) > 1 && length(chl) > 1){ + assertthat::assert_that(length(time) == length(sst), + msg = "time and sst must have the same length") + assertthat::assert_that(length(time) == length(chl), + msg = "time and chl must have the same length") + } + + # Validate cellID if provided + if (!is.null(cellID)) { + assertthat::assert_that(is.numeric(cellID), msg = "cellID must be numeric") + assertthat::assert_that(length(cellID) == length(time), + msg = "cellID must have the same length as time") + } + + # Validate time vector properties + assertthat::assert_that(length(time) > 1, msg = "time must have at least 2 values") + assertthat::assert_that(all(!is.na(time)), msg = "time cannot contain NA values") + assertthat::assert_that(all(diff(time) > 0), msg = "time values must be increasing") + + # Calculate dt and tmax from time vector + dt_values <- diff(time) + dt <- dt_values[1] # Use first time step as dt + + # Check if time steps are uniform - ERROR if not consistent + max_dt_diff <- max(abs(dt_values - dt)) + if (max_dt_diff > dt * 0.001) { # Allow only 0.1% variation (much stricter) + stop("Time steps are not uniform. Maximum deviation: ", round(max_dt_diff, 6), + " (", round(100 * max_dt_diff / dt, 2), "% of dt). ", + "ZooMSS requires uniform time steps for accurate results.") + } + + tmax <- max(time) # Maximum time value (not duration) + + # Validate temporal parameters + assertthat::assert_that(dt > 0, msg = "calculated dt must be positive") + # Note: tmax can be any value (positive, negative, or zero) as it's the final time point + + # Validate environmental data ranges + assertthat::assert_that(all(!is.na(sst)), msg = "sst cannot contain NA values") + assertthat::assert_that(all(!is.na(chl)), msg = "chl cannot contain NA values") + assertthat::assert_that(all(sst >= -2 & sst <= 35), + msg = "sst values must be within ocean range (-2 to 35 deg C)") + assertthat::assert_that(all(chl >= 0 & chl <= 50), + msg = "chl values must be within range (0 to 50 mg/m^3)") + + # Create formatted data frame + if (is.null(cellID)) { + formatted_data <- data.frame( + time = time, + time_step = seq_along(time), + sst = sst, + chl = chl + ) + } else { + formatted_data <- data.frame( + time = time, + time_step = seq_along(time), + sst = sst, + chl = chl, + cellID = cellID + ) + } + + # Provide summary information + n_time_points <- nrow(formatted_data) + n_time_steps <- n_time_points - 1 + + cat("ZooMSS input parameters created:\n") + cat("- Time points:", n_time_points, "(time values provided)\n") + cat("- Time steps:", n_time_steps, "(intervals to simulate)\n") + cat("- Time range:", round(min(formatted_data$time), 3), "to", + round(max(formatted_data$time), 3), "years\n") + cat("- dt =", round(dt, 4), "years\n") + cat("- SST range:", round(min(formatted_data$sst), 1), "to", + round(max(formatted_data$sst), 1), "deg C\n") + cat("- Chlorophyll range:", round(min(formatted_data$chl), 2), "to", + round(max(formatted_data$chl), 2), "mg/m^3\n") + + # Helpful reminder about time vector interpretation + if (length(time) > 1 && all(diff(time) == 1) && min(time) %% 1 == 0 && max(time) %% 1 == 0) { + cat("- Note: Time vector", min(time), ":", max(time), "creates", n_time_steps, + "time steps (intervals) from", length(time), "time points.\n") + } + + return(formatted_data) +} + + +#' Create Environmental Time Series +#' +#' @title Generate synthetic environmental data for ZooMSS testing +#' @description Creates simple synthetic environmental time series with optional seasonal +#' variation for testing ZooMSS model runs when real environmental data is not available. +#' @details This function generates synthetic sea surface temperature and chlorophyll +#' time series that can be used for testing ZooMSS model behavior. The function can +#' create either static environmental conditions or seasonal cycles with sinusoidal +#' variation. This is particularly useful for: +#' - Testing model sensitivity to environmental forcing +#' - Creating idealized scenarios for model exploration +#' - Generating data when real environmental data is unavailable +#' +#' The seasonal option creates SST and chlorophyll cycles that are out of phase, +#' mimicking typical ocean patterns where chlorophyll peaks when SST is lower. +#' +#' @param n_years Number of years to generate +#' @param dt Time step size in years +#' @param base_sst Base sea surface temperature in deg C (default: 15) +#' @param base_chl Base chlorophyll concentration in mg/m^3 (default: 0.5) +#' @param seasonal Logical, whether to add seasonal variation (default: TRUE) +#' @param sst_amplitude Amplitude of SST seasonal variations in deg C (default: 3) +#' @param chl_amplitude Amplitude of chlorophyll seasonal variations in mg/m^3 (default: 0.2) +#' +#' @return Data frame with columns: time, sst, chl +#' @export +#' +#' @examples +#' # Create seasonal environmental data +#' env_data <- createEnviroData( +#' n_years = 10, +#' dt = 0.01, +#' seasonal = TRUE +#' ) +#' +#' # Create static environmental conditions +#' static_data <- createEnviroData( +#' n_years = 5, +#' dt = 0.01, +#' seasonal = FALSE, +#' base_sst = 20, +#' base_chl = 1.0 +#' ) +#' +createEnviroData <- function(n_years, + dt, + base_sst = 15, + base_chl = 0.5, + seasonal = TRUE, + sst_amplitude = 3, + chl_amplitude = 0.2) { + + # Create time vector + time_years <- seq(0, n_years, by = dt) + + if (seasonal) { + # Seasonal patterns (peaks in different seasons) + sst_values <- base_sst + sst_amplitude * sin(2 * pi * time_years) # Annual cycle + chl_values <- base_chl + chl_amplitude * sin(2 * pi * time_years + pi) # Inverse to SST + } else { + # Static values + sst_values <- rep(base_sst, length(time_years)) + chl_values <- rep(base_chl, length(time_years)) + } + + return(data.frame( + time = time_years, + sst = sst_values, + chl = chl_values + )) +} diff --git a/R/utils_pipe.R b/R/utils_pipe.R new file mode 100644 index 0000000..c453c56 --- /dev/null +++ b/R/utils_pipe.R @@ -0,0 +1,20 @@ +#' Pipe operator +#' +#' See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details. +#' +#' @name %>% +#' @rdname pipe +#' @keywords internal +#' @export +#' @importFrom magrittr %>% +#' @usage lhs \%>\% rhs +#' @param lhs A value or the magrittr placeholder. +#' @param rhs A function call using the magrittr semantics. +#' @return The result of calling `rhs(lhs)`. +NULL + +#' @importFrom rlang .data +NULL + +#' @importFrom rlang := +NULL diff --git a/R/zoomss_groups.R b/R/zoomss_groups.R new file mode 100644 index 0000000..ebbe3df --- /dev/null +++ b/R/zoomss_groups.R @@ -0,0 +1,250 @@ +#' Get Default ZooMSS Functional Groups +#' +#' @title Load default or custom functional groups for ZooMSS model +#' @description Provides access to the default ZooMSS functional groups or loads custom +#' groups from a file. This function is the primary way to obtain Groups data for +#' ZooMSS model runs. +#' @details This function provides flexible access to functional groups data: +#' - **Default groups**: Returns the standard ZooMSS functional groups (12 groups) +#' - **Custom file**: Loads and validates groups from a user-provided CSV file +#' - **Template creation**: Exports default groups to a file for user modification +#' +#' The default groups include: Flagellates, Ciliates, Larvaceans, OmniCopepods, +#' CarnCopepods, Euphausiids, Chaetognaths, Salps, Jellyfish, and three Fish groups +#' (Small, Medium, Large). +#' +#' All groups data is validated to ensure it contains required columns and +#' reasonable parameter values for successful model runs. +#' +#' @param source Character string specifying data source. Options: +#' \itemize{ +#' \item "default": Use built-in ZooMSS functional groups (default) +#' \item "file": Load groups from a CSV file +#' \item "template": Export default groups to a file for modification +#' } +#' @param file Path to CSV file when source="file" or source="template" +#' +#' @return Data frame containing functional groups with required columns: +#' Species, Type, W0, Wmax, and other biological parameters +#' @export +#' +#' @examples +#' \dontrun{ +#' # Use default groups +#' Groups <- getGroups() +#' +#' # Create a template file for modification +#' getGroups(source = "template", file = "my_groups.csv") +#' +#' # Load custom groups from file +#' custom_groups <- getGroups(source = "file", file = "my_groups.csv") +#' +#' # Modify default groups programmatically +#' Groups <- getGroups() +#' Groups$W0[Groups$Species == "Flagellates"] <- -12.5 # Modify minimum size +#' } +#' +getGroups <- function(source = "default", file = NULL) { + + source <- match.arg(source, choices = c("default", "file", "template")) + + switch(source, + "default" = { + # Load from package data - this would reference the built-in GroupInputs + groups <- loadDefaultGroups() + message("Using default ZooMSS functional groups. Use getGroups() to customize.") + return(groups) + }, + + "file" = { + if (is.null(file)) { + stop("file path must be specified when source='file'") + } + if (!file.exists(file)) { + stop("File not found: ", file) + } + + groups <- utils::read.csv(file, stringsAsFactors = FALSE) + + # Validate the loaded groups + validateGroups(groups) + return(groups) + }, + + "template" = { + if (is.null(file)) { + stop("file path must be specified when source='template'") + } + + # Get default groups and write to file + default_groups <- loadDefaultGroups() + utils::write.csv(default_groups, file, row.names = FALSE) + + message("Template functional groups written to: ", file) + message("Edit this file to customize groups, then load with:") + message("Groups <- getGroups(source='file', file='", file, "')") + + return(default_groups) + } + ) +} + +#' Load Default Functional Groups Data +#' +#' @title Internal function to load default ZooMSS groups +#' @description Loads the default functional groups from the package data or CSV file. +#' This is an internal function used by getGroups(). +#' @details This function handles the actual loading of default groups data, +#' whether from package data (if available) or from the CSV file in data-raw. +#' +#' @return Data frame with default functional groups +#' @keywords internal +#' +loadDefaultGroups <- function() { + + # First try to load from package data + tryCatch({ + + # This will work when the package is properly installed + utils::data("GroupInputs", package = "zoomss", envir = environment()) + if (exists("GroupInputs", envir = environment())) { + return(get("GroupInputs", envir = environment())) + } + }, error = function(e) { + # Package data not available, try other locations + }) + + # Try loading from inst/extdata (for installed packages) + package_file <- system.file("extdata", "GroupInputs.csv", package = "zoomss") + + if (package_file != "") { + groups <- readr::read_csv(package_file, show_col_types = FALSE) + message("Loaded default functional groups from package extdata") + return(groups) + } + + # Try loading from data-raw (for development) + if (file.exists("data-raw/GroupInputs.csv")) { + groups <- readr::read_csv("data-raw/GroupInputs.csv", show_col_types = FALSE) + message("Loaded default functional groups from data-raw/GroupInputs.csv") + return(groups) + } + + # If we get here, no default groups were found + stop("Default groups file not found. Please ensure GroupInputs data is available.", + "\n Try installing the package or ensure GroupInputs.csv exists in data-raw/") +} + +#' Validate Functional Groups Data +#' +#' @title Validate ZooMSS functional groups data structure and values +#' @description Performs comprehensive validation of functional groups data to ensure +#' it meets ZooMSS model requirements. +#' @details This function validates: +#' - Required column names are present +#' - Data types are correct +#' - Parameter values are within reasonable ranges +#' - No missing values in critical columns +#' - Size ranges are logical (W0 < Wmax) +#' +#' @param groups Data frame containing functional groups data +#' +#' @return TRUE if validation passes (invisibly), otherwise throws an error +#' @export +#' +#' @examples +#' \dontrun{ +#' Groups <- getGroups() +#' validateGroups(Groups) # Should pass +#' +#' # This would fail validation: +#' bad_groups <- Groups +#' bad_groups$W0 <- NULL +#' validateGroups(bad_groups) # Error: missing required column +#' } +#' +validateGroups <- function(groups) { + + # Load assertthat for validation + if (!requireNamespace("assertthat", quietly = TRUE)) { + stop("assertthat package required for groups validation") + } + + # Check that groups is a data frame + assertthat::assert_that(is.data.frame(groups), + msg = "Groups must be a data frame") + + # Check required columns exist (based on actual GroupInputs.csv structure) + required_cols <- c("Species", "Type", "FeedType", "Prop", "W0", "Wmax", "Wmat", + "SearchCoef", "SearchExp", "PPMRscale", "PPMR", "FeedWidth", + "GrossGEscale", "Carbon", "Repro", "Fmort", "Fmort_W0", + "Fmort_Wmax", "PlotColour") + + missing_cols <- setdiff(required_cols, names(groups)) + assertthat::assert_that(length(missing_cols) == 0, + msg = paste("Missing required columns:", paste(missing_cols, collapse = ", "))) + + # Check data types and ranges + assertthat::assert_that(is.character(groups$Species) || is.factor(groups$Species), + msg = "Species column must be character or factor") + + assertthat::assert_that(all(!is.na(groups$Species)), + msg = "Species names cannot be NA") + + assertthat::assert_that(all(!duplicated(groups$Species)), + msg = "Species names must be unique") + + # Check size parameters + assertthat::assert_that(is.numeric(groups$W0), + msg = "W0 (minimum weight) must be numeric") + + assertthat::assert_that(is.numeric(groups$Wmax), + msg = "Wmax (maximum weight) must be numeric") + + assertthat::assert_that(all(groups$W0 < groups$Wmax), + msg = "W0 must be less than Wmax for all groups") + + # Check reasonable size ranges (log10 weights) + assertthat::assert_that(all(groups$W0 >= -15 & groups$W0 <= 5), + msg = "W0 values should be between -15 and 5 (log10 grams)") + + assertthat::assert_that(all(groups$Wmax >= -10 & groups$Wmax <= 10), + msg = "Wmax values should be between -10 and 10 (log10 grams)") + + # Check maturation weight + assertthat::assert_that(all(groups$Wmat >= groups$W0 & groups$Wmat <= groups$Wmax), + msg = "Wmat must be between W0 and Wmax") + + # Check Type values + valid_types <- c("Zooplankton", "Fish") + assertthat::assert_that(all(groups$Type %in% valid_types), + msg = paste("Type must be one of:", paste(valid_types, collapse = ", "))) + + # Check FeedType values + valid_feedtypes <- c("Carnivore", "Omnivore", "FilterFeeder", "Heterotroph") + assertthat::assert_that(all(groups$FeedType %in% valid_feedtypes), + msg = paste("FeedType must be one of:", paste(valid_feedtypes, collapse = ", "))) + + # Check biological parameters are positive where required + assertthat::assert_that(all(groups$SearchCoef > 0), + msg = "SearchCoef must be positive") + + assertthat::assert_that(all(groups$SearchExp > 0), + msg = "SearchExp must be positive") + + assertthat::assert_that(all(groups$FeedWidth > 0), + msg = "FeedWidth must be positive") + + assertthat::assert_that(all(groups$GrossGEscale > 0), + msg = "GrossGEscale must be positive") + + assertthat::assert_that(all(groups$Carbon > 0 & groups$Carbon <= 1), + msg = "Carbon content must be between 0 and 1") + + # Check fishing mortality is non-negative + assertthat::assert_that(all(groups$Fmort >= 0), + msg = "Fmort (fishing mortality) must be non-negative") + + message("Functional groups validation passed") + return(invisible(TRUE)) +} diff --git a/R/zoomss_model.R b/R/zoomss_model.R new file mode 100644 index 0000000..c306235 --- /dev/null +++ b/R/zoomss_model.R @@ -0,0 +1,93 @@ +#' Run Complete ZooMSS Model Simulation +#' +#' @title Main ZooMSS model function for complete simulations +#' @description This is the main wrapper function that orchestrates a complete ZooMSS +#' model simulation from parameter setup through model execution to output processing. +#' @details This function coordinates the entire ZooMSS modeling workflow: +#' 1. Validates that environmental time series data is provided +#' 2. Sets up model parameters using the Groups data and input parameters +#' 3. Initializes the model structure and feeding kernels +#' 4. Runs the model forward in time with dynamic environmental forcing +#' 5. Processes outputs by averaging the final 50% of the simulation +#' 6. Returns organized results including abundances, diets, growth, and mortality +#' +#' This is the primary entry point for +#' running ZooMSS simulations with environmental forcing. +#' +#' @param input_params Data frame containing model parameters and environmental time series. +#' Must include columns: time (time vector in years), sst (sea surface temperature), +#' and chl (chlorophyll). Can optionally include cellID for spatial data. The time step (dt) +#' and maximum time (tmax) are automatically calculated from the time vector. Can be created using createInputParams(). +#' @param Groups Data frame defining functional groups with their biological parameters. +#' Must include columns defining species characteristics, size ranges, and feeding parameters. +#' If NULL, uses default ZooMSS functional groups. Can be obtained/customized using +#' getGroups(). +#' @param isave Save frequency in time steps (default: 10) +#' +#' @return Complete ZooMSS model results object containing: +#' \itemize{ +#' \item param: Model parameters and environmental forcing data +#' \item time: Time values corresponding to saved results (accounting for isave) +#' \item abundance: Abundance time series (time x groups x size classes) +#' \item growth: Growth rate time series +#' \item mortality: Mortality rate time series +#' \item diet: Diet composition time series +#' \item Additional model structure and kernel data +#' } +#' @export +#' +#' @examples +#' \dontrun{ +#' # Basic usage with default groups +#' env_data <- createEnviroData(10, 0.01) +#' input_params <- createInputParams(env_data$time, env_data$sst, env_data$chl) +#' results <- zoomss_model(input_params, isave = 50) +#' +#' # Using custom groups +#' Groups <- getGroups() # Get default groups +#' Groups$W0[1] <- -12.5 # Modify a parameter +#' results <- zoomss_model(input_params, Groups, isave = 100) +#' +#' # Loading groups from file +#' custom_groups <- getGroups(source = "file", file = "my_groups.csv") +#' results <- zoomss_model(input_params, custom_groups) +#' } +#' +zoomss_model <- function(input_params, Groups = NULL, isave = 1){ + + # Handle default Groups parameter + if (is.null(Groups)) { + Groups <- getGroups(source = "default") + } else { + # Validate user-provided Groups + validateGroups(Groups) + } + + input_params <- untibble(input_params) + + # Validate that input_params has the required environmental data + if (nrow(input_params) > 1 && all(c("time", "sst", "chl") %in% names(input_params))) { + # Environmental time series found - proceed with model + } else { + stop("No environmental time series provided and input_params doesn't contain expanded time series data") + } + + ################### RUN THE MODEL ################### + param <- zoomss_params(Groups, input_params, isave) # Set up parameter list + model <- zoomss_setup(param) # Set up model equation stuff + model_output <- zoomss_run(model) # Run the model + + my_rename <- function(.x, ..., .strict = TRUE) { + pos <- tidyselect::eval_rename(quote(c(...)), .x, strict = .strict) + names(.x)[pos] <- names(pos) + .x + } + + model_output <- model_output %>% + my_rename(abundance = "N", growth = "gg", mortality = "Z") # Make variables more easily readable + + model_output$biomass = getBiomass(model_output, units = "ww") + model_output$biomassC <- getBiomass(model_output, units = "carbon") + + return(model_output) +} diff --git a/R/zoomss_mvf.R b/R/zoomss_mvf.R new file mode 100644 index 0000000..d8fb696 --- /dev/null +++ b/R/zoomss_mvf.R @@ -0,0 +1,77 @@ +#' McKendrick-von Foerster Equation Solver (Base R Implementation) +#' +#' @title Solve McKendrick-von Foerster equation for size-structured populations +#' @description Solves the McKendrick-von Foerster (MvF) partial differential equation +#' for size-structured population dynamics using a finite difference approach in base R. +#' @details This function implements the numerical solution to the McKendrick-von Foerster +#' equation, which describes how populations change across size classes over time. +#' The equation is solved using an upwind finite difference scheme that handles: +#' - Growth through size classes (advection term) +#' - Diffusion between adjacent size classes +#' - Source and sink terms from feeding and mortality +#' +#' The function processes each functional group separately and applies boundary conditions +#' appropriate for size-structured models. The last size class is set to zero abundance +#' to represent maximum size limits. +#' +#' This is a core computational component of ZooMSS that updates population abundances +#' at each time step based on growth, mortality, and reproduction processes. +#' +#' @param ngrps Number of functional groups in the model +#' @param curr_min_size Vector of minimum size class indices for each group +#' @param curr_max_size Vector of maximum size class indices for each group +#' @param A_iter Matrix of advection coefficients for current iteration +#' @param C_iter Matrix of diagonal coefficients for current iteration +#' @param Nb_iter Matrix to store updated abundances for current iteration +#' @param S_iter Matrix of source terms for current iteration +#' @param A Matrix of advection coefficients +#' @param B Matrix of diffusion coefficients +#' @param C Matrix of diagonal coefficients +#' @param Nb Matrix of abundances to be updated +#' @param S Matrix of source terms +#' +#' @return Updated abundance matrix (Nb) with new size-class distributions +#' +#' @examples +#' \dontrun{ +#' # This function is typically called internally by zoomss_run +#' # Example shows the structure of parameters needed: +#' ngrps <- 9 +#' ngrid <- 100 +#' curr_min_size <- c(1, 10, 20, 30, 40, 50, 60, 70, 80) +#' curr_max_size <- c(30, 40, 50, 60, 70, 80, 90, 95, 100) +#' +#' # Initialize coefficient matrices +#' A <- matrix(0, nrow = ngrps, ncol = ngrid) +#' B <- matrix(0, nrow = ngrps, ncol = ngrid) +#' C <- matrix(1, nrow = ngrps, ncol = ngrid) +#' S <- matrix(0, nrow = ngrps, ncol = ngrid) +#' Nb <- matrix(0.1, nrow = ngrps, ncol = ngrid) +#' +#' # Run MvF solver +#' updated_abundances <- zoomss_mvf(ngrps, curr_min_size, curr_max_size, +#' A, C, Nb, S, A, B, C, Nb, S) +#' } +#' +zoomss_mvf <- function(ngrps, curr_min_size, curr_max_size, A_iter, C_iter, Nb_iter, S_iter, A, B, C, Nb, S){ + + for(i in 1:ngrps){ + + idx_curr <- (curr_min_size[i]+1):curr_max_size[i] ## Set size range index for current group + + for(j in idx_curr){ ## Find the abundance at the next size class with standard MvF + Nb_iter[i,j] <- (S_iter[i,j] + A_iter[i,j]*Nb[i,j-1])/(C_iter[i,j]) + + if(j >= (idx_curr[1]+1)){ ## Find abundance with MvF with diffusion + k <- j - 1 + Nb[i,k] <- (S[i,k] + A[i,k] * Nb[i,k-1] + B[i,k] * Nb_iter[i,k+1]) / C[i,k] + } + + # MvF without diffusion for last size class + if(j == idx_curr[length(idx_curr)]){ + Nb[i,j] <- 0 + } + } + } + return(Nb) +} diff --git a/R/zoomss_params.R b/R/zoomss_params.R new file mode 100644 index 0000000..7e49af0 --- /dev/null +++ b/R/zoomss_params.R @@ -0,0 +1,167 @@ +#' Set Up ZooMSS Model Parameters +#' +#' @title Initialize and validate ZooMSS model parameters +#' @description Sets up the complete parameter list for ZooMSS model runs, including +#' functional group parameters, model dimensions, and environmental forcing data. +#' @details This function creates a comprehensive parameter object that contains: +#' +#' **Static Parameters (fixed across time steps):** +#' - Model dimensions (number of groups, size classes, time steps) +#' - Biological parameters (growth efficiency, mortality rates) +#' - Size class definitions and ranges for each functional group +#' - Phytoplankton size spectrum parameters +#' +#' **Dynamic Parameters (calculated from environmental data):** +#' - Phytoplankton abundance time series based on chlorophyll +#' - Temperature effects on metabolism for zooplankton and fish +#' - Environmental forcing validation and interpolation +#' +#' The function validates that environmental time series data covers the full +#' simulation period and pre-calculates time-varying parameters to optimize +#' model performance during the main simulation loop. +#' +#' @param Groups Data frame containing functional group definitions with columns: +#' Species, Type, W0 (log min size), Wmax (log max size), and various biological parameters +#' @param input_params Data frame with model parameters including: +#' time (time vector in years), sst (sea surface temperature), and chl (chlorophyll). +#' The time vector can start at any value and the model automatically calculates dt (time step) and tmax (maximum time). +#' @param isave Save frequency in time steps (default: 50) +#' +#' @return List containing comprehensive model parameters: +#' \itemize{ +#' \item Groups: Functional group definitions +#' \item ngrps: Number of functional groups +#' \item ngrid: Number of size classes +#' \item w: Size class weights (g) +#' \item tmax, dt, isave: Temporal parameters +#' \item zoo_grps, fish_grps: Indices for different organism types +#' \item phyto_int, phyto_slope: Time series of phytoplankton parameters +#' \item temp_eff_zoo, temp_eff_fish: Time series of temperature effects +#' \item Additional biological and physical parameters +#' } +#' +#' @examples +#' \dontrun{ +#' # Load functional groups +#' data(Groups) +#' +#' # Create environmental time series +#' env_data <- createEnviroData(10, 0.01) +#' input_params <- createInputParams(env_data$time, env_data$sst, env_data$chl) +#' +#' # Generate parameter list +#' params <- zoomss_params(Groups, input_params, isave = 50) +#' } +#' +zoomss_params <- function(Groups, input_params, isave){ + + # Calculate dt and tmax from time column in input_params + time_values <- input_params$time + dt_calc <- time_values[2] - time_values[1] # Use first time step difference + tmax_calc <- max(time_values) # Maximum time value (not duration) + + # Check if time steps are uniform - ERROR if not consistent + if (length(time_values) > 2) { + dt_diffs <- diff(time_values) + max_diff <- max(abs(dt_diffs - dt_calc)) + if (max_diff > dt_calc * 0.001) { # Allow only 0.1% variation + stop("Time steps are not uniform in input_params. Maximum deviation: ", + round(max_diff, 6), " (", round(100 * max_diff / dt_calc, 2), "% of dt). ", + "ZooMSS requires uniform time steps for accurate results.") + } + } + + param <- list( + Groups = Groups, # Read in functional group specific parameters from file + ngrps = dim(Groups)[1], # no. of Groups + dx = 0.1, # log10 weight step + day = 12, # day length (hours of each day in sun) + tmax = tmax_calc, # max years - calculated from time + dt = dt_calc, # timestep - calculated from time + w0 = 10^(min(Groups$W0)), # minimum size class + wMax = 10^(max(Groups$Wmax)),# maximum size class + gge_base = 0.25, # baseline gross growth efficiency + ZSpre = 1, # senescence mortality prefactor + ZSexp = 0.3, # senescence mortality exponent + w0_phyto = 10^(-14.5), # minimum phytoplankton size class (1um) + # wMax_phyto will be calculated from time series + zoo_grps = which(Groups$Type == "Zooplankton"), # Which rows are zooplankton + fish_grps = which(Groups$Type == "Fish"), # Which rows are fish + num_zoo = sum(Groups$Type == "Zooplankton"), # How many zooplankton + num_fish = sum(Groups$Type == "Fish"), # How many fish + cc_phyto = 0.1, # Carbon content of phytoplankton size classes + isave = isave # how often to save results every 'isave' time steps + ) + + # Process provided time series + n_time_steps <- nrow(input_params) + + ## Add additional parameters which are based on the parameter set + param2 <- list( + nsave = max(1, floor(n_time_steps / param$isave)), # Number of time slots to save (regular intervals only, minimum 1) + ntime = n_time_steps, # Total number of time steps to simulate + itimemax = n_time_steps # Number of iterations for time loop (one for each time point) + ) + # Pre-calculate phytoplankton parameters for each time step + + # Initialize arrays to store time-varying parameters (optimize memory allocation) + param2$phyto_int <- numeric(n_time_steps) + param2$phyto_slope <- numeric(n_time_steps) + param2$phyto_max <- numeric(n_time_steps) + param2$wMax_phyto <- numeric(n_time_steps) + + # Pre-calculate temperature effects for each time step (more efficient than in-loop) + param2$temp_eff_zoo <- matrix(NA, nrow = n_time_steps, ncol = param$num_zoo) + param2$temp_eff_fish <- matrix(NA, nrow = n_time_steps, ncol = param$num_fish) + + # Check if phytoplankton parameters are already in input_params (expanded format) + if (nrow(input_params) == n_time_steps && all(c("phyto_int", "phyto_slope", "phyto_max") %in% names(input_params))) { + cat("Using pre-calculated phytoplankton parameters from input_params\n") + + # Use pre-calculated values (most efficient path) + param2$phyto_int <- input_params$phyto_int + param2$phyto_slope <- input_params$phyto_slope + param2$phyto_max <- input_params$phyto_max + param2$wMax_phyto <- 10^input_params$phyto_max + + # Calculate temperature effects for each time step - consistent temperature formula throughout model + temp_factor <- 2^((input_params$sst - 30)/10) + param2$temp_eff_zoo[,] <- temp_factor # preallocated above for all groups + param2$temp_eff_fish[,] <- temp_factor # preallocated above for all groups + + } else { + cat("Calculating phytoplankton parameters from environmental time series\n") + + # Calculate phytoplankton parameters for each time step + + # Calculate phytoplankton parameters using the existing function + phyto_params <- calculatePhytoParam(input_params) + + param2$phyto_int <- phyto_params$phyto_int + param2$phyto_slope <- phyto_params$phyto_slope + param2$phyto_max <- phyto_params$phyto_max + param2$wMax_phyto <- 10^phyto_params$phyto_max + + # Temperature effects (same calculation throughout model) + temp_factor <- 2^((input_params$sst - 30)/10) + param2$temp_eff_zoo[,] <- temp_factor # preallocated above for all groups + param2$temp_eff_fish[,] <- temp_factor # preallocated above for all groups + } + + # Store the maximum wMax_phyto from time series for grid creation + param2$wMax_phyto <- max(param2$wMax_phyto) + + # Add final parameters that depend on the complete parameter set (calculate only once) + param2$w_log10 <- round(seq(from = min(Groups$W0), to = max(Groups$Wmax), param$dx), digits = 2) # Set up log10 weight grid + param2$w <- 10^(seq(from = min(Groups$W0), to = max(Groups$Wmax), param$dx)) # Set up weight grid + param2$w_phyto <- 10^(seq(from = log10(param$w0_phyto), to = log10(param2$wMax_phyto), param$dx)) # Set up phytoplankton size classes + param2$ngrid <- length(param2$w) # total number of size classes for zoo and fish + param2$ngridPP <- length(param2$w_phyto) # total number of size classes for phyto + + # Final parameter combination + # Exclude time series vectors from input_params since they're now stored as _ts arrays in param2 + input_params_filtered <- input_params[!names(input_params) %in% c("tmax", "dt", "isave", "time_step", "phyto_int", "phyto_slope", "phyto_max")] + + param_final <- c(input_params_filtered, param, param2) + return(param_final) +} diff --git a/R/zoomss_plotting.R b/R/zoomss_plotting.R new file mode 100644 index 0000000..9dd1b6d --- /dev/null +++ b/R/zoomss_plotting.R @@ -0,0 +1,328 @@ +#' Plot Predator-Prey Mass Ratio (PPMR) +#' +#' @title Visualize predator-prey mass ratio patterns in ZooMSS results +#' @description Creates a plot showing the distribution of predator-prey mass ratios (PPMR) +#' across functional groups, providing insights into the trophic structure of the ecosystem. +#' @details This function calculates and visualizes PPMR patterns by: +#' - Computing theoretical PPMR values for each functional group and size class +#' - Weighting by biomass to show realized community patterns +#' - Creating a density plot of PPMR distribution across the community +#' - Overlaying species-specific PPMR values as points +#' +#' PPMR is a key ecological metric that describes the size relationship between +#' predators and their prey, providing insight into food web structure and +#' energy transfer efficiency in marine ecosystems. +#' +#' @param mdl ZooMSS results object containing model outputs and parameters +#' @param idx The time index to plot +#' +#' @return ggplot object showing PPMR distribution with species-specific overlays +#' @export +#' +#' @examples +#' \dontrun{ +#' # After running ZooMSS model +#' results <- zoomss_model(input_params, Groups) +#' ppmr_plot <- plotPPMR(results) +#' print(ppmr_plot) +#' } +#' +plotPPMR <- function(mdl, idx){ + + out <- extractPPMR(mdl) + + out <- out[[idx]] # Subset to the required timestep + + ggplot2::ggplot() + + ggplot2::geom_line(data = out[[2]], mapping = ggplot2::aes(x = .data$Betas, y = .data$y, colour = .data$Species), linewidth = 1) + + ggplot2::geom_line(data = out[[1]], mapping = ggplot2::aes(x = .data$x, y = .data$y), linewidth = 1.2) + + ggplot2::theme_bw() + + ggplot2::theme(plot.margin=grid::unit(c(0,0,0,0), "mm")) + + ggplot2::labs(x = expression('log' [10] * PPMR), + y = "Zoop. Biomass Proportion", subtitle = "PPMR") + + ggplot2::geom_vline(data = out[[1]], mapping = ggplot2::aes(xintercept = .data$mn_beta), colour = 'black') + + ggplot2::scale_x_continuous(expand = c(0, 0)) + + ggplot2::scale_y_continuous(expand = c(0, 0)) + + ggplot2::scale_colour_manual(values = c("Flagellates" = mdl$param$Groups$PlotColour[mdl$param$Groups$Species=="Flagellates"], + "Ciliates" = mdl$param$Groups$PlotColour[mdl$param$Groups$Species=="Ciliates"], + "Larvaceans" = mdl$param$Groups$PlotColour[mdl$param$Groups$Species=="Larvaceans"], + "Salps" = mdl$param$Groups$PlotColour[mdl$param$Groups$Species=="Salps"], + "Jellyfish" = mdl$param$Groups$PlotColour[mdl$param$Groups$Species=="Jellyfish"], + "CarnCopepods" = mdl$param$Groups$PlotColour[mdl$param$Groups$Species=="CarnCopepods"], + "Chaetognaths" = mdl$param$Groups$PlotColour[mdl$param$Groups$Species=="Chaetognaths"], + "Euphausiids" = mdl$param$Groups$PlotColour[mdl$param$Groups$Species=="Euphausiids"], + "OmniCopepods" = mdl$param$Groups$PlotColour[mdl$param$Groups$Species=="OmniCopepods"])) +} + +#' Plot Size Spectra for ZooMSS Results +#' +#' @title Visualize abundance size spectra across functional groups +#' @description Creates a log-log plot of abundance versus body size for all functional groups, +#' showing the classic size spectrum pattern in marine ecosystems. +#' @details This function visualizes the abundance size spectrum by: +#' - Converting abundance data to long format with body weights +#' - Filtering out zero abundances to focus on active size classes +#' - Creating log-log plots colored by functional group +#' - Using species-specific colors defined in the Groups parameter table +#' +#' Size spectra are fundamental patterns in marine ecology, typically showing +#' declining abundance with increasing body size. This visualization helps +#' assess model realism and identify dominant size classes within each +#' functional group. +#' +#' @param mdl ZooMSS results object containing model outputs and parameters +#' @param by Character string specifying the metric to plot. Options: "abundance", "biomass", "mortality", "growth" (default: "abundance") +#' @param n_years The number of years (from the end) over which to average the size spectra +#' +#' @return ggplot object showing log abundance vs log body weight by species +#' @export +#' +#' @examples +#' \dontrun{ +#' # After running ZooMSS model +#' results <- zoomss_model(input_params, Groups) +#' size_plot <- plotSizeSpectra(results) +#' print(size_plot) +#' } +#' +plotSizeSpectra <- function(mdl, by = "abundance", n_years = 10) { + + species <- averageTimeSeries(mdl, var = by, n_years = n_years) + + rownames(species) <- mdl$param$Groups$Species + species <- tibble::as_tibble(t(species)) + + species <- species %>% + tibble::add_column("Weight" = mdl$param$w) %>% + tidyr::pivot_longer(-"Weight", names_to = "Species", values_to = by) %>% + dplyr::filter(.data[[by]] > 0) %>% + dplyr::mutate(Species = factor(.data$Species, levels = mdl$param$Groups$Species)) + + ggplot2::ggplot(data = species, + mapping = ggplot2::aes(x = log10(.data$Weight), + y = log10(.data[[by]]), + colour = .data$Species)) + + ggplot2::geom_line() + + ggplot2::geom_point() + + ggplot2::scale_color_manual(values = mdl$param$Groups$PlotColour) + + ggplot2::theme_bw() + + ggplot2::labs(subtitle = paste(stringr::str_to_title(by), "Spectrum")) + +} + +#' Plot Time Series Data for ZooMSS Results +#' +#' @title Unified function to visualize time series changes for different metrics +#' @description Creates time series plots showing how abundance, biomass, mortality, or growth +#' rates of functional groups change throughout the ZooMSS simulation period. +#' @details This function creates time series visualizations by: +#' - **Abundance**: Summing abundances across size classes, log-transformed y-axis +#' - **Biomass**: Calculating biomass (abundance × weight), with optional stacking and proportional scaling +#' - **Mortality**: Averaging predation mortality rates across size classes +#' - **Growth**: Averaging growth rates across size classes, log-transformed y-axis +#' +#' All plots use species-specific colors and filter out zero values. Time series plots help identify: +#' - Equilibration time for model runs +#' - Seasonal or cyclical patterns in ecological metrics +#' - Relative patterns between functional groups +#' - Model stability and convergence behavior +#' +#' @param mdl ZooMSS results object containing model outputs with time series data +#' @param by Character string specifying the metric to plot. Options: "abundance", "biomass", "mortality", "growth" (default: "abundance") +#' @param species Character vector of species names to include. If NULL, all species included (default: NULL, applies to all metrics) +#' @param type Character vector of plot type. Use `line` for the default line plot, `stack` or `fill` (as per geom_area) for stacked or proportional plots. (default: "line") +#' @param transform Character vector of the required y-axis transformation. Options from `scale_*_continuous` (Default: "identity). +#' +#' @return ggplot object showing the requested time series by species +#' @export +#' +#' @examples +#' \dontrun{ +#' # After running ZooMSS model +#' results <- zoomss_model(input_params, Groups) +#' +#' # Plot different metrics +#' abundance_plot <- plotTimeSeries(results, by = "abundance", transform = "log10") +#' biomass_plot <- plotTimeSeries(results, by = "biomass", transform = "log10") +#' mortality_plot <- plotTimeSeries(results, by = "mortality") +#' growth_plot <- plotTimeSeries(results, by = "growth") +#' +#' stacked_plot <- plotTimeSeries(results, by = "biomass", type = "stack") +#' prop_plot <- plotTimeSeries(results, by = "biomass", type = "fill") +#' +#' # Focus on specific species (works for all metrics) +#' copepod_plot <- plotTimeSeries(results, by = "biomass", +#' species = c("OmniCopepods", "CarnCopepods")) +#' abundance_copepods <- plotTimeSeries(results, by = "abundance", +#' species = c("OmniCopepods", "CarnCopepods")) +#' mortality_copepods <- plotTimeSeries(results, by = "mortality", +#' species = c("OmniCopepods", "CarnCopepods")) +#' growth_copepods <- plotTimeSeries(results, by = "growth", +#' species = c("OmniCopepods", "CarnCopepods")) +#' } +#' +plotTimeSeries <- function(mdl, by = "abundance", type = "line", + transform = "identity", species = NULL) { + + # Validate inputs + assertthat::assert_that( + is.list(mdl), + msg = "mdl must be a list." + ) + + assertthat::assert_that( + "abundance" %in% names(mdl), + msg = "Time series data not available. Model may not have been run correctly." + ) + assertthat::assert_that( + by %in% c("abundance", "biomass", "mortality", "growth"), + msg = paste0("'by' must be one of: ", paste(c("abundance", "biomass", "mortality", "growth"), collapse = ", ")) + ) + + assertthat::assert_that( + type %in% c("line", "stack", "fill"), + msg = paste0("'type' must be one of: ", paste(c("line", "stack", "fill"), collapse = ", ")) + ) + + assertthat::assert_that( + transform %in% c("identity", "log", "log10", "log1p", "log2", "logit"), + msg = paste0("'transform' must be one of: ", paste(c(c("identity", "log", "log10", "log1p", "log2", "logit")), collapse = ", ")) + ) + + assertthat::assert_that( + is.null(species) || all(species %in% mdl$param$Groups$Species), + msg = paste0("All elements of 'species' must be in: ", paste(mdl$param$Groups$Species, collapse = ", ")) + ) + + # Calculate data based on requested variable + data_matrix <- switch( by, + "abundance" = mdl$abundance %>% reduceSize(), + "biomass" = mdl$biomass %>% reduceSize(), + "mortality" = mdl$mortality %>% reduceSize(method = "mean"), + "growth" = mdl$growth %>% reduceSize(method = "mean") + ) + + # Set up data frame + colnames(data_matrix) <- mdl$param$Groups$Species + data_df <- tibble::as_tibble(data_matrix) + data_df$Time <- mdl$time + + # Filter species if specified + if (!is.null(species)) { + data_df <- data_df[, c("Time", species)] + } + + # Convert to long format + data_long <- data_df %>% + tidyr::pivot_longer(-"Time", names_to = "Species", values_to = by) %>% + dplyr::filter(!!rlang::sym(by) > 0) %>% + dplyr::mutate(Species = factor(.data$Species, levels = mdl$param$Groups$Species)) + + # Get colors for plotting + if (!is.null(species)) { + species_indices <- match(intersect(species, mdl$param$Groups$Species), mdl$param$Groups$Species) + plot_colors <- mdl$param$Groups$PlotColour[species_indices] + names(plot_colors) <- mdl$param$Groups$Species[species_indices] + } else { + plot_colors <- mdl$param$Groups$PlotColour + names(plot_colors) <- mdl$param$Groups$Species + } + + + # Do plotting + if (type %in% c("fill", "stack")) { + + # Stacked and proportion area plot for any metric + gg <- ggplot2::ggplot(data = data_long, + mapping = ggplot2::aes(x = .data$Time, + y = !!rlang::sym(by), + fill = .data$Species)) + + ggplot2::geom_area(position = type, alpha = 0.7) + + ggplot2::scale_fill_manual(values = plot_colors) + + ggplot2::scale_y_continuous(transform = transform, expand = c(0, 0)) + + } else if (type == "line") { + + gg <- ggplot2::ggplot(data = data_long, + mapping = ggplot2::aes(x = .data$Time, + y = !!rlang::sym(by), + colour = .data$Species)) + + ggplot2::scale_y_continuous(transform = transform) + + ggplot2::geom_line(linewidth = 1) + + # ggplot2::geom_point(size = 1.2) + + ggplot2::scale_color_manual(values = plot_colors) + + } + + gg <- gg + + ggplot2::theme_bw() + + ggplot2::scale_x_continuous(expand = c(0, 0)) + + ggplot2::labs(y = stringr::str_to_sentence(by)) + + ggplot2::xlab("Time (years)") + return(gg) +} + + + + + + +#' Plot Environmental Time Series +#' +#' @title Plot environmental forcing data +#' @description Creates plots of sea surface temperature and chlorophyll time series +#' for visualizing environmental forcing data used in ZooMSS model runs. +#' @details This function creates two separate plots with different y-axes scales: +#' - SST plot (red line) with temperature in deg C +#' - Chlorophyll plot (green line) with concentration in mg/m^3 +#' +#' The plots can be combined using the patchwork package if available, otherwise +#' separate plots are returned as a list. This helps users visualize the +#' environmental forcing that drives ZooMSS model dynamics. +#' +#' @param env_data Environmental data frame with time, sst, chl columns +#' +#' @return ggplot object (if patchwork available) or list of two ggplot objects +#' @export +#' +#' @examples +#' # Create sample data and plot +#' env_data <- data.frame( +#' time = 1:100, +#' dt = 0.01, +#' sst = 15 + 3*sin(2*pi*(1:100)/50), +#' chl = 0.5 + 0.2*cos(2*pi*(1:100)/50) +#' ) +#' plots <- plotEnvironment(env_data) +#' +plotEnvironment <- function(env_data) { + + # Convert to long format for plotting + env_long <- tidyr::pivot_longer(env_data, + cols = c("sst", "chl"), + names_to = "variable", + values_to = "value") + + # Create separate y-axes for SST and chlorophyll + p1 <- ggplot2::ggplot(data = dplyr::filter(env_long, .data$variable == "sst"), + ggplot2::aes(x = .data$time, y = .data$value)) + + ggplot2::geom_line(color = "red", linewidth = 1) + + ggplot2::labs(y = "SST (deg C)", title = "Environmental Forcing") + + ggplot2::theme_bw() + + ggplot2::theme(axis.title.x = ggplot2::element_blank()) + + p2 <- ggplot2::ggplot(data = dplyr::filter(env_long, .data$variable == "chl"), + ggplot2::aes(x = .data$time, y = .data$value)) + + ggplot2::geom_line(color = "green", linewidth = 1) + + ggplot2::labs(x = "Time (years)", y = "Chlorophyll (mg/m^3)") + + ggplot2::theme_bw() + + # Combine plots + if (requireNamespace("patchwork", quietly = TRUE)) { + return(patchwork::wrap_plots(p1, p2, ncol = 1)) + } else { + cat("Install patchwork package to combine plots\n") + return(list(sst_plot = p1, chl_plot = p2)) + } +} + diff --git a/R/zoomss_run.R b/R/zoomss_run.R new file mode 100644 index 0000000..1328a6a --- /dev/null +++ b/R/zoomss_run.R @@ -0,0 +1,269 @@ +#' Run ZooMSS Model Forward in Time +#' +#' @title Execute the main ZooMSS simulation loop with dynamic environmental forcing +#' @description Runs the ZooMSS model forward in time, updating environmental conditions +#' and population dynamics at each time step using the McKendrick-von Foerster framework. +#' @details This is the core simulation engine of ZooMSS that: +#' +#' **Environmental Dynamics:** +#' - Updates phytoplankton abundance spectrum based on chlorophyll time series +#' - Applies temperature effects on zooplankton and fish metabolism +#' - Recalculates feeding kernels with current environmental conditions +#' +#' **Population Dynamics:** +#' - Solves McKendrick-von Foerster equation for size-structured growth +#' - Updates feeding interactions between all size classes and groups +#' - Calculates mortality from predation, senescence, and fishing +#' - Handles recruitment and boundary conditions for each functional group +#' +#' **Time Integration:** +#' - Processes model through all time steps with adaptive environmental forcing +#' - Saves output at specified intervals for memory efficiency +#' - Maintains mass balance and numerical stability throughout simulation +#' +#' Unlike static models, this version dynamically updates phytoplankton spectra +#' and temperature effects at each time step based on provided environmental data. +#' +#' @param model Model object created by zoomss_setup containing: +#' - param: Complete parameter list with environmental time series +#' - Feeding kernels and biological rate parameters +#' - Initial conditions and model structure +#' +#' @return List containing complete model output: +#' \itemize{ +#' \item param: Model parameters used in simulation +#' \item N: Abundance time series (time x groups x size classes) +#' \item gg: Growth rate time series +#' \item diet: Diet composition time series +#' \item Z: Mortality rate time series +#' \item time: Time values corresponding to saved results (accounting for isave) +#' \item w: Size class weights (g) +#' \item Additional time series data and model results +#' } +#' +#' @examples +#' \dontrun{ +#' # Set up model parameters and structure +#' params <- zoomss_params(Groups, input_params) +#' model <- zoomss_setup(params) +#' +#' # Run the simulation +#' results <- zoomss_run(model) +#' +#' # Access final abundances +#' final_abundances <- results$N[dim(results$N)[1],,] +#' } +#' +zoomss_run <- function(model){ + + # Pull out some useful parameters - just a shortcut + param <- model$param + dt <- model$param$dt[1] # Use scalar value instead of vector + dx <- model$param$dx # This should already be scalar + ngrps <- model$param$ngrps + ngrid <- model$param$ngrid + w <- model$param$w + W0 <- param$Groups$W0 + Wmax <- param$Groups$Wmax + fish_grps <- model$param$fish_grps + assim_eff <- model$assim_eff + dynam_dietkernel <- model$dynam_dietkernel + dynam_growthkernel <- model$dynam_growthkernel + dynam_mortkernel <- model$dynam_mortkernel + dynam_diffkernel <- model$dynam_diffkernel + + # Get pre-calculated phytoplankton and temperature time series from param + phyto_int <- param$phyto_int + phyto_slope <- param$phyto_slope + temp_eff_zoo <- param$temp_eff_zoo + temp_eff_fish <- param$temp_eff_fish + + curr_min_size <- vector() + curr_max_size <- vector() + for (i in 1:ngrps){ + curr_min_size[i] <- which(round(log10(w), digits = 2) == W0[i]) + curr_max_size[i] <- which(round(log10(w), digits = 2) == Wmax[i]) + } + + idx_iter <- 2:ngrid + idx <- 2:(ngrid-1) + itimemax <- param$itimemax # Number of time points to simulate + + if(length(param$zoo_grps) > 1){ # If there's only one zoo group, then you do not need w0idx. All this stuff gives you info about all zoo groups except the smallest zoo group. + w0idx <- which(W0 > min(W0) & is.na(param$Groups$Prop) == FALSE) + w0mins <- rep(0, length(w0idx)) + props_z <- param$Groups$Prop[w0idx] # Zooplankton proportions + + for(i in 1:length(w0idx)){ + # Which size class is the smallest size class for each functional group + w0mins[i] <- which(round(log10(w), digits = 2) == W0[w0idx[i]]) + } + } + + # Matrices for MvF and MvF-D numeric solution + A_iter <- matrix(0, nrow = ngrps, ncol = ngrid) + C_iter <- matrix(0, nrow = ngrps, ncol = ngrid) + S_iter <- matrix(0, nrow = ngrps, ncol = ngrid) + + A <- matrix(0, nrow = ngrps, ncol = ngrid) + B <- matrix(0, nrow = ngrps, ncol = ngrid) + C <- matrix(0, nrow = ngrps, ncol = ngrid) + S <- matrix(0, nrow = ngrps, ncol = ngrid) + + # Temporary Matrices that get updated each time step some of these saved for output + N <- matrix(model$N[1,,], nrow = ngrps, ncol = ngrid) # Abundances of functional groups, dim 1 = groups, dim 2 = size classes + + pb <- progress::progress_bar$new( + format = "ZooMSS Time Loop [:bar] :percent eta: :eta elapsed: :elapsed", + total = itimemax, + width = 60, + show_after = 0 + ) + + # BIG TIME LOOP + for (itime in 1:itimemax){ + + pb$tick() # Update progress bar + + # DYNAMIC ENVIRONMENTAL FORCING - Update for current time step + current_phyto_int <- phyto_int[itime] # Phytoplankton intercept (varies with chlorophyll) + current_phyto_slope <- phyto_slope[itime] # Phytoplankton slope (varies with chlorophyll) + + # Update phytoplankton abundance spectrum with current environmental parameters + model$nPP <- 10^(current_phyto_int)*(param$w_phyto^(current_phyto_slope)) + + # Update temperature effects matrix for all groups based on current SST + # Temperature affects feeding rates, growth, and mortality + if(param$num_zoo > 0) { + for(i in 1:param$num_zoo) { + zoo_grp_idx <- param$zoo_grps[i] + model$temp_eff[zoo_grp_idx, ] <- temp_eff_zoo[itime, i] + } + } + + if(param$num_fish > 0) { + for(i in 1:param$num_fish) { + fish_grp_idx <- param$fish_grps[i] + model$temp_eff[fish_grp_idx, ] <- temp_eff_fish[itime, i] + } + } + + # Calculate phytoplankton feeding using CURRENT environmental conditions + # These must be recalculated each time step because both nPP and temp_eff change + current_ingested_phyto <- model$temp_eff*(rowSums(sweep(model$phyto_growthkernel, 3, model$nPP, "*"), dims = 2)) + current_diff_phyto <- model$temp_eff^2*(rowSums(sweep(model$phyto_diffkernel, 3, model$nPP, "*"), dims = 2)) + + # Update senescence mortality with current temperature effects (no compounding - always from base) + model$M_sb <- model$M_sb_base * model$temp_eff + + # Calculate multipliers for growth, predation, and diffusion + growth_multiplier <- colSums(N * assim_eff) # 1 x n_sizes + predation_multiplier <- N * model$temp_eff # n_species x n_sizes (now using updated temp_eff) + diffusion_multiplier <- colSums(N * (assim_eff^2)) # 1 x n_sizes + + ### DO GROWTH + # Apply temperature effects to growth kernel (consistent with model temperature scaling) + temp_growth_kernel <- sweep(dynam_growthkernel, c(1,2), model$temp_eff, '*') + dim(temp_growth_kernel) <- c(ngrps*ngrid, ngrid) + cs <- .colSums(growth_multiplier * t(temp_growth_kernel), m = ngrid, n = ngrps*ngrid) + dim(cs) <- c(ngrps, ngrid) + + gg <- current_ingested_phyto + cs + + ### DO MORTALITY + + sw2 <- sweep(dynam_mortkernel, c(2,3), predation_multiplier, '*') # n_sizes x n_species x n_sizes + ap2 <- aperm(sw2, c(2,3,1)) + M2 <- .colSums(colSums(ap2),ngrid,ngrid) # 1 x n_sizes + Z <- sweep(model$M_sb + model$fish_mort, 2, M2, '+') # Total dynamic spectrum mortality (n_species x n_sizes) + rm(sw2, ap2) + + + ### DO DIFFUSION + # Apply temperature effects to diffusion kernel (consistent with model temperature scaling) + temp_diff_kernel <- sweep(dynam_diffkernel, c(1,2), model$temp_eff^2, '*') + dim(temp_diff_kernel) <- c(ngrps*ngrid, ngrid) + cs <- .colSums(diffusion_multiplier * t(temp_diff_kernel), m = ngrid, n = ngrps*ngrid) + dim(cs) <- c(ngrps, ngrid) + diff <- current_diff_phyto + cs + + ### MvF WITH DIFFUSION ALGORITHM + # Numerical implementation matrices (for MvF without diffusion) + A_iter[,idx_iter] <- dt/dx * gg[,idx_iter-1] # Growth stuff + C_iter[,idx_iter] <- 1 + dt * Z[,idx_iter] + dt/dx * gg[,idx_iter] # Mortality + S_iter[,idx_iter] <- N[,idx_iter] # N at..... + N_iter <- N # Current Abundance + N_iter[1,1] <- N[1,1] # This forces R to make a copy of the variable. Otherwise N is linked to N_iter in the Rcpp code and they change together. + + # Numerical implementation matrices (for MvF WITH diffusion) + A[,idx] <- dt/dx * (gg[,idx-1] + diff[,idx-1] * (log(10)/2+1/(2*dx))) # Growth stuff + B[,idx] <- diff[,idx+1] * dt/(2*dx^2) # Diffusion term + C[,idx] <- 1 + dt * Z[,idx] + dt/dx*(gg[,idx] + diff[,idx] * (log(10)/2+1/dx)) # Mortality + S[,idx] <- N[,idx] + + # The original Base R code for the MvF equation + N <- zoomss_mvf(ngrps, curr_min_size, curr_max_size, + A_iter, C_iter, N_iter, S_iter, + A, B, C, N, S) + + #### Keep smallest fish community size class as equal to equivalent zooplankton size class + ### Keep smallest zooplankton size class abundnace for each group locked to others in size spectrum + if(length(param$zoo_grps) > 1){ # If you only have one zoo group, it will be locked to phyto spectrum so you do not need to do this + for(i in 1:length(w0idx)){ + w_min_curr <- w0mins[i] + exclude_mins <- w0idx[which(w0mins == w_min_curr)] + N[w0idx[i], w_min_curr] <- props_z[i] * sum(N[-exclude_mins, w_min_curr]) + } + } + + fish_mins <- unlist(lapply(W0[fish_grps], + function(x){which(round(log10(w), digits = 2) == x)})) + + if(length(fish_grps) > 1 & length(param$zoo_grps) > 1){ + N[fish_grps,fish_mins] <- (1/length(fish_grps))*(colSums(N[-fish_grps,fish_mins])) + }else{ + N[fish_grps, fish_mins] <- (1/length(fish_grps))*sum(N[-fish_grps, fish_mins]) + } + + + # Save results (at regular intervals AND always at the final time step): + # Save output at regular intervals only + save_this_step <- (itime %% param$isave) == 0 + + if(save_this_step){ + isav <- itime/param$isave + + ## Phytoplankton diet - calculate using CURRENT dynamic conditions + # Use current phytoplankton spectrum and temperature effects (both change each time step) + current_pico_diet <- model$temp_eff*(rowSums(sweep(model$phyto_dietkernel, 3, model$nPP*c(log10(model$param$w_phyto) < -11.5), "*"), dims = 2)) + current_nano_diet <- model$temp_eff*(rowSums(sweep(model$phyto_dietkernel, 3, model$nPP*c(log10(model$param$w_phyto) >= -11.5 & log10(model$param$w_phyto) < -8.5), "*"), dims = 2)) + current_micro_diet <- model$temp_eff*(rowSums(sweep(model$phyto_dietkernel, 3, model$nPP*c(log10(model$param$w_phyto) >= -8.5), "*"), dims = 2)) + + # Calculate total consumption by multiplying diet potential by current abundances + pico_phyto_diet <- rowSums(current_pico_diet*N) # Pico-phytoplankton consumption + nano_phyto_diet <- rowSums(current_nano_diet*N) # Nano-phytoplankton consumption + micro_phyto_diet <- rowSums(current_micro_diet*N) # Micro-phytoplankton consumption + + ## Functional group diet - use proper kernel-based calculation (consistent with model structure) + ### Create an ngrps*ngrid*ngrps*ngrid array of abundances, to save time without sweeps: dim1 = pred groups, dim 2 = pred sizes, dim 3 = prey groups, dim 4 = prey sizes + N_array_temp <- aperm(replicate(ngrid, N), c(3,1,2)) + N_array <- aperm(replicate(ngrps, N_array_temp), c(4,1,2,3)) + # Apply temperature effects to diet kernel like phytoplankton diets + temp_dynam_dietkernel <- sweep(dynam_dietkernel, c(1,2), model$temp_eff, "*") + dynam_diet <- rowSums(aperm(rowSums(sweep(temp_dynam_dietkernel*N_array, c(1,2), N, "*"), dims = 3), c(1,3,2)), dims = 2) + + # Save current time accounting for isave interval + model$time[isav] <- param$time[itime] + + model$N[isav,,] <- N # Save N by taxa and size + model$Z[isav,,] <- Z ## Save mortality + model$gg[isav,,] <- gg ## Save growth + + model$diet[isav,,1:3] <- cbind(pico_phyto_diet, nano_phyto_diet, micro_phyto_diet) + model$diet[isav,,c(4:(dim(param$Groups)[1]+3))] <- dynam_diet + + } + } # End of time loop + return(model) + +} diff --git a/R/zoomss_setup.R b/R/zoomss_setup.R new file mode 100644 index 0000000..2c9c001 --- /dev/null +++ b/R/zoomss_setup.R @@ -0,0 +1,282 @@ +#' Setup ZooMSS Model Structure and Feeding Kernels +#' +#' @title Initialize ZooMSS model components and calculate feeding interactions +#' @description Sets up the ZooMSS model structure by calculating feeding kernels, mortality +#' rates, and other model components that remain static during the simulation. +#' @details This function initializes the core ZooMSS model structure by calculating: +#' +#' **Static Components (calculated once):** +#' - Feeding preference kernels based on predator-prey size ratios +#' - Search volumes and encounter rates between size classes +#' - Baseline mortality rates (senescence, fishing) +#' - Initial abundance distributions for all functional groups +#' +#' **Dynamic Component Structures (updated during run):** +#' - Phytoplankton feeding kernels (structure calculated here, values updated with environment) +#' - Growth and diffusion kernels for zooplankton and fish interactions +#' - Diet and mortality tracking arrays +#' +#' **Model Architecture:** +#' - Size-structured populations across logarithmic size classes +#' - Multiple functional groups with different feeding behaviors +#' - Environmental coupling through phytoplankton and temperature +#' +#' The function separates static calculations (done once for efficiency) from +#' dynamic calculations (updated each time step in zoomss_run). +#' +#' @param param Complete parameter list created by zoomss_params containing: +#' - Groups: Functional group definitions and biological parameters +#' - Model dimensions (ngrps, ngrid, time parameters) +#' - Environmental forcing time series +#' - Physical and biological constants +#' +#' @return Model object containing: +#' \itemize{ +#' \item param: Input parameters (passed through) +#' \item dynam_xxx: Dynamic feeding kernel arrays for group interactions (where xxx = growthkernel, diffkernel, dietkernel, mortkernel) +#' \item phyto_xxx: Phytoplankton feeding kernel arrays (where xxx = growthkernel, diffkernel, dietkernel) +#' \item nPP: Initial phytoplankton abundance spectrum +#' \item M_sb_base: Baseline senescence mortality rates +#' \item fish_mort: Fishing mortality rates +#' \item assim_eff: Assimilation efficiency matrix +#' \item temp_eff: Temperature effect matrix (initialized) +#' \item N: Initial abundance arrays +#' \item time: Time array for storing time values (initialized as NA) +#' \item Additional model structure components +#' } +#' +#' @examples +#' \dontrun{ +#' # Create parameters for model setup +#' params <- zoomss_params(Groups, input_params) +#' +#' # Initialize model structure +#' model <- zoomss_setup(params) +#' +#' # Model is now ready for time integration with zoomss_run +#' results <- zoomss_run(model) +#' } +#' +zoomss_setup <- function(param){ + + ## Dynamic prey availability matrix: dim1 is predators, dim2 is predator size classes, + ## dim3 is prey groups, dim 4 is prey size classes. + dynam_theta <- array(1, dim = c(param$ngrps, param$ngrid, param$ngrps, param$ngrid)) + + + ## Makes the model object, full of constant functions for model + model <- list( + param = param, + + # Dynamic component kernels (these don't change with environment, only with abundances) + dynam_growthkernel = array(NA, dim = c(param$ngrps, param$ngrid, param$ngrid)), # predation on zoo and fish + dynam_diffkernel = array(NA, dim = c(param$ngrps, param$ngrid, param$ngrid)), # diffusion from zoo and fish consumption + dynam_dietkernel = array(NA, dim = c(param$ngrps, param$ngrid, param$ngrid)), # diet from zoo and fish + dynam_mortkernel = array(NA, dim = c(param$ngrps, param$ngrid, param$ngrid)), # mortality from predation on dynamic component + + # Phytoplankton kernels (these don't change with environment, only with phytoplankton spectrum) + phyto_growthkernel = array(NA, dim = c(param$ngrps, param$ngrid, param$ngridPP)), # predation on phytoplankton + phyto_diffkernel = array(NA, dim = c(param$ngrps, param$ngrid, param$ngridPP)), # diffusion from phytoplankton consumption + phyto_dietkernel = array(NA, dim = c(param$ngrps, param$ngrid, param$ngridPP)), # diet from phytoplankton + + # Phytoplankton spectrum - will be updated dynamically with current time step parameters + nPP = 10^(param$phyto_int[1])*(param$w_phyto^(param$phyto_slope[1])), # Phytoplankton abundance spectrum (dynamic) + + # Static mortality and group parameters + M_sb_base = matrix(0, nrow = param$ngrps, ncol = param$ngrid), # base senescence mortality (before temp effect) + fish_mort = matrix(0, nrow = param$ngrps, ncol = param$ngrid), # fishing mortality + + # Assimilation efficiency (constant) + assim_eff = matrix(param$Groups$GrossGEscale * param$Groups$Carbon, nrow = param$ngrps, ncol = length(param$w)), + + # Temperature effects matrix - initialize with first timestep values + temp_eff = matrix(1, nrow = param$ngrps, ncol = param$ngrid), # Will be updated dynamically in run + M_sb = matrix(0, nrow = param$ngrps, ncol = param$ngrid), # senescence mortality with temp effect + + # Phytoplankton feeding parameters (for maintaining compatibility) + phyto_theta = matrix(1, nrow = param$ngrps, ncol = param$ngrid, byrow = TRUE), + + time = array(NA, dim = c(param$nsave)), # time values corresponding to saved results + N = array(NA, dim = c(param$nsave, param$ngrps, param$ngrid)), # dynamic abundance spectrum + Z = array(NA, dim = c(param$nsave, param$ngrps, param$ngrid)), # Total mortality + gg = array(NA, dim = c(param$nsave, param$ngrps, param$ngrid)), # Growth + diet = array(NA, dim = c(param$nsave, c(param$ngrps), c(param$ngrps+3))) # diet + + ) + + # Set phyto_theta for carnivores + model$phyto_theta[which(param$Groups$FeedType == 'Carnivore'),] <- 0 # Carnivorous groups can't eat phyto + + # GGE for different groups + assim_phyto <- (param$Groups$GrossGEscale) * param$cc_phyto # Phytoplankton + + #### INITIAL DYNAMIC POPULATION ABUNDANCES + # Use the first time step for initial conditions + a_dynam <- 10^(param$phyto_int[1])*(param$w[1]^(param$phyto_slope[1]+1)) # calculate coefficient for initial dynamic spectrum + + # Initial abundances form a continuation of the plankton spectrum, with a slope of -1 + tempN <- matrix(a_dynam*(param$w)^-1, nrow = param$ngrps, ncol = param$ngrid, byrow = TRUE) + props_z <- param$Groups$Prop[param$zoo_grps] # Zooplankton proportions + tempN[param$zoo_grps,] <- props_z * tempN[param$zoo_grps,] # Set abundances of diff zoo groups based on smallest size class proportions + tempN[param$fish_grps,] <- (1/param$num_fish) * tempN[param$fish_grps,] # Set abundandances of fish groups based on smallest size class proportions + + # For each group, set densities at w > Winf and w < Wmin to 0 + tempN[unlist(tapply(param$w_log10, seq_along(param$w), function(wx,Winf) Winf < wx, Winf = param$Groups$Wmax))] <- 0 + tempN[unlist(tapply(param$w_log10, seq_along(param$w), function(wx,Wmin) Wmin > wx, Wmin = param$Groups$W0))] <- 0 + model$N[1,,] <- tempN + + # Fishing mortality (yr^-1) + for(g in 1:param$ngrps){ + model$fish_mort[g,match(param$Groups$Fmort_W0[g], param$w_log10):match(param$Groups$Fmort_Wmax[g], param$w_log10)] <- param$Groups$Fmort[g] + } + + ### MATRICES FOR LOG TRANSFORM OF EQUATION (these don't change with environment) + # Dynamic component matrices + gg_log_t_dynam <- ((param$w^-1) %*% t(param$w))/log(10) # Growth + diff_log_t_dynam <- ((param$w^-2) %*% t(param$w^2))/log(10) # Diffusion + diet_log_t_dynam <- matrix(param$w, nrow = length(param$w), ncol = length(param$w), byrow = TRUE) # Diet/ingestion + + # Phytoplankton component matrices + gg_log_t_phyto <- ((param$w^-1) %*% t(param$w_phyto))/log(10) # Growth from phytoplankton + diff_log_t_phyto <- ((param$w^-2) %*% t(param$w_phyto^2))/log(10) # Diffusion from phytoplankton + diet_log_t_phyto <- matrix(param$w_phyto, nrow = length(param$w), ncol = length(param$w_phyto), byrow = TRUE) # Diet from phytoplankton + + ### PREDATION KERNELS FOR DYNAMIC SPECTRUM (constant across time) + dynam_pred_weight_matrix <- matrix(param$w, nrow = param$ngrid, ncol = param$ngrid) + dynam_prey_weight_matrix <- matrix(param$w, nrow = param$ngrid, ncol = param$ngrid, byrow = TRUE) + + ### PREDATION KERNELS FOR PHYTOPLANKTON (constant across time) + phyto_pred_weight_matrix <- matrix(param$w, nrow = param$ngrid, ncol = param$ngridPP) + phyto_prey_weight_matrix <- matrix(param$w_phyto, nrow = param$ngrid, ncol = param$ngridPP, byrow = TRUE) + + ## Search Volume storage + SearchVol <- matrix(NA, nrow = param$ngrps, ncol = param$ngrid) # Search volume + + # Simpson's Rule matrices for growth, diffusion and mortality integrals + simp_dynam <- array(1, dim = param$ngrid) + simp_dynam[c(seq(2, param$ngrid-1,2))] <- 4 + simp_dynam[c(seq(3, param$ngrid-1,2))] <- 2 + sm_dynam <- matrix(simp_dynam, nrow = param$ngrid, ncol = param$ngrid, byrow = TRUE) * (param$dx/3) + + # Simpson's Rule for phytoplankton + simp_phyto <- array(1, dim = param$ngridPP) + simp_phyto[c(seq(2, param$ngridPP-1,2))] <- 4 + simp_phyto[c(seq(3, param$ngridPP-1,2))] <- 2 + sm_phyto <- matrix(simp_phyto, nrow = param$ngrid, ncol = param$ngridPP, byrow = TRUE) * (param$dx/3) + + #### CALCULATES CONSTANT BITS OF THE MODEL FUNCTIONS FOR EACH GROUP + for(i in 1:param$ngrps){ + ## Base senescence mortality (before temperature effect) + if(param$Groups$Type[i] == "Zooplankton"){ + model$M_sb_base[i,] <- param$ZSpre*(param$w/(10^(param$Groups$Wmat[i])))^param$ZSexp + model$M_sb_base[i, 10^(param$Groups$Wmax[i]) < param$w] <- 0 + model$M_sb_base[i, 10^(param$Groups$Wmat[i]) > param$w] <- 0 + } + + if(param$Groups$Type[i] == "Fish"){ + model$M_sb_base[i,] <- 0.1*param$ZSpre*(param$w/(10^(param$Groups$Wmat[i])))^param$ZSexp + model$M_sb_base[i, 10^(param$Groups$Wmax[i]) < param$w] <- 0 + model$M_sb_base[i, 10^(param$Groups$Wmat[i]) > param$w] <- 0 + } + + ### Search volume + SearchVol[i,] <- (param$Groups$SearchCoef[i])*(param$w^(param$Groups$SearchExp[i])) + SearchVol[i, 10^(param$Groups$Wmax[i]) < param$w] <- 0 + SearchVol[i, 10^(param$Groups$W0[i]) > param$w] <- 0 + + ### Predation Kernels for dynamic spectrum (these don't change with environment) + if(!is.na(param$Groups$PPMRscale[i])){ # If group has a PPMR scaling value (m-value) + # Calculate PPMR for zooplankton, which changes according to body-size (Wirtz, 2012) + D.z <- 2*(3*param$w*1e12/(4*pi))^(1/3) # convert body mass g to ESD (um) + betas <- (exp(0.02*log(D.z)^2 - param$Groups$PPMRscale[i] + 1.832))^3 # Wirtz's equation + beta_mat_dynam <- matrix(betas, nrow = param$ngrid, ncol = param$ngrid) + + # Calculate feeding kernels + sp_dynam_predkernel <- exp(-0.5*(log((beta_mat_dynam*dynam_prey_weight_matrix)/ + dynam_pred_weight_matrix)/param$Groups$FeedWidth[i])^2)/ + sqrt(2*pi*param$Groups$FeedWidth[i]^2) + + # The feeding kernel of filter feeders is not expected to change much with increasing size so we fix it here + if(param$Groups$FeedType[i] == "FilterFeeder"){ + w0idx <- which(param$Groups$W0[i] == param$w_log10) + sp_dynam_predkernel <- matrix(sp_dynam_predkernel[w0idx,], nrow = param$ngrid, ncol = param$ngrid, byrow = TRUE) + rm(w0idx) + } + + } else { # If group is fish + beta_mat_dynam <- matrix(param$Groups$PPMR[i], nrow = param$ngrid, ncol = param$ngrid) + + # Calculate feeding kernels + sp_dynam_predkernel <- exp(-0.5*(log((beta_mat_dynam*dynam_prey_weight_matrix)/ + dynam_pred_weight_matrix)/param$Groups$FeedWidth[i])^2)/ + sqrt(2*pi*param$Groups$FeedWidth[i]^2) + } + + ### PHYTOPLANKTON FEEDING KERNELS + # Calculate phytoplankton predation kernel - consistent with model PPMR scaling + if(!is.na(param$Groups$PPMRscale[i])){ # If group has a PPMR scaling value (m-value) + # Calculate PPMR for zooplankton, which changes according to body-size (Wirtz, 2012) + D.z <- 2*(3*param$w*1e12/(4*pi))^(1/3) # convert body mass g to ESD (um) + betas <- (exp(0.02*log(D.z)^2 - param$Groups$PPMRscale[i] + 1.832))^3 # Wirtz's equation + beta_mat_phyto <- matrix(betas, nrow = param$ngrid, ncol = param$ngridPP) + } else { # If group is fish + beta_mat_phyto <- matrix(param$Groups$PPMR[i], nrow = param$ngrid, ncol = param$ngridPP) + } + + sp_phyto_predkernel <- exp(-0.5*(log((beta_mat_phyto*phyto_prey_weight_matrix)/ + phyto_pred_weight_matrix)/param$Groups$FeedWidth[i])^2)/ + sqrt(2*pi*param$Groups$FeedWidth[i]^2) + + # For filter feeders, fix the phytoplankton feeding kernel too + if(param$Groups$FeedType[i] == "FilterFeeder"){ + w0idx <- which(param$Groups$W0[i] == param$w_log10) + sp_phyto_predkernel <- matrix(sp_phyto_predkernel[w0idx,], nrow = param$ngrid, ncol = param$ngridPP, byrow = TRUE) + } + + ### GROWTH INTEGRAL CONSTANTS FOR PHYTOPLANKTON + model$phyto_growthkernel[i,,] <- matrix(SearchVol[i,], nrow = param$ngrid, ncol = param$ngridPP) * + sp_phyto_predkernel * gg_log_t_phyto * sm_phyto + + ### DIET INTEGRAL CONSTANTS FOR PHYTOPLANKTON + model$phyto_dietkernel[i,,] <- matrix(SearchVol[i,], nrow = param$ngrid, ncol = param$ngridPP)* + sp_phyto_predkernel*diet_log_t_phyto*sm_phyto + + ### DIFFUSION INTEGRAL CONSTANTS FOR PHYTOPLANKTON + model$phyto_diffkernel[i,,] <- matrix(SearchVol[i,], nrow = param$ngrid, ncol = param$ngridPP)* + sp_phyto_predkernel*diff_log_t_phyto*sm_phyto + + ### GROWTH INTEGRAL CONSTANTS FOR DYNAMIC SPECTRUM + model$dynam_growthkernel[i,,] <- matrix(SearchVol[i,], nrow = param$ngrid, ncol = param$ngrid)* + sp_dynam_predkernel*gg_log_t_dynam*sm_dynam + + ### DIET INTEGRAL CONSTANTS FOR DYNAMIC SPECTRUM + model$dynam_dietkernel[i,,] <- matrix(SearchVol[i,], nrow = param$ngrid, ncol = param$ngrid)* + sp_dynam_predkernel*diet_log_t_dynam*sm_dynam + + ### DIFFUSION INTEGRAL CONSTANTS FOR DYNAMIC SPECTRUM + model$dynam_diffkernel[i,,] <- matrix(SearchVol[i,], nrow = param$ngrid, ncol = param$ngrid)* + sp_dynam_predkernel*diff_log_t_dynam*sm_dynam + + ### MORTALITY INTEGRAL CONSTANTS FOR DYNAMIC SPECTRUM + # Prey are rows, predators are columns + model$dynam_mortkernel[i,,] <- matrix(SearchVol[i,], nrow = param$ngrid, ncol = param$ngrid, byrow = TRUE)* + t(sp_dynam_predkernel)*sm_dynam + } + + # Transform mortkernel dimensions to match original model expectations + model$dynam_mortkernel <- aperm(model$dynam_mortkernel, c(2,1,3)) + + ## Incorporate carnivory (groups that can't eat phyto), temperature effects and gross growth efficiency (assim) + model$phyto_growthkernel <- sweep(sweep(model$phyto_growthkernel, c(1,2), model$phyto_theta, "*"), 1, assim_phyto, "*") + model$phyto_diffkernel <- sweep(sweep(model$phyto_diffkernel, c(1,2), model$phyto_theta, "*"), 1, assim_phyto^2, "*") + model$phyto_dietkernel <- sweep(sweep(model$phyto_dietkernel, c(1,2), model$phyto_theta, "*"), 1, 1, "*") + + ## Initialize M_sb with temperature effects applied (consistent with model structure) + model$M_sb <- model$temp_eff * model$M_sb_base # Incorporate temp effect on senescence mortality + + ## Convert diet kernel to 4D for proper calculation (consistent with model structure) + # We need four dimensions for diet matrix: pred groups x pred sizes x prey groups x prey sizes + model$dynam_dietkernel <- sweep(dynam_theta, c(1,2,4), model$dynam_dietkernel, "*") + + return(model) +} # End of Setup function diff --git a/README.Rmd b/README.Rmd new file mode 100644 index 0000000..6444a9a --- /dev/null +++ b/README.Rmd @@ -0,0 +1,57 @@ +--- +output: github_document +--- + + + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + fig.path = "man/figures/README-", + out.width = "100%" +) +``` + +# Zooplankton Model of Size Spectrum (ZooMSS) + + + +[![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental) +[![Windows](https://github.com/MathMarEcol/zoomss/actions/workflows/Windows.yaml/badge.svg)](https://github.com/MathMarEcol/zoomss/actions/workflows/Windows.yaml) +[![Linux](https://github.com/MathMarEcol/zoomss/actions/workflows/Linux.yaml/badge.svg)](https://github.com/MathMarEcol/zoomss/actions/workflows/Linux.yaml) +[![MacOS](https://github.com/MathMarEcol/zoomss/actions/workflows/MacOS.yaml/badge.svg)](https://github.com/MathMarEcol/zoomss/actions/workflows/MacOS.yaml) +[![issues - zoomss](https://img.shields.io/github/issues/MathMarEcol/zoomss)](https://github.com/MathMarEcol/zoomss/issues) +[![Codecov test coverage](https://codecov.io/gh/MathMarEcol/zoomss/graph/badge.svg)](https://app.codecov.io/gh/MathMarEcol/zoomss) + + +## Overview of ZooMSS + +The Zooplankton Model of Size Spectra (ZooMSS) is a functional size-spectrum model of the marine ecosystem (following Heneghan et al. 2016) to resolve phytoplankton, nine zooplankton functional groups (heterotrophic flagellates and ciliates, omnivorous and carnivorous copepods, larvaceans, euphausiids, salps, chaetognaths and jellyfish) and three size-based fish groups. Zooplankton functional groups are resolved using their body-size ranges, size-based feeding characteristics and carbon content, and the zooplankton community emerges from the model across global environmental gradients, depending on the functional traits of the different groups. + +We developed the Zooplankton Model of Size Spectra (ZooMSSv2) based on the prototype of Heneghan et al. (2016). ZooMSS uses the functional size-spectrum framework (Blanchard et al., 2017) to resolve the body size ranges, size-based feeding characteristics and carbon content of nine zooplankton groups and three fish groups. The model supports time-varying environmental conditions enabling studies of seasonal cycles, climate change scenarios, and ecosystem responses to environmental variability. + +ZooMSS represents the marine ecosystem as three communities: phytoplankton, zooplankton and fish. The zooplankton community consists of nine of the most abundant zooplankton groups, and the fish community was made up of a small, medium and large group. Dynamics of the phytoplankton are not explicitly resolved in the model, rather the mean size structure of the phytoplankton community is estimated directly from satellite chlorophyll a observations (Brewin et al., 2010; Barnes et al., 2011; Hirata et al., 2011). Abundances of the zooplankton and fish communities are driven by size-dependent processes of growth and mortality, with the temporal dynamics of each functional group governed by separate second-order McKendrick-von Foerster equations. + + +## Installation + +You can install the development version of zoomss from [GitHub](https://github.com/) with: + +``` r +# install.packages("pak") +pak::pak("MathMarEcol/zoomss") +``` + +## Publications + +1. Heneghan, R.F., Everett, J.D., Blanchard, J.L., Richardson, A.J., 2016. Zooplankton Are Not Fish: Improving Zooplankton Realism in Size-Spectrum Models Mediates Energy Transfer in Food Webs. Front. Mar. Sci. 3, 1–15. https://doi.org/10.3389/fmars.2016.00201 + +2. Heneghan, R.F., Everett, J.D., Sykes, P., Batten, S.D., Edwards, M., Takahashi, K., Suthers, I.M., Blanchard, J.L., Richardson, A.J., in review, A global size-spectrum model of the marine ecosystem that resolves zooplankton composition. Ecological Modelling + +## Getting Help + +If you encounter problems running the model, raise an issue on GitHub: https://github.com/MathMarEcol/ZoopSizeSpectraModel/issues + +If you find errors or want to improve the model, we'd love you to make the changes and submit a pull request for us to review and approve. + diff --git a/README.md b/README.md index fc04f8e..1086087 100644 --- a/README.md +++ b/README.md @@ -1,72 +1,83 @@ -# Model code for Zooplankton Model of Size Spectrum (ZooMSS) + -## Overview of ZooMSS - -The Zooplankton Model of Size Spectra (ZooMSS) is a functional size-spectrum model of the marine ecosystem (following Heneghan et al. 2016, ZooMSSv1) to resolve phytoplankton, nine zooplankton functional groups (heterotrophic flagellates and ciliates, omnivorous and carnivorous copepods, larvaceans, euphausiids, salps, chaetognaths and jellyfish) and three size-based fish groups. Zooplankton functional groups are resolved using their body-size ranges, size- based feeding characteristics and carbon content, and the zooplankton community emerges from the model across global environmental gradients, depending on the functional traits of the different groups. - -We developed the Zooplankton Model of Size Spectra version 2 (ZooMSSv2) based on the prototype of Heneghan et al. (2016). ZooMSSv2 uses the functional size-spectrum framework (Blanchard et al., 2017) to resolve the body size ranges, size-based feeding characteristics and carbon content of nine zooplankton groups and three fish groups. The model is run on 5° grid squares across the global ocean. For each region, the model is forced with the long- term mean satellite sea surface temperature and chlorophyll a from MODIS-Aqua. - -ZooMSSv2 represents the marine ecosystem as three communities: phytoplankton, zooplankton and fish. The zooplankton community consists of nine of the most abundant zooplankton groups, and the fish community was made up of a small, medium and large group. Dynamics of the phytoplankton are not explicitly resolved in the model, rather the mean size structure of the phytoplankton community is estimated directly from satellite chlorophyll a observations (Brewin et al., 2010; Barnes et al., 2011; Hirata et al., 2011). Abundances of the zooplankton and fish communities are driven by size-dependent processes of growth and mortality, with the temporal dynamics of each functional group governed by separate second- order McKendrick-von Foerster equations. - - -## How to run ZooMSS using `R` - -### Model Structure - -The model is split into 5 main files. - -1. Setup_RUN_NAME.R - Set up your own specific simulation. This is the only file you usually need to edit. - -2. fZooMSS_Model.R - The top-level model function which seuqentially runs the following 3 functions, and saves the output. +# Zooplankton Model of Size Spectrum (ZooMSS) - + fZooMSS_Params.R - Set all the parameter values for the model. - - + fZooMSS_Setup.R - Do all calculations which can be done in advance of the time loop. - - + fZooMSS_Run.R - Contains the time-dependent loop. + -### Input files + -ZooMSS requires two input files: +[![Lifecycle: +experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental) +[![Windows](https://github.com/MathMarEcol/zoomss/actions/workflows/Windows.yaml/badge.svg)](https://github.com/MathMarEcol/zoomss/actions/workflows/Windows.yaml) +[![Linux](https://github.com/MathMarEcol/zoomss/actions/workflows/Linux.yaml/badge.svg)](https://github.com/MathMarEcol/zoomss/actions/workflows/Linux.yaml) +[![MacOS](https://github.com/MathMarEcol/zoomss/actions/workflows/MacOS.yaml/badge.svg)](https://github.com/MathMarEcol/zoomss/actions/workflows/MacOS.yaml) +[![issues - +zoomss](https://img.shields.io/github/issues/MathMarEcol/zoomss)](https://github.com/MathMarEcol/zoomss/issues) +[![Codecov test +coverage](https://codecov.io/gh/MathMarEcol/zoomss/graph/badge.svg)](https://app.codecov.io/gh/MathMarEcol/zoomss) + -1. TestGroups.csv which contains all the taxa-specific parameter values, including size ranges. - -2. And RDS file which contains all environmental data for each grid cell. This includes chlorophyll a (chlo), sea surface temperature (sst), bathymetry (bathy), phytoplankton slope and intercept, and latitude/longitude which is useful for plotting. - - -### Running -To run the model, you simply need to provide the relevent information in Setup_RUN_NAME.R and run the script. - -### Plotting -Besides writing your own plotting routines, you can now easily plot the overall species-resolved size-spectra and the PPMRs. -Run using: -* `gg <- ZooMSS_Plot_SizeSpectra(dat)` -* `gg <- ZooMSS_Plot_PPMR(dat)` - -If you have saved the timesteps you can plot the timeseries: -* `gg <- ZooMSS_Plot_AbundTimeSeries(dat)` -* `gg <- ZooMSS_Plot_GrowthTimeSeries(dat)` -* `gg <- ZooMSS_Plot_PredTimeSeries(dat)` -* `gg_list <- fZooMSS_Plot_RuntimeAveraging(file_name)` -* `fZooMSS_Plot_Wavelet(file_name, species_name)` - -where `dat` is the model output list, and `gg` is a ggplot output from the plotting routines. +## Overview of ZooMSS -### ZooMSS Dashboard -Assuming you have saved all the time-steps (using `SaveTimeSteps <- TRUE`) you can explore the output using our newly created **ZooMSS Dashboard**. To access, go here: https://jaseeverett.shinyapps.io/ZooMSS_Dashboard/. Please drop us a line with any comments or ideas. +The Zooplankton Model of Size Spectra (ZooMSS) is a functional +size-spectrum model of the marine ecosystem (following Heneghan et +al. 2016) to resolve phytoplankton, nine zooplankton functional groups +(heterotrophic flagellates and ciliates, omnivorous and carnivorous +copepods, larvaceans, euphausiids, salps, chaetognaths and jellyfish) +and three size-based fish groups. Zooplankton functional groups are +resolved using their body-size ranges, size-based feeding +characteristics and carbon content, and the zooplankton community +emerges from the model across global environmental gradients, depending +on the functional traits of the different groups. + +We developed the Zooplankton Model of Size Spectra (ZooMSSv2) based on +the prototype of Heneghan et al. (2016). ZooMSS uses the functional +size-spectrum framework (Blanchard et al., 2017) to resolve the body +size ranges, size-based feeding characteristics and carbon content of +nine zooplankton groups and three fish groups. The model supports +time-varying environmental conditions enabling studies of seasonal +cycles, climate change scenarios, and ecosystem responses to +environmental variability. + +ZooMSS represents the marine ecosystem as three communities: +phytoplankton, zooplankton and fish. The zooplankton community consists +of nine of the most abundant zooplankton groups, and the fish community +was made up of a small, medium and large group. Dynamics of the +phytoplankton are not explicitly resolved in the model, rather the mean +size structure of the phytoplankton community is estimated directly from +satellite chlorophyll a observations (Brewin et al., 2010; Barnes et +al., 2011; Hirata et al., 2011). Abundances of the zooplankton and fish +communities are driven by size-dependent processes of growth and +mortality, with the temporal dynamics of each functional group governed +by separate second-order McKendrick-von Foerster equations. + +## Installation + +You can install the development version of zoomss from +[GitHub](https://github.com/) with: + +``` r +# install.packages("pak") +pak::pak("MathMarEcol/zoomss") +``` ## Publications -1. Heneghan, R.F., Everett, J.D., Blanchard, J.L., Richardson, A.J., 2016. Zooplankton Are Not Fish: Improving Zooplankton Realism in Size-Spectrum Models Mediates Energy Transfer in Food Webs. Front. Mar. Sci. 3, 1–15. https://doi.org/10.3389/fmars.2016.00201 - -2. Heneghan, R.F., Everett, J.D., Sykes, P., Batten, S.D., Edwards, M., Takahashi, K., Suthers, I.M., Blanchard, J.L., Richardson, A.J., in review, A global size-spectrum model of the marine ecosystem that resolves zooplankton composition. Ecological Modelling +1. Heneghan, R.F., Everett, J.D., Blanchard, J.L., Richardson, + A.J., 2016. Zooplankton Are Not Fish: Improving Zooplankton Realism + in Size-Spectrum Models Mediates Energy Transfer in Food Webs. + Front. Mar. Sci. 3, 1–15. +2. Heneghan, R.F., Everett, J.D., Sykes, P., Batten, S.D., Edwards, M., + Takahashi, K., Suthers, I.M., Blanchard, J.L., Richardson, A.J., in + review, A global size-spectrum model of the marine ecosystem that + resolves zooplankton composition. Ecological Modelling ## Getting Help -If you are running the model come across a problem, raise an issue on GitHub: https://github.com/MathMarEcol/ZoopSizeSpectraModel/issues - -If you find some errors, or just want to improve the model, we'd love you to go ahead and make the changes and then submit a pull request for us to check and approve. - +If you encounter problems running the model, raise an issue on GitHub: + +If you find errors or want to improve the model, we’d love you to make +the changes and submit a pull request for us to review and approve. diff --git a/UserManual/ZooMSS_User_Manual.Rmd b/UserManual/ZooMSS_User_Manual.Rmd deleted file mode 100644 index eeae992..0000000 --- a/UserManual/ZooMSS_User_Manual.Rmd +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: "ZooMSS User Manual" -author: "The UQ ZooMSS Team" -date: "18/03/2020" -output: pdf_document ---- - -```{r setup, include=FALSE} -knitr::opts_chunk$set(echo = TRUE) -``` - -Note: This is still very much a work in progress. - -## Overview of ZooMSS - -The Zooplankton Model of Size Spectra (ZooMSS) is a functional size-spectrum model of the marine ecosystem (following Heneghan et al. 2016, ZooMSSv1) to resolve phytoplankton, nine zooplankton functional groups (heterotrophic flagellates and ciliates, omnivorous and carnivorous copepods, larvaceans, euphausiids, salps, chaetognaths and jellyfish) and three size-based fish groups. Zooplankton functional groups are resolved using their body-size ranges, size- based feeding characteristics and carbon content, and the zooplankton community emerges from the model across global environmental gradients, depending on the functional traits of the different groups. - -We developed the Zooplankton Model of Size Spectra version 2 (ZooMSSv2) based on the prototype of Heneghan et al. (2016). ZooMSSv2 uses the functional size-spectrum framework (Blanchard et al., 2017) to resolve the body size ranges, size-based feeding characteristics and carbon content of nine zooplankton groups and three fish groups. The model is run on 5° grid squares across the global ocean. For each region, the model is forced with the long- term mean satellite sea surface temperature and chlorophyll a from MODIS-Aqua. - -ZooMSSv2 represents the marine ecosystem as three communities: phytoplankton, zooplankton and fish. The zooplankton community consists of nine of the most abundant zooplankton groups, and the fish community was made up of a small, medium and large group. Dynamics of the phytoplankton are not explicitly resolved in the model, rather the mean size structure of the phytoplankton community is estimated directly from satellite chlorophyll a observations (Brewin et al., 2010; Barnes et al., 2011; Hirata et al., 2011). Abundances of the zooplankton and fish communities are driven by size-dependent processes of growth and mortality, with the temporal dynamics of each functional group governed by separate second- order McKendrick-von Foerster equations. - - -## How to run ZooMSS using `R` - -### Model Structure - -The model is split into 5 main files. - -1. Setup_RUN_NAME.R - Set up your own specific simulation. This is the only file you usually need to edit. - -2. fZooMSS_Model.R - The top-level model function which seuqentially runs the following 3 functions, and saves the output. - - + fZooMSS_Params.R - Set all the parameter values for the model. - - + fZooMSS_Setup.R - Do all calculations which can be done in advance of the time loop. - - + fZooMSS_Run.R - Contains the time-dependent loop. - -### Input files - -ZooMSS requires two input files: - -1. TestGroups.csv which contains all the taxa-specific parameter values, including size ranges. - -2. And RDS file which contains all environmental data for each grid cell. This includes chlorophyll a (chlo), sea surface temperature (sst), bathymetry (bathy), phytoplankton slope and intercept, and latitude/longitude which is useful for plotting. - - -### Parameter Values - -Insert table from Heneghan et al (in review) - -### Output - -TBC - -### Running -To run the model, you simply need to provide the relevent information in Setup_RUN_NAME.R and run the script. - -### Plotting - -TBC - -## Useful reading - -Datta Paper -The other thing to look at would be some of the numerical methods we use - - Simpson’s method for the growth, mortality and diffusion integrals and - - a semi-implicit upward finite difference scheme to solve the PDE at each time step. - For the PDE numerical method, check out Appendix 1 of my thesis (attached) - Info on the difference scheme in Press’ 2007 book: Numerical Recipes, the Art of Scientific Computing (Available at UQ Library) - - -On 1 Apr 2020, at 06:50, Richardson, Anthony (O&A, St. Lucia) wrote: - - - -## Publications - -1. Heneghan, R.F., Everett, J.D., Blanchard, J.L., Richardson, A.J., 2016. Zooplankton Are Not Fish: Improving Zooplankton Realism in Size-Spectrum Models Mediates Energy Transfer in Food Webs. Front. Mar. Sci. 3, 1–15. https://doi.org/10.3389/fmars.2016.00201 - -2. Heneghan, R.F., Everett, J.D., Sykes, P., Batten, S.D., Edwards, M., Takahashi, K., Suthers, I.M., Blanchard, J.L., Richardson, A.J., in review, A global size-spectrum model of the marine ecosystem that resolves zooplankton composition. Ecological Modelling - -## References - -TBC - -## Getting Help - -If you are running the model come across a problem, raise an issue on GitHub: https://github.com/MathMarEcol/ZooMSS/issues - -If you find some errors, or just want to improve the model, we'd love you to go ahead and make the changes and then submit a pull request for us to check and approve. - -Same for this manual. If there is information lacking, errors etc, please fix it rather than just reporting it. This should be a team effort. - - diff --git a/UserManual/ZooMSS_User_Manual.pdf b/UserManual/ZooMSS_User_Manual.pdf deleted file mode 100644 index eb86a7f..0000000 Binary files a/UserManual/ZooMSS_User_Manual.pdf and /dev/null differ diff --git a/ZooMSS.Rproj b/ZooMSS.Rproj deleted file mode 100644 index d054d72..0000000 --- a/ZooMSS.Rproj +++ /dev/null @@ -1,17 +0,0 @@ -Version: 1.0 - -RestoreWorkspace: Default -SaveWorkspace: Default -AlwaysSaveHistory: Default - -EnableCodeIndexing: Yes -UseSpacesForTab: Yes -NumSpacesForTab: 2 -Encoding: UTF-8 - -RnwWeave: Sweave -LaTeX: pdfLaTeX - -StripTrailingWhitespace: Yes - -QuitChildProcessesOnExit: Yes diff --git a/_pkgdown.yml b/_pkgdown.yml new file mode 100644 index 0000000..3592095 --- /dev/null +++ b/_pkgdown.yml @@ -0,0 +1,44 @@ +url: https://MathMarEcol.github.io/zoomss +development: + mode: devel + destination: docs + version_label: info + version_tooltip: The package is in the early stages of development. Use with caution. +reference: +- title: Data + desc: Data related functions and datasets +- contents: + - GroupInputs + - getGroups + - calculatePhytoParam + - createEnviroData + - createInputParams + - validateGroups +- title: Model Runs + desc: Functions for running the model +- contents: + - starts_with("zoomss_") +- title: Plotting + desc: Functions for plotting. +- contents: + - starts_with("plot") +- title: Data wrangling + desc: Helper functions to convert units and data format +- contents: + - starts_with("average") + - starts_with("extract") + - starts_with("get") + - starts_with("reduce") +- title: Private functions + desc: Functions to be unexported +- contents: + - untibble +navbar: + structure: + right: [github, search] +template: + bootstrap: 5 + bootswatch: lumen #cerulean materia sandstone zephyr yeti + bslib: + toc: true + toc-expand: 3 diff --git a/data-raw/DATASET.R b/data-raw/DATASET.R new file mode 100644 index 0000000..665dbb1 --- /dev/null +++ b/data-raw/DATASET.R @@ -0,0 +1,12 @@ +## code to prepare `DATASET` dataset goes here + +# Create package data objects for ZooMSS +# This script creates the .rda files in the data/ directory + +# Load GroupInputs from CSV +GroupInputs <- readr::read_csv("data-raw/GroupInputs.csv", show_col_types = FALSE) + + +# Save the data +usethis::use_data(GroupInputs, overwrite = TRUE) + diff --git a/TestGroups.csv b/data-raw/GroupInputs.csv similarity index 100% rename from TestGroups.csv rename to data-raw/GroupInputs.csv diff --git a/data-raw/Unused.R b/data-raw/Unused.R new file mode 100644 index 0000000..9403fcb --- /dev/null +++ b/data-raw/Unused.R @@ -0,0 +1,167 @@ +#' Calculate Species-Level Biomass +#' +#' @title Sum biomass across size classes for each functional group +#' @description Converts abundance to biomass and sums across all size classes +#' to provide total biomass per functional group per spatial cell. +#' @details This function combines abundance-to-biomass conversion with size-class +#' aggregation in one step, providing species-level biomass summaries useful +#' for spatial analyses and ecological comparisons. +#' +#' @param res List of abundance matrices from ZooMSS output +#' @param vmdl ZooMSS model object containing weight vector (param$w) +#' +#' @return List of vectors with total biomass per functional group (grams wet weight) +#' @export +#' +zExtractBiomassSpecies = function(res, vmdl) { + # if (dim(res[[1]])[2] != length(mdl$param$w)){print("error")} + Biomass <- purrr::map(res, function(x) apply(sweep(x, 2, vmdl$param$w, '*'), 1, sum)) + return(Biomass) +} + + + + +#' Convert Abundance to Carbon Biomass +#' +#' @title Convert ZooMSS abundances to carbon biomass across all size classes +#' @description Converts abundance data to carbon biomass by multiplying by body weights +#' and then by carbon content factors for each functional group. +#' @details This function performs a two-step conversion: +#' 1. Abundance to wet weight biomass (using body weights) +#' 2. Wet weight to carbon biomass (using group-specific carbon content) +#' +#' Carbon biomass is essential for biogeochemical analyses and comparisons +#' with field data that are often reported in carbon units. +#' +#' @param res List of abundance matrices from ZooMSS output +#' @param vmdl ZooMSS model object containing weight vector and carbon content factors +#' +#' @return List of carbon biomass matrices (grams carbon) +#' @export +#' +zCarbonBiomass <- function(res, vmdl) { + if (dim(res[[1]])[2] != length(vmdl$param$w)){print("error")} + Biomass <- purrr::map(res, function(x) sweep(x, 2, vmdl$param$w, '*')) # Biomass in grams (WW) + Biomass <- purrr::map(Biomass, function(x) sweep(x, 1, vmdl$param$Groups$Carbon, '*')) # Now convert to Carbon + return(Biomass) +} + +#' Convert Abundance to Species-Level Carbon Biomass +#' +#' @title Convert abundances to carbon biomass and sum across size classes +#' @description Converts abundance data to carbon biomass and then sums across all +#' size classes to provide total carbon biomass per functional group. +#' @details This function combines carbon biomass conversion with size-class aggregation: +#' 1. Converts abundance to wet weight biomass +#' 2. Converts to carbon biomass using group-specific factors +#' 3. Sums across all size classes for each functional group +#' +#' Provides species-level carbon biomass useful for ecological stoichiometry +#' and biogeochemical cycle analyses. +#' +#' @param res List of abundance matrices from ZooMSS output +#' @param vmdl ZooMSS model object containing weight vector and carbon content factors +#' +#' @return List of vectors with total carbon biomass per functional group (grams carbon) +#' @export +#' +zSpeciesCarbonBiomass <- function(res, vmdl) { + if (dim(res[[1]])[2] != length(vmdl$param$w)){print("error")} + Biomass <- purrr::map(res, function(x) sweep(x, 2, vmdl$param$w, '*')) # Biomass in grams (WW) + Biomass <- purrr::map(Biomass, function(x) sweep(x, 1, vmdl$param$Groups$Carbon, '*')) # Now convert to Carbon + Biomass <- reduceSize(Biomass) + + return(Biomass) +} + +#' Calculate Size-Class Biomass +#' +#' @title Sum biomass across functional groups for each size class +#' @description Converts abundance to biomass and sums across all functional groups +#' to provide total biomass per size class per spatial cell. +#' @details This function provides size-class-level biomass by summing across +#' functional groups. Useful for analyzing community size structure and +#' comparing size spectrum patterns between locations. +#' +#' @param res List of abundance matrices from ZooMSS output +#' @param w Vector of body weights for each size class (grams) +#' +#' @return List of vectors with total biomass per size class (grams wet weight) +#' @export +#' +zExtractBiomassSize = function(res, w) { + if (dim(res[[1]])[2] != length(w)){print("error")} + Biomass <- purrr::map(res, function(x) apply(sweep(x, 2, w, '*'), 2, sum)) + return(Biomass) +} + + + + +#' Convert List to Tibble Format +#' +#' @title Convert ZooMSS list output to tibble with species names +#' @description Converts ZooMSS list output to a tibble format with proper column +#' names based on functional group species names. +#' @details This function converts aggregated ZooMSS output (typically from +#' reduceSize or similar functions) into a tibble format suitable for +#' analysis and visualization. Currently designed for 2D data (species x cells). +#' +#' @param li List of vectors/matrices from ZooMSS aggregation functions +#' @param vmdl ZooMSS model object containing species names (param$Groups$Species) +#' +#' @return Tibble with columns named by species and rows representing spatial cells +#' @export +#' +zConvert2Tibble <- function(li, vmdl){ + df <- tibble::as_tibble(matrix(unlist(li), nrow=length(li), byrow=T), .name_repair = "unique") %>% + dplyr::rename_with(~vmdl$param$Groups$Species) + return(df) +} + + + + + +#' Create Diet Matrix in Long Tibble Format +#' +#' @title Convert diet matrix to long format for analysis and visualization +#' @description Converts ZooMSS diet matrix from wide format to long (tidy) format +#' with predator-prey relationships clearly defined. +#' @details This function transforms diet matrices into a long format suitable for +#' analysis and visualization of feeding relationships. The resulting tibble +#' contains predator-prey pairs with diet fraction values, making it easy to +#' analyze trophic interactions and create food web visualizations. +#' +#' @param mat Diet matrix from ZooMSS output (predators x prey) +#' @param mdl ZooMSS model object containing species names for labelling +#' +#' @return Long tibble with columns: Predator, Prey, Diet +#' @export +#' +makeDietTibble <- function(mdl){ + + mdl <- out + + + tibble::as_tibble(mdl$diet, .name_repair = "unique") + + suppressMessages( + out <- tibble::as_tibble(mat, .name_repair = "unique") %>% + dplyr::rename_with(~c("Phyto_Small", "Phyto_Med", "Phyto_Large", mdl$param$Groups$Species)) %>% + dplyr::mutate(Predator = mdl$param$Groups$Species) %>% + tidyr::pivot_longer(cols = .data$Phyto_Small:.data$Fish_Large, names_to = "Prey", values_to = "Diet") + ) + return(out) +} + + + + + + + + + + diff --git a/ZooMSS_RUN_NAME.pbs b/data-raw/ZooMSS_RUN_NAME.pbs similarity index 100% rename from ZooMSS_RUN_NAME.pbs rename to data-raw/ZooMSS_RUN_NAME.pbs diff --git a/data-raw/setup_RUN_NAME.R b/data-raw/setup_RUN_NAME.R new file mode 100644 index 0000000..849c2ff --- /dev/null +++ b/data-raw/setup_RUN_NAME.R @@ -0,0 +1,97 @@ +## ZooMSS Setup Script +## This script demonstrates how to run ZooMSS with time-varying environmental data +## Based on the original setup by Dr Jason Everett, Dr Ryan Heneghan, and Mr Patrick Sykes +## Environmental forcing - August 2025 + +# Load all required functions +source("zoomss_model.R") #source the model code +source("zXtras.R") # For calculatePhytoParam and other utilities +source("zEnvironmental_Utils.R") # For environmental time series functions + +plotting <- FALSE + +# Setup user defined parameters ------------------------------------------- +dt <- 0.01 # years^-1 - time step for creating time vector +tmax <- 250 # years - total simulation time +cellID <- 1 +isave <- 100 # Model save frequency +base_sst <- 15 +base_chlo <- 0.01 + +# Create time vector (dt and tmax only used here for time vector creation) +time_vec <- seq(0, tmax, by = dt) + +# Create environmental data with the same length as time vector +n_time_steps <- length(time_vec) + +# Create input_params dataframe using new time-based approach +# Note: dt and tmax are automatically calculated from time_vec in createInputParams +input_params <- createInputParams( + time = time_vec, + sst = rep(base_sst, n_time_steps), + chl = rep(base_chlo, n_time_steps), + cellID = rep(cellID, n_time_steps), + isave = isave +) + +# Alternative: add time-varying patterns +# input_params$chl <- 0.01 + 0.00015 * input_params$time_step # Linear increasing Chlorophyll +# input_params$chl <- 0.5 + 0.49 * sin(2 * pi * input_params$time) # Chlorophyll cycles between 0.01-0.99 mg/m³ + +# Ensure chlorophyll stays positive +input_params$chl <- pmax(input_params$chl, 0.01) +cat("Environmental data created with", nrow(input_params), "timesteps covering", + max(input_params$time), "years\n") + +plotEnvironment(input_params) + + +# Setup jobname +jobname <- "20250813_chl0_01" # This is the job name to save the run +enviro_row <- 1 # Which row of the environmental data to use +HPC <- FALSE # Is this being run on a HPC +Groups <- read.csv("GroupInputs.csv", stringsAsFactors = FALSE) # Load functional group information + +if (HPC == TRUE){ + ID <- as.integer(Sys.getenv('PBS_ARRAY_INDEX')) +} else { + ID <- enviro_row +} +ID_char <- sprintf("%04d",ID) + +# Create dynamic environmental time series +cat("\nCreating dynamic environmental scenario...\n") +cat("✅ Environmental input_params created with", nrow(input_params), "rows\n") +cat("- SST range:", round(min(input_params$sst), 1), "to", round(max(input_params$sst), 1), "°C\n") +cat("- Chlorophyll range:", round(min(input_params$chlo), 2), "to", round(max(input_params$chlo), 2), "mg/m³\n") + + +cat("Running model...\n") +out <- zoomss_model(input_params, Groups) +cat("✅ Model run completed successfully!\n") + + +# Save outputs +if (HPC == FALSE) { + save(out, input_params, + file = paste0(jobname, "_", ID_char, ".RData")) + cat("Results saved to:", paste0(jobname, "_", ID_char, ".RData"), "\n") +} + +# Optional: Generate plots if you want to visualize results +# NOTE: Plotting disabled temporarily due to PPMR plot issue - core model works perfectly + +if (isTRUE(plotting)){ + source("zPlot.R") + + # Plot results + # (ggPPMR_dynamic <- plotPPMR(out)) + (ggSizeSpec <- plotSizeSpectra(out)) + (ggAbundTS <- zPlot_AbundTimeSeries(out)) + (ggGrowthTS <- zPlot_GrowthTimeSeries(out)) + (ggBiomassTS <- zPlot_BiomassTimeSeries(out)) + (ggBiomassTS_stacked <- zPlot_BiomassTimeSeries(out, stacked = TRUE)) + + cat("✅ Plots generated successfully!\n") +} + diff --git a/fZooMSS_MvF_Rcpp.cpp b/data-raw/src/zoomss_mvf.cpp similarity index 96% rename from fZooMSS_MvF_Rcpp.cpp rename to data-raw/src/zoomss_mvf.cpp index d97e311..b59a1aa 100644 --- a/fZooMSS_MvF_Rcpp.cpp +++ b/data-raw/src/zoomss_mvf.cpp @@ -2,7 +2,7 @@ using namespace Rcpp; // [[Rcpp::export]] -NumericMatrix fZooMSS_MvF_Rcpp(int cngrps, +NumericMatrix zMvF_Rcpp(int cngrps, NumericMatrix cN_iter, NumericMatrix cA_iter, NumericMatrix cC_iter, @@ -31,4 +31,4 @@ NumericMatrix fZooMSS_MvF_Rcpp(int cngrps, } return cN; -} \ No newline at end of file +} diff --git a/data/GroupInputs.rda b/data/GroupInputs.rda new file mode 100644 index 0000000..e74f699 Binary files /dev/null and b/data/GroupInputs.rda differ diff --git a/docs/404.html b/docs/404.html new file mode 100644 index 0000000..106bc51 --- /dev/null +++ b/docs/404.html @@ -0,0 +1,75 @@ + + + + + + + +Page not found (404) • zoomss + + + + + + + + Skip to contents + + +
+
+
+ +Content not found. Please use links in the navbar. + +
+
+ + +
+ + + +
+
+ + + + + + + diff --git a/docs/LICENSE-text.html b/docs/LICENSE-text.html new file mode 100644 index 0000000..77abfab --- /dev/null +++ b/docs/LICENSE-text.html @@ -0,0 +1,57 @@ + +License • zoomss + Skip to contents + + +
+
+
+ +
YEAR: 2025
+COPYRIGHT HOLDER: zoomss authors
+
+ +
+ + +
+ + + +
+ + + + + + + diff --git a/docs/LICENSE.html b/docs/LICENSE.html new file mode 100644 index 0000000..75fbeec --- /dev/null +++ b/docs/LICENSE.html @@ -0,0 +1,61 @@ + +MIT License • zoomss + Skip to contents + + +
+
+
+ +
+ +

Copyright (c) 2025 zoomss authors

+

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+
+ +
+ + +
+ + + +
+ + + + + + + diff --git a/docs/articles/index.html b/docs/articles/index.html new file mode 100644 index 0000000..766e28d --- /dev/null +++ b/docs/articles/index.html @@ -0,0 +1,59 @@ + +Articles • zoomss + Skip to contents + + +
+
+
+ +
+

All vignettes

+
+ +
Getting started with ZooMSS
+
+
+
+ + +
+ + + +
+ + + + + + + diff --git a/docs/articles/zoomss.html b/docs/articles/zoomss.html new file mode 100644 index 0000000..3ab6e63 --- /dev/null +++ b/docs/articles/zoomss.html @@ -0,0 +1,177 @@ + + + + + + + +Getting started with ZooMSS • zoomss + + + + + + + + Skip to contents + + +
+ + + + +
+
+ + + + +
+

Input Data +

+

ZooMSS requires two sets of input data:

+
    +
  1. Groups - Contains all taxa-specific parameter +values for each model group, including size ranges and functional group +properties.

  2. +
  3. Environmental data - A Time-series dataframe +with time series of environmental conditions with time, +sst, and chl columns.

  4. +
+
+
+

Running the default Model +

+

Get the default published Groups dataframe using:

+
+Groups <- getGroups()
+#> Using default ZooMSS functional groups. Use getGroups() to customize.
+

Now create an environmental data time-series using the helper +function. This time-series uses a constant sea surface temperature +(sst) and chlorophyll a (chl) with a +0.1 yr-1 timestep (dt).

+
+env_data <- createInputParams(time = seq(0, 100, by = 0.1) ,
+                              sst = 15,
+                              chl = 0.15)
+#> ZooMSS input parameters created:
+#> - Time points: 1001 (time values provided)
+#> - Time steps: 1000 (intervals to simulate)
+#> - Time range: 0 to 100 years
+#> - dt = 0.1 years
+#> - SST range: 15 to 15 deg C
+#> - Chlorophyll range: 0.15 to 0.15 mg/m^3
+

We can look at the environment data and check everything is ok +with:

+
+plotEnvironment(env_data)
+

+

Now we run ZooMSS and save every isave timestep to +reduce storage requirements.

+
+mdl <- zoomss_model(input_params = env_data, Groups = Groups, isave = 2)
+#> Functional groups validation passed
+#> Calculating phytoplankton parameters from environmental time series
+
+
+

Plotting +

+

The model includes several built-in plotting functions for analysis +and visualization.

+
+

Time Series Analysis +

+

These plots display total abundance and mean growth/mortality across +all size classes through time.

+
+
+library(patchwork)
+p1 <- plotTimeSeries(mdl, by = "abundance") # Plot abundance time series
+p2 <- plotTimeSeries(mdl, by = "growth") # Plot growth rate time series
+p3 <- plotTimeSeries(mdl, by = "mortality") # Plot predation mortality time series
+
+wrap_plots(p1, p2, p3, nrow = 3, guides = "collect")
+

+

We can also plot total biomass through time.

+
+p4 <- plotTimeSeries(mdl, by = "biomass") + theme(legend.position = "none") # Plot biomass 
+p5 <- plotTimeSeries(mdl, by = "biomass", stacked = TRUE) # Plot stacked biomass 
+p6 <- plotTimeSeries(mdl, by = "biomass", stacked = TRUE, proportion = TRUE) # Plot proportional stacked biomass 
+
+wrap_plots(p4, p5, p6, nrow = 3, guides = "collect")
+

+
+
+

Static Plots for a given model time point +

+

Plot mean species-resolved size spectra for the final +n_years.

+
+plotSizeSpectra(mdl, n_years = 10)
+#> Averaging final 10 years (50 saved time steps with isave = 2) of N from 500 total saved time steps.
+

+

Plot predator-prey mass ratios for the idx timestep

+
+plotPPMR(mdl, idx = 500) # Plot final timestep
+

+
+
+
+
+ + + +
+ + + +
+
+ + + + + + + diff --git a/docs/articles/zoomss_files/figure-html/unnamed-chunk-3-1.png b/docs/articles/zoomss_files/figure-html/unnamed-chunk-3-1.png new file mode 100644 index 0000000..3690be3 Binary files /dev/null and b/docs/articles/zoomss_files/figure-html/unnamed-chunk-3-1.png differ diff --git a/docs/articles/zoomss_files/figure-html/unnamed-chunk-4-1.png b/docs/articles/zoomss_files/figure-html/unnamed-chunk-4-1.png new file mode 100644 index 0000000..eb681c7 Binary files /dev/null and b/docs/articles/zoomss_files/figure-html/unnamed-chunk-4-1.png differ diff --git a/docs/authors.html b/docs/authors.html new file mode 100644 index 0000000..217a93f --- /dev/null +++ b/docs/authors.html @@ -0,0 +1,91 @@ + +Authors and Citation • zoomss + Skip to contents + + +
+
+
+ +
+

Authors

+ +
  • +

    Jason D. Everett. Author, maintainer. +

    +
  • +
  • +

    Ryan F. Heneghan. Author. +

    +
  • +
  • +

    Kieran Murphy. Author. +

    +
  • +
  • +

    Anthony J. Richardson. Author. +

    +
  • +
+ +
+

Citation

+

Source: DESCRIPTION

+ +

Everett J, Heneghan R, Murphy K, Richardson A (2025). +zoomss: Zooplankton Model of Size Spectra. +R package version 0.1.0, https://github.com/MathMarEcol/zoomss. +

+
@Manual{,
+  title = {zoomss: Zooplankton Model of Size Spectra},
+  author = {Jason D. Everett and Ryan F. Heneghan and Kieran Murphy and Anthony J. Richardson},
+  year = {2025},
+  note = {R package version 0.1.0},
+  url = {https://github.com/MathMarEcol/zoomss},
+}
+
+ +
+ + +
+ + + +
+ + + + + + + diff --git a/docs/bootstrap-toc.css b/docs/bootstrap-toc.css new file mode 100644 index 0000000..5a85941 --- /dev/null +++ b/docs/bootstrap-toc.css @@ -0,0 +1,60 @@ +/*! + * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) + * Copyright 2015 Aidan Feldman + * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ + +/* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ + +/* All levels of nav */ +nav[data-toggle='toc'] .nav > li > a { + display: block; + padding: 4px 20px; + font-size: 13px; + font-weight: 500; + color: #767676; +} +nav[data-toggle='toc'] .nav > li > a:hover, +nav[data-toggle='toc'] .nav > li > a:focus { + padding-left: 19px; + color: #563d7c; + text-decoration: none; + background-color: transparent; + border-left: 1px solid #563d7c; +} +nav[data-toggle='toc'] .nav > .active > a, +nav[data-toggle='toc'] .nav > .active:hover > a, +nav[data-toggle='toc'] .nav > .active:focus > a { + padding-left: 18px; + font-weight: bold; + color: #563d7c; + background-color: transparent; + border-left: 2px solid #563d7c; +} + +/* Nav: second level (shown on .active) */ +nav[data-toggle='toc'] .nav .nav { + display: none; /* Hide by default, but at >768px, show it */ + padding-bottom: 10px; +} +nav[data-toggle='toc'] .nav .nav > li > a { + padding-top: 1px; + padding-bottom: 1px; + padding-left: 30px; + font-size: 12px; + font-weight: normal; +} +nav[data-toggle='toc'] .nav .nav > li > a:hover, +nav[data-toggle='toc'] .nav .nav > li > a:focus { + padding-left: 29px; +} +nav[data-toggle='toc'] .nav .nav > .active > a, +nav[data-toggle='toc'] .nav .nav > .active:hover > a, +nav[data-toggle='toc'] .nav .nav > .active:focus > a { + padding-left: 28px; + font-weight: 500; +} + +/* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */ +nav[data-toggle='toc'] .nav > .active > ul { + display: block; +} diff --git a/docs/bootstrap-toc.js b/docs/bootstrap-toc.js new file mode 100644 index 0000000..1cdd573 --- /dev/null +++ b/docs/bootstrap-toc.js @@ -0,0 +1,159 @@ +/*! + * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) + * Copyright 2015 Aidan Feldman + * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ +(function() { + 'use strict'; + + window.Toc = { + helpers: { + // return all matching elements in the set, or their descendants + findOrFilter: function($el, selector) { + // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/ + // http://stackoverflow.com/a/12731439/358804 + var $descendants = $el.find(selector); + return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])'); + }, + + generateUniqueIdBase: function(el) { + var text = $(el).text(); + var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-'); + return anchor || el.tagName.toLowerCase(); + }, + + generateUniqueId: function(el) { + var anchorBase = this.generateUniqueIdBase(el); + for (var i = 0; ; i++) { + var anchor = anchorBase; + if (i > 0) { + // add suffix + anchor += '-' + i; + } + // check if ID already exists + if (!document.getElementById(anchor)) { + return anchor; + } + } + }, + + generateAnchor: function(el) { + if (el.id) { + return el.id; + } else { + var anchor = this.generateUniqueId(el); + el.id = anchor; + return anchor; + } + }, + + createNavList: function() { + return $(''); + }, + + createChildNavList: function($parent) { + var $childList = this.createNavList(); + $parent.append($childList); + return $childList; + }, + + generateNavEl: function(anchor, text) { + var $a = $(''); + $a.attr('href', '#' + anchor); + $a.text(text); + var $li = $('
  • '); + $li.append($a); + return $li; + }, + + generateNavItem: function(headingEl) { + var anchor = this.generateAnchor(headingEl); + var $heading = $(headingEl); + var text = $heading.data('toc-text') || $heading.text(); + return this.generateNavEl(anchor, text); + }, + + // Find the first heading level (`

    `, then `

    `, etc.) that has more than one element. Defaults to 1 (for `

    `). + getTopLevel: function($scope) { + for (var i = 1; i <= 6; i++) { + var $headings = this.findOrFilter($scope, 'h' + i); + if ($headings.length > 1) { + return i; + } + } + + return 1; + }, + + // returns the elements for the top level, and the next below it + getHeadings: function($scope, topLevel) { + var topSelector = 'h' + topLevel; + + var secondaryLevel = topLevel + 1; + var secondarySelector = 'h' + secondaryLevel; + + return this.findOrFilter($scope, topSelector + ',' + secondarySelector); + }, + + getNavLevel: function(el) { + return parseInt(el.tagName.charAt(1), 10); + }, + + populateNav: function($topContext, topLevel, $headings) { + var $context = $topContext; + var $prevNav; + + var helpers = this; + $headings.each(function(i, el) { + var $newNav = helpers.generateNavItem(el); + var navLevel = helpers.getNavLevel(el); + + // determine the proper $context + if (navLevel === topLevel) { + // use top level + $context = $topContext; + } else if ($prevNav && $context === $topContext) { + // create a new level of the tree and switch to it + $context = helpers.createChildNavList($prevNav); + } // else use the current $context + + $context.append($newNav); + + $prevNav = $newNav; + }); + }, + + parseOps: function(arg) { + var opts; + if (arg.jquery) { + opts = { + $nav: arg + }; + } else { + opts = arg; + } + opts.$scope = opts.$scope || $(document.body); + return opts; + } + }, + + // accepts a jQuery object, or an options object + init: function(opts) { + opts = this.helpers.parseOps(opts); + + // ensure that the data attribute is in place for styling + opts.$nav.attr('data-toggle', 'toc'); + + var $topContext = this.helpers.createChildNavList(opts.$nav); + var topLevel = this.helpers.getTopLevel(opts.$scope); + var $headings = this.helpers.getHeadings(opts.$scope, topLevel); + this.helpers.populateNav($topContext, topLevel, $headings); + } + }; + + $(function() { + $('nav[data-toggle="toc"]').each(function(i, el) { + var $nav = $(el); + Toc.init($nav); + }); + }); +})(); diff --git a/docs/docsearch.css b/docs/docsearch.css new file mode 100644 index 0000000..e5f1fe1 --- /dev/null +++ b/docs/docsearch.css @@ -0,0 +1,148 @@ +/* Docsearch -------------------------------------------------------------- */ +/* + Source: https://github.com/algolia/docsearch/ + License: MIT +*/ + +.algolia-autocomplete { + display: block; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1 +} + +.algolia-autocomplete .ds-dropdown-menu { + width: 100%; + min-width: none; + max-width: none; + padding: .75rem 0; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, .1); + box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .175); +} + +@media (min-width:768px) { + .algolia-autocomplete .ds-dropdown-menu { + width: 175% + } +} + +.algolia-autocomplete .ds-dropdown-menu::before { + display: none +} + +.algolia-autocomplete .ds-dropdown-menu [class^=ds-dataset-] { + padding: 0; + background-color: rgb(255,255,255); + border: 0; + max-height: 80vh; +} + +.algolia-autocomplete .ds-dropdown-menu .ds-suggestions { + margin-top: 0 +} + +.algolia-autocomplete .algolia-docsearch-suggestion { + padding: 0; + overflow: visible +} + +.algolia-autocomplete .algolia-docsearch-suggestion--category-header { + padding: .125rem 1rem; + margin-top: 0; + font-size: 1.3em; + font-weight: 500; + color: #00008B; + border-bottom: 0 +} + +.algolia-autocomplete .algolia-docsearch-suggestion--wrapper { + float: none; + padding-top: 0 +} + +.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column { + float: none; + width: auto; + padding: 0; + text-align: left +} + +.algolia-autocomplete .algolia-docsearch-suggestion--content { + float: none; + width: auto; + padding: 0 +} + +.algolia-autocomplete .algolia-docsearch-suggestion--content::before { + display: none +} + +.algolia-autocomplete .ds-suggestion:not(:first-child) .algolia-docsearch-suggestion--category-header { + padding-top: .75rem; + margin-top: .75rem; + border-top: 1px solid rgba(0, 0, 0, .1) +} + +.algolia-autocomplete .ds-suggestion .algolia-docsearch-suggestion--subcategory-column { + display: block; + padding: .1rem 1rem; + margin-bottom: 0.1; + font-size: 1.0em; + font-weight: 400 + /* display: none */ +} + +.algolia-autocomplete .algolia-docsearch-suggestion--title { + display: block; + padding: .25rem 1rem; + margin-bottom: 0; + font-size: 0.9em; + font-weight: 400 +} + +.algolia-autocomplete .algolia-docsearch-suggestion--text { + padding: 0 1rem .5rem; + margin-top: -.25rem; + font-size: 0.8em; + font-weight: 400; + line-height: 1.25 +} + +.algolia-autocomplete .algolia-docsearch-footer { + width: 110px; + height: 20px; + z-index: 3; + margin-top: 10.66667px; + float: right; + font-size: 0; + line-height: 0; +} + +.algolia-autocomplete .algolia-docsearch-footer--logo { + background-image: url("data:image/svg+xml;utf8,"); + background-repeat: no-repeat; + background-position: 50%; + background-size: 100%; + overflow: hidden; + text-indent: -9000px; + width: 100%; + height: 100%; + display: block; + transform: translate(-8px); +} + +.algolia-autocomplete .algolia-docsearch-suggestion--highlight { + color: #FF8C00; + background: rgba(232, 189, 54, 0.1) +} + + +.algolia-autocomplete .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight { + box-shadow: inset 0 -2px 0 0 rgba(105, 105, 105, .5) +} + +.algolia-autocomplete .ds-suggestion.ds-cursor .algolia-docsearch-suggestion--content { + background-color: rgba(192, 192, 192, .15) +} diff --git a/docs/docsearch.js b/docs/docsearch.js new file mode 100644 index 0000000..b35504c --- /dev/null +++ b/docs/docsearch.js @@ -0,0 +1,85 @@ +$(function() { + + // register a handler to move the focus to the search bar + // upon pressing shift + "/" (i.e. "?") + $(document).on('keydown', function(e) { + if (e.shiftKey && e.keyCode == 191) { + e.preventDefault(); + $("#search-input").focus(); + } + }); + + $(document).ready(function() { + // do keyword highlighting + /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */ + var mark = function() { + + var referrer = document.URL ; + var paramKey = "q" ; + + if (referrer.indexOf("?") !== -1) { + var qs = referrer.substr(referrer.indexOf('?') + 1); + var qs_noanchor = qs.split('#')[0]; + var qsa = qs_noanchor.split('&'); + var keyword = ""; + + for (var i = 0; i < qsa.length; i++) { + var currentParam = qsa[i].split('='); + + if (currentParam.length !== 2) { + continue; + } + + if (currentParam[0] == paramKey) { + keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20")); + } + } + + if (keyword !== "") { + $(".contents").unmark({ + done: function() { + $(".contents").mark(keyword); + } + }); + } + } + }; + + mark(); + }); +}); + +/* Search term highlighting ------------------------------*/ + +function matchedWords(hit) { + var words = []; + + var hierarchy = hit._highlightResult.hierarchy; + // loop to fetch from lvl0, lvl1, etc. + for (var idx in hierarchy) { + words = words.concat(hierarchy[idx].matchedWords); + } + + var content = hit._highlightResult.content; + if (content) { + words = words.concat(content.matchedWords); + } + + // return unique words + var words_uniq = [...new Set(words)]; + return words_uniq; +} + +function updateHitURL(hit) { + + var words = matchedWords(hit); + var url = ""; + + if (hit.anchor) { + url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor; + } else { + url = hit.url + '?q=' + escape(words.join(" ")); + } + + return url; +} diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..ec2347d --- /dev/null +++ b/docs/index.html @@ -0,0 +1,151 @@ + + + + + + + +Zooplankton Model of Size Spectra • zoomss + + + + + + + + + + Skip to contents + + +
    +
    +
    + + + + +
    +

    Overview of ZooMSS +

    +

    The Zooplankton Model of Size Spectra (ZooMSS) is a functional size-spectrum model of the marine ecosystem (following Heneghan et al. 2016) to resolve phytoplankton, nine zooplankton functional groups (heterotrophic flagellates and ciliates, omnivorous and carnivorous copepods, larvaceans, euphausiids, salps, chaetognaths and jellyfish) and three size-based fish groups. Zooplankton functional groups are resolved using their body-size ranges, size-based feeding characteristics and carbon content, and the zooplankton community emerges from the model across global environmental gradients, depending on the functional traits of the different groups.

    +

    We developed the Zooplankton Model of Size Spectra (ZooMSSv2) based on the prototype of Heneghan et al. (2016). ZooMSS uses the functional size-spectrum framework (Blanchard et al., 2017) to resolve the body size ranges, size-based feeding characteristics and carbon content of nine zooplankton groups and three fish groups. The model supports time-varying environmental conditions enabling studies of seasonal cycles, climate change scenarios, and ecosystem responses to environmental variability.

    +

    ZooMSS represents the marine ecosystem as three communities: phytoplankton, zooplankton and fish. The zooplankton community consists of nine of the most abundant zooplankton groups, and the fish community was made up of a small, medium and large group. Dynamics of the phytoplankton are not explicitly resolved in the model, rather the mean size structure of the phytoplankton community is estimated directly from satellite chlorophyll a observations (Brewin et al., 2010; Barnes et al., 2011; Hirata et al., 2011). Abundances of the zooplankton and fish communities are driven by size-dependent processes of growth and mortality, with the temporal dynamics of each functional group governed by separate second-order McKendrick-von Foerster equations.

    +
    +
    +

    Installation +

    +

    You can install the development version of zoomss from GitHub with:

    +
    +# install.packages("pak")
    +pak::pak("MathMarEcol/zoomss")
    +
    +
    +

    Publications +

    +
      +
    1. Heneghan, R.F., Everett, J.D., Blanchard, J.L., Richardson, A.J., 2016. Zooplankton Are Not Fish: Improving Zooplankton Realism in Size-Spectrum Models Mediates Energy Transfer in Food Webs. Front. Mar. Sci. 3, 1–15. https://doi.org/10.3389/fmars.2016.00201

    2. +
    3. Heneghan, R.F., Everett, J.D., Sykes, P., Batten, S.D., Edwards, M., Takahashi, K., Suthers, I.M., Blanchard, J.L., Richardson, A.J., in review, A global size-spectrum model of the marine ecosystem that resolves zooplankton composition. Ecological Modelling

    4. +
    +
    +
    +

    Getting Help +

    +

    If you encounter problems running the model, raise an issue on GitHub: https://github.com/MathMarEcol/ZoopSizeSpectraModel/issues

    +

    If you find errors or want to improve the model, we’d love you to make the changes and submit a pull request for us to review and approve.

    +
    +
    +
    +
    + + +
    + + + +
    +
    + + + + + + + diff --git a/docs/link.svg b/docs/link.svg new file mode 100644 index 0000000..88ad827 --- /dev/null +++ b/docs/link.svg @@ -0,0 +1,12 @@ + + + + + + diff --git a/docs/pkgdown.css b/docs/pkgdown.css new file mode 100644 index 0000000..80ea5b8 --- /dev/null +++ b/docs/pkgdown.css @@ -0,0 +1,384 @@ +/* Sticky footer */ + +/** + * Basic idea: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/ + * Details: https://github.com/philipwalton/solved-by-flexbox/blob/master/assets/css/components/site.css + * + * .Site -> body > .container + * .Site-content -> body > .container .row + * .footer -> footer + * + * Key idea seems to be to ensure that .container and __all its parents__ + * have height set to 100% + * + */ + +html, body { + height: 100%; +} + +body { + position: relative; +} + +body > .container { + display: flex; + height: 100%; + flex-direction: column; +} + +body > .container .row { + flex: 1 0 auto; +} + +footer { + margin-top: 45px; + padding: 35px 0 36px; + border-top: 1px solid #e5e5e5; + color: #666; + display: flex; + flex-shrink: 0; +} +footer p { + margin-bottom: 0; +} +footer div { + flex: 1; +} +footer .pkgdown { + text-align: right; +} +footer p { + margin-bottom: 0; +} + +img.icon { + float: right; +} + +/* Ensure in-page images don't run outside their container */ +.contents img { + max-width: 100%; + height: auto; +} + +/* Fix bug in bootstrap (only seen in firefox) */ +summary { + display: list-item; +} + +/* Typographic tweaking ---------------------------------*/ + +.contents .page-header { + margin-top: calc(-60px + 1em); +} + +dd { + margin-left: 3em; +} + +/* Section anchors ---------------------------------*/ + +a.anchor { + display: none; + margin-left: 5px; + width: 20px; + height: 20px; + + background-image: url(./link.svg); + background-repeat: no-repeat; + background-size: 20px 20px; + background-position: center center; +} + +h1:hover .anchor, +h2:hover .anchor, +h3:hover .anchor, +h4:hover .anchor, +h5:hover .anchor, +h6:hover .anchor { + display: inline-block; +} + +/* Fixes for fixed navbar --------------------------*/ + +.contents h1, .contents h2, .contents h3, .contents h4 { + padding-top: 60px; + margin-top: -40px; +} + +/* Navbar submenu --------------------------*/ + +.dropdown-submenu { + position: relative; +} + +.dropdown-submenu>.dropdown-menu { + top: 0; + left: 100%; + margin-top: -6px; + margin-left: -1px; + border-radius: 0 6px 6px 6px; +} + +.dropdown-submenu:hover>.dropdown-menu { + display: block; +} + +.dropdown-submenu>a:after { + display: block; + content: " "; + float: right; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + border-width: 5px 0 5px 5px; + border-left-color: #cccccc; + margin-top: 5px; + margin-right: -10px; +} + +.dropdown-submenu:hover>a:after { + border-left-color: #ffffff; +} + +.dropdown-submenu.pull-left { + float: none; +} + +.dropdown-submenu.pull-left>.dropdown-menu { + left: -100%; + margin-left: 10px; + border-radius: 6px 0 6px 6px; +} + +/* Sidebar --------------------------*/ + +#pkgdown-sidebar { + margin-top: 30px; + position: -webkit-sticky; + position: sticky; + top: 70px; +} + +#pkgdown-sidebar h2 { + font-size: 1.5em; + margin-top: 1em; +} + +#pkgdown-sidebar h2:first-child { + margin-top: 0; +} + +#pkgdown-sidebar .list-unstyled li { + margin-bottom: 0.5em; +} + +/* bootstrap-toc tweaks ------------------------------------------------------*/ + +/* All levels of nav */ + +nav[data-toggle='toc'] .nav > li > a { + padding: 4px 20px 4px 6px; + font-size: 1.5rem; + font-weight: 400; + color: inherit; +} + +nav[data-toggle='toc'] .nav > li > a:hover, +nav[data-toggle='toc'] .nav > li > a:focus { + padding-left: 5px; + color: inherit; + border-left: 1px solid #878787; +} + +nav[data-toggle='toc'] .nav > .active > a, +nav[data-toggle='toc'] .nav > .active:hover > a, +nav[data-toggle='toc'] .nav > .active:focus > a { + padding-left: 5px; + font-size: 1.5rem; + font-weight: 400; + color: inherit; + border-left: 2px solid #878787; +} + +/* Nav: second level (shown on .active) */ + +nav[data-toggle='toc'] .nav .nav { + display: none; /* Hide by default, but at >768px, show it */ + padding-bottom: 10px; +} + +nav[data-toggle='toc'] .nav .nav > li > a { + padding-left: 16px; + font-size: 1.35rem; +} + +nav[data-toggle='toc'] .nav .nav > li > a:hover, +nav[data-toggle='toc'] .nav .nav > li > a:focus { + padding-left: 15px; +} + +nav[data-toggle='toc'] .nav .nav > .active > a, +nav[data-toggle='toc'] .nav .nav > .active:hover > a, +nav[data-toggle='toc'] .nav .nav > .active:focus > a { + padding-left: 15px; + font-weight: 500; + font-size: 1.35rem; +} + +/* orcid ------------------------------------------------------------------- */ + +.orcid { + font-size: 16px; + color: #A6CE39; + /* margins are required by official ORCID trademark and display guidelines */ + margin-left:4px; + margin-right:4px; + vertical-align: middle; +} + +/* Reference index & topics ----------------------------------------------- */ + +.ref-index th {font-weight: normal;} + +.ref-index td {vertical-align: top; min-width: 100px} +.ref-index .icon {width: 40px;} +.ref-index .alias {width: 40%;} +.ref-index-icons .alias {width: calc(40% - 40px);} +.ref-index .title {width: 60%;} + +.ref-arguments th {text-align: right; padding-right: 10px;} +.ref-arguments th, .ref-arguments td {vertical-align: top; min-width: 100px} +.ref-arguments .name {width: 20%;} +.ref-arguments .desc {width: 80%;} + +/* Nice scrolling for wide elements --------------------------------------- */ + +table { + display: block; + overflow: auto; +} + +/* Syntax highlighting ---------------------------------------------------- */ + +pre, code, pre code { + background-color: #f8f8f8; + color: #333; +} +pre, pre code { + white-space: pre-wrap; + word-break: break-all; + overflow-wrap: break-word; +} + +pre { + border: 1px solid #eee; +} + +pre .img, pre .r-plt { + margin: 5px 0; +} + +pre .img img, pre .r-plt img { + background-color: #fff; +} + +code a, pre a { + color: #375f84; +} + +a.sourceLine:hover { + text-decoration: none; +} + +.fl {color: #1514b5;} +.fu {color: #000000;} /* function */ +.ch,.st {color: #036a07;} /* string */ +.kw {color: #264D66;} /* keyword */ +.co {color: #888888;} /* comment */ + +.error {font-weight: bolder;} +.warning {font-weight: bolder;} + +/* Clipboard --------------------------*/ + +.hasCopyButton { + position: relative; +} + +.btn-copy-ex { + position: absolute; + right: 0; + top: 0; + visibility: hidden; +} + +.hasCopyButton:hover button.btn-copy-ex { + visibility: visible; +} + +/* headroom.js ------------------------ */ + +.headroom { + will-change: transform; + transition: transform 200ms linear; +} +.headroom--pinned { + transform: translateY(0%); +} +.headroom--unpinned { + transform: translateY(-100%); +} + +/* mark.js ----------------------------*/ + +mark { + background-color: rgba(255, 255, 51, 0.5); + border-bottom: 2px solid rgba(255, 153, 51, 0.3); + padding: 1px; +} + +/* vertical spacing after htmlwidgets */ +.html-widget { + margin-bottom: 10px; +} + +/* fontawesome ------------------------ */ + +.fab { + font-family: "Font Awesome 5 Brands" !important; +} + +/* don't display links in code chunks when printing */ +/* source: https://stackoverflow.com/a/10781533 */ +@media print { + code a:link:after, code a:visited:after { + content: ""; + } +} + +/* Section anchors --------------------------------- + Added in pandoc 2.11: https://github.com/jgm/pandoc-templates/commit/9904bf71 +*/ + +div.csl-bib-body { } +div.csl-entry { + clear: both; +} +.hanging-indent div.csl-entry { + margin-left:2em; + text-indent:-2em; +} +div.csl-left-margin { + min-width:2em; + float:left; +} +div.csl-right-inline { + margin-left:2em; + padding-left:1em; +} +div.csl-indent { + margin-left: 2em; +} diff --git a/docs/pkgdown.js b/docs/pkgdown.js new file mode 100644 index 0000000..1a99c65 --- /dev/null +++ b/docs/pkgdown.js @@ -0,0 +1,162 @@ +/* http://gregfranko.com/blog/jquery-best-practices/ */ +(function($) { + $(function() { + + $('nav.navbar').headroom(); + + Toc.init({ + $nav: $("#toc"), + $scope: $("main h2, main h3, main h4, main h5, main h6") + }); + + if ($('#toc').length) { + $('body').scrollspy({ + target: '#toc', + offset: $("nav.navbar").outerHeight() + 1 + }); + } + + // Activate popovers + $('[data-bs-toggle="popover"]').popover({ + container: 'body', + html: true, + trigger: 'focus', + placement: "top", + sanitize: false, + }); + + $('[data-bs-toggle="tooltip"]').tooltip(); + + /* Clipboard --------------------------*/ + + function changeTooltipMessage(element, msg) { + var tooltipOriginalTitle=element.getAttribute('data-bs-original-title'); + element.setAttribute('data-bs-original-title', msg); + $(element).tooltip('show'); + element.setAttribute('data-bs-original-title', tooltipOriginalTitle); + } + + if(ClipboardJS.isSupported()) { + $(document).ready(function() { + var copyButton = ""; + + $("div.sourceCode").addClass("hasCopyButton"); + + // Insert copy buttons: + $(copyButton).prependTo(".hasCopyButton"); + + // Initialize tooltips: + $('.btn-copy-ex').tooltip({container: 'body'}); + + // Initialize clipboard: + var clipboard = new ClipboardJS('[data-clipboard-copy]', { + text: function(trigger) { + return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, ""); + } + }); + + clipboard.on('success', function(e) { + changeTooltipMessage(e.trigger, 'Copied!'); + e.clearSelection(); + }); + + clipboard.on('error', function(e) { + changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); + }); + + }); + } + + /* Search marking --------------------------*/ + var url = new URL(window.location.href); + var toMark = url.searchParams.get("q"); + var mark = new Mark("main#main"); + if (toMark) { + mark.mark(toMark, { + accuracy: { + value: "complementary", + limiters: [",", ".", ":", "/"], + } + }); + } + + /* Search --------------------------*/ + /* Adapted from https://github.com/rstudio/bookdown/blob/2d692ba4b61f1e466c92e78fd712b0ab08c11d31/inst/resources/bs4_book/bs4_book.js#L25 */ + // Initialise search index on focus + var fuse; + $("#search-input").focus(async function(e) { + if (fuse) { + return; + } + + $(e.target).addClass("loading"); + var response = await fetch($("#search-input").data("search-index")); + var data = await response.json(); + + var options = { + keys: ["what", "text", "code"], + ignoreLocation: true, + threshold: 0.1, + includeMatches: true, + includeScore: true, + }; + fuse = new Fuse(data, options); + + $(e.target).removeClass("loading"); + }); + + // Use algolia autocomplete + var options = { + autoselect: true, + debug: true, + hint: false, + minLength: 2, + }; + var q; +async function searchFuse(query, callback) { + await fuse; + + var items; + if (!fuse) { + items = []; + } else { + q = query; + var results = fuse.search(query, { limit: 20 }); + items = results + .filter((x) => x.score <= 0.75) + .map((x) => x.item); + if (items.length === 0) { + items = [{dir:"Sorry 😿",previous_headings:"",title:"No results found.",what:"No results found.",path:window.location.href}]; + } + } + callback(items); +} + $("#search-input").autocomplete(options, [ + { + name: "content", + source: searchFuse, + templates: { + suggestion: (s) => { + if (s.title == s.what) { + return `${s.dir} >
    ${s.title}
    `; + } else if (s.previous_headings == "") { + return `${s.dir} >
    ${s.title}
    > ${s.what}`; + } else { + return `${s.dir} >
    ${s.title}
    > ${s.previous_headings} > ${s.what}`; + } + }, + }, + }, + ]).on('autocomplete:selected', function(event, s) { + window.location.href = s.path + "?q=" + q + "#" + s.id; + }); + }); +})(window.jQuery || window.$) + +document.addEventListener('keydown', function(event) { + // Check if the pressed key is '/' + if (event.key === '/') { + event.preventDefault(); // Prevent any default action associated with the '/' key + document.getElementById('search-input').focus(); // Set focus to the search input + } +}); diff --git a/docs/pkgdown.yml b/docs/pkgdown.yml new file mode 100644 index 0000000..4537f40 --- /dev/null +++ b/docs/pkgdown.yml @@ -0,0 +1,9 @@ +pandoc: '3.4' +pkgdown: 2.1.3 +pkgdown_sha: ~ +articles: + zoomss: zoomss.html +last_built: 2025-08-21T03:22Z +urls: + reference: https://MathMarEcol.github.io/zoomss/reference + article: https://MathMarEcol.github.io/zoomss/articles diff --git a/docs/reference/GroupInputs-1.png b/docs/reference/GroupInputs-1.png new file mode 100644 index 0000000..6a0e009 Binary files /dev/null and b/docs/reference/GroupInputs-1.png differ diff --git a/docs/reference/GroupInputs.html b/docs/reference/GroupInputs.html new file mode 100644 index 0000000..fb2382a --- /dev/null +++ b/docs/reference/GroupInputs.html @@ -0,0 +1,177 @@ + +Default functional groups for the ZooMSS model — GroupInputs • zoomss + Skip to contents + + +
    +
    +
    + +
    +

    A dataset containing the biological parameters for different +functional groups used in the ZooMSS size-structured marine ecosystem model. +These represent various taxa from flagellates to large fish, each defined +by their feeding behavior, size ranges, and physiological parameters.

    +
    + +
    +

    Usage

    +
    GroupInputs
    +
    + +
    +

    Format

    +

    A data frame with 12 rows (functional groups) and 19 columns:

    Species
    +

    Character. Name of the functional group/taxa

    + +
    Type
    +

    Character. Broad category (Zooplankton or Fish)

    + +
    FeedType
    +

    Character. Feeding strategy (Heterotroph, FilterFeeder, Omnivore, Carnivore)

    + +
    Prop
    +

    Numeric. Initial proportion of total biomass

    + +
    W0
    +

    Numeric. Log10 minimum body weight (g) for the group

    + +
    Wmax
    +

    Numeric. Log10 maximum body weight (g) for the group

    + +
    Wmat
    +

    Numeric. Log10 maturation body weight (g)

    + +
    SearchCoef
    +

    Numeric. Search coefficient for predation interactions

    + +
    SearchExp
    +

    Numeric. Search exponent for predation scaling

    + +
    PPMRscale
    +

    Numeric. Predator-prey mass ratio scaling parameter

    + +
    PPMR
    +

    Numeric. Predator-prey mass ratio (for fish groups)

    + +
    FeedWidth
    +

    Numeric. Feeding kernel width parameter

    + +
    GrossGEscale
    +

    Numeric. Gross growth efficiency scaling

    + +
    Carbon
    +

    Numeric. Carbon content proportion

    + +
    Repro
    +

    Numeric. Reproduction parameter

    + +
    Fmort
    +

    Numeric. Fishing mortality rate

    + +
    Fmort_W0
    +

    Numeric. Log10 minimum weight for fishing mortality

    + +
    Fmort_Wmax
    +

    Numeric. Log10 maximum weight for fishing mortality

    + +
    PlotColour
    +

    Character. Color code for plotting the functional group

    + + +
    +
    +

    Source

    +

    Marine ecological literature and ZooMSS model development

    +
    +
    +

    Details

    +

    ZooMSS Functional Groups Data

    +

    The GroupInputs dataset defines 12 functional groups spanning from +small microzooplankton (flagellates, ciliates) through various mesozooplankton +groups (copepods, euphausiids, chaetognaths) to gelatinous zooplankton (salps, jellyfish) +and three fish size classes (small, medium, large). Each group is characterized by:

    • Size ranges: W0 to Wmax define the body size spectrum

    • +
    • Feeding behavior: Different strategies for resource acquisition

    • +
    • Interaction parameters: Search rates and predator-prey relationships

    • +
    • Physiological rates: Growth efficiency and carbon content

    • +

    These parameters are based on marine ecological literature and represent +typical values for temperate marine ecosystems.

    +
    + +
    +

    Examples

    +
    data(GroupInputs)
    +head(GroupInputs)
    +#> # A tibble: 6 × 19
    +#>   Species  Type  FeedType  Prop    W0  Wmax  Wmat SearchCoef SearchExp PPMRscale
    +#>   <chr>    <chr> <chr>    <dbl> <dbl> <dbl> <dbl>      <dbl>     <dbl>     <dbl>
    +#> 1 Flagell… Zoop… Heterot…  0.1  -12    -6.8  -8.8        640       0.8      1.5 
    +#> 2 Ciliates Zoop… Heterot…  0.1   -9.3  -6.3  -8.3        640       0.8      0.04
    +#> 3 Larvace… Zoop… FilterF…  0.1   -6.4  -3.2  -5.2        640       0.8     -3   
    +#> 4 OmniCop… Zoop… Omnivore  0.04  -7.5  -3.5  -5.5        640       0.8     -0.5 
    +#> 5 CarnCop… Zoop… Carnivo…  0.06  -7.5  -2.5  -4.5        640       0.8      1.5 
    +#> 6 Euphaus… Zoop… Omnivore  0.1   -4.2   0.2  -1.8        640       0.8     -2   
    +#> # ℹ 9 more variables: PPMR <dbl>, FeedWidth <dbl>, GrossGEscale <dbl>,
    +#> #   Carbon <dbl>, Repro <dbl>, Fmort <dbl>, Fmort_W0 <dbl>, Fmort_Wmax <dbl>,
    +#> #   PlotColour <chr>
    +
    +# View size ranges across groups
    +plot(GroupInputs$W0, GroupInputs$Wmax, 
    +     col = GroupInputs$PlotColour,
    +     xlab = "Log10 Min Weight", ylab = "Log10 Max Weight")
    +text(GroupInputs$W0, GroupInputs$Wmax, GroupInputs$Species, pos = 3, cex = 0.7)
    +
    +
    +
    +
    + + +
    + + + +
    + + + + + + + diff --git a/docs/reference/index.html b/docs/reference/index.html new file mode 100644 index 0000000..99cd813 --- /dev/null +++ b/docs/reference/index.html @@ -0,0 +1,259 @@ + +Package index • zoomss + Skip to contents + + +
    +
    +
    + +
    +

    Data

    + +

    Data related functions and datasets

    + + +
    + + + + +
    + + GroupInputs + +
    +
    Default functional groups for the ZooMSS model
    +
    + + getGroups() + +
    +
    Load default or custom functional groups for ZooMSS model
    +
    + + calculatePhytoParam() + +
    +
    Calculate phytoplankton abundance spectrum from chlorophyll data
    +
    + + createEnviroData() + +
    +
    Generate synthetic environmental data for ZooMSS testing
    +
    + + createInputParams() + +
    +
    Create input parameters data frame for ZooMSS model runs
    +
    + + validateGroups() + +
    +
    Validate ZooMSS functional groups data structure and values
    +
    +

    Model Runs

    + +

    Functions for running the model

    + + +
    + + + + +
    + + zoomss_model() + +
    +
    Main ZooMSS model function for complete simulations
    +
    + + zoomss_mvf() + +
    +
    Solve McKendrick-von Foerster equation for size-structured populations
    +
    + + zoomss_params() + +
    +
    Initialize and validate ZooMSS model parameters
    +
    + + zoomss_run() + +
    +
    Execute the main ZooMSS simulation loop with dynamic environmental forcing
    +
    + + zoomss_setup() + +
    +
    Initialize ZooMSS model components and calculate feeding interactions
    +
    +

    Plotting

    + +

    Functions for plotting.

    + + +
    + + + + +
    + + plotEnvironment() + +
    +
    Plot environmental forcing data
    +
    + + plotPPMR() + +
    +
    Visualize predator-prey mass ratio patterns in ZooMSS results
    +
    + + plotSizeSpectra() + +
    +
    Visualize abundance size spectra across functional groups
    +
    + + plotTimeSeries() + +
    +
    Unified function to visualize time series changes for different metrics
    +
    +

    Data wrangling

    + +

    Helper functions to convert units and data format

    + + +
    + + + + +
    + + averageTimeSeries() + +
    +
    Calculate mean of final portion of ZooMSS time series
    +
    + + extractPPMR() + +
    +
    Calculate predator-prey mass ratio data for visualization
    +
    + + extractSizeRange() + +
    +
    Extract specific size class range from model variable
    +
    + + extractTrophicLevels() + +
    +
    Compute trophic levels for functional groups using diet composition
    +
    + + getBiomass() + +
    +
    Convert ZooMSS abundance matrices to biomass by multiplying by body weights
    +
    + + getGroups() + +
    +
    Load default or custom functional groups for ZooMSS model
    +
    + + reduceAll() + +
    +
    Sum abundances across all groups and size classes
    +
    + + reduceSize() + +
    +
    Aggregate ZooMSS abundances across all size classes
    +
    + + reduceSpecies() + +
    +
    Aggregate ZooMSS abundances across all functional groups
    +
    +

    Private functions

    + +

    Functions to be unexported

    + + +
    + + + + +
    + + untibble() + +
    +
    Convert tibble to data frame for efficiency
    +
    +
    + + +
    + + + +
    + + + + + + + diff --git a/docs/reference/pipe.html b/docs/reference/pipe.html new file mode 100644 index 0000000..18dc753 --- /dev/null +++ b/docs/reference/pipe.html @@ -0,0 +1,81 @@ + +Pipe operator — %>% • zoomss + Skip to contents + + +
    +
    +
    + +
    +

    See magrittr::%>% for details.

    +
    + +
    +

    Usage

    +
    lhs %>% rhs
    +
    + +
    +

    Arguments

    + + +
    lhs
    +

    A value or the magrittr placeholder.

    + + +
    rhs
    +

    A function call using the magrittr semantics.

    + +
    +
    +

    Value

    +

    The result of calling rhs(lhs).

    +
    + +
    + + +
    + + + +
    + + + + + + + diff --git a/docs/reference/untibble.html b/docs/reference/untibble.html new file mode 100644 index 0000000..1258d79 --- /dev/null +++ b/docs/reference/untibble.html @@ -0,0 +1,87 @@ + +Convert tibble to data frame for efficiency — untibble • zoomss + Skip to contents + + +
    +
    +
    + +
    +

    Removes tibble attributes and converts to a plain data frame +for improved speed and memory efficiency in computational workflows.

    +
    + +
    +

    Usage

    +
    untibble(tibble)
    +
    + +
    +

    Arguments

    + + +
    tibble
    +

    A tibble or data frame object to convert

    + +
    +
    +

    Value

    +

    Plain data frame without tibble attributes

    +
    +
    +

    Details

    +

    Remove Tibble Attributes

    +

    This utility function strips tibble-specific attributes that can +slow down operations in tight computational loops. Used internally by +ZooMSS for performance optimization when working with large datasets.

    +
    + +
    + + +
    + + + +
    + + + + + + + diff --git a/docs/reference/zAveOutput.html b/docs/reference/zAveOutput.html new file mode 100644 index 0000000..50d7090 --- /dev/null +++ b/docs/reference/zAveOutput.html @@ -0,0 +1,103 @@ + +Calculate mean of final portion of ZooMSS time series — zAveOutput • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Calculates the mean of the final portion (default 50%) of a time series +to obtain equilibrium values after model spin-up period.

    +
    + +
    +
    zAveOutput(x, prop = 0.5)
    +
    + +
    +

    Arguments

    + + +
    x
    +

    3D array with dimensions (time, groups, size_classes)

    + + +
    prop
    +

    Proportion of final time series to average (default: 0.5)

    + +
    +
    +

    Value

    +

    2D array with averaged values (groups x size_classes)

    +
    +
    +

    Details

    +

    Calculate Average Output from Model Time Series

    +

    This function removes the initial transient period from time series data +and calculates the mean of the remaining portion, providing representative +steady-state values. Essential for obtaining equilibrium abundances, growth rates, +and other model outputs after the model has reached dynamic equilibrium.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zBiomass.html b/docs/reference/zBiomass.html new file mode 100644 index 0000000..0356e84 --- /dev/null +++ b/docs/reference/zBiomass.html @@ -0,0 +1,102 @@ + +Convert ZooMSS abundance matrices to biomass by multiplying by body weights — getBiomass • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Converts abundance data to wet weight biomass by multiplying abundances +by the corresponding body weights for each size class.

    +
    + +
    +
    getBiomass(res, vmdl)
    +
    + +
    +

    Arguments

    + + +
    res
    +

    List of abundance matrices from ZooMSS output

    + + +
    vmdl
    +

    ZooMSS model object containing weight vector (param$w)

    + +
    +
    +

    Value

    +

    List of biomass matrices in grams wet weight

    +
    +
    +

    Details

    +

    Convert Abundance to Biomass

    +

    This function transforms abundance matrices to biomass by applying the +weight vector across size classes. Essential for analyses requiring biomass +units rather than abundance counts.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zCalculatePhytoParam.html b/docs/reference/zCalculatePhytoParam.html new file mode 100644 index 0000000..db4d1a8 --- /dev/null +++ b/docs/reference/zCalculatePhytoParam.html @@ -0,0 +1,114 @@ + +Calculate phytoplankton abundance spectrum from chlorophyll data — calculatePhytoParam • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Converts chlorophyll concentration data to phytoplankton size spectrum +parameters (slope, intercept, maximum size) using established oceanographic relationships.

    +
    + +
    +
    calculatePhytoParam(df)
    +
    + +
    +

    Arguments

    + + +
    df
    +

    Data frame containing chlorophyll data (chl column in mg/m^3) and +optionally phytoplankton biomass (phy column in g/m^3)

    + +
    +
    +

    Value

    +

    Data frame with added columns:

    • phyto_slope: Power law slope for phytoplankton size spectrum

    • +
    • phyto_int: Log10 intercept for phytoplankton abundance

    • +
    • phyto_max: Maximum phytoplankton size (log10 grams)

    • +
    • pico_biom, nano_biom, micro_biom: Biomass in each size class

    • +
    +
    +

    Details

    +

    Calculate Phytoplankton Size Spectrum Parameters

    +

    This function implements the Brewin et al. (2015) algorithm to partition +chlorophyll among picophytoplankton, nanophytoplankton, and microphytoplankton size +classes, then calculates:

    • Size spectrum slope and intercept parameters

    • +
    • Maximum phytoplankton size based on micro proportion

    • +
    • Biomass estimates for each size class

    • +

    These parameters drive the dynamic phytoplankton spectrum in ZooMSS that serves +as the base of the food web. The function can work with either chlorophyll-only +data (using empirical relationships) or direct phytoplankton biomass measurements.

    +
    +
    +

    References

    +

    Brewin, R.J.W., et al. (2015). A three-component model of phytoplankton size class +for the Atlantic Ocean. Ecological Modelling, 306, 90-101.

    +

    Maranon, E., et al. (2014). Resource supply overrides temperature as a controlling +factor of marine phytoplankton growth. PLoS ONE, 9(6), e99312.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zCarbonBiomass.html b/docs/reference/zCarbonBiomass.html new file mode 100644 index 0000000..37e3957 --- /dev/null +++ b/docs/reference/zCarbonBiomass.html @@ -0,0 +1,103 @@ + +Convert ZooMSS abundances to carbon biomass across all size classes — zCarbonBiomass • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Converts abundance data to carbon biomass by multiplying by body weights +and then by carbon content factors for each functional group.

    +
    + +
    +
    zCarbonBiomass(res, vmdl)
    +
    + +
    +

    Arguments

    + + +
    res
    +

    List of abundance matrices from ZooMSS output

    + + +
    vmdl
    +

    ZooMSS model object containing weight vector and carbon content factors

    + +
    +
    +

    Value

    +

    List of carbon biomass matrices (grams carbon)

    +
    +
    +

    Details

    +

    Convert Abundance to Carbon Biomass

    +

    This function performs a two-step conversion:

    1. Abundance to wet weight biomass (using body weights)

    2. +
    3. Wet weight to carbon biomass (using group-specific carbon content)

    4. +

    Carbon biomass is essential for biogeochemical analyses and comparisons +with field data that are often reported in carbon units.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zConvert2Tibble.html b/docs/reference/zConvert2Tibble.html new file mode 100644 index 0000000..8a0925d --- /dev/null +++ b/docs/reference/zConvert2Tibble.html @@ -0,0 +1,102 @@ + +Convert ZooMSS list output to tibble with species names — zConvert2Tibble • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Converts ZooMSS list output to a tibble format with proper column +names based on functional group species names.

    +
    + +
    +
    zConvert2Tibble(li, vmdl)
    +
    + +
    +

    Arguments

    + + +
    li
    +

    List of vectors/matrices from ZooMSS aggregation functions

    + + +
    vmdl
    +

    ZooMSS model object containing species names (param$Groups$Species)

    + +
    +
    +

    Value

    +

    Tibble with columns named by species and rows representing spatial cells

    +
    +
    +

    Details

    +

    Convert List to Tibble Format

    +

    This function converts aggregated ZooMSS output (typically from +reduceSize or similar functions) into a tibble format suitable for +analysis and visualization. Currently designed for 2D data (species x cells).

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zCreateInputs.html b/docs/reference/zCreateInputs.html new file mode 100644 index 0000000..939833f --- /dev/null +++ b/docs/reference/zCreateInputs.html @@ -0,0 +1,130 @@ + +Create input parameters data frame for ZooMSS model runs — createInputParams • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Creates a properly formatted input parameters data frame for ZooMSS model +simulations, combining temporal parameters with environmental time series data.

    +
    + +
    +
    createInputParams(time, sst, chl, cellID = NULL)
    +
    + +
    +

    Arguments

    + + +
    time
    +

    Numeric vector of time values in years (must be increasing and uniform, can start at any value)

    + + +
    sst
    +

    Numeric vector of sea surface temperature values in deg C

    + + +
    chl
    +

    Numeric vector of chlorophyll concentration values in mg/m^3

    + + +
    cellID
    +

    Optional numeric vector of cell identifiers for spatial data (default: NULL)

    + +
    +
    +

    Value

    +

    Data frame with columns: time, time_step, sst, chl, and cellID (if provided)

    +
    +
    +

    Details

    +

    Create ZooMSS Input Parameters Object

    +

    This function combines environmental time series (SST and chlorophyll) with +time data to create the input_params object required by zoomss_model(). +The function performs validation checks using assertthat to ensure:

    • All input vectors are numeric and of equal length

    • +
    • SST values are within reasonable ocean range (-2 to 35 deg C)

    • +
    • Chlorophyll values are positive and within typical range (0 to 50 mg/m^3)

    • +
    • Time values are increasing and reasonable

    • +
    + +
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +# Create simple environmental time series
    +time_vec <- seq(0, 10, 0.01)  # 10 years with 0.01 year time steps
    +sst_vec <- 15 + 3*sin(2*pi*time_vec/1)  # annual cycle
    +chl_vec <- 0.5 + 0.2*cos(2*pi*time_vec/1)  # annual cycle
    +
    +# Create input parameters object
    +input_params <- createInputParams(time_vec, sst_vec, chl_vec)
    +
    +# Use with ZooMSS model
    +results <- zoomss_model(input_params, Groups, isave = 50)
    +} # }
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zCreateSimpleTimeSeries.html b/docs/reference/zCreateSimpleTimeSeries.html new file mode 100644 index 0000000..796a1be --- /dev/null +++ b/docs/reference/zCreateSimpleTimeSeries.html @@ -0,0 +1,157 @@ + +Generate synthetic environmental data for ZooMSS testing — createEnviroData • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Creates simple synthetic environmental time series with optional seasonal +variation for testing ZooMSS model runs when real environmental data is not available.

    +
    + +
    +
    createEnviroData(
    +  n_time_steps,
    +  dt,
    +  base_sst = 15,
    +  base_chl = 0.5,
    +  seasonal = TRUE,
    +  sst_amplitude = 3,
    +  chl_amplitude = 0.2
    +)
    +
    + +
    +

    Arguments

    + + +
    n_time_steps
    +

    Number of time steps to generate

    + + +
    dt
    +

    Time step size in years

    + + +
    base_sst
    +

    Base sea surface temperature in deg C (default: 15)

    + + +
    base_chl
    +

    Base chlorophyll concentration in mg/m^3 (default: 0.5)

    + + +
    seasonal
    +

    Logical, whether to add seasonal variation (default: TRUE)

    + + +
    sst_amplitude
    +

    Amplitude of SST seasonal variations in deg C (default: 3)

    + + +
    chl_amplitude
    +

    Amplitude of chlorophyll seasonal variations in mg/m^3 (default: 0.2)

    + +
    +
    +

    Value

    +

    Data frame with columns: time, sst, chl

    +
    +
    +

    Details

    +

    Create Simple Environmental Time Series for Testing

    +

    This function generates synthetic sea surface temperature and chlorophyll +time series that can be used for testing ZooMSS model behavior. The function can +create either static environmental conditions or seasonal cycles with sinusoidal +variation. This is particularly useful for:

    • Testing model sensitivity to environmental forcing

    • +
    • Creating idealized scenarios for model exploration

    • +
    • Generating data when real environmental data is unavailable

    • +

    The seasonal option creates SST and chlorophyll cycles that are out of phase, +mimicking typical ocean patterns where chlorophyll peaks when SST is lower.

    +
    + +
    +

    Examples

    +
    # Create seasonal environmental data
    +env_data <- createEnviroData(
    +  n_time_steps = 1000,
    +  dt = 0.01,
    +  seasonal = TRUE
    +)
    +#> Error in createEnviroData(n_time_steps = 1000, dt = 0.01, seasonal = TRUE): unused argument (n_time_steps = 1000)
    +
    +# Create static environmental conditions
    +static_data <- createEnviroData(
    +  n_time_steps = 500,
    +  dt = 0.01,
    +  seasonal = FALSE,
    +  base_sst = 20,
    +  base_chl = 1.0
    +)
    +#> Error in createEnviroData(n_time_steps = 500, dt = 0.01, seasonal = FALSE,     base_sst = 20, base_chl = 1): unused argument (n_time_steps = 500)
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zExtractSizeRange.html b/docs/reference/zExtractSizeRange.html new file mode 100644 index 0000000..328af8a --- /dev/null +++ b/docs/reference/zExtractSizeRange.html @@ -0,0 +1,107 @@ + +Extract specific size class range from abundance matrices — extractSizeRange • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Subsets ZooMSS output to include only specified size classes, +useful for focusing analysis on particular size ranges.

    +
    + +
    +
    extractSizeRange(list_in, minb, maxb)
    +
    + +
    +

    Arguments

    + + +
    list_in
    +

    List of abundance matrices from ZooMSS output

    + + +
    minb
    +

    Minimum size class index to extract

    + + +
    maxb
    +

    Maximum size class index to extract

    + +
    +
    +

    Value

    +

    List of abundance matrices with only specified size classes

    +
    +
    +

    Details

    +

    Extract Size Range from ZooMSS Output

    +

    This function extracts a subset of size classes from the full +ZooMSS output matrices. Useful for analyzing specific size ranges +(e.g., microzooplankton, mesozooplankton) or excluding boundary effects +from model analysis.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zExtract_PPMR.html b/docs/reference/zExtract_PPMR.html new file mode 100644 index 0000000..8bb0da2 --- /dev/null +++ b/docs/reference/zExtract_PPMR.html @@ -0,0 +1,101 @@ + +Calculate predator-prey mass ratio data for visualization — extractPPMR • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Calculates predator-prey mass ratio (PPMR) values and biomass weightings +for creating PPMR distribution plots in ZooMSS analysis.

    +
    + +
    +
    extractPPMR(dat)
    +
    + +
    +

    Arguments

    + + +
    dat
    +

    ZooMSS results object containing abundances and model parameters

    + +
    +
    +

    Value

    +

    List containing PPMR density data and species-specific values for plotting

    +
    +
    +

    Details

    +

    Calculate PPMR Data for Plotting

    +

    This function computes theoretical and realized PPMR patterns by:

    • Calculating size-dependent PPMR values using Wirtz 2012 equations

    • +
    • Weighting by biomass to show community-level patterns

    • +
    • Computing species-specific PPMR values

    • +
    • Handling special cases for filter feeders (larvaceans, salps)

    • +

    This is a helper function primarily used by plotPPMR for visualization. +PPMR analysis provides insights into food web structure and predation patterns.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zGetGroups.html b/docs/reference/zGetGroups.html new file mode 100644 index 0000000..c94e9df --- /dev/null +++ b/docs/reference/zGetGroups.html @@ -0,0 +1,131 @@ + +Load default or custom functional groups for ZooMSS model — getGroups • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Provides access to the default ZooMSS functional groups or loads custom +groups from a file. This function is the primary way to obtain Groups data for +ZooMSS model runs.

    +
    + +
    +
    getGroups(source = c("default", "file", "template"), file = NULL)
    +
    + +
    +

    Arguments

    + + +
    source
    +

    Character string specifying data source. Options:

    • "default": Use built-in ZooMSS functional groups

    • +
    • "file": Load groups from a CSV file

    • +
    • "template": Export default groups to a file for modification

    • +
    + + +
    file
    +

    Path to CSV file when source="file" or source="template"

    + +
    +
    +

    Value

    +

    Data frame containing functional groups with required columns: +Species, Type, W0, Wmax, and other biological parameters

    +
    +
    +

    Details

    +

    Get Default ZooMSS Functional Groups

    +

    This function provides flexible access to functional groups data:

    • Default groups: Returns the standard ZooMSS functional groups (9 groups)

    • +
    • Custom file: Loads and validates groups from a user-provided CSV file

    • +
    • Template creation: Exports default groups to a file for user modification

    • +

    The default groups include: Flagellates, Ciliates, Larvaceans, OmniCopepods, +CarnCopepods, Euphausiids, Chaetognaths, Salps, and Jellyfish.

    +

    All groups data is validated to ensure it contains required columns and +reasonable parameter values for successful model runs.

    +
    + +
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +# Use default groups
    +Groups <- getGroups()
    +
    +# Create a template file for modification
    +getGroups(source = "template", file = "my_groups.csv")
    +
    +# Load custom groups from file
    +custom_groups <- getGroups(source = "file", file = "my_groups.csv")
    +
    +# Modify default groups programmatically
    +Groups <- getGroups()
    +Groups$W0[Groups$Species == "Flagellates"] <- -12.5  # Modify minimum size
    +} # }
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zLoadDefaultGroups.html b/docs/reference/zLoadDefaultGroups.html new file mode 100644 index 0000000..bb656ab --- /dev/null +++ b/docs/reference/zLoadDefaultGroups.html @@ -0,0 +1,89 @@ + +Internal function to load default ZooMSS groups — loadDefaultGroups • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Loads the default functional groups from the package data or CSV file. +This is an internal function used by getGroups().

    +
    + +
    +
    loadDefaultGroups()
    +
    + +
    +

    Value

    +

    Data frame with default functional groups

    +
    +
    +

    Details

    +

    Load Default Functional Groups Data

    +

    This function handles the actual loading of default groups data, +whether from package data (if available) or from the CSV file in data-raw.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zMakeDietTibble.html b/docs/reference/zMakeDietTibble.html new file mode 100644 index 0000000..1d2e2cb --- /dev/null +++ b/docs/reference/zMakeDietTibble.html @@ -0,0 +1,103 @@ + +Convert diet matrix to long format for analysis and visualization — makeDietTibble • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Converts ZooMSS diet matrix from wide format to long (tidy) format +with predator-prey relationships clearly defined.

    +
    + +
    +
    makeDietTibble(mat, mdl)
    +
    + +
    +

    Arguments

    + + +
    mat
    +

    Diet matrix from ZooMSS output (predators x prey)

    + + +
    mdl
    +

    ZooMSS model object containing species names for labeling

    + +
    +
    +

    Value

    +

    Long tibble with columns: Predator, Prey, Diet

    +
    +
    +

    Details

    +

    Create Diet Matrix in Long Tibble Format

    +

    This function transforms diet matrices into a long format suitable for +analysis and visualization of feeding relationships. The resulting tibble +contains predator-prey pairs with diet fraction values, making it easy to +analyze trophic interactions and create food web visualizations.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zPlotEnvironment.html b/docs/reference/zPlotEnvironment.html new file mode 100644 index 0000000..6cd5858 --- /dev/null +++ b/docs/reference/zPlotEnvironment.html @@ -0,0 +1,113 @@ + +Plot environmental forcing data — plotEnvironment • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Creates plots of sea surface temperature and chlorophyll time series +for visualizing environmental forcing data used in ZooMSS model runs.

    +
    + +
    +
    plotEnvironment(env_data)
    +
    + +
    +

    Arguments

    + + +
    env_data
    +

    Environmental data frame with time, sst, chlo columns

    + +
    +
    +

    Value

    +

    ggplot object (if patchwork available) or list of two ggplot objects

    +
    +
    +

    Details

    +

    Plot Environmental Time Series

    +

    This function creates two separate plots with different y-axes scales:

    • SST plot (red line) with temperature in deg C

    • +
    • Chlorophyll plot (green line) with concentration in mg/m^3

    • +

    The plots can be combined using the patchwork package if available, otherwise +separate plots are returned as a list. This helps users visualize the +environmental forcing that drives ZooMSS model dynamics.

    +
    + +
    +

    Examples

    +
    # Create sample data and plot
    +env_data <- data.frame(
    +  time = 1:100,
    +  dt = 0.01,
    +  sst = 15 + 3*sin(2*pi*(1:100)/50),
    +  chlo = 0.5 + 0.2*cos(2*pi*(1:100)/50)
    +)
    +plots <- plotEnvironment(env_data)
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zPlot_AbundTimeSeries.html b/docs/reference/zPlot_AbundTimeSeries.html new file mode 100644 index 0000000..d012c96 --- /dev/null +++ b/docs/reference/zPlot_AbundTimeSeries.html @@ -0,0 +1,114 @@ + +Visualize abundance changes over time for each functional group — zPlot_AbundTimeSeries • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Creates time series plots showing how total abundance of each functional +group changes throughout the ZooMSS simulation period.

    +
    + +
    +
    zPlot_AbundTimeSeries(dat)
    +
    + +
    +

    Arguments

    + + +
    dat
    +

    ZooMSS results object containing model outputs with time series data

    + +
    +
    +

    Value

    +

    ggplot object showing abundance time series by species

    +
    +
    +

    Details

    +

    Plot Abundance Time Series

    +

    This function creates time series visualization by:

    • Summing abundances across all size classes for each functional group

    • +
    • Converting to long format for ggplot visualization

    • +
    • Plotting log-transformed abundance over time

    • +
    • Using species-specific colors and filtering out zero abundances

    • +

    Time series plots help identify:

    • Equilibration time for model runs

    • +
    • Seasonal or cyclical patterns in abundance

    • +
    • Relative abundance patterns between functional groups

    • +
    • Model stability and convergence behavior

    • +
    + +
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +# After running ZooMSS model with SaveTimeSteps = TRUE
    +results <- zoomss_model(input_params, Groups, SaveTimeSteps = TRUE)
    +time_plot <- zPlot_AbundTimeSeries(results)
    +print(time_plot)
    +} # }
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zPlot_BiomassTimeSeries.html b/docs/reference/zPlot_BiomassTimeSeries.html new file mode 100644 index 0000000..7278328 --- /dev/null +++ b/docs/reference/zPlot_BiomassTimeSeries.html @@ -0,0 +1,145 @@ + +Visualize biomass changes over time with multiple display options — zPlot_BiomassTimeSeries • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Creates flexible time series plots showing how total biomass of functional +groups changes throughout the ZooMSS simulation, with options for line plots, +stacked area plots, and proportional displays.

    +
    + +
    +
    zPlot_BiomassTimeSeries(
    +  dat,
    +  stacked = FALSE,
    +  proportional = FALSE,
    +  species = NULL
    +)
    +
    + +
    +

    Arguments

    + + +
    dat
    +

    ZooMSS results object containing model outputs with time series data

    + + +
    stacked
    +

    Logical, whether to create stacked area plot instead of line plot (default: FALSE)

    + + +
    proportional
    +

    Logical, whether to show proportions instead of absolute values (default: FALSE)

    + + +
    species
    +

    Character vector of species names to include in plot. If NULL, all species included (default: NULL)

    + +
    +
    +

    Value

    +

    ggplot object showing biomass time series by species

    +
    +
    +

    Details

    +

    Plot Biomass Time Series

    +

    This function creates biomass time series visualization with multiple options:

    • Line plots: Individual species biomass trajectories over time

    • +
    • Stacked plots: Cumulative biomass showing total ecosystem biomass

    • +
    • Proportional plots: Relative biomass contributions (0-1 scale)

    • +
    • Species filtering: Focus on specific functional groups

    • +

    The function calculates biomass by multiplying abundance by body weights and +summing across size classes for each functional group. Different plot types help +visualize different aspects of ecosystem dynamics:

    • Line plots show individual group patterns and relative magnitudes

    • +
    • Stacked plots show total ecosystem biomass and contributions

    • +
    • Proportional plots highlight shifts in community composition

    • +
    + +
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +# After running ZooMSS model with SaveTimeSteps = TRUE
    +results <- zoomss_model(input_params, Groups, SaveTimeSteps = TRUE)
    +
    +# Basic line plot of all species
    +biomass_plot <- zPlot_BiomassTimeSeries(results)
    +
    +# Stacked area plot showing total biomass
    +stacked_plot <- zPlot_BiomassTimeSeries(results, stacked = TRUE)
    +
    +# Proportional plot showing relative contributions
    +prop_plot <- zPlot_BiomassTimeSeries(results, proportional = TRUE)
    +
    +# Focus on specific groups
    +copepod_plot <- zPlot_BiomassTimeSeries(results,
    +                                              species = c("OmniCopepods", "CarnCopepods"))
    +} # }
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zPlot_GrowthTimeSeries.html b/docs/reference/zPlot_GrowthTimeSeries.html new file mode 100644 index 0000000..a4d7db3 --- /dev/null +++ b/docs/reference/zPlot_GrowthTimeSeries.html @@ -0,0 +1,114 @@ + +Visualize growth rate changes over time for each functional group — zPlot_GrowthTimeSeries • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Creates time series plots showing how average growth rates of each functional +group change throughout the ZooMSS simulation period.

    +
    + +
    +
    zPlot_GrowthTimeSeries(dat)
    +
    + +
    +

    Arguments

    + + +
    dat
    +

    ZooMSS results object containing model outputs with time series data

    + +
    +
    +

    Value

    +

    ggplot object showing growth rate time series by species

    +
    +
    +

    Details

    +

    Plot Growth Rate Time Series

    +

    This function creates growth rate time series by:

    • Averaging growth rates across all size classes for each functional group

    • +
    • Converting to long format for ggplot visualization

    • +
    • Plotting log-transformed growth rates over time

    • +
    • Using species-specific colors and filtering out zero values

    • +

    Growth rate time series help assess:

    • Environmental effects on organism growth

    • +
    • Seasonal patterns in productivity

    • +
    • Differences in growth potential between functional groups

    • +
    • Model response to changing environmental conditions

    • +
    + +
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +# After running ZooMSS model with SaveTimeSteps = TRUE
    +results <- zoomss_model(input_params, Groups, SaveTimeSteps = TRUE)
    +growth_plot <- zPlot_GrowthTimeSeries(results)
    +print(growth_plot)
    +} # }
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zPlot_PPMR.html b/docs/reference/zPlot_PPMR.html new file mode 100644 index 0000000..3b8dbcb --- /dev/null +++ b/docs/reference/zPlot_PPMR.html @@ -0,0 +1,113 @@ + +Visualize predator-prey mass ratio patterns in ZooMSS results — plotPPMR • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Creates a plot showing the distribution of predator-prey mass ratios (PPMR) +across functional groups, providing insights into the trophic structure of the ecosystem.

    +
    + +
    +
    plotPPMR(dat)
    +
    + +
    +

    Arguments

    + + +
    dat
    +

    ZooMSS results object containing model outputs and parameters

    + +
    +
    +

    Value

    +

    ggplot object showing PPMR distribution with species-specific overlays

    +
    +
    +

    Details

    +

    Plot Predator-Prey Mass Ratio (PPMR) Distribution

    +

    This function calculates and visualizes PPMR patterns by:

    • Computing theoretical PPMR values for each functional group and size class

    • +
    • Weighting by biomass to show realized community patterns

    • +
    • Creating a density plot of PPMR distribution across the community

    • +
    • Overlaying species-specific PPMR values as points

    • +

    PPMR is a key ecological metric that describes the size relationship between +predators and their prey, providing insight into food web structure and +energy transfer efficiency in marine ecosystems.

    +
    + +
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +# After running ZooMSS model
    +results <- zoomss_model(input_params, Groups, SaveTimeSteps = FALSE)
    +ppmr_plot <- plotPPMR(results)
    +print(ppmr_plot)
    +} # }
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zPlot_PredTimeSeries.html b/docs/reference/zPlot_PredTimeSeries.html new file mode 100644 index 0000000..40650bc --- /dev/null +++ b/docs/reference/zPlot_PredTimeSeries.html @@ -0,0 +1,114 @@ + +Visualize predation mortality changes over time for each functional group — zPlot_PredTimeSeries • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Creates time series plots showing how average predation mortality rates of each +functional group change throughout the ZooMSS simulation period.

    +
    + +
    +
    zPlot_PredTimeSeries(dat)
    +
    + +
    +

    Arguments

    + + +
    dat
    +

    ZooMSS results object containing model outputs with time series data

    + +
    +
    +

    Value

    +

    ggplot object showing predation mortality time series by species

    +
    +
    +

    Details

    +

    Plot Predation Mortality Time Series

    +

    This function creates predation mortality time series by:

    • Averaging predation mortality rates across all size classes for each functional group

    • +
    • Converting to long format for ggplot visualization

    • +
    • Plotting mortality rates over time without log transformation

    • +
    • Using species-specific colors and filtering out zero values

    • +

    Predation mortality time series help assess:

    • Predation pressure on different functional groups over time

    • +
    • Seasonal or temporal patterns in predation intensity

    • +
    • Relative vulnerability of functional groups to predation

    • +
    • Model dynamics and predator-prey interactions

    • +
    + +
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +# After running ZooMSS model with SaveTimeSteps = TRUE
    +results <- zoomss_model(input_params, Groups, SaveTimeSteps = TRUE)
    +mortality_plot <- zPlot_PredTimeSeries(results)
    +print(mortality_plot)
    +} # }
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zPlot_SizeSpectra.html b/docs/reference/zPlot_SizeSpectra.html new file mode 100644 index 0000000..da2af2b --- /dev/null +++ b/docs/reference/zPlot_SizeSpectra.html @@ -0,0 +1,114 @@ + +Visualize abundance size spectra across functional groups — plotSizeSpectra • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Creates a log-log plot of abundance versus body size for all functional groups, +showing the classic size spectrum pattern in marine ecosystems.

    +
    + +
    +
    plotSizeSpectra(dat)
    +
    + +
    +

    Arguments

    + + +
    dat
    +

    ZooMSS results object containing model outputs and parameters

    + +
    +
    +

    Value

    +

    ggplot object showing log abundance vs log body weight by species

    +
    +
    +

    Details

    +

    Plot Size Spectra for ZooMSS Results

    +

    This function visualizes the abundance size spectrum by:

    • Converting abundance data to long format with body weights

    • +
    • Filtering out zero abundances to focus on active size classes

    • +
    • Creating log-log plots colored by functional group

    • +
    • Using species-specific colors defined in the Groups parameter table

    • +

    Size spectra are fundamental patterns in marine ecology, typically showing +declining abundance with increasing body size. This visualization helps +assess model realism and identify dominant size classes within each +functional group.

    +
    + +
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +# After running ZooMSS model
    +results <- zoomss_model(input_params, Groups, SaveTimeSteps = FALSE)
    +size_plot <- plotSizeSpectra(results)
    +print(size_plot)
    +} # }
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zSizeBiomass.html b/docs/reference/zSizeBiomass.html new file mode 100644 index 0000000..2e475bd --- /dev/null +++ b/docs/reference/zSizeBiomass.html @@ -0,0 +1,102 @@ + +Sum biomass across functional groups for each size class — zExtractBiomassSize • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Converts abundance to biomass and sums across all functional groups +to provide total biomass per size class per spatial cell.

    +
    + +
    +
    zExtractBiomassSize(res, w)
    +
    + +
    +

    Arguments

    + + +
    res
    +

    List of abundance matrices from ZooMSS output

    + + +
    w
    +

    Vector of body weights for each size class (grams)

    + +
    +
    +

    Value

    +

    List of vectors with total biomass per size class (grams wet weight)

    +
    +
    +

    Details

    +

    Calculate Size-Class Biomass

    +

    This function provides size-class-level biomass by summing across +functional groups. Useful for analyzing community size structure and +comparing size spectrum patterns between locations.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zSpeciesBiomass.html b/docs/reference/zSpeciesBiomass.html new file mode 100644 index 0000000..8182358 --- /dev/null +++ b/docs/reference/zSpeciesBiomass.html @@ -0,0 +1,102 @@ + +Sum biomass across size classes for each functional group — zExtractBiomassSpecies • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Converts abundance to biomass and sums across all size classes +to provide total biomass per functional group per spatial cell.

    +
    + +
    +
    zExtractBiomassSpecies(res, vmdl)
    +
    + +
    +

    Arguments

    + + +
    res
    +

    List of abundance matrices from ZooMSS output

    + + +
    vmdl
    +

    ZooMSS model object containing weight vector (param$w)

    + +
    +
    +

    Value

    +

    List of vectors with total biomass per functional group (grams wet weight)

    +
    +
    +

    Details

    +

    Calculate Species-Level Biomass

    +

    This function combines abundance-to-biomass conversion with size-class +aggregation in one step, providing species-level biomass summaries useful +for spatial analyses and ecological comparisons.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zSpeciesCarbonBiomass.html b/docs/reference/zSpeciesCarbonBiomass.html new file mode 100644 index 0000000..efbeefd --- /dev/null +++ b/docs/reference/zSpeciesCarbonBiomass.html @@ -0,0 +1,104 @@ + +Convert abundances to carbon biomass and sum across size classes — zSpeciesCarbonBiomass • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Converts abundance data to carbon biomass and then sums across all +size classes to provide total carbon biomass per functional group.

    +
    + +
    +
    zSpeciesCarbonBiomass(res, vmdl)
    +
    + +
    +

    Arguments

    + + +
    res
    +

    List of abundance matrices from ZooMSS output

    + + +
    vmdl
    +

    ZooMSS model object containing weight vector and carbon content factors

    + +
    +
    +

    Value

    +

    List of vectors with total carbon biomass per functional group (grams carbon)

    +
    +
    +

    Details

    +

    Convert Abundance to Species-Level Carbon Biomass

    +

    This function combines carbon biomass conversion with size-class aggregation:

    1. Converts abundance to wet weight biomass

    2. +
    3. Converts to carbon biomass using group-specific factors

    4. +
    5. Sums across all size classes for each functional group

    6. +

    Provides species-level carbon biomass useful for ecological stoichiometry +and biogeochemical cycle analyses.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zSumAll.html b/docs/reference/zSumAll.html new file mode 100644 index 0000000..d4c6773 --- /dev/null +++ b/docs/reference/zSumAll.html @@ -0,0 +1,98 @@ + +Sum abundances across all groups and size classes — reduceAll • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Calculates total abundance across all functional groups and size classes, +providing a single abundance value per spatial cell.

    +
    + +
    +
    reduceAll(list_in)
    +
    + +
    +

    Arguments

    + + +
    list_in
    +

    List of abundance matrices (typically from multiple spatial cells)

    + +
    +
    +

    Value

    +

    Vector of total abundance values (one per spatial cell)

    +
    +
    +

    Details

    +

    Sum All ZooMSS Output

    +

    This function provides the most aggregated view of ZooMSS output by +summing across both functional groups and size classes. Useful for comparing +total community abundance between locations or time periods.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zSumSize.html b/docs/reference/zSumSize.html new file mode 100644 index 0000000..06bf48c --- /dev/null +++ b/docs/reference/zSumSize.html @@ -0,0 +1,120 @@ + +Collection of helper functions for analyzing ZooMSS model outputs — reduceSize • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    This file contains utility functions for processing, analyzing, and +transforming ZooMSS model outputs for visualization and interpretation.

    +

    Sums abundance values across all size classes for each functional group, +providing total abundance per group.

    +
    + +
    +
    reduceSize(list_in)
    +
    + +
    +

    Arguments

    + + +
    list_in
    +

    List of abundance matrices (typically from multiple spatial cells)

    + +
    +
    +

    Value

    +

    List of vectors with total abundance per functional group

    +
    +
    +

    Details

    +

    ZooMSS Utility Functions for Analysis and Post-Processing

    +

    The utility functions in this file provide tools for:

    • Converting between abundance and biomass

    • +
    • Aggregating results across size classes or functional groups

    • +
    • Calculating ecological metrics (trophic levels, PPMR)

    • +
    • Processing environmental data for model input

    • +
    • Data format conversions for analysis workflows

    • +

    These functions are essential for the ZooMSS analysis pipeline and help users +work with model outputs in different formats depending on their research needs. +Sum ZooMSS Output Across Size Bins

    +

    This function collapses the size dimension of ZooMSS output by summing +across all size classes. Useful for analyzing total abundance patterns without +size structure detail.

    +
    + +
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +# After running ZooMSS model
    +results <- zoomss_model(input_params, Groups, SaveTimeSteps = FALSE)
    +total_abundances <- reduceSize(results$abundances)
    +} # }
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zSumSpecies.html b/docs/reference/zSumSpecies.html new file mode 100644 index 0000000..3396679 --- /dev/null +++ b/docs/reference/zSumSpecies.html @@ -0,0 +1,98 @@ + +Aggregate ZooMSS abundances across all functional groups — reduceSpecies • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Sums abundance values across all functional groups for each size class, +providing total abundance per size class.

    +
    + +
    +
    reduceSpecies(list_in)
    +
    + +
    +

    Arguments

    + + +
    list_in
    +

    List of abundance matrices (typically from multiple spatial cells)

    + +
    +
    +

    Value

    +

    List of vectors with total abundance per size class

    +
    +
    +

    Details

    +

    Sum ZooMSS Output Across Functional Groups

    +

    This function collapses the functional group dimension by summing across +all groups for each size class. Useful for analyzing community size spectrum +patterns without functional group detail.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zTrophicLevel.html b/docs/reference/zTrophicLevel.html new file mode 100644 index 0000000..3ace135 --- /dev/null +++ b/docs/reference/zTrophicLevel.html @@ -0,0 +1,118 @@ + +Compute trophic levels for functional groups using diet composition — extractTrophicLevels • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Calculates trophic levels for each functional group based on their +diet composition using an iterative Gauss-Seidel algorithm.

    +
    + +
    +
    extractTrophicLevels(diet_matrix)
    +
    + +
    +

    Arguments

    + + +
    diet_matrix
    +

    12x15 matrix where rows are predators (functional groups) and +columns are prey (first 3 columns are phytoplankton size classes, remaining 12 are +zooplankton/fish groups). Values represent diet fractions.

    + +
    +
    +

    Value

    +

    Vector of trophic levels for each functional group (length 12)

    +
    +
    +

    Details

    +

    Calculate Trophic Levels from Diet Matrix

    +

    This function computes trophic levels by:

    • Starting with phytoplankton at trophic level 1.0

    • +
    • Initializing all other groups at trophic level 2.0

    • +
    • Iteratively updating trophic levels based on weighted diet composition

    • +
    • Continuing until convergence (difference < 0.01) or maximum iterations (100)

    • +

    Trophic level calculation follows: TL = 1 + sum(diet_fraction_i * TL_prey_i)

    +

    This provides a quantitative measure of each group's position in the food web +and is useful for analyzing ecosystem structure and energy transfer efficiency.

    +
    + +
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +# After running ZooMSS model
    +results <- zoomss_model(input_params, Groups, SaveTimeSteps = FALSE)
    +trophic_levels <- extractTrophicLevels(results$diets)
    +
    +# View trophic levels by group
    +names(trophic_levels) <- results$model$param$Groups$Species
    +print(trophic_levels)
    +} # }
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zValidateGroups.html b/docs/reference/zValidateGroups.html new file mode 100644 index 0000000..15844ae --- /dev/null +++ b/docs/reference/zValidateGroups.html @@ -0,0 +1,114 @@ + +Validate ZooMSS functional groups data structure and values — validateGroups • zoomss + + +
    +
    + + + +
    +
    + + +
    +

    Performs comprehensive validation of functional groups data to ensure +it meets ZooMSS model requirements.

    +
    + +
    +
    validateGroups(groups)
    +
    + +
    +

    Arguments

    + + +
    groups
    +

    Data frame containing functional groups data

    + +
    +
    +

    Value

    +

    TRUE if validation passes (invisibly), otherwise throws an error

    +
    +
    +

    Details

    +

    Validate Functional Groups Data

    +

    This function validates:

    • Required column names are present

    • +
    • Data types are correct

    • +
    • Parameter values are within reasonable ranges

    • +
    • No missing values in critical columns

    • +
    • Size ranges are logical (W0 < Wmax)

    • +
    + +
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +Groups <- getGroups()
    +validateGroups(Groups)  # Should pass
    +
    +# This would fail validation:
    +bad_groups <- Groups
    +bad_groups$W0 <- NULL
    +validateGroups(bad_groups)  # Error: missing required column
    +} # }
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.1.3.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/zoomss_model.html b/docs/reference/zoomss_model.html new file mode 100644 index 0000000..039a9e3 --- /dev/null +++ b/docs/reference/zoomss_model.html @@ -0,0 +1,132 @@ + +Main ZooMSS model function for complete simulations — zoomss_model • zoomss + Skip to contents + + +
    +
    +
    + +
    +

    This is the main wrapper function that orchestrates a complete ZooMSS +model simulation from parameter setup through model execution to output processing.

    +
    + +
    +

    Usage

    +
    zoomss_model(input_params, Groups = NULL, isave = 1)
    +
    + +
    +

    Arguments

    + + +
    input_params
    +

    Data frame containing model parameters and environmental time series. +Must include columns: time (time vector in years), sst (sea surface temperature), +and chl (chlorophyll). Can optionally include cellID for spatial data. The time step (dt) +and maximum time (tmax) are automatically calculated from the time vector. Can be created using createInputParams().

    + + +
    Groups
    +

    Data frame defining functional groups with their biological parameters. +Must include columns defining species characteristics, size ranges, and feeding parameters. +If NULL, uses default ZooMSS functional groups. Can be obtained/customized using +getGroups().

    + + +
    isave
    +

    Save frequency in time steps (default: 10)

    + +
    +
    +

    Value

    +

    Complete ZooMSS model results object containing:

    • param: Model parameters and environmental forcing data

    • +
    • N: Abundance time series (time x groups x size classes)

    • +
    • gg: Growth rate time series

    • +
    • Z: Mortality rate time series

    • +
    • diet: Diet composition time series

    • +
    • time: Time values corresponding to saved results (accounting for isave)

    • +
    • Additional model structure and kernel data

    • +
    +
    +

    Details

    +

    Run Complete ZooMSS Model Simulation

    +

    This function coordinates the entire ZooMSS modeling workflow:

    1. Validates that environmental time series data is provided

    2. +
    3. Sets up model parameters using the Groups data and input parameters

    4. +
    5. Initializes the model structure and feeding kernels

    6. +
    7. Runs the model forward in time with dynamic environmental forcing

    8. +
    9. Processes outputs by averaging the final 50% of the simulation

    10. +
    11. Returns organized results including abundances, diets, growth, and mortality

    12. +

    This is the primary entry point for +running ZooMSS simulations with environmental forcing.

    +
    + +
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +# Basic usage with default groups
    +env_data <- createEnviroData(10, 0.01)
    +input_params <- createInputParams(env_data$time, env_data$sst, env_data$chl)
    +results <- zoomss_model(input_params, isave = 50)
    +
    +# Using custom groups
    +Groups <- getGroups()  # Get default groups
    +Groups$W0[1] <- -12.5          # Modify a parameter
    +results <- zoomss_model(input_params, Groups, isave = 100)
    +
    +# Loading groups from file
    +custom_groups <- getGroups(source = "file", file = "my_groups.csv")
    +results <- zoomss_model(input_params, custom_groups)
    +} # }
    +
    +
    +
    +
    + + +
    + + + +
    + + + + + + + diff --git a/docs/reference/zoomss_mvf.html b/docs/reference/zoomss_mvf.html new file mode 100644 index 0000000..aa0da93 --- /dev/null +++ b/docs/reference/zoomss_mvf.html @@ -0,0 +1,175 @@ + +Solve McKendrick-von Foerster equation for size-structured populations — zoomss_mvf • zoomss + Skip to contents + + +
    +
    +
    + +
    +

    Solves the McKendrick-von Foerster (MvF) partial differential equation +for size-structured population dynamics using a finite difference approach in base R.

    +
    + +
    +

    Usage

    +
    zoomss_mvf(
    +  ngrps,
    +  curr_min_size,
    +  curr_max_size,
    +  A_iter,
    +  C_iter,
    +  Nb_iter,
    +  S_iter,
    +  A,
    +  B,
    +  C,
    +  Nb,
    +  S
    +)
    +
    + +
    +

    Arguments

    + + +
    ngrps
    +

    Number of functional groups in the model

    + + +
    curr_min_size
    +

    Vector of minimum size class indices for each group

    + + +
    curr_max_size
    +

    Vector of maximum size class indices for each group

    + + +
    A_iter
    +

    Matrix of advection coefficients for current iteration

    + + +
    C_iter
    +

    Matrix of diagonal coefficients for current iteration

    + + +
    Nb_iter
    +

    Matrix to store updated abundances for current iteration

    + + +
    S_iter
    +

    Matrix of source terms for current iteration

    + + +
    A
    +

    Matrix of advection coefficients

    + + +
    B
    +

    Matrix of diffusion coefficients

    + + +
    C
    +

    Matrix of diagonal coefficients

    + + +
    Nb
    +

    Matrix of abundances to be updated

    + + +
    S
    +

    Matrix of source terms

    + +
    +
    +

    Value

    +

    Updated abundance matrix (Nb) with new size-class distributions

    +
    +
    +

    Details

    +

    McKendrick-von Foerster Equation Solver (Base R Implementation)

    +

    This function implements the numerical solution to the McKendrick-von Foerster +equation, which describes how populations change across size classes over time. +The equation is solved using an upwind finite difference scheme that handles:

    • Growth through size classes (advection term)

    • +
    • Diffusion between adjacent size classes

    • +
    • Source and sink terms from feeding and mortality

    • +

    The function processes each functional group separately and applies boundary conditions +appropriate for size-structured models. The last size class is set to zero abundance +to represent maximum size limits.

    +

    This is a core computational component of ZooMSS that updates population abundances +at each time step based on growth, mortality, and reproduction processes.

    +
    + +
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +# This function is typically called internally by zoomss_run
    +# Example shows the structure of parameters needed:
    +ngrps <- 9
    +ngrid <- 100
    +curr_min_size <- c(1, 10, 20, 30, 40, 50, 60, 70, 80)
    +curr_max_size <- c(30, 40, 50, 60, 70, 80, 90, 95, 100)
    +
    +# Initialize coefficient matrices
    +A <- matrix(0, nrow = ngrps, ncol = ngrid)
    +B <- matrix(0, nrow = ngrps, ncol = ngrid) 
    +C <- matrix(1, nrow = ngrps, ncol = ngrid)
    +S <- matrix(0, nrow = ngrps, ncol = ngrid)
    +Nb <- matrix(0.1, nrow = ngrps, ncol = ngrid)
    +
    +# Run MvF solver
    +updated_abundances <- zoomss_mvf(ngrps, curr_min_size, curr_max_size,
    +                                       A, C, Nb, S, A, B, C, Nb, S)
    +} # }
    +
    +
    +
    +
    + + +
    + + + +
    + + + + + + + diff --git a/docs/reference/zoomss_params.html b/docs/reference/zoomss_params.html new file mode 100644 index 0000000..b8123bb --- /dev/null +++ b/docs/reference/zoomss_params.html @@ -0,0 +1,130 @@ + +Initialize and validate ZooMSS model parameters — zoomss_params • zoomss + Skip to contents + + +
    +
    +
    + +
    +

    Sets up the complete parameter list for ZooMSS model runs, including +functional group parameters, model dimensions, and environmental forcing data.

    +
    + +
    +

    Usage

    +
    zoomss_params(Groups, input_params, isave)
    +
    + +
    +

    Arguments

    + + +
    Groups
    +

    Data frame containing functional group definitions with columns: +Species, Type, W0 (log min size), Wmax (log max size), and various biological parameters

    + + +
    input_params
    +

    Data frame with model parameters including: +time (time vector in years), sst (sea surface temperature), and chl (chlorophyll). +The time vector can start at any value and the model automatically calculates dt (time step) and tmax (maximum time).

    + + +
    isave
    +

    Save frequency in time steps (default: 50)

    + +
    +
    +

    Value

    +

    List containing comprehensive model parameters:

    • Groups: Functional group definitions

    • +
    • ngrps: Number of functional groups

    • +
    • ngrid: Number of size classes

    • +
    • w: Size class weights (g)

    • +
    • tmax, dt, isave: Temporal parameters

    • +
    • zoo_grps, fish_grps: Indices for different organism types

    • +
    • phyto_int_ts, phyto_slope_ts: Time series of phytoplankton parameters

    • +
    • temp_eff_zoo_ts, temp_eff_fish_ts: Time series of temperature effects

    • +
    • Additional biological and physical parameters

    • +
    +
    +

    Details

    +

    Set Up ZooMSS Model Parameters

    +

    This function creates a comprehensive parameter object that contains:

    +

    Static Parameters (fixed across time steps):

    • Model dimensions (number of groups, size classes, time steps)

    • +
    • Biological parameters (growth efficiency, mortality rates)

    • +
    • Size class definitions and ranges for each functional group

    • +
    • Phytoplankton size spectrum parameters

    • +

    Dynamic Parameters (calculated from environmental data):

    • Phytoplankton abundance time series based on chlorophyll

    • +
    • Temperature effects on metabolism for zooplankton and fish

    • +
    • Environmental forcing validation and interpolation

    • +

    The function validates that environmental time series data covers the full +simulation period and pre-calculates time-varying parameters to optimize +model performance during the main simulation loop.

    +
    + +
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +# Load functional groups
    +data(Groups)
    +
    +# Create environmental time series
    +env_data <- createEnviroData(10, 0.01)
    +input_params <- createInputParams(env_data$time, env_data$sst, env_data$chl)
    +
    +# Generate parameter list
    +params <- zoomss_params(Groups, input_params, isave = 50)
    +} # }
    +
    +
    +
    +
    + + +
    + + + +
    + + + + + + + diff --git a/docs/reference/zoomss_run.html b/docs/reference/zoomss_run.html new file mode 100644 index 0000000..dac1963 --- /dev/null +++ b/docs/reference/zoomss_run.html @@ -0,0 +1,123 @@ + +Execute the main ZooMSS simulation loop with dynamic environmental forcing — zoomss_run • zoomss + Skip to contents + + +
    +
    +
    + +
    +

    Runs the ZooMSS model forward in time, updating environmental conditions +and population dynamics at each time step using the McKendrick-von Foerster framework.

    +
    + +
    +

    Usage

    +
    zoomss_run(model)
    +
    + +
    +

    Arguments

    + + +
    model
    +

    Model object created by zoomss_setup containing:

    • param: Complete parameter list with environmental time series

    • +
    • Feeding kernels and biological rate parameters

    • +
    • Initial conditions and model structure

    • +
    + +
    +
    +

    Value

    +

    List containing complete model output:

    • param: Model parameters used in simulation

    • +
    • N: Abundance time series (time x groups x size classes)

    • +
    • gg: Growth rate time series

    • +
    • diet: Diet composition time series

    • +
    • Z: Mortality rate time series

    • +
    • time: Time values corresponding to saved results (accounting for isave)

    • +
    • w: Size class weights (g)

    • +
    • Additional time series data and model results

    • +
    +
    +

    Details

    +

    Run ZooMSS Model Forward in Time

    +

    This is the core simulation engine of ZooMSS that:

    +

    Environmental Dynamics:

    • Updates phytoplankton abundance spectrum based on chlorophyll time series

    • +
    • Applies temperature effects on zooplankton and fish metabolism

    • +
    • Recalculates feeding kernels with current environmental conditions

    • +

    Population Dynamics:

    • Solves McKendrick-von Foerster equation for size-structured growth

    • +
    • Updates feeding interactions between all size classes and groups

    • +
    • Calculates mortality from predation, senescence, and fishing

    • +
    • Handles recruitment and boundary conditions for each functional group

    • +

    Time Integration:

    • Processes model through all time steps with adaptive environmental forcing

    • +
    • Saves output at specified intervals for memory efficiency

    • +
    • Maintains mass balance and numerical stability throughout simulation

    • +

    Unlike static models, this version dynamically updates phytoplankton spectra +and temperature effects at each time step based on provided environmental data.

    +
    + +
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +# Set up model parameters and structure
    +params <- zoomss_params(Groups, input_params)
    +model <- zoomss_setup(params)
    +
    +# Run the simulation
    +results <- zoomss_run(model)
    +
    +# Access final abundances
    +final_abundances <- results$N[dim(results$N)[1],,]
    +} # }
    +
    +
    +
    +
    + + +
    + + + +
    + + + + + + + diff --git a/docs/reference/zoomss_setup.html b/docs/reference/zoomss_setup.html new file mode 100644 index 0000000..f80ad2a --- /dev/null +++ b/docs/reference/zoomss_setup.html @@ -0,0 +1,126 @@ + +Initialize ZooMSS model components and calculate feeding interactions — zoomss_setup • zoomss + Skip to contents + + +
    +
    +
    + +
    +

    Sets up the ZooMSS model structure by calculating feeding kernels, mortality +rates, and other model components that remain static during the simulation.

    +
    + +
    +

    Usage

    +
    zoomss_setup(param)
    +
    + +
    +

    Arguments

    + + +
    param
    +

    Complete parameter list created by zoomss_params containing:

    • Groups: Functional group definitions and biological parameters

    • +
    • Model dimensions (ngrps, ngrid, time parameters)

    • +
    • Environmental forcing time series

    • +
    • Physical and biological constants

    • +
    + +
    +
    +

    Value

    +

    Model object containing:

    • param: Input parameters (passed through)

    • +
    • dynam_xxx: Dynamic feeding kernel arrays for group interactions (where xxx = growthkernel, diffkernel, dietkernel, mortkernel)

    • +
    • phyto_xxx: Phytoplankton feeding kernel arrays (where xxx = growthkernel, diffkernel, dietkernel)

    • +
    • nPP: Initial phytoplankton abundance spectrum

    • +
    • M_sb_base: Baseline senescence mortality rates

    • +
    • fish_mort: Fishing mortality rates

    • +
    • assim_eff: Assimilation efficiency matrix

    • +
    • temp_eff: Temperature effect matrix (initialized)

    • +
    • N: Initial abundance arrays

    • +
    • time: Time array for storing time values (initialized as NA)

    • +
    • Additional model structure components

    • +
    +
    +

    Details

    +

    Setup ZooMSS Model Structure and Feeding Kernels

    +

    This function initializes the core ZooMSS model structure by calculating:

    +

    Static Components (calculated once):

    • Feeding preference kernels based on predator-prey size ratios

    • +
    • Search volumes and encounter rates between size classes

    • +
    • Baseline mortality rates (senescence, fishing)

    • +
    • Initial abundance distributions for all functional groups

    • +

    Dynamic Component Structures (updated during run):

    • Phytoplankton feeding kernels (structure calculated here, values updated with environment)

    • +
    • Growth and diffusion kernels for zooplankton and fish interactions

    • +
    • Diet and mortality tracking arrays

    • +

    Model Architecture:

    • Size-structured populations across logarithmic size classes

    • +
    • Multiple functional groups with different feeding behaviors

    • +
    • Environmental coupling through phytoplankton and temperature

    • +

    The function separates static calculations (done once for efficiency) from +dynamic calculations (updated each time step in zoomss_run).

    +
    + +
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +# Create parameters for model setup
    +params <- zoomss_params(Groups, input_params)
    +
    +# Initialize model structure
    +model <- zoomss_setup(params)
    +
    +# Model is now ready for time integration with zoomss_run
    +results <- zoomss_run(model)
    +} # }
    +
    +
    +
    +
    + + +
    + + + +
    + + + + + + + diff --git a/docs/sitemap.xml b/docs/sitemap.xml new file mode 100644 index 0000000..db9d6ab --- /dev/null +++ b/docs/sitemap.xml @@ -0,0 +1,70 @@ + +https://MathMarEcol.github.io/zoomss/404.html +https://MathMarEcol.github.io/zoomss/LICENSE-text.html +https://MathMarEcol.github.io/zoomss/LICENSE.html +https://MathMarEcol.github.io/zoomss/articles/index.html +https://MathMarEcol.github.io/zoomss/articles/zoomss.html +https://MathMarEcol.github.io/zoomss/authors.html +https://MathMarEcol.github.io/zoomss/index.html +https://MathMarEcol.github.io/zoomss/reference/GroupInputs.html +https://MathMarEcol.github.io/zoomss/reference/averageTimeSeries.html +https://MathMarEcol.github.io/zoomss/reference/calculatePhytoParam.html +https://MathMarEcol.github.io/zoomss/reference/createEnviroData.html +https://MathMarEcol.github.io/zoomss/reference/createInputParams.html +https://MathMarEcol.github.io/zoomss/reference/extractPPMR.html +https://MathMarEcol.github.io/zoomss/reference/extractSizeRange.html +https://MathMarEcol.github.io/zoomss/reference/extractTrophicLevels.html +https://MathMarEcol.github.io/zoomss/reference/getBiomass.html +https://MathMarEcol.github.io/zoomss/reference/getGroups.html +https://MathMarEcol.github.io/zoomss/reference/index.html +https://MathMarEcol.github.io/zoomss/reference/loadDefaultGroups.html +https://MathMarEcol.github.io/zoomss/reference/pipe.html +https://MathMarEcol.github.io/zoomss/reference/plotEnvironment.html +https://MathMarEcol.github.io/zoomss/reference/plotPPMR.html +https://MathMarEcol.github.io/zoomss/reference/plotSizeSpectra.html +https://MathMarEcol.github.io/zoomss/reference/plotTimeSeries.html +https://MathMarEcol.github.io/zoomss/reference/reduceAll.html +https://MathMarEcol.github.io/zoomss/reference/reduceSize.html +https://MathMarEcol.github.io/zoomss/reference/reduceSpecies.html +https://MathMarEcol.github.io/zoomss/reference/untibble.html +https://MathMarEcol.github.io/zoomss/reference/validateGroups.html +https://MathMarEcol.github.io/zoomss/reference/zAveOutput.html +https://MathMarEcol.github.io/zoomss/reference/zBiomass.html +https://MathMarEcol.github.io/zoomss/reference/zCalculatePhytoParam.html +https://MathMarEcol.github.io/zoomss/reference/zCarbonBiomass.html +https://MathMarEcol.github.io/zoomss/reference/zConvert2Tibble.html +https://MathMarEcol.github.io/zoomss/reference/zCreateInputs.html +https://MathMarEcol.github.io/zoomss/reference/zCreateSimpleTimeSeries.html +https://MathMarEcol.github.io/zoomss/reference/zExtractAllSum.html +https://MathMarEcol.github.io/zoomss/reference/zExtractBiomassSize.html +https://MathMarEcol.github.io/zoomss/reference/zExtractBiomassSpecies.html +https://MathMarEcol.github.io/zoomss/reference/zExtractSizeRange.html +https://MathMarEcol.github.io/zoomss/reference/zExtractSizeSum.html +https://MathMarEcol.github.io/zoomss/reference/zExtractSpeciesSum.html +https://MathMarEcol.github.io/zoomss/reference/zExtractTrophicLevels.html +https://MathMarEcol.github.io/zoomss/reference/zExtract_PPMR.html +https://MathMarEcol.github.io/zoomss/reference/zGetGroups.html +https://MathMarEcol.github.io/zoomss/reference/zLoadDefaultGroups.html +https://MathMarEcol.github.io/zoomss/reference/zMakeDietTibble.html +https://MathMarEcol.github.io/zoomss/reference/zPlotEnvironment.html +https://MathMarEcol.github.io/zoomss/reference/zPlot_AbundTimeSeries.html +https://MathMarEcol.github.io/zoomss/reference/zPlot_BiomassTimeSeries.html +https://MathMarEcol.github.io/zoomss/reference/zPlot_GrowthTimeSeries.html +https://MathMarEcol.github.io/zoomss/reference/zPlot_PPMR.html +https://MathMarEcol.github.io/zoomss/reference/zPlot_PredTimeSeries.html +https://MathMarEcol.github.io/zoomss/reference/zPlot_SizeSpectra.html +https://MathMarEcol.github.io/zoomss/reference/zSizeBiomass.html +https://MathMarEcol.github.io/zoomss/reference/zSpeciesBiomass.html +https://MathMarEcol.github.io/zoomss/reference/zSpeciesCarbonBiomass.html +https://MathMarEcol.github.io/zoomss/reference/zSumAll.html +https://MathMarEcol.github.io/zoomss/reference/zSumSize.html +https://MathMarEcol.github.io/zoomss/reference/zSumSpecies.html +https://MathMarEcol.github.io/zoomss/reference/zTrophicLevel.html +https://MathMarEcol.github.io/zoomss/reference/zValidateGroups.html +https://MathMarEcol.github.io/zoomss/reference/zoomss_model.html +https://MathMarEcol.github.io/zoomss/reference/zoomss_mvf.html +https://MathMarEcol.github.io/zoomss/reference/zoomss_params.html +https://MathMarEcol.github.io/zoomss/reference/zoomss_run.html +https://MathMarEcol.github.io/zoomss/reference/zoomss_setup.html + + diff --git a/envirodata_fiveDeg_20200317.rds b/envirodata_fiveDeg_20200317.rds deleted file mode 100644 index 48315c9..0000000 Binary files a/envirodata_fiveDeg_20200317.rds and /dev/null differ diff --git a/fZooMSS_MergeMultipleCells.R b/fZooMSS_MergeMultipleCells.R deleted file mode 100644 index e48a68b..0000000 --- a/fZooMSS_MergeMultipleCells.R +++ /dev/null @@ -1,43 +0,0 @@ -# This script takes a run name and loads all -# the data from the individual cells and -# merges them into a single list -# -# -# Written by Jason Everett (UQ/CSIRO/UNSW) -# Written: Sunday 2nd February 2020 -# Last Updated: Friday 9th October 2020 - -fZooMSS_MergeMultipleCells <- function(){ - run <- basename(getwd()) - - library(tidyverse) - files <- sort(list.files("RawOutput", full.names = TRUE)) - - res <- list() - diets <- list() - growth <- list() - - for (f in 1:length(files)){ - out <- read_rds(files[f]) - - res[[f]] <- out$abundances - growth[[f]] <- out$growth - diets[[f]] <- out$diets - - if (f == 1){ - mdl <- out$model - } - - rm(out) - } - - saveRDS(mdl, paste0("Output/model_",run,".RDS")) - saveRDS(res, paste0("Output/res_",run,".RDS")) - saveRDS(growth, paste0("Output/growth_",run,".RDS")) - saveRDS(diets, paste0("Output/diets_",run,".RDS")) - - save(list = c("res", "growth", "diets", "mdl"), file = paste0(paste0("Output/full_",run,".RData"))) - - print("Consider running `tar -cf RawOutput.tar RawOutput` to reduce the number of files to be synced") - -} diff --git a/fZooMSS_Model.R b/fZooMSS_Model.R deleted file mode 100644 index a7c3f0a..0000000 --- a/fZooMSS_Model.R +++ /dev/null @@ -1,44 +0,0 @@ -fZooMSS_Model <- function(input_params, Groups, SaveTimeSteps){ - - source("fZooMSS_Params.R") - source("fZooMSS_Setup.R") - source("fZooMSS_MvF_BaseR.R") - # sourceCpp("fZooMSS_MvF_Rcpp.cpp") - source("fZooMSS_Run.R") - source("fZooMSS_Xtras.R") - - input_params <- untibble(input_params) - - ################### RUN THE MODEL ################### - param <- fZooMSS_Params(Groups, input_params) # Set up parameter list - model <- fZooMSS_Setup(param) # Set up model equation stuff - model_output <- fZooMSS_Run(model) # Run the model - - ################### AVERAGE THE LAST 50 % OF THE MODEL RUN ################### - - ave_abundances <- fZooMSS_AveOutput(model_output$N) - ave_diets <- fZooMSS_AveOutput(model_output$diet) - ave_growth <- fZooMSS_AveOutput(model_output$gg) - ave_mort <- fZooMSS_AveOutput(model_output$Z) - - if (SaveTimeSteps == TRUE){ - model_output$Abundance <- rowSums(model$N, dims = 2) ## Save Total Abundance - model_output$Biomass <- colSums(aperm(sweep(model$N, 3, model$param$w, "*"), c(3,1,2))) - - results <- list("abundances" = ave_abundances, # Save mean abundance - "diets" = ave_diets, # Save mean diets - "growth" = ave_growth, # Save mean growth - "mortality" = ave_mort, # Save mean predation - "model" = model_output) # Save whole model - } - if (SaveTimeSteps == FALSE){ - reduce_output <- list(param = model_output$param) # Create a new list so we can have identical structure of model$param - results <- list("abundances" = ave_abundances, # Save mean abundance - "diets" = ave_diets, # Save mean diets - "growth" = ave_growth, # Save mean growth - "mortality" = ave_mort, # Save mean predation - "model" = reduce_output) # Save parameters only - } - - return(results) -} diff --git a/fZooMSS_MvF_BaseR.R b/fZooMSS_MvF_BaseR.R deleted file mode 100644 index c2d7b55..0000000 --- a/fZooMSS_MvF_BaseR.R +++ /dev/null @@ -1,22 +0,0 @@ -fZooMSS_MvF_BaseR <- function(ngrps, curr_min_size, curr_max_size, A_iter, C_iter, Nb_iter, S_iter, A, B, C, Nb, S){ - - for(i in 1:ngrps){ - - idx_curr <- (curr_min_size[i]+1):curr_max_size[i] ## Set size range index for current group - - for(j in idx_curr){ ## Find the abundance at the next size class with standard MvF - Nb_iter[i,j] <- (S_iter[i,j] + A_iter[i,j]*Nb[i,j-1])/(C_iter[i,j]) - - if(j >= (idx_curr[1]+1)){ ## Find abundance with MvF with diffusion - k <- j - 1 - Nb[i,k] <- (S[i,k] + A[i,k] * Nb[i,k-1] + B[i,k] * Nb_iter[i,k+1]) / C[i,k] - } - - # MvF without diffusion for last size class - if(j == idx_curr[length(idx_curr)]){ - Nb[i,j] <- 0 - } - } - } - return(Nb) -} \ No newline at end of file diff --git a/fZooMSS_Params.R b/fZooMSS_Params.R deleted file mode 100644 index fc2c283..0000000 --- a/fZooMSS_Params.R +++ /dev/null @@ -1,44 +0,0 @@ -## Set up Model Parameter List, this imports "Groups", but also sets parameters that are -## fixed across all Groups, or required to run the model - -## Last Updated Tuesday 17th March 2020 -## - -fZooMSS_Params <- function(Groups, input_params){ - - param <- list( - Groups = Groups, # Read in functional group specific parameters from file - ngrps = dim(Groups)[1], # no. of Groups - dx = 0.1, # log10 weight step - day = 12, # day length (hours of each day in sun) - tmax = input_params$tmax, # max years - dt = input_params$dt, # timestep - w0 = 10^(min(Groups$W0)), # minimum dynamic size class - wMax = 10^(max(Groups$Wmax)),# maximum dynamic size class - gge_base = 0.25, # baseline gross growth efficiency - ZSpre = 1, # senescence mortality prefactor - ZSexp = 0.3, # senescence mortality exponent - w0_phyto = 10^(-14.5), # minimum phytoplankton size class (1um) - wMax_phyto = 10^input_params$phyto_max, # maximum phytoplankton size class - zoo_grps = which(Groups$Type == "Zooplankton"), # Which rows are zooplankton - fish_grps = which(Groups$Type == "Fish"), # Which rows are fish - num_zoo = sum(Groups$Type == "Zooplankton"), # How many zooplankton - num_fish = sum(Groups$Type == "Fish"), # How many fish - cc_phyto = 0.1, # Carbon content of phytoplankton size classes - isave = 100 # how often to save results every 'isave' time steps - ) - - ## Add additional parameters which are based on the parameter set - param2 <- list( - w_log10 = round(seq(from = min(Groups$W0), to = max(Groups$Wmax), param$dx), digits = 2), # Set up log10 dynamic weight grid - w = 10^(seq(from = min(Groups$W0), to = max(Groups$Wmax), param$dx)), # Set up log10 dynamic weight grid - w_phyto = 10^(seq(from = log10(param$w0_phyto), to = log10(param$wMax_phyto), param$dx)), # Set up phytoplankton size classes - nsave = floor(param$tmax/(param$dt*param$isave)) # Number of time slots to save - ) - - param2$ngrid <- length(param2$w) # total number of size classes for zoo and fish - param2$ngridPP <- length(param2$w_phyto) # total number of size classes for phyto - - param <- c(input_params, param, param2) # Join with input_params - return(param) -} diff --git a/fZooMSS_Plot.R b/fZooMSS_Plot.R deleted file mode 100644 index db5abf3..0000000 --- a/fZooMSS_Plot.R +++ /dev/null @@ -1,125 +0,0 @@ -library(ggplot2) -library(dplyr) -library(tidyr) -library(tibble) - -# Plot PPMR -fZooMSS_Plot_PPMR <- function(dat){ - - out <- PPMR_plot(dat) - - gg <- ggplot() + - geom_line(data = out[[2]], mapping = aes(x = Betas, y = y, colour = Species), linewidth = 1) + - geom_line(data = out[[1]], mapping = aes(x = x, y = y), linewidth = 1.2) + - theme_bw() + - theme(plot.margin=grid::unit(c(0,0,0,0), "mm")) + - labs(x = expression('log' [10] * PPMR), - y = "Zoop. Biomass Proportion", subtitle = "PPMR") + - geom_vline(data = out[[1]], mapping = aes(xintercept = mn_beta), colour = 'black') + - scale_x_continuous(expand = c(0, 0)) + - scale_y_continuous(expand = c(0, 0)) + - scale_colour_manual(values = c("Flagellates" = dat$model$param$Groups$PlotColour[dat$model$param$Groups$Species=="Flagellates"], - "Ciliates" = dat$model$param$Groups$PlotColour[dat$model$param$Groups$Species=="Ciliates"], - "Larvaceans" = dat$model$param$Groups$PlotColour[dat$model$param$Groups$Species=="Larvaceans"], - "Salps" = dat$model$param$Groups$PlotColour[dat$model$param$Groups$Species=="Salps"], - "Jellyfish" = dat$model$param$Groups$PlotColour[dat$model$param$Groups$Species=="Jellyfish"], - "CarnCopepods" = dat$model$param$Groups$PlotColour[dat$model$param$Groups$Species=="CarnCopepods"], - "Chaetognaths" = dat$model$param$Groups$PlotColour[dat$model$param$Groups$Species=="Chaetognaths"], - "Euphausiids" = dat$model$param$Groups$PlotColour[dat$model$param$Groups$Species=="Euphausiids"], - "OmniCopepods" = dat$model$param$Groups$PlotColour[dat$model$param$Groups$Species=="OmniCopepods"])) -} - -# Plot Size Spectra -fZooMSS_Plot_SizeSpectra <- function(dat) { - species <- dat$abundances - - rownames(species) <- dat$model$param$Groups$Species - species <- as_tibble(t(species)) - - species <- species %>% - add_column("Weight" = dat$model$param$w) %>% - pivot_longer(-Weight, names_to = "Species", values_to = "Abundance") %>% - filter(Abundance > 0) %>% - mutate(Species = factor(Species, levels = dat$model$param$Groups$Species)) - - gg <- ggplot(data = species, mapping = aes(x = log10(Weight), y = log10(Abundance), colour = Species)) + - geom_line() + - geom_point() + - scale_color_manual(values = dat$model$param$Groups$PlotColour) + - theme_bw() + - labs(subtitle = "Abundance Spectrum") -} - -# Plot abundance by time -fZooMSS_Plot_AbundTimeSeries <- function(dat){ - tspecies <- rowSums(dat$model$N, dims = 2) - colnames(tspecies) <- dat$model$param$Groups$Species - tspecies <- as_tibble(tspecies) - tspecies$Time <- seq(dat$model$param$dt * dat$model$param$isave, - dat$model$param$tmax, - dat$model$param$dt * dat$model$param$isave) - tspecies <- tspecies %>% - pivot_longer(-Time, names_to = "Species", values_to = "Abundance") %>% - filter(Abundance > 0) %>% - mutate(Species = factor(Species, levels = dat$model$param$Groups$Species)) - - gg <- ggplot(data = tspecies, mapping = aes(x = Time, y = log10(Abundance), colour = Species)) + - geom_line(linewidth = 1) + - geom_point(size = 1.2) + - scale_color_manual(values = dat$model$param$Groups$PlotColour) + - theme_bw() + - scale_x_continuous(expand = c(0, 0)) + - scale_y_continuous(expand = c(0, 0)) + - labs(subtitle = "Abundance") + - xlab("Time (Years)") -} - -# Plot growth by time -fZooMSS_Plot_GrowthTimeSeries <- function(dat){ - gr <- rowSums(dat$model$gg, dims = 2) / length(dat$model$param$w) - colnames(gr) <- dat$model$param$Groups$Species - gr <- as_tibble(gr) - gr$Time <- seq(dat$model$param$dt * dat$model$param$isave, - dat$model$param$tmax, - dat$model$param$dt * dat$model$param$isave) - gr <- gr %>% - pivot_longer(-Time, names_to = "Species", values_to = "Growth") %>% - filter(Growth > 0) %>% - mutate(Species = factor(Species, levels = dat$model$param$Groups$Species)) - - gg <- ggplot(data = gr, mapping = aes(x = Time, y = log10(Growth), colour = Species)) + - geom_line(linewidth = 1) + - geom_point(size = 1.2) + - scale_color_manual(values = dat$model$param$Groups$PlotColour) + - theme_bw() + - scale_x_continuous(expand = c(0, 0)) + - scale_y_continuous(expand = c(0, 0)) + - labs(subtitle = "Growth Rate") + - xlab("Time (Years)") -} - - -# Plot predation by time -fZooMSS_Plot_PredTimeSeries <- function(dat){ - - Z <- rowSums(dat$model$Z,dims = 2) / length(dat$model$param$w) - colnames(Z) <- dat$model$param$Groups$Species - Z <- as_tibble(Z) - Z$Time <- seq(dat$model$param$dt * dat$model$param$isave, - dat$model$param$tmax, - dat$model$param$dt * dat$model$param$isave) - Z <- Z %>% - pivot_longer(-Time, names_to = "Species", values_to = "Mortality") %>% - filter(Mortality > 0) %>% - mutate(Species = factor(Species, levels = dat$model$param$Groups$Species)) - - gg <- ggplot(data = Z, mapping = aes(x = Time, y = Mortality, colour = Species)) + - geom_line(linewidth = 1) + - geom_point(size = 1.2) + - scale_color_manual(values = dat$model$param$Groups$PlotColour) + - theme_bw() + - scale_x_continuous(expand = c(0, 0)) + - scale_y_continuous(expand = c(0, 0)) + - labs(subtitle = "Mortality Rate") + - xlab("Time (Years)") -} diff --git a/fZooMSS_Run.R b/fZooMSS_Run.R deleted file mode 100644 index ed6da4e..0000000 --- a/fZooMSS_Run.R +++ /dev/null @@ -1,186 +0,0 @@ -## Run model forward in time using previosly defined setup and model lists - -## Last Updated Tuesday 17th March 2020 -## - -fZooMSS_Run <- function(model){ - - # Pull out some useful parameters - just a shortcut - param <- model$param - dt <- model$param$dt - dx <- model$param$dx - ngrps <- model$param$ngrps - ngrid <- model$param$ngrid - w <- model$param$w - W0 <- param$Groups$W0 - Wmax <- param$Groups$Wmax - fish_grps <- model$param$fish_grps - assim_eff <- model$assim_eff - temp_eff <- model$temp_eff - dynam_dietkernel <- model$dynam_dietkernel - dynam_growthkernel <- model$dynam_growthkernel - dynam_mortkernel <- model$dynam_mortkernel - dynam_diffkernel <- model$dynam_diffkernel - diff_phyto <- model$diff_phyto - ingested_phyto <- model$ingested_phyto - - curr_min_size <- vector() - curr_max_size <- vector() - for (i in 1:ngrps){ - curr_min_size[i] <- which(round(log10(w), digits = 2) == W0[i]) - curr_max_size[i] <- which(round(log10(w), digits = 2) == Wmax[i]) - } - - idx_iter <- 2:ngrid - idx <- 2:(ngrid-1) - itimemax <- param$tmax / dt #max index of time array - - if(length(param$zoo_grps) > 1){ # If there's only one zoo group, then you do not need w0idx. All this stuff gives you info about all zoo groups except the smallest zoo group. - w0idx <- which(W0 > min(W0) & is.na(param$Groups$Prop) == FALSE) - w0mins <- rep(0, length(w0idx)) - props_z <- param$Groups$Prop[w0idx] # Zooplankton proportions - - for(i in 1:length(w0idx)){ - # Which size class is the smallest size class for each functional group - w0mins[i] <- which(round(log10(w), digits = 2) == W0[w0idx[i]]) - } - } - - # Matrices for MvF and MvF-D numeric solution - A_iter <- matrix(0, nrow = ngrps, ncol = ngrid) - C_iter <- matrix(0, nrow = ngrps, ncol = ngrid) - S_iter <- matrix(0, nrow = ngrps, ncol = ngrid) - - A <- matrix(0, nrow = ngrps, ncol = ngrid) - B <- matrix(0, nrow = ngrps, ncol = ngrid) - C <- matrix(0, nrow = ngrps, ncol = ngrid) - S <- matrix(0, nrow = ngrps, ncol = ngrid) - - # Temporary Matrices that get updated each time step some of these saved for output - N <- matrix(model$N[1,,], nrow = ngrps, ncol = ngrid) # Abundances of functional groups, dim 1 = groups, dim 2 = size classes - - pb <- txtProgressBar(min = 0, max = itimemax, initial = 1, style = 3) # Initial progress bar - - # BIG TIME LOOP - for (itime in 1:itimemax){ - - setTxtProgressBar(pb, itime) # Update progress bar - - growth_multiplier <- colSums(N * assim_eff) # 1 x n_sizes - predation_multiplier <- N * temp_eff # n_species x n_sizes - diffusion_multiplier <- colSums(N * (assim_eff^2)) # 1 x n_sizes - - ### DO GROWTH - dim(dynam_growthkernel) <- c(ngrps*ngrid, ngrid) - cs <- .colSums(growth_multiplier * t(dynam_growthkernel), m = ngrid, n = ngrps*ngrid) - dim(cs) <- c(ngrps, ngrid) - gg <- ingested_phyto + cs - - # sw <- sweep(dynam_growthkernel, 3, growth_multiplier, '*') # n_species x n_sizes x n_sizes - # ap <- aperm(sw, c(3,1,2)) # n_sizes x n_species x n_sizes - # cs <- colSums(ap) # n_species x n_sizes - # gg <- model$ingested_phyto + cs - # rm(sw, ap, cs) - - ### DO MORTALITY - # dynam_mortkernel <- model$dynam_mortkernel - # cs <- colSums(predation_multiplier * t(dynam_mortkernel)) - # dim(cs) <- c(ngrps, ngrid) - # gg <- ingested_phyto + cs - - sw2 <- sweep(dynam_mortkernel, c(2,3), predation_multiplier, '*') # n_sizes x n_species x n_sizes - ap2 <- aperm(sw2, c(2,3,1)) - M2 <- .colSums(colSums(ap2),ngrid,ngrid) # 1 x n_sizes - Z <- sweep(model$M_sb + model$fish_mort, 2, M2, '+') # Total dynamic spectrum mortality (n_species x n_sizes) - rm(sw2, ap2) - - - # Tried to speed up the code above but not luck so far - JDE 16th March 2022 - # browser() - # ap2 <- array(NA, dim = c(ngrps, ngrid, ngrid)) - # for (iix in 1:ngrid){ - # ap2[,,iix] <- dynam_mortkernel[iix,,] * predation_multiplier - # } - - ### DO DIFFUSION - dim(dynam_diffkernel) <- c(ngrps*ngrid, ngrid) - cs <- .colSums(diffusion_multiplier * t(dynam_diffkernel), m = ngrid, n = ngrps*ngrid) - dim(cs) <- c(ngrps, ngrid) - diff <- diff_phyto + cs - - # sw3 <- sweep(dynam_diffkernel, 3, diffusion_multiplier, '*') - # ap3 <- aperm(sw3, c(3,1,2)) - # cs3 <- colSums(ap3) - # diff <- diff_phyto + cs3 - # rm(sw3, ap3, cs3) - - ### MvF WITH DIFFUSION ALGORITHM - # Numerical implementation matrices (for MvF without diffusion) - A_iter[,idx_iter] <- dt/dx * gg[,idx_iter-1] # Growth stuff - C_iter[,idx_iter] <- 1 + dt * Z[,idx_iter] + dt/dx * gg[,idx_iter] # Mortality - S_iter[,idx_iter] <- N[,idx_iter] # N at..... - N_iter <- N # Current Abundance - N_iter[1,1] <- N[1,1] # This forces R to make a copy of the variable. Otherwise N is linked to N_iter in the Rcpp code and they change together. - - # Numerical implementation matrices (for MvF WITH diffusion) - A[,idx] <- dt/dx * (gg[,idx-1] + diff[,idx-1] * (log(10)/2+1/(2*dx))) # Growth stuff - B[,idx] <- diff[,idx+1] * dt/(2*dx^2) # Diffusion term - C[,idx] <- 1 + dt * Z[,idx] + dt/dx*(gg[,idx] + diff[,idx] * (log(10)/2+1/dx)) # Mortality - S[,idx] <- N[,idx] - - # The original Base R code for the MvF equation - N <- fZooMSS_MvF_BaseR(ngrps, curr_min_size, curr_max_size, - A_iter, C_iter, N_iter, S_iter, - A, B, C, N, S) - - # N <- fZooMSS_MvF_Rcpp(cngrps=ngrps, cN_iter=N_iter, - # cA_iter=A_iter, cC_iter=C_iter, cS_iter=S_iter, - # cN=N, cA=A, cB=B, cC=C, cS=S, - # ccurr_min_size=curr_min_size, ccurr_max_size=curr_max_size) - - - #### Keep smallest fish community size class as equal to equivalent zooplankton size class - ### Keep smallest zooplankton size class abundnace for each group locked to others in size spectrum - if(length(param$zoo_grps) > 1){ # If you only have one zoo group, it will be locked to phyto spectrum so you do not need to do this - for(i in 1:length(w0idx)){ - w_min_curr <- w0mins[i] - exclude_mins <- w0idx[which(w0mins == w_min_curr)] - N[w0idx[i], w_min_curr] <- props_z[i] * sum(N[-exclude_mins, w_min_curr]) - } - } - - fish_mins <- unlist(lapply(W0[fish_grps], - function(x){which(round(log10(w), digits = 2) == x)})) - - if(length(fish_grps) > 1 & length(param$zoo_grps) > 1){ - N[fish_grps,fish_mins] <- (1/length(fish_grps))*(colSums(N[-fish_grps,fish_mins])) - }else{ - N[fish_grps, fish_mins] <- (1/length(fish_grps))*sum(N[-fish_grps, fish_mins]) - } - - - # Save results: - if((itime %% param$isave) == 0){ - isav <- itime/param$isave - - ## Phytoplankton diet - pico_phyto_diet <- rowSums(model$diet_pico_phyto*N) # Pico-phytoplankton - nano_phyto_diet <- rowSums(model$diet_nano_phyto*N) # Nano-phytoplankton - micro_phyto_diet <- rowSums(model$diet_micro_phyto*N) # Micro-phytoplankton - - ## Functional group diet - ### Create an ngrps*ngrid*ngrps*ngrid array of abundances, to save time without sweeps: dim1 = pred groups, dim 2 = pred sizes, dim 3 = prey groups, dim 4 = prey sizes - N_array_temp <- aperm(replicate(ngrid, N), c(3,1,2)) - N_array <- aperm(replicate(ngrps, N_array_temp), c(4,1,2,3)) - dynam_diet <- rowSums(aperm(rowSums(sweep(dynam_dietkernel*N_array, c(1,2), N, "*"), dims = 3), c(1,3,2)), dims = 2) - - model$diet[isav,,1:3] <- cbind(pico_phyto_diet, nano_phyto_diet, micro_phyto_diet) - model$diet[isav,,c(4:(dim(param$Groups)[1]+3))] <- dynam_diet - model$N[isav,,] <- N # Save N by taxa and size - model$Z[isav,,] <- Z ## Save mortality - model$gg[isav,,] <- gg ## Save growth - } - } # End of time loop - return(model) - -} \ No newline at end of file diff --git a/fZooMSS_Setup.R b/fZooMSS_Setup.R deleted file mode 100644 index dbeb549..0000000 --- a/fZooMSS_Setup.R +++ /dev/null @@ -1,275 +0,0 @@ -## The Setup function calculates the feeding kernels, dvm (if included), temp effects... -## everything that can be solved before we start iterating through time to solve MvF-D - -## Last Updated Tuesday 17th March 2020 -## - -fZooMSS_Setup <- function(param){ - - ## Commented out DVM as it is unused at the moment (April 2020) - ## Diel Vertical Migration - change availability of phyto to zoo - ## and zoo to fish based on slope of phytoplankton (calculated as - ## proportion of day searching for food and available for predation) - # dvm_max <- param$day/24 # maximum proportion of day spent migrating - # ESD_sizes <- 2*(3/(4*pi)*w)^(1/3) # convert g wet weight to ESD (cm) - # dvm <- dvm_max*(1.02*(ESD_sizes) - 0.02) # size-dependent amount of time spent away from surface - # dvm[which(w < 10^-5.4)] <- 0 # Microzoo don't migrate (ESD < 0.02cm) - # dvm[which(w > 10^-0.3)] <- dvm_max # Macrozoo migrate max time (ESD > 10cm) - # dvm_mat <- matrix(dvm, nrow = param$ngrid, ncol = param$ngrid, byrow = TRUE) # Matrix of dvm, nrow = number of pred size classes - - ## This works out the proportion of time an predator of size w will have access to a prey of size w', for all w and w' - # dvm_mat <- 1 - dvm_mat - # dvm_mat[lower.tri(dvm_mat)] <- 0 - # dvm_mat <- t(dvm_mat) + dvm_mat - # diag(dvm_mat) <- diag(dvm_mat)/2 - - - ## Dynamic prey availability matrix: dim1 is predators, dim2 is predator size classes, - ## dim3 is prey groups, dim 4 is prey size classes. - # dynam_theta <- array(1, dim = c(param$ngrps, param$ngrid, param$ngrps, param$ngrid)) - # dynam_theta <- sweep(dynam_theta, c(2,4), dvm_mat,"*") - - - ## Phyto availability matrix: rows are predators, columns are their size classes, - ## entries are time spent feeding on phytoplankton for the size class - # phyto_theta <- matrix(1-dvm, nrow = param$ngrps, ncol = param$ngrid, byrow = TRUE) - # phyto_theta[which(param$Groups$FeedType == 'Carnivore'),] <- 0 # Carnivorous groups can't eat phyto - - ## End commented out DVM - - ### IN PLACE OF DVM - dynam_theta <- array(1, dim = c(param$ngrps, param$ngrid, param$ngrps, param$ngrid)) - phyto_theta <- matrix(1, nrow = param$ngrps, ncol = param$ngrid, byrow = TRUE) - phyto_theta[which(param$Groups$FeedType == 'Carnivore'),] <- 0 # Carnivorous groups can't eat phyto - ### - - - ## Makes the model object, full of constant functions for model - model <- list( - param = param, - nPP = 10^(param$phyto_int)*(param$w_phyto^(param$phyto_slope)), # Phytoplankton abundance spectrum - - # Group parameters storage - phyto_growthkernel = array(NA, dim = c(param$ngrps, param$ngrid, param$ngridPP)), # predation on phytoplankton - phyto_diffkernel = array(NA, dim = c(param$ngrps, param$ngrid, param$ngridPP)), # diffusion from phytoplankton consumption - phyto_dietkernel = array(NA, dim = c(param$ngrps, param$ngrid, param$ngridPP)), # diet from phytoplankton - dynam_growthkernel = array(NA, dim = c(param$ngrps, param$ngrid, param$ngrid)), # predation on zoo and fish - dynam_diffkernel = array(NA, dim = c(param$ngrps, param$ngrid, param$ngrid)), # diffusion from zoo and fish consumption - dynam_dietkernel = array(NA, dim = c(param$ngrps, param$ngrid, param$ngrid)), # diet from zoo and fish - dynam_mortkernel = array(NA, dim = c(param$ngrps, param$ngrid, param$ngrid)), # mortality from predation on dynamic component - M_sb = matrix(0, nrow = param$ngrps, ncol = param$ngrid), # senescence mortality - fish_mort = matrix(0, nrow = param$ngrps, ncol = param$ngrid), # fishing mortality - - # Assimilation efficiency and temperature effect storage, by group and size class - # assim_eff = matrix(0, nrow = param$ngrps, ncol = param$ngrid), # Commented out because it is calculated below - temp_eff = matrix(0, nrow = param$ngrps, ncol = param$ngrid), - - #### STORAGE FOR DIET KERNELS - phyto_dietkernel = array(NA, dim = c(param$ngrps, param$ngrid, param$ngridPP)), - dynam_dietkernel = array(NA, dim = c(param$ngrps, param$ngrid, param$ngrid)), - - # Output storage - N = array(NA, dim = c(param$nsave, param$ngrps, param$ngrid)), # dynamic abundance spectrum - Z = array(NA, dim = c(param$nsave, param$ngrps, param$ngrid)), # Total mortality - gg = array(NA, dim = c(param$nsave, param$ngrps, param$ngrid)), # Growth - diet = array(NA, dim = c(param$nsave, c(param$ngrps), c(param$ngrps+3))) # diet - ) - - # GGE for different groups - assim_phyto <- (param$Groups$GrossGEscale) * param$cc_phyto # Phytoplankton - # assim_dynam <- matrix(param$Groups$GrossGEscale*param$Groups$Carbon, nrow = ngrps, ncol = ngrps, byrow = TRUE) # rows are predators, columns are prey - model$assim_eff = matrix(param$Groups$GrossGEscale * param$Groups$Carbon, nrow = param$ngrps, ncol = length(model$param$w)) - - #### INITIAL DYNAMIC POPULATION ABUNDANCES - a_dynam <- 10^(param$phyto_int)*(param$w[1]^(param$phyto_slope+1)) # calculate coefficient for initial dynamic spectrum, so that N(w_phyto) equals N(w_dynam) at w[1] - - # Initial abundances form a continuation of the plankton spectrum, with a slope of -1 - tempN <- matrix(a_dynam*(param$w)^-1, nrow = param$ngrps, ncol = param$ngrid, byrow = TRUE) - props_z <- param$Groups$Prop[param$zoo_grps] # Zooplankton proportions - tempN[param$zoo_grps,] <- props_z * tempN[param$zoo_grps,] # Set abundances of diff zoo groups based on smallest size class proportions - tempN[param$fish_grps,] <- (1/param$num_fish) * tempN[param$fish_grps,] # Set abundandances of fish groups based on smallest size class proportions - - # For each group, set densities at w > Winf and w < Wmin to 0 - tempN[unlist(tapply(param$w_log10, 1:length(param$w), function(wx,Winf) Winf < wx, Winf = param$Groups$Wmax))] <- 0 - tempN[unlist(tapply(param$w_log10, 1:length(param$w), function(wx,Wmin) Wmin > wx, Wmin = param$Groups$W0))] <- 0 - model$N[1,,] <- tempN - - # Fishing mortality (yr^-1) - THere will be a better way to do this with apply if someone is interested.... - for(g in 1:12){ - model$fish_mort[g,match(param$Groups$Fmort_W0[g], param$w_log10):match(param$Groups$Fmort_Wmax[g], param$w_log10)] <- param$Groups$Fmort[g] - } - - ### MATRICES FOR LOG TRANSFORM OF EQUATION - # Predators are rows, phyto prey weights are columns - gg_log_t_phyto <- ((param$w^-1) %*% t(param$w_phyto))/log(10) # Growth - diff_log_t_phyto <- ((param$w^-2) %*% t(param$w_phyto^2))/log(10) # Diffusion - diet_log_t_phyto <- matrix(param$w_phyto, nrow = length(param$w), ncol = length(param$w_phyto), byrow = TRUE) # Diet/Ingestion - - # Predators are rows, dynam prey weights are columns - gg_log_t_dynam <- ((param$w^-1) %*% t(param$w))/log(10) # Growth - diff_log_t_dynam <- ((param$w^-2) %*% t(param$w^2))/log(10) # Diffusion - diet_log_t_dynam <- matrix(param$w, nrow = length(param$w), ncol = length(param$w), byrow = TRUE) # Diet/ingestion - - ### PREDATION KERNELS FOR PHYTOPLANKTON SPECTRUM AND DYNAMIC SPECTRUM - phyto_pred_weight_matrix <- matrix(param$w, nrow = param$ngrid, ncol = param$ngridPP) - dynam_pred_weight_matrix <- matrix(param$w, nrow = param$ngrid, ncol = param$ngrid) - phyto_prey_weight_matrix <- matrix(param$w_phyto, nrow = param$ngrid, ncol = param$ngridPP, byrow = TRUE) - dynam_prey_weight_matrix <- matrix(param$w, nrow = param$ngrid, ncol = param$ngrid, byrow = TRUE) - - ## Search Volume storage - SearchVol <- matrix(NA, nrow = param$ngrps, ncol = param$ngrid) # Search volume - - # Simpson's Rule matrices for growth, diffusion and mortality integrals - simp_phyto <- array(1, dim = param$ngridPP) - simp_phyto[c(seq(2, param$ngridPP-1,2))] <- 4 - simp_phyto[c(seq(3, param$ngridPP-1,2))] <- 2 - sm_phyto <- matrix(simp_phyto, nrow = param$ngrid, ncol = param$ngridPP, byrow = TRUE) * (param$dx/3) - - simp_dynam <- array(1, dim = param$ngrid) - simp_dynam[c(seq(2, param$ngrid-1,2))] <- 4 - simp_dynam[c(seq(3, param$ngrid-1,2))] <- 2 - sm_dynam <- matrix(simp_dynam, nrow = param$ngrid, ncol = param$ngrid, byrow = TRUE) * (param$dx/3) - - ## Temperature Effect Matrix - # Effect of temperature on feeding and predation rate - #temp_flag <- 2.4^((environ$sst)/10) - #temp_cil <- 2.8^((environ$sst)/10) - #temp_gel <- 1.75^((environ$sst)/10) - #temp_larv <- 2.2^((environ$sst)/10) - #temp_chaet <- 2.44^((environ$sst)/10) - #temp_crust <- 2.57^((environ$sst)/10) - #temp_ocop <- 2.8^((environ$sst)/10) - #temp_ccop <- 2.8^((environ$sst)/10) - #temp_fish <- 2.6^((environ$sst)/10) - - #temp_zoo <- c(temp_flag, temp_cil, temp_larv, temp_ocop, temp_ccop, temp_crust, temp_chaet, temp_larv, temp_gel) - #temp_fish <- rep(temp_fish, num_fish) - - #temp_zoo <- rep(exp(23.93 - 0.59/(8.62e-05*(273+environ$sst))), num_zoo) # exp(23.93 - 0.59/(8.62e-05*(273+environ$sst))) - #temp_fish <- rep(exp(23.93 - 0.59/(8.62e-05*(273+environ$sst))), num_fish) # exp(25.55 - 0.63/(8.62e-05*(273+environ$sst)))/exp(23.93 - 0.59/(8.62e-05*(273+environ$sst))) - - ### Q10 OF 2 FOR ALL ZOO AND FISH - temp_zoo <- rep(2.^((param$sst - 30)/10), param$num_zoo) # exp(23.93 - 0.59/(8.62e-05*(273+environ$sst))) - temp_fish <- rep(2.^((param$sst - 30)/10), param$num_fish) - model$temp_eff <- matrix(c(temp_zoo, temp_fish), nrow = param$ngrps, ncol = param$ngrid) - - #### CALCULATES CONSTANT BITS OF THE MODEL FUNCTIONS FOR EACH GROUP - for(i in 1:param$ngrps){ - ## Senescence mortality - if(param$Groups$Type[i] == "Zooplankton"){ - model$M_sb[i,] <- param$ZSpre*(param$w/(10^(param$Groups$Wmat[i])))^param$ZSexp - model$M_sb[i, 10^(param$Groups$Wmax[i]) < param$w] <- 0 - model$M_sb[i, 10^(param$Groups$Wmat[i]) > param$w] <- 0 - } - - if(param$Groups$Type[i] == "Fish"){ - model$M_sb[i,] <- 0.1*param$ZSpre*(param$w/(10^(param$Groups$Wmat[i])))^param$ZSexp - model$M_sb[i, 10^(param$Groups$Wmax[i]) < param$w] <- 0 - model$M_sb[i, 10^(param$Groups$Wmat[i]) > param$w] <- 0 - } - - ### Search volume - SearchVol[i,] <- (param$Groups$SearchCoef[i])*(param$w^(param$Groups$SearchExp[i])) - SearchVol[i, 10^(param$Groups$Wmax[i]) < param$w] <- 0 - SearchVol[i, 10^(param$Groups$W0[i]) > param$w] <- 0 - - ### Predation Kernels - # if(param$Groups$Type[i] == "Zooplankton"){ # If group is zooplankton - if(!is.na(param$Groups$PPMRscale[i])){ # If group has a PPMR scaling value (m-value) - # Calculate PPMR for zooplankton, which changes according to body-size (Wirtz, 2012) - D.z <- 2*(3*param$w*1e12/(4*pi))^(1/3) # convert body mass g to ESD (um) - betas <- (exp(0.02*log(D.z)^2 - param$Groups$PPMRscale[i] + 1.832))^3 # Wirtz's equation - beta_mat_phyto <- matrix(betas, nrow = param$ngrid, ncol = param$ngridPP) - beta_mat_dynam <- matrix(betas, nrow = param$ngrid, ncol = param$ngrid) - - # Calculate feeding kernels - sp_phyto_predkernel <- exp(-0.5*(log((beta_mat_phyto*phyto_prey_weight_matrix)/ - phyto_pred_weight_matrix)/param$Groups$FeedWidth[i])^2)/ - sqrt(2*pi*param$Groups$FeedWidth[i]^2) - sp_dynam_predkernel <- exp(-0.5*(log((beta_mat_dynam*dynam_prey_weight_matrix)/ - dynam_pred_weight_matrix)/param$Groups$FeedWidth[i])^2)/ - sqrt(2*pi*param$Groups$FeedWidth[i]^2) - - # The feeding kernel of filter feeders is not expected to change much with increasing size so we fix it here - if(param$Groups$FeedType[i] == "FilterFeeder"){ - w0idx <- which(param$Groups$W0[i] == param$w_log10) - sp_phyto_predkernel <- matrix(sp_phyto_predkernel[w0idx,], nrow = param$ngrid, ncol = param$ngridPP, byrow = TRUE) - sp_dynam_predkernel <- matrix(sp_dynam_predkernel[w0idx,], nrow = param$ngrid, ncol = param$ngrid, byrow = TRUE) - rm(w0idx) - } - - } else { # If group is fish - beta_mat_phyto <- matrix(param$Groups$PPMR[i], nrow = param$ngrid, ncol = param$ngridPP) - beta_mat_dynam <- matrix(param$Groups$PPMR[i], nrow = param$ngrid, ncol = param$ngrid) - - # Calculate feeding kernels - sp_phyto_predkernel <- exp(-0.5*(log((beta_mat_phyto*phyto_prey_weight_matrix)/ - phyto_pred_weight_matrix)/param$Groups$FeedWidth[i])^2)/ - sqrt(2*pi*param$Groups$FeedWidth[i]^2) - sp_dynam_predkernel <- exp(-0.5*(log((beta_mat_dynam*dynam_prey_weight_matrix)/ - dynam_pred_weight_matrix)/param$Groups$FeedWidth[i])^2)/ - sqrt(2*pi*param$Groups$FeedWidth[i]^2) - } - - ### GROWTH INTEGRAL CONSTANTS - # Predators are rows, prey are columns - model$phyto_growthkernel[i,,] <- matrix(SearchVol[i,], nrow = param$ngrid, ncol = param$ngridPP) * - sp_phyto_predkernel * gg_log_t_phyto * sm_phyto - model$dynam_growthkernel[i,,] <- matrix(SearchVol[i,], nrow = param$ngrid, ncol = param$ngrid)* - sp_dynam_predkernel*gg_log_t_dynam*sm_dynam - - ### DIET INTEGRAL CONSTANTS - # Predators are rows, prey are columns - model$phyto_dietkernel[i,,] <- matrix(SearchVol[i,], nrow = param$ngrid, ncol = param$ngridPP)* - sp_phyto_predkernel*diet_log_t_phyto*sm_phyto - model$dynam_dietkernel[i,,] <- matrix(SearchVol[i,], nrow = param$ngrid, ncol = param$ngrid)* - sp_dynam_predkernel*diet_log_t_dynam*sm_dynam - - ### DIFFUSION INTEGRAL CONSTANTS - # Predators are rows, prey are columns - model$phyto_diffkernel[i,,] <- matrix(SearchVol[i,], nrow = param$ngrid, ncol = param$ngridPP)* - sp_phyto_predkernel*diff_log_t_phyto*sm_phyto - model$dynam_diffkernel[i,,] <- matrix(SearchVol[i,], nrow = param$ngrid, ncol = param$ngrid)* - sp_dynam_predkernel*diff_log_t_dynam*sm_dynam - - ### MORTALITY INTEGRAL CONSTANTS - # Prey are rows, predators are columns - model$dynam_mortkernel[i,,] <- matrix(SearchVol[i,], nrow = param$ngrid, ncol = param$ngrid, byrow = TRUE)* - t(sp_dynam_predkernel)*sm_dynam - } - - # no_sen = which(param$Groups$species == c("Flagellates", "Ciliates")) # no senescence mortality for flagellates and ciliates - #model$M_sb[c(ngrps)] = 0 - model$M_sb <- model$temp_eff * model$M_sb # Incorporate temp effect on senscence mortality - - ## Incorporate carnivory (groups that can't eat phyto), temperature effects and gross growth efficiency (assim) - model$phyto_growthkernel <- sweep(sweep(model$phyto_growthkernel, c(1,2), phyto_theta, "*"), 1, assim_phyto, "*") - model$phyto_diffkernel <- sweep(sweep(model$phyto_diffkernel, c(1,2), phyto_theta, "*"), 1, assim_phyto^2, "*") - model$phyto_dietkernel <- sweep(sweep(model$phyto_dietkernel, c(1,2), phyto_theta, "*"), 1, 1, "*") - - # Dim 1 = pred group, dim2 = pred sizes, dim 3 = prey sizes - model$dynam_growthkernel <- sweep(model$dynam_growthkernel, c(1,2), model$temp_eff, '*') - model$dynam_diffkernel <- sweep(model$dynam_diffkernel, c(1,2), model$temp_eff^2, '*') - - # We still need four dimensions for diet matrix - model$dynam_dietkernel <- sweep(sweep(sweep(dynam_theta, c(1,2,4), model$dynam_dietkernel, "*"), - c(1,3), 1, "*"), c(1,2), model$temp_eff, "*") - - # We won't sweep through temp_effect here, but do it in fZooMSS_Run function. This is to make sure - # it can still work in the future if we have different temperature effects for different groups, - # so then dynam_mortkernel is dim1 = prey sizes, dim 2 = pred groups, dim 3 = pred size - model$dynam_mortkernel <- aperm(model$dynam_mortkernel, c(2,1,3)) - - #### Because phyto spectrum is constant, we can solve the phyto component of growth, and diffusion before time loop - model$ingested_phyto <- model$temp_eff*(rowSums(sweep(model$phyto_growthkernel, 3, model$nPP, "*"), dims = 2)) # Ingested phyto - model$diff_phyto <- model$temp_eff^2*(rowSums(sweep(model$phyto_diffkernel, 3, model$nPP, "*"), dims = 2)) # Diffusion from phyto - model$diet_phyto <- model$temp_eff*(rowSums(sweep(model$phyto_dietkernel, 3, model$nPP, "*"), dims = 2)) # Diet of total phyto - model$diet_phyto_all_sizes <- sweep(sweep(model$phyto_dietkernel, 3, model$nPP, "*"), c(1,2), model$temp_eff, "*") # Diet of total phyto, with all size classes of phyto maintained - - ## Diet of phyto from pico, nano and micro size classes - model$diet_pico_phyto <- model$temp_eff*(rowSums(sweep(model$phyto_dietkernel, 3, model$nPP*c(log10(model$param$w_phyto) < -11.5), "*"), dims = 2)) - model$diet_nano_phyto <- model$temp_eff*(rowSums(sweep(model$phyto_dietkernel, 3, model$nPP*c(log10(model$param$w_phyto) >= -11.5 & log10(model$param$w_phyto) < -8.5), "*"), dims = 2)) - model$diet_micro_phyto <- model$temp_eff*(rowSums(sweep(model$phyto_dietkernel, 3, model$nPP*c(log10(model$param$w_phyto) >= -8.5), "*"), dims = 2)) - - return(model) -} # End of Setup function \ No newline at end of file diff --git a/fZooMSS_Xtras.R b/fZooMSS_Xtras.R deleted file mode 100644 index 948bff6..0000000 --- a/fZooMSS_Xtras.R +++ /dev/null @@ -1,249 +0,0 @@ -# This script contains a list of helper functions which can be used to analyse and plot the ZooMSS output - - -# Sum ZooMSS output across size bins -fZooMSS_SumSize = function(list_in) { - out <- map(list_in, function(x) apply(x, 1, sum)) # Sum ZooMSS output across the size bins - return(out) -} - -# Sum ZooMSS output across species bins -fZooMSS_SumSpecies = function(list_in) { - out <- map(list_in, function(x) apply(x, 2, sum)) # Sum ZooMSS output across the species bins - return(out) -} - -# Summarise the biomass for each grid-cell by species -fZooMSS_SpeciesBiomass = function(res, vmdl) { - # if (dim(res[[1]])[2] != length(mdl$param$w)){print("error")} - Biomass <- map(res, function(x) apply(sweep(x, 2, vmdl$param$w, '*'), 1, sum)) - return(Biomass) -} - -# Sum ZooMSS output across all species and sizes -fZooMSS_SumAll = function(list_in) { - out <- unlist(map(list_in, function(x) sum(x))) # Sum ZooMSS output across the species bins - return(out) -} - -# Convert Abundance to Biomass for all species and weight classes -fZooMSS_Biomass <- function(res, vmdl) { - if (dim(res[[1]])[2] != length(vmdl$param$w)){print("error")} - Biomass <- map(res, function(x) sweep(x, 2, vmdl$param$w, '*')) # Biomass in grams - return(Biomass) -} - -# Convert Abundance to Carbon Biomass for all species and weight classes -fZooMSS_CarbonBiomass <- function(res, vmdl) { - if (dim(res[[1]])[2] != length(vmdl$param$w)){print("error")} - Biomass <- map(res, function(x) sweep(x, 2, vmdl$param$w, '*')) # Biomass in grams (WW) - Biomass <- map(Biomass, function(x) sweep(x, 1, vmdl$param$Groups$Carbon, '*')) # Now convert to Carbon - return(Biomass) -} - -# Convert Abundance to Carbon Biomass for all species and weight classes -fZooMSS_SpeciesCarbonBiomass <- function(res, vmdl) { - if (dim(res[[1]])[2] != length(vmdl$param$w)){print("error")} - Biomass <- map(res, function(x) sweep(x, 2, vmdl$param$w, '*')) # Biomass in grams (WW) - Biomass <- map(Biomass, function(x) sweep(x, 1, vmdl$param$Groups$Carbon, '*')) # Now convert to Carbon - Biomass <- fZooMSS_SumSize(Biomass) - - return(Biomass) -} - -# Summarise the biomass for each grid-cell by size-class -fZooMSS_SizeBiomass = function(res,w) { - if (dim(res[[1]])[2] != length(w)){print("error")} - Biomass <- map(res, function(x) apply(sweep(x, 2, w, '*'), 2, sum)) - return(Biomass) -} - -# Sum ZooMSS output across size bins -fZooMSS_ExtractSizeRange = function(list_in, minb, maxb) { - out <- map(list_in, function(x) x[,minb:maxb] ) - return(out) -} - - -# Function to calculate the mean of the last 50 % of the model -fZooMSS_AveOutput = function(x, prop = 0.5){ - ave_x <- colMeans(x[(ceiling(dim(x)[1] - prop*(dim(x)[1])):dim(x)[1]),,], dims = 1) - return(ave_x) -} - -# Remove nonsense attributes if we are working for speed and memory efficiency. -untibble <- function (tibble) { - data.frame(unclass(tibble), check.names = FALSE, stringsAsFactors = FALSE) -} ## escape the nonsense - - -# At the moment you need to subset the zoomss data by species or size in order to use this function. -# I will rewrite sometime to include other variables but at the moment its only for 2D data -fZooMSS_Convert2Tibble <- function(li, vmdl){ - df <- as_tibble(matrix(unlist(li), nrow=length(li), byrow=T), .name_repair = "unique") %>% - rename_with(~vmdl$param$Groups$Species) - return(df) -} - -fZooMSS_AddEnviro <- function(Zoo, venviro){ - df <- Zoo %>% - mutate(cellID = 1:n()) %>% # Create a cellID - left_join(dplyr::select(venviro, cellID, chlo, sst, phyto_int, phyto_slope, phyto_max, Lat, Lon, geometry), by = "cellID") %>% - rename(SST = sst, Chl = chlo) %>% - mutate(Chl_log10 = log10(Chl)) - return(df) -} - - -# Return the diet matrix as a long tibble -fZooMSS_MakeDietTibble <- function(mat, mdl){ - suppressMessages( - out <- as_tibble(mat, .name_repair = "unique") %>% - rename_with(~c("Phyto_Small", "Phyto_Med", "Phyto_Large", mdl$param$Groups$Species)) %>% - mutate(Predator = mdl$param$Groups$Species) %>% - pivot_longer(cols = Phyto_Small:Fish_Large, names_to = "Prey", values_to = "Diet") - ) - return(out) -} - - -PPMR_plot = function(dat){ - - min_size = min(dat$model$param$Groups$W0) # smallest size class - max_size = max(dat$model$param$Groups$Wmax) # largest size class - w = 10^(seq(from = min_size, to = max_size, 0.1)) # all size classes - - # Calculate PPMR (beta) table, where dim1 = group, dim2 = body size with - # value being PPMR for that body size (this is not realised PPMR - not - # emergent from diet but calculated from m-values and Wirtz, 2012 equation) - D.z = 2*(3*(w)*1e12/(4*pi))^(1/3) # convert body mass g to ESD (um) - zoo_m = dat$model$param$Groups$PPMRscale # pull out PPMR scaling values from parameter table - betas = log10(t(sapply(zoo_m, function(x){(exp(0.02*log(D.z)^2 - x + 1.832))^3}))) # Convert m to betas, using Wirtz 2012 equation - betas = betas[-which(is.na(dat$model$param$Groups$PPMRscale)),] # remove fish rows - - ## Modify beta matrix for larvaceans and salps - all size classes for these groups feed on same prey, so log10PPMR increases by 0.1 for each 0.1 log10 size interval - betas[which(dat$model$param$Groups$Species=="Larvaceans"),45:75] <- betas[which(dat$model$param$Groups$Species=="Larvaceans"),44] + seq(0.1,3.1,0.1) # Larvaceans (index 44 in w vector is smallest size class, 75 is maximum size class) - betas[which(dat$model$param$Groups$Species=="Salps"),61:121] <- betas[which(dat$model$param$Groups$Species=="Salps"),61] + seq(0.1,6.1,0.1) # Larvaceans (index 61 in w vector is smallest size class, 121 is maximum size class - - # Calculate ave abundances across oligo/eutro grid squares, then calculate ave - # biomass and proportion of total zoo biomass that is from each group size class - - ave = matrix(0, nrow = dim(dat$model$param$Groups)[1], ncol = length(w)) - for(i in 1:length(dat$abundances)){ - ave = ave + dat$abundances[[i]]/length(dat$abundances) - } - ave_biom = sweep(ave, 2, w, "*") # Calculate oligo biomass for zoo groups - ave_biom = ave_biom[-which(is.na(dat$model$param$Groups$PPMRscale)),] # remove rows for fish - beta_props = ave_biom/sum(ave_biom) # Calculate fraction of zoo biomass in each group, in each size class - - out <- list() - out[[1]] <- betas - out[[2]] <- beta_props - names(out) <- c("betas", "beta_props") - - temp <- density(betas, weights = beta_props) - - out <- tibble("x" = temp$x, "y" = temp$y, "mn_beta" = sum(beta_props*betas)) - - spbeta_props = ave_biom/rowSums(ave_biom) # Species specific proportions - spPPMR <- tibble("Species" = as.factor(dat$model$param$Groups$Species[-which(is.na(dat$model$param$Groups$PPMRscale))]), "Betas" = rowSums(spbeta_props*betas), "y" = NA) # Get species-specific PPMR - - for (s in 1:length(spPPMR$Species)){ - spPPMR$y[s] <- out$y[which.min(abs(out$x - spPPMR$Betas[s]))] - } - - spPPMR <- spPPMR %>% - mutate(y = y * 0) %>% - bind_rows(spPPMR) - - out2 <- list() - out2[[1]] <- out - out2[[2]] <- spPPMR - - return(out2) -} - - - -## Function to calculate slope intercept and maximum size of phytoplankton spectrum, for zooplankton -## resolved size spectrum model (Heneghan et al. in prep). - -# Last updated 17th September 2020 - -fZooMSS_CalculatePhytoParam = function(df){ # chlo is chlorophyll concentration in mg m^-3, phy is mean euphotic zone phyto in g wet weight m-3 - - ## Calculate pico, nano, micro phytoplankton proportions of total chlorophyll - ## BREWIN ET AL., 2015 - pico <- (0.13*(1-exp(-0.8/0.13*df$chlo)))/df$chlo - nano <- (0.77*(1-exp(-0.94/0.77*df$chlo)))/df$chlo - pico - micro <- (df$chlo - 0.77*(1-exp(-0.94/0.77*df$chlo)))/df$chlo - - if("phy" %in% colnames(df)){ - tot_biom <- df$phy - } else { - ## Convert total chlorophyll to g m^-3 total wet weight - biomass - ## Allocate total chlorophyll to the three size classes - c_chl <- ((df$chlo^0.89)*(10^1.79))/df$chlo # chlo:carbon ratio, from Maranon et al. 2014 - tot_biom_c <- c_chl*df$chlo/1000 # (convert to grams carbon) - tot_biom <- tot_biom_c*(1/0.1) # convert to grams wet weight, assuming 0.1 C:ww - } - - # Break up total biom into pico, nano and micro - df$pico_biom <- pico*tot_biom - df$nano_biom <- nano*tot_biom - df$micro_biom <- micro*tot_biom - - ## Find abundances at boundaries of pico, nano size ranges, by analytically - ## solving integral of N = aw^b - - w_0 <- -14.5 # log minimum size of picophytoplankton - w_1 <- -11.5 # log minimum size of nanophytoplankton (max size of pico also) - w_2 <- -8.5 # log minimum size of macrophytoplankton (max size of nano also) - - df$phyto_slope <- (log10(df$pico_biom) - log10(df$nano_biom) - w_1 + w_2)/(w_1 - w_2) # Calculate slope - df$phyto_int <- log10(df$pico_biom*(df$phyto_slope+1)/((10^(w_1))^(df$phyto_slope+1) - (10^(w_0))^(df$phyto_slope+1))) # Calculate intercept - - ## Calculate maximum size - df$phyto_max <- 0.1*round((-8.4 + 2*micro)/0.1) # Maximum size depends on the proportion of micro - max_phyto <- rep(-7, length(df$chlo)) # Set -7 to be the max possible size for phyto - df$phyto_max <- pmin(max_phyto, df$phyto_max) - - return(df) -} - - -## TROPHIC LEVEL FUNCTION, takes a 12x15 matrix of diets (predators are rows, prey are columns) from ZooMSS and calculates -## trophic levels of predator groups. - -fZooMSS_TrophicLevel <- function(diet_matrix){ - - phyto_tl <- 1 # Phyto TL is 1 - start_dynam_tl <- rep(2,12) # Start TL - start at 2 for all zoo and fish groups - - # To be truly generic I need to fix these up with testgroup references #TODO - curr_phyto_diet <- rowSums(diet_matrix[,1:3]) # Current phyto diet - curr_dynam_diet <- diet_matrix[,4:15] # Current heterotroph diet - - total_diet <- curr_phyto_diet + rowSums(curr_dynam_diet) # Total consumption, in grams wet weight, by pred group - - curr_phyto_frac <- curr_phyto_diet/total_diet # Fraction of diet from phyto, by pred group and pred sizes - curr_dynam_frac <- sweep(curr_dynam_diet, 1, total_diet, '/') # Fraction of diet from each prey group for each pred group - - n <- 1 - eps_diff <- 1 - - while(eps_diff > 0.01 & n < 100){ # Gauss-Siedel iterative loop to calculate trophic levels, stops when converged or number of loops reaches 100 - n <- n + 1 - eps <- start_dynam_tl[10] - - calc_dynam_tl = sweep(curr_dynam_frac, 2, start_dynam_tl, '*') - calc_dynam_tl[which(is.nan(calc_dynam_tl) == TRUE)] = 0 # Get rid of nans - these are entrys where there is no biomass for a given group - #calc_dynam_tl[which(calc_dynam_tl == Inf)] = 0 # Get rid of infinite values, occurs with asymptotic size bins, because there is no biomass to have a diet in those bins - start_dynam_tl = 1+phyto_tl*curr_phyto_frac + rowSums(calc_dynam_tl) # Update trophic level matrix - - eps_diff <- abs(eps - start_dynam_tl[10]) - } # End Gauss-Siedel loop - - return(start_dynam_tl) - -} # End trophic level function diff --git a/man/GroupInputs.Rd b/man/GroupInputs.Rd new file mode 100644 index 0000000..7089fc0 --- /dev/null +++ b/man/GroupInputs.Rd @@ -0,0 +1,71 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.R +\docType{data} +\name{GroupInputs} +\alias{GroupInputs} +\title{Default functional groups for the ZooMSS model} +\format{ +A data frame with 12 rows (functional groups) and 19 columns: +\describe{ +\item{Species}{Character. Name of the functional group/taxa} +\item{Type}{Character. Broad category (Zooplankton or Fish)} +\item{FeedType}{Character. Feeding strategy (Heterotroph, FilterFeeder, Omnivore, Carnivore)} +\item{Prop}{Numeric. Initial proportion of total biomass} +\item{W0}{Numeric. Log10 minimum body weight (g) for the group} +\item{Wmax}{Numeric. Log10 maximum body weight (g) for the group} +\item{Wmat}{Numeric. Log10 maturation body weight (g)} +\item{SearchCoef}{Numeric. Search coefficient for predation interactions} +\item{SearchExp}{Numeric. Search exponent for predation scaling} +\item{PPMRscale}{Numeric. Predator-prey mass ratio scaling parameter} +\item{PPMR}{Numeric. Predator-prey mass ratio (for fish groups)} +\item{FeedWidth}{Numeric. Feeding kernel width parameter} +\item{GrossGEscale}{Numeric. Gross growth efficiency scaling} +\item{Carbon}{Numeric. Carbon content proportion} +\item{Repro}{Numeric. Reproduction parameter} +\item{Fmort}{Numeric. Fishing mortality rate} +\item{Fmort_W0}{Numeric. Log10 minimum weight for fishing mortality} +\item{Fmort_Wmax}{Numeric. Log10 maximum weight for fishing mortality} +\item{PlotColour}{Character. Color code for plotting the functional group} +} +} +\source{ +Marine ecological literature and ZooMSS model development +} +\usage{ +GroupInputs +} +\description{ +A dataset containing the biological parameters for different +functional groups used in the ZooMSS size-structured marine ecosystem model. +These represent various taxa from flagellates to large fish, each defined +by their feeding behavior, size ranges, and physiological parameters. +} +\details{ +ZooMSS Functional Groups Data + +The GroupInputs dataset defines 12 functional groups spanning from +small microzooplankton (flagellates, ciliates) through various mesozooplankton +groups (copepods, euphausiids, chaetognaths) to gelatinous zooplankton (salps, jellyfish) +and three fish size classes (small, medium, large). Each group is characterized by: +\itemize{ +\item \strong{Size ranges}: W0 to Wmax define the body size spectrum +\item \strong{Feeding behavior}: Different strategies for resource acquisition +\item \strong{Interaction parameters}: Search rates and predator-prey relationships +\item \strong{Physiological rates}: Growth efficiency and carbon content +} + +These parameters are based on marine ecological literature and represent +typical values for temperate marine ecosystems. +} +\examples{ +data(GroupInputs) +head(GroupInputs) + +# View size ranges across groups +plot(GroupInputs$W0, GroupInputs$Wmax, + col = GroupInputs$PlotColour, + xlab = "Log10 Min Weight", ylab = "Log10 Max Weight") +text(GroupInputs$W0, GroupInputs$Wmax, GroupInputs$Species, pos = 3, cex = 0.7) +} +\concept{ZooMSS-data} +\keyword{datasets} diff --git a/man/averageTimeSeries.Rd b/man/averageTimeSeries.Rd new file mode 100644 index 0000000..68a34e3 --- /dev/null +++ b/man/averageTimeSeries.Rd @@ -0,0 +1,43 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{averageTimeSeries} +\alias{averageTimeSeries} +\title{Calculate mean of final portion of ZooMSS time series} +\usage{ +averageTimeSeries(mdl, var, n_years = 10) +} +\arguments{ +\item{mdl}{ZooMSS model results object containing model parameters and output arrays} + +\item{var}{Character string specifying which variable to extract and average (e.g., "N", "Growth", "Mort")} + +\item{n_years}{Number of years from the end of the time series to average (default: 10)} +} +\value{ +2D array with averaged values (groups x size_classes) +} +\description{ +Calculates the mean of the final n years of a time series +to obtain equilibrium values after model spin-up period. +} +\details{ +Calculate Average Output from Model Time Series + +This function removes the initial transient period from time series data +and calculates the mean of the final n years, providing representative +steady-state values. Essential for obtaining equilibrium abundances, growth rates, +and other model outputs after the model has reached dynamic equilibrium. +} +\examples{ +\dontrun{ +# Run ZooMSS model +results <- zoomss_model(input_params, Groups) + +# Average final 3 years of abundance data +avg_abundance <- averageTimeSeries(results, "N", n_years = 3) + +# Average final 10 years of growth data (default) +avg_growth <- averageTimeSeries(results, "gg") +} + +} diff --git a/man/calculatePhytoParam.Rd b/man/calculatePhytoParam.Rd new file mode 100644 index 0000000..384832d --- /dev/null +++ b/man/calculatePhytoParam.Rd @@ -0,0 +1,48 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{calculatePhytoParam} +\alias{calculatePhytoParam} +\title{Calculate phytoplankton abundance spectrum from chlorophyll data} +\usage{ +calculatePhytoParam(dat) +} +\arguments{ +\item{dat}{Data frame containing chlorophyll data (chl column in mg/m^3) and +optionally phytoplankton biomass (phy column in g/m^3)} +} +\value{ +Data frame with added columns: +\itemize{ +\item phyto_slope: Power law slope for phytoplankton size spectrum +\item phyto_int: Log10 intercept for phytoplankton abundance +\item phyto_max: Maximum phytoplankton size (log10 grams) +\item pico_biom, nano_biom, micro_biom: Biomass in each size class +} +} +\description{ +Converts chlorophyll concentration data to phytoplankton size spectrum +parameters (slope, intercept, maximum size) using established oceanographic relationships. +} +\details{ +Calculate Phytoplankton Size Spectrum Parameters + +This function implements the Brewin et al. (2015) algorithm to partition +chlorophyll among picophytoplankton, nanophytoplankton, and microphytoplankton size +classes, then calculates: +\itemize{ +\item Size spectrum slope and intercept parameters +\item Maximum phytoplankton size based on micro proportion +\item Biomass estimates for each size class +} + +These parameters drive the dynamic phytoplankton spectrum in ZooMSS that serves +as the base of the food web. The function can work with either chlorophyll-only +data (using empirical relationships) or direct phytoplankton biomass measurements. +} +\references{ +Brewin, R.J.W., et al. (2015). A three-component model of phytoplankton size class +for the Atlantic Ocean. Ecological Modelling, 306, 90-101. + +Maranon, E., et al. (2014). Resource supply overrides temperature as a controlling +factor of marine phytoplankton growth. PLoS ONE, 9(6), e99312. +} diff --git a/man/createEnviroData.Rd b/man/createEnviroData.Rd new file mode 100644 index 0000000..f617cd1 --- /dev/null +++ b/man/createEnviroData.Rd @@ -0,0 +1,72 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils_enviro.R +\name{createEnviroData} +\alias{createEnviroData} +\title{Generate synthetic environmental data for ZooMSS testing} +\usage{ +createEnviroData( + n_years, + dt, + base_sst = 15, + base_chl = 0.5, + seasonal = TRUE, + sst_amplitude = 3, + chl_amplitude = 0.2 +) +} +\arguments{ +\item{n_years}{Number of years to generate} + +\item{dt}{Time step size in years} + +\item{base_sst}{Base sea surface temperature in deg C (default: 15)} + +\item{base_chl}{Base chlorophyll concentration in mg/m^3 (default: 0.5)} + +\item{seasonal}{Logical, whether to add seasonal variation (default: TRUE)} + +\item{sst_amplitude}{Amplitude of SST seasonal variations in deg C (default: 3)} + +\item{chl_amplitude}{Amplitude of chlorophyll seasonal variations in mg/m^3 (default: 0.2)} +} +\value{ +Data frame with columns: time, sst, chl +} +\description{ +Creates simple synthetic environmental time series with optional seasonal +variation for testing ZooMSS model runs when real environmental data is not available. +} +\details{ +Create Environmental Time Series + +This function generates synthetic sea surface temperature and chlorophyll +time series that can be used for testing ZooMSS model behavior. The function can +create either static environmental conditions or seasonal cycles with sinusoidal +variation. This is particularly useful for: +\itemize{ +\item Testing model sensitivity to environmental forcing +\item Creating idealized scenarios for model exploration +\item Generating data when real environmental data is unavailable +} + +The seasonal option creates SST and chlorophyll cycles that are out of phase, +mimicking typical ocean patterns where chlorophyll peaks when SST is lower. +} +\examples{ +# Create seasonal environmental data +env_data <- createEnviroData( + n_years = 10, + dt = 0.01, + seasonal = TRUE +) + +# Create static environmental conditions +static_data <- createEnviroData( + n_years = 5, + dt = 0.01, + seasonal = FALSE, + base_sst = 20, + base_chl = 1.0 +) + +} diff --git a/man/createInputParams.Rd b/man/createInputParams.Rd new file mode 100644 index 0000000..5298b84 --- /dev/null +++ b/man/createInputParams.Rd @@ -0,0 +1,52 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils_enviro.R +\name{createInputParams} +\alias{createInputParams} +\title{Create input parameters data frame for ZooMSS model runs} +\usage{ +createInputParams(time, sst, chl, cellID = NULL) +} +\arguments{ +\item{time}{Numeric vector of time values in years (must be increasing and uniform, can start at any value)} + +\item{sst}{Numeric vector of sea surface temperature values in deg C} + +\item{chl}{Numeric vector of chlorophyll concentration values in mg/m^3} + +\item{cellID}{Optional numeric vector of cell identifiers for spatial data (default: NULL)} +} +\value{ +Data frame with columns: time, time_step, sst, chl, and cellID (if provided) +} +\description{ +Creates a properly formatted input parameters data frame for ZooMSS model +simulations, combining temporal parameters with environmental time series data. +} +\details{ +Create ZooMSS Input Parameters Object + +This function combines environmental time series (SST and chlorophyll) with +time data to create the input_params object required by zoomss_model(). +The function performs validation checks using assertthat to ensure: +\itemize{ +\item All input vectors are numeric and of equal length +\item SST values are within reasonable ocean range (-2 to 35 deg C) +\item Chlorophyll values are positive and within typical range (0 to 50 mg/m^3) +\item Time values are increasing and reasonable +} +} +\examples{ +\dontrun{ +# Create simple environmental time series +time_vec <- seq(0, 10, 0.01) # 10 years with 0.01 year time steps +sst_vec <- 15 + 3*sin(2*pi*time_vec/1) # annual cycle +chl_vec <- 0.5 + 0.2*cos(2*pi*time_vec/1) # annual cycle + +# Create input parameters object +input_params <- createInputParams(time_vec, sst_vec, chl_vec) + +# Use with ZooMSS model +results <- zoomss_model(input_params, Groups, isave = 50) +} + +} diff --git a/man/extractPPMR.Rd b/man/extractPPMR.Rd new file mode 100644 index 0000000..2c43cf4 --- /dev/null +++ b/man/extractPPMR.Rd @@ -0,0 +1,38 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{extractPPMR} +\alias{extractPPMR} +\title{Calculate predator-prey mass ratio data for visualization} +\usage{ +extractPPMR(mdl) +} +\arguments{ +\item{mdl}{ZooMSS results object containing abundance data (N) and model parameters} +} +\value{ +For 2D input: List containing PPMR density data and species-specific values for plotting +For 3D input: Array where first dimension is time, containing PPMR results for each timestep +} +\description{ +Calculates predator-prey mass ratio (PPMR) values and biomass weightings +for creating PPMR distribution plots in ZooMSS analysis. +} +\details{ +Calculate PPMR Data for Plotting + +This function computes theoretical and realized PPMR patterns by: +\itemize{ +\item Calculating size-dependent PPMR values using Wirtz 2012 equations +\item Weighting by biomass to show community-level patterns +\item Computing species-specific PPMR values +\item Handling special cases for filter feeders (larvaceans, salps) +\item Processing either time-averaged abundances (2D) or full time series (3D) +} + +The function dynamically determines size class ranges for larvaceans and salps +based on their W0 and Wmax values. For 3D abundance arrays, it calculates +PPMR for each time step separately. + +This is a helper function primarily used by plotPPMR for visualization. +PPMR analysis provides insights into food web structure and predation patterns. +} diff --git a/man/extractSizeRange.Rd b/man/extractSizeRange.Rd new file mode 100644 index 0000000..f1bdff0 --- /dev/null +++ b/man/extractSizeRange.Rd @@ -0,0 +1,46 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{extractSizeRange} +\alias{extractSizeRange} +\title{Extract specific size class range from model variable} +\usage{ +extractSizeRange(mdl, var, min_size, max_size) +} +\arguments{ +\item{mdl}{ZooMSS model results object containing model parameters and output arrays} + +\item{var}{Character string specifying which variable to extract (e.g., "N", "Z", "Growth")} + +\item{min_size}{Minimum size (log10 grams) to extract} + +\item{max_size}{Maximum size (log10 grams) to extract} +} +\value{ +Array with same dimensions as original variable but subsetted size range +} +\description{ +Subsets ZooMSS model output to include only specified size range, +useful for focusing analysis on particular size ranges. +} +\details{ +Extract Size Range from ZooMSS Output + +This function extracts a subset of size classes from the specified +ZooMSS model variable. Useful for analyzing specific size ranges +(e.g., microzooplankton, mesozooplankton) or excluding boundary effects +from model analysis. The function converts log10 size values to size class +indices automatically. +} +\examples{ +\dontrun{ +# Run ZooMSS model +results <- zoomss_model(input_params, Groups) + +# Extract mesozooplankton size range from abundance data +meso_abundance <- extractSizeRange(results, "N", min_size = -8, max_size = -5) + +# Extract microzooplankton size range from growth data +micro_growth <- extractSizeRange(results, "Growth", min_size = -10, max_size = -8) +} + +} diff --git a/man/extractTrophicLevels.Rd b/man/extractTrophicLevels.Rd new file mode 100644 index 0000000..6a8162d --- /dev/null +++ b/man/extractTrophicLevels.Rd @@ -0,0 +1,53 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{extractTrophicLevels} +\alias{extractTrophicLevels} +\title{Compute trophic levels for functional groups using diet composition} +\usage{ +extractTrophicLevels(mdl) +} +\arguments{ +\item{mdl}{ZooMSS model results object containing 3D diet data (mdl$diet). +Dimensions are time, groups, prey_items where columns 1:3 are always +phytoplankton size classes and remaining columns are zooplankton/fish groups.} +} +\value{ +Matrix where rows are time steps and columns are functional groups +} +\description{ +Calculates trophic levels for each functional group based on their +diet composition using an iterative Gauss-Seidel algorithm. +} +\details{ +Calculate Trophic Levels from Diet Matrix + +This function computes trophic levels by: +\itemize{ +\item Starting with phytoplankton at trophic level 1.0 +\item Initializing all other groups at trophic level 2.0 +\item Iteratively updating trophic levels based on weighted diet composition +\item Continuing until convergence (difference < 0.01) or maximum iterations (100) +\item Processing 3D diet arrays with time series data +} + +Trophic level calculation follows: TL = 1 + sum(diet_fraction_i * TL_prey_i) + +The function calculates trophic levels for each time step separately and +dynamically determines the number of groups from the diet matrix dimensions. + +This provides a quantitative measure of each group's position in the food web +and is useful for analyzing ecosystem structure and energy transfer efficiency. +} +\examples{ +\dontrun{ +# After running ZooMSS model with 3D time series +results <- zoomss_model(input_params, Groups) +trophic_levels <- extractTrophicLevels(results) # Returns matrix (time x groups) + +# View trophic levels by group for final time step +final_tl <- trophic_levels[nrow(trophic_levels), ] +names(final_tl) <- results$param$Groups$Species +print(final_tl) +} + +} diff --git a/man/getBiomass.Rd b/man/getBiomass.Rd new file mode 100644 index 0000000..ddaba52 --- /dev/null +++ b/man/getBiomass.Rd @@ -0,0 +1,45 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{getBiomass} +\alias{getBiomass} +\title{Convert ZooMSS abundance matrices to biomass by multiplying by body weights} +\usage{ +getBiomass(mdl, units = "ww") +} +\arguments{ +\item{mdl}{ZooMSS model object containing abundance array (N) and weight vector (param$w)} + +\item{units}{Character string specifying biomass units: "ww" for wet weight (default) or "carbon" for carbon biomass} +} +\value{ +3D array of biomass values with same dimensions as N. Units depend on the units parameter: +\itemize{ +\item "ww": grams wet weight +\item "carbon": grams carbon +} +} +\description{ +Converts abundance data to wet weight biomass by multiplying abundances +by the corresponding body weights for each size class. Optionally converts to carbon biomass. +} +\details{ +Convert Abundance to Biomass + +This function transforms abundance matrices to biomass by applying the +weight vector across size classes. Essential for analyses requiring biomass +units rather than abundance counts. Works with 3D arrays (time, groups, size_classes). +Can convert to either wet weight or carbon biomass units. +} +\examples{ +\dontrun{ +# Run ZooMSS model +results <- zoomss_model(input_params, Groups) + +# Convert abundances to wet weight biomass +biomass_ww <- getBiomass(results, units = "ww") + +# Convert abundances to carbon biomass +biomass_carbon <- getBiomass(results, units = "carbon") +} + +} diff --git a/man/getGroups.Rd b/man/getGroups.Rd new file mode 100644 index 0000000..5d10b3b --- /dev/null +++ b/man/getGroups.Rd @@ -0,0 +1,61 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/zoomss_groups.R +\name{getGroups} +\alias{getGroups} +\title{Load default or custom functional groups for ZooMSS model} +\usage{ +getGroups(source = "default", file = NULL) +} +\arguments{ +\item{source}{Character string specifying data source. Options: +\itemize{ +\item "default": Use built-in ZooMSS functional groups (default) +\item "file": Load groups from a CSV file +\item "template": Export default groups to a file for modification +}} + +\item{file}{Path to CSV file when source="file" or source="template"} +} +\value{ +Data frame containing functional groups with required columns: +Species, Type, W0, Wmax, and other biological parameters +} +\description{ +Provides access to the default ZooMSS functional groups or loads custom +groups from a file. This function is the primary way to obtain Groups data for +ZooMSS model runs. +} +\details{ +Get Default ZooMSS Functional Groups + +This function provides flexible access to functional groups data: +\itemize{ +\item \strong{Default groups}: Returns the standard ZooMSS functional groups (12 groups) +\item \strong{Custom file}: Loads and validates groups from a user-provided CSV file +\item \strong{Template creation}: Exports default groups to a file for user modification +} + +The default groups include: Flagellates, Ciliates, Larvaceans, OmniCopepods, +CarnCopepods, Euphausiids, Chaetognaths, Salps, Jellyfish, and three Fish groups +(Small, Medium, Large). + +All groups data is validated to ensure it contains required columns and +reasonable parameter values for successful model runs. +} +\examples{ +\dontrun{ +# Use default groups +Groups <- getGroups() + +# Create a template file for modification +getGroups(source = "template", file = "my_groups.csv") + +# Load custom groups from file +custom_groups <- getGroups(source = "file", file = "my_groups.csv") + +# Modify default groups programmatically +Groups <- getGroups() +Groups$W0[Groups$Species == "Flagellates"] <- -12.5 # Modify minimum size +} + +} diff --git a/man/loadDefaultGroups.Rd b/man/loadDefaultGroups.Rd new file mode 100644 index 0000000..cc5e3f2 --- /dev/null +++ b/man/loadDefaultGroups.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/zoomss_groups.R +\name{loadDefaultGroups} +\alias{loadDefaultGroups} +\title{Internal function to load default ZooMSS groups} +\usage{ +loadDefaultGroups() +} +\value{ +Data frame with default functional groups +} +\description{ +Loads the default functional groups from the package data or CSV file. +This is an internal function used by getGroups(). +} +\details{ +Load Default Functional Groups Data + +This function handles the actual loading of default groups data, +whether from package data (if available) or from the CSV file in data-raw. +} +\keyword{internal} diff --git a/man/pipe.Rd b/man/pipe.Rd new file mode 100644 index 0000000..e3de016 --- /dev/null +++ b/man/pipe.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils_pipe.R +\name{\%>\%} +\alias{\%>\%} +\title{Pipe operator} +\usage{ +lhs \%>\% rhs +} +\arguments{ +\item{lhs}{A value or the magrittr placeholder.} + +\item{rhs}{A function call using the magrittr semantics.} +} +\value{ +The result of calling \code{rhs(lhs)}. +} +\description{ +See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details. +} +\keyword{internal} diff --git a/man/plotEnvironment.Rd b/man/plotEnvironment.Rd new file mode 100644 index 0000000..4d2c2c3 --- /dev/null +++ b/man/plotEnvironment.Rd @@ -0,0 +1,42 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/zoomss_plotting.R +\name{plotEnvironment} +\alias{plotEnvironment} +\title{Plot environmental forcing data} +\usage{ +plotEnvironment(env_data) +} +\arguments{ +\item{env_data}{Environmental data frame with time, sst, chl columns} +} +\value{ +ggplot object (if patchwork available) or list of two ggplot objects +} +\description{ +Creates plots of sea surface temperature and chlorophyll time series +for visualizing environmental forcing data used in ZooMSS model runs. +} +\details{ +Plot Environmental Time Series + +This function creates two separate plots with different y-axes scales: +\itemize{ +\item SST plot (red line) with temperature in deg C +\item Chlorophyll plot (green line) with concentration in mg/m^3 +} + +The plots can be combined using the patchwork package if available, otherwise +separate plots are returned as a list. This helps users visualize the +environmental forcing that drives ZooMSS model dynamics. +} +\examples{ +# Create sample data and plot +env_data <- data.frame( + time = 1:100, + dt = 0.01, + sst = 15 + 3*sin(2*pi*(1:100)/50), + chl = 0.5 + 0.2*cos(2*pi*(1:100)/50) +) +plots <- plotEnvironment(env_data) + +} diff --git a/man/plotPPMR.Rd b/man/plotPPMR.Rd new file mode 100644 index 0000000..94861e3 --- /dev/null +++ b/man/plotPPMR.Rd @@ -0,0 +1,44 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/zoomss_plotting.R +\name{plotPPMR} +\alias{plotPPMR} +\title{Visualize predator-prey mass ratio patterns in ZooMSS results} +\usage{ +plotPPMR(mdl, idx) +} +\arguments{ +\item{mdl}{ZooMSS results object containing model outputs and parameters} + +\item{idx}{The time index to plot} +} +\value{ +ggplot object showing PPMR distribution with species-specific overlays +} +\description{ +Creates a plot showing the distribution of predator-prey mass ratios (PPMR) +across functional groups, providing insights into the trophic structure of the ecosystem. +} +\details{ +Plot Predator-Prey Mass Ratio (PPMR) + +This function calculates and visualizes PPMR patterns by: +\itemize{ +\item Computing theoretical PPMR values for each functional group and size class +\item Weighting by biomass to show realized community patterns +\item Creating a density plot of PPMR distribution across the community +\item Overlaying species-specific PPMR values as points +} + +PPMR is a key ecological metric that describes the size relationship between +predators and their prey, providing insight into food web structure and +energy transfer efficiency in marine ecosystems. +} +\examples{ +\dontrun{ +# After running ZooMSS model +results <- zoomss_model(input_params, Groups) +ppmr_plot <- plotPPMR(results) +print(ppmr_plot) +} + +} diff --git a/man/plotSizeSpectra.Rd b/man/plotSizeSpectra.Rd new file mode 100644 index 0000000..65d243a --- /dev/null +++ b/man/plotSizeSpectra.Rd @@ -0,0 +1,47 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/zoomss_plotting.R +\name{plotSizeSpectra} +\alias{plotSizeSpectra} +\title{Visualize abundance size spectra across functional groups} +\usage{ +plotSizeSpectra(mdl, by = "abundance", n_years = 10) +} +\arguments{ +\item{mdl}{ZooMSS results object containing model outputs and parameters} + +\item{by}{Character string specifying the metric to plot. Options: "abundance", "biomass", "mortality", "growth" (default: "abundance")} + +\item{n_years}{The number of years (from the end) over which to average the size spectra} +} +\value{ +ggplot object showing log abundance vs log body weight by species +} +\description{ +Creates a log-log plot of abundance versus body size for all functional groups, +showing the classic size spectrum pattern in marine ecosystems. +} +\details{ +Plot Size Spectra for ZooMSS Results + +This function visualizes the abundance size spectrum by: +\itemize{ +\item Converting abundance data to long format with body weights +\item Filtering out zero abundances to focus on active size classes +\item Creating log-log plots colored by functional group +\item Using species-specific colors defined in the Groups parameter table +} + +Size spectra are fundamental patterns in marine ecology, typically showing +declining abundance with increasing body size. This visualization helps +assess model realism and identify dominant size classes within each +functional group. +} +\examples{ +\dontrun{ +# After running ZooMSS model +results <- zoomss_model(input_params, Groups) +size_plot <- plotSizeSpectra(results) +print(size_plot) +} + +} diff --git a/man/plotTimeSeries.Rd b/man/plotTimeSeries.Rd new file mode 100644 index 0000000..bcd7419 --- /dev/null +++ b/man/plotTimeSeries.Rd @@ -0,0 +1,77 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/zoomss_plotting.R +\name{plotTimeSeries} +\alias{plotTimeSeries} +\title{Unified function to visualize time series changes for different metrics} +\usage{ +plotTimeSeries( + mdl, + by = "abundance", + type = "line", + transform = "identity", + species = NULL +) +} +\arguments{ +\item{mdl}{ZooMSS results object containing model outputs with time series data} + +\item{by}{Character string specifying the metric to plot. Options: "abundance", "biomass", "mortality", "growth" (default: "abundance")} + +\item{type}{Character vector of plot type. Use \code{line} for the default line plot, \code{stack} or \code{fill} (as per geom_area) for stacked or proportional plots. (default: "line")} + +\item{transform}{Character vector of the required y-axis transformation. Options from \verb{scale_*_continuous} (Default: "identity).} + +\item{species}{Character vector of species names to include. If NULL, all species included (default: NULL, applies to all metrics)} +} +\value{ +ggplot object showing the requested time series by species +} +\description{ +Creates time series plots showing how abundance, biomass, mortality, or growth +rates of functional groups change throughout the ZooMSS simulation period. +} +\details{ +Plot Time Series Data for ZooMSS Results + +This function creates time series visualizations by: +\itemize{ +\item \strong{Abundance}: Summing abundances across size classes, log-transformed y-axis +\item \strong{Biomass}: Calculating biomass (abundance × weight), with optional stacking and proportional scaling +\item \strong{Mortality}: Averaging predation mortality rates across size classes +\item \strong{Growth}: Averaging growth rates across size classes, log-transformed y-axis +} + +All plots use species-specific colors and filter out zero values. Time series plots help identify: +\itemize{ +\item Equilibration time for model runs +\item Seasonal or cyclical patterns in ecological metrics +\item Relative patterns between functional groups +\item Model stability and convergence behavior +} +} +\examples{ +\dontrun{ +# After running ZooMSS model +results <- zoomss_model(input_params, Groups) + +# Plot different metrics +abundance_plot <- plotTimeSeries(results, by = "abundance", transform = "log10") +biomass_plot <- plotTimeSeries(results, by = "biomass", transform = "log10") +mortality_plot <- plotTimeSeries(results, by = "mortality") +growth_plot <- plotTimeSeries(results, by = "growth") + +stacked_plot <- plotTimeSeries(results, by = "biomass", type = "stack") +prop_plot <- plotTimeSeries(results, by = "biomass", type = "fill") + +# Focus on specific species (works for all metrics) +copepod_plot <- plotTimeSeries(results, by = "biomass", + species = c("OmniCopepods", "CarnCopepods")) +abundance_copepods <- plotTimeSeries(results, by = "abundance", + species = c("OmniCopepods", "CarnCopepods")) +mortality_copepods <- plotTimeSeries(results, by = "mortality", + species = c("OmniCopepods", "CarnCopepods")) +growth_copepods <- plotTimeSeries(results, by = "growth", + species = c("OmniCopepods", "CarnCopepods")) +} + +} diff --git a/man/reduceAll.Rd b/man/reduceAll.Rd new file mode 100644 index 0000000..fac9505 --- /dev/null +++ b/man/reduceAll.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{reduceAll} +\alias{reduceAll} +\title{Aggregate abundances across all groups and size classes} +\usage{ +reduceAll(x, method = "sum") +} +\arguments{ +\item{x}{3D array outptut from ZooMSS model} + +\item{method}{Character string specifying aggregation method: "sum" (default) or "mean".} +} +\value{ +Vector of total abundance values (one per spatial cell) +} +\description{ +Calculates total abundance across all functional groups and size classes using the specified method. +} +\details{ +Aggregate abundances across all groups and size classes + +This function provides the most aggregated view of ZooMSS output by applying the method across both functional groups and size classes. +} diff --git a/man/reduceSize.Rd b/man/reduceSize.Rd new file mode 100644 index 0000000..8616486 --- /dev/null +++ b/man/reduceSize.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{reduceSize} +\alias{reduceSize} +\title{Aggregate ZooMSS abundances across all size classes} +\usage{ +reduceSize(x, method = "sum") +} +\arguments{ +\item{x}{3D array outptut from ZooMSS model} + +\item{method}{Character string specifying aggregation method: "sum" (default) or "mean".} +} +\value{ +List of vectors with total abundance per functional group +} +\description{ +Sums abundance values across all size classes for each functional group, +providing total abundance per group. +} +\details{ +Sum ZooMSS Output Across Size Bins + +This function collapses the size dimension of ZooMSS output by summing +across all size classes. Useful for analyzing total abundance patterns without +size structure detail. +} +\examples{ +\dontrun{ +# After running ZooMSS model +results <- zoomss_model(input_params, Groups) +total_abundances <- reduceSize(results$abundances) +} + +} diff --git a/man/reduceSpecies.Rd b/man/reduceSpecies.Rd new file mode 100644 index 0000000..45aa940 --- /dev/null +++ b/man/reduceSpecies.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{reduceSpecies} +\alias{reduceSpecies} +\title{Aggregate ZooMSS abundances across all species} +\usage{ +reduceSpecies(x, method = "sum") +} +\arguments{ +\item{x}{3D array outptut from ZooMSS model} + +\item{method}{Character string specifying aggregation method: "sum" (default) or "mean".} +} +\value{ +Array with species dimension reduced using the specified method +} +\description{ +Aggregates abundance values across all species bins for each functional group and size class using the specified method. +} +\details{ +Aggregate ZooMSS abundances across all species + +This function collapses the species dimension by applying the specified method (sum or mean) across all species bins. +} diff --git a/man/untibble.Rd b/man/untibble.Rd new file mode 100644 index 0000000..6de5d85 --- /dev/null +++ b/man/untibble.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{untibble} +\alias{untibble} +\title{Convert tibble to data frame for efficiency} +\usage{ +untibble(tibble) +} +\arguments{ +\item{tibble}{A tibble or data frame object to convert} +} +\value{ +Plain data frame without tibble attributes +} +\description{ +Removes tibble attributes and converts to a plain data frame +for improved speed and memory efficiency in computational workflows. +} +\details{ +Remove Tibble Attributes + +This utility function strips tibble-specific attributes that can +slow down operations in tight computational loops. Used internally by +ZooMSS for performance optimization when working with large datasets. +} diff --git a/man/validateGroups.Rd b/man/validateGroups.Rd new file mode 100644 index 0000000..9bb1459 --- /dev/null +++ b/man/validateGroups.Rd @@ -0,0 +1,42 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/zoomss_groups.R +\name{validateGroups} +\alias{validateGroups} +\title{Validate ZooMSS functional groups data structure and values} +\usage{ +validateGroups(groups) +} +\arguments{ +\item{groups}{Data frame containing functional groups data} +} +\value{ +TRUE if validation passes (invisibly), otherwise throws an error +} +\description{ +Performs comprehensive validation of functional groups data to ensure +it meets ZooMSS model requirements. +} +\details{ +Validate Functional Groups Data + +This function validates: +\itemize{ +\item Required column names are present +\item Data types are correct +\item Parameter values are within reasonable ranges +\item No missing values in critical columns +\item Size ranges are logical (W0 < Wmax) +} +} +\examples{ +\dontrun{ +Groups <- getGroups() +validateGroups(Groups) # Should pass + +# This would fail validation: +bad_groups <- Groups +bad_groups$W0 <- NULL +validateGroups(bad_groups) # Error: missing required column +} + +} diff --git a/man/zoomss_model.Rd b/man/zoomss_model.Rd new file mode 100644 index 0000000..b5ab12e --- /dev/null +++ b/man/zoomss_model.Rd @@ -0,0 +1,71 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/zoomss_model.R +\name{zoomss_model} +\alias{zoomss_model} +\title{Main ZooMSS model function for complete simulations} +\usage{ +zoomss_model(input_params, Groups = NULL, isave = 1) +} +\arguments{ +\item{input_params}{Data frame containing model parameters and environmental time series. +Must include columns: time (time vector in years), sst (sea surface temperature), +and chl (chlorophyll). Can optionally include cellID for spatial data. The time step (dt) +and maximum time (tmax) are automatically calculated from the time vector. Can be created using createInputParams().} + +\item{Groups}{Data frame defining functional groups with their biological parameters. +Must include columns defining species characteristics, size ranges, and feeding parameters. +If NULL, uses default ZooMSS functional groups. Can be obtained/customized using +getGroups().} + +\item{isave}{Save frequency in time steps (default: 10)} +} +\value{ +Complete ZooMSS model results object containing: +\itemize{ +\item param: Model parameters and environmental forcing data +\item time: Time values corresponding to saved results (accounting for isave) +\item abundance: Abundance time series (time x groups x size classes) +\item growth: Growth rate time series +\item mortality: Mortality rate time series +\item diet: Diet composition time series +\item Additional model structure and kernel data +} +} +\description{ +This is the main wrapper function that orchestrates a complete ZooMSS +model simulation from parameter setup through model execution to output processing. +} +\details{ +Run Complete ZooMSS Model Simulation + +This function coordinates the entire ZooMSS modeling workflow: +\enumerate{ +\item Validates that environmental time series data is provided +\item Sets up model parameters using the Groups data and input parameters +\item Initializes the model structure and feeding kernels +\item Runs the model forward in time with dynamic environmental forcing +\item Processes outputs by averaging the final 50\% of the simulation +\item Returns organized results including abundances, diets, growth, and mortality +} + +This is the primary entry point for +running ZooMSS simulations with environmental forcing. +} +\examples{ +\dontrun{ +# Basic usage with default groups +env_data <- createEnviroData(10, 0.01) +input_params <- createInputParams(env_data$time, env_data$sst, env_data$chl) +results <- zoomss_model(input_params, isave = 50) + +# Using custom groups +Groups <- getGroups() # Get default groups +Groups$W0[1] <- -12.5 # Modify a parameter +results <- zoomss_model(input_params, Groups, isave = 100) + +# Loading groups from file +custom_groups <- getGroups(source = "file", file = "my_groups.csv") +results <- zoomss_model(input_params, custom_groups) +} + +} diff --git a/man/zoomss_mvf.Rd b/man/zoomss_mvf.Rd new file mode 100644 index 0000000..8588119 --- /dev/null +++ b/man/zoomss_mvf.Rd @@ -0,0 +1,94 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/zoomss_mvf.R +\name{zoomss_mvf} +\alias{zoomss_mvf} +\title{Solve McKendrick-von Foerster equation for size-structured populations} +\usage{ +zoomss_mvf( + ngrps, + curr_min_size, + curr_max_size, + A_iter, + C_iter, + Nb_iter, + S_iter, + A, + B, + C, + Nb, + S +) +} +\arguments{ +\item{ngrps}{Number of functional groups in the model} + +\item{curr_min_size}{Vector of minimum size class indices for each group} + +\item{curr_max_size}{Vector of maximum size class indices for each group} + +\item{A_iter}{Matrix of advection coefficients for current iteration} + +\item{C_iter}{Matrix of diagonal coefficients for current iteration} + +\item{Nb_iter}{Matrix to store updated abundances for current iteration} + +\item{S_iter}{Matrix of source terms for current iteration} + +\item{A}{Matrix of advection coefficients} + +\item{B}{Matrix of diffusion coefficients} + +\item{C}{Matrix of diagonal coefficients} + +\item{Nb}{Matrix of abundances to be updated} + +\item{S}{Matrix of source terms} +} +\value{ +Updated abundance matrix (Nb) with new size-class distributions +} +\description{ +Solves the McKendrick-von Foerster (MvF) partial differential equation +for size-structured population dynamics using a finite difference approach in base R. +} +\details{ +McKendrick-von Foerster Equation Solver (Base R Implementation) + +This function implements the numerical solution to the McKendrick-von Foerster +equation, which describes how populations change across size classes over time. +The equation is solved using an upwind finite difference scheme that handles: +\itemize{ +\item Growth through size classes (advection term) +\item Diffusion between adjacent size classes +\item Source and sink terms from feeding and mortality +} + +The function processes each functional group separately and applies boundary conditions +appropriate for size-structured models. The last size class is set to zero abundance +to represent maximum size limits. + +This is a core computational component of ZooMSS that updates population abundances +at each time step based on growth, mortality, and reproduction processes. +} +\examples{ +\dontrun{ +# This function is typically called internally by zoomss_run +# Example shows the structure of parameters needed: +ngrps <- 9 +ngrid <- 100 +curr_min_size <- c(1, 10, 20, 30, 40, 50, 60, 70, 80) +curr_max_size <- c(30, 40, 50, 60, 70, 80, 90, 95, 100) + +# Initialize coefficient matrices +A <- matrix(0, nrow = ngrps, ncol = ngrid) +B <- matrix(0, nrow = ngrps, ncol = ngrid) +C <- matrix(1, nrow = ngrps, ncol = ngrid) +S <- matrix(0, nrow = ngrps, ncol = ngrid) +Nb <- matrix(0.1, nrow = ngrps, ncol = ngrid) + +# Run MvF solver +updated_abundances <- zoomss_mvf(ngrps, curr_min_size, curr_max_size, + A, C, Nb, S, A, B, C, Nb, S) +} + +} diff --git a/man/zoomss_params.Rd b/man/zoomss_params.Rd new file mode 100644 index 0000000..8f6687a --- /dev/null +++ b/man/zoomss_params.Rd @@ -0,0 +1,74 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/zoomss_params.R +\name{zoomss_params} +\alias{zoomss_params} +\title{Initialize and validate ZooMSS model parameters} +\usage{ +zoomss_params(Groups, input_params, isave) +} +\arguments{ +\item{Groups}{Data frame containing functional group definitions with columns: +Species, Type, W0 (log min size), Wmax (log max size), and various biological parameters} + +\item{input_params}{Data frame with model parameters including: +time (time vector in years), sst (sea surface temperature), and chl (chlorophyll). +The time vector can start at any value and the model automatically calculates dt (time step) and tmax (maximum time).} + +\item{isave}{Save frequency in time steps (default: 50)} +} +\value{ +List containing comprehensive model parameters: +\itemize{ +\item Groups: Functional group definitions +\item ngrps: Number of functional groups +\item ngrid: Number of size classes +\item w: Size class weights (g) +\item tmax, dt, isave: Temporal parameters +\item zoo_grps, fish_grps: Indices for different organism types +\item phyto_int, phyto_slope: Time series of phytoplankton parameters +\item temp_eff_zoo, temp_eff_fish: Time series of temperature effects +\item Additional biological and physical parameters +} +} +\description{ +Sets up the complete parameter list for ZooMSS model runs, including +functional group parameters, model dimensions, and environmental forcing data. +} +\details{ +Set Up ZooMSS Model Parameters + +This function creates a comprehensive parameter object that contains: + +\strong{Static Parameters (fixed across time steps):} +\itemize{ +\item Model dimensions (number of groups, size classes, time steps) +\item Biological parameters (growth efficiency, mortality rates) +\item Size class definitions and ranges for each functional group +\item Phytoplankton size spectrum parameters +} + +\strong{Dynamic Parameters (calculated from environmental data):} +\itemize{ +\item Phytoplankton abundance time series based on chlorophyll +\item Temperature effects on metabolism for zooplankton and fish +\item Environmental forcing validation and interpolation +} + +The function validates that environmental time series data covers the full +simulation period and pre-calculates time-varying parameters to optimize +model performance during the main simulation loop. +} +\examples{ +\dontrun{ +# Load functional groups +data(Groups) + +# Create environmental time series +env_data <- createEnviroData(10, 0.01) +input_params <- createInputParams(env_data$time, env_data$sst, env_data$chl) + +# Generate parameter list +params <- zoomss_params(Groups, input_params, isave = 50) +} + +} diff --git a/man/zoomss_run.Rd b/man/zoomss_run.Rd new file mode 100644 index 0000000..3eb6d15 --- /dev/null +++ b/man/zoomss_run.Rd @@ -0,0 +1,77 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/zoomss_run.R +\name{zoomss_run} +\alias{zoomss_run} +\title{Execute the main ZooMSS simulation loop with dynamic environmental forcing} +\usage{ +zoomss_run(model) +} +\arguments{ +\item{model}{Model object created by zoomss_setup containing: +\itemize{ +\item param: Complete parameter list with environmental time series +\item Feeding kernels and biological rate parameters +\item Initial conditions and model structure +}} +} +\value{ +List containing complete model output: +\itemize{ +\item param: Model parameters used in simulation +\item N: Abundance time series (time x groups x size classes) +\item gg: Growth rate time series +\item diet: Diet composition time series +\item Z: Mortality rate time series +\item time: Time values corresponding to saved results (accounting for isave) +\item w: Size class weights (g) +\item Additional time series data and model results +} +} +\description{ +Runs the ZooMSS model forward in time, updating environmental conditions +and population dynamics at each time step using the McKendrick-von Foerster framework. +} +\details{ +Run ZooMSS Model Forward in Time + +This is the core simulation engine of ZooMSS that: + +\strong{Environmental Dynamics:} +\itemize{ +\item Updates phytoplankton abundance spectrum based on chlorophyll time series +\item Applies temperature effects on zooplankton and fish metabolism +\item Recalculates feeding kernels with current environmental conditions +} + +\strong{Population Dynamics:} +\itemize{ +\item Solves McKendrick-von Foerster equation for size-structured growth +\item Updates feeding interactions between all size classes and groups +\item Calculates mortality from predation, senescence, and fishing +\item Handles recruitment and boundary conditions for each functional group +} + +\strong{Time Integration:} +\itemize{ +\item Processes model through all time steps with adaptive environmental forcing +\item Saves output at specified intervals for memory efficiency +\item Maintains mass balance and numerical stability throughout simulation +} + +Unlike static models, this version dynamically updates phytoplankton spectra +and temperature effects at each time step based on provided environmental data. +} +\examples{ +\dontrun{ +# Set up model parameters and structure +params <- zoomss_params(Groups, input_params) +model <- zoomss_setup(params) + +# Run the simulation +results <- zoomss_run(model) + +# Access final abundances +final_abundances <- results$N[dim(results$N)[1],,] +} + +} diff --git a/man/zoomss_setup.Rd b/man/zoomss_setup.Rd new file mode 100644 index 0000000..8e62b50 --- /dev/null +++ b/man/zoomss_setup.Rd @@ -0,0 +1,80 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/zoomss_setup.R +\name{zoomss_setup} +\alias{zoomss_setup} +\title{Initialize ZooMSS model components and calculate feeding interactions} +\usage{ +zoomss_setup(param) +} +\arguments{ +\item{param}{Complete parameter list created by zoomss_params containing: +\itemize{ +\item Groups: Functional group definitions and biological parameters +\item Model dimensions (ngrps, ngrid, time parameters) +\item Environmental forcing time series +\item Physical and biological constants +}} +} +\value{ +Model object containing: +\itemize{ +\item param: Input parameters (passed through) +\item dynam_xxx: Dynamic feeding kernel arrays for group interactions (where xxx = growthkernel, diffkernel, dietkernel, mortkernel) +\item phyto_xxx: Phytoplankton feeding kernel arrays (where xxx = growthkernel, diffkernel, dietkernel) +\item nPP: Initial phytoplankton abundance spectrum +\item M_sb_base: Baseline senescence mortality rates +\item fish_mort: Fishing mortality rates +\item assim_eff: Assimilation efficiency matrix +\item temp_eff: Temperature effect matrix (initialized) +\item N: Initial abundance arrays +\item time: Time array for storing time values (initialized as NA) +\item Additional model structure components +} +} +\description{ +Sets up the ZooMSS model structure by calculating feeding kernels, mortality +rates, and other model components that remain static during the simulation. +} +\details{ +Setup ZooMSS Model Structure and Feeding Kernels + +This function initializes the core ZooMSS model structure by calculating: + +\strong{Static Components (calculated once):} +\itemize{ +\item Feeding preference kernels based on predator-prey size ratios +\item Search volumes and encounter rates between size classes +\item Baseline mortality rates (senescence, fishing) +\item Initial abundance distributions for all functional groups +} + +\strong{Dynamic Component Structures (updated during run):} +\itemize{ +\item Phytoplankton feeding kernels (structure calculated here, values updated with environment) +\item Growth and diffusion kernels for zooplankton and fish interactions +\item Diet and mortality tracking arrays +} + +\strong{Model Architecture:} +\itemize{ +\item Size-structured populations across logarithmic size classes +\item Multiple functional groups with different feeding behaviors +\item Environmental coupling through phytoplankton and temperature +} + +The function separates static calculations (done once for efficiency) from +dynamic calculations (updated each time step in zoomss_run). +} +\examples{ +\dontrun{ +# Create parameters for model setup +params <- zoomss_params(Groups, input_params) + +# Initialize model structure +model <- zoomss_setup(params) + +# Model is now ready for time integration with zoomss_run +results <- zoomss_run(model) +} + +} diff --git a/setup_RUN_NAME.R b/setup_RUN_NAME.R deleted file mode 100644 index 31fce63..0000000 --- a/setup_RUN_NAME.R +++ /dev/null @@ -1,77 +0,0 @@ -## This is the development version of the model published in Heneghan et al., (2020): -## This version models multiple zooplankton functional groups, and three fish groups -## -## If you save timesteps, you can examine the model dynamics at -## https://jaseeverett.shinyapps.io/ZooMSS_Dashboard/ -## Alternatively you can clone the ZooMSS_Dashboard from Github -## https://github.com/MathMarEcol/ZooMSS_Dashboard -## -## -## Code written by Dr Jason Everett (UQ/UNSW/CSIRO), Dr Ryan Heneghan (QUT) and Mr Patrick Sykes (UQ) -## Last updated Friday 31st March 2023 - -# library(Rcpp) # Only needed if we are running with Rcpp code. -source("fZooMSS_Model.R") #source the model code -source("fZooMSS_Xtras.R") - - -# Setup user defined parameters ------------------------------------------- - -# enviro_data <- readRDS("enviroData_oneDeg_20210728.rds") # Load environmental data at 1 degree resolution -# enviro_data <- readRDS("enviroData_fiveDeg_20200317.rds") # Load environmental data at 5 degree resolution - -# # You can also create your own environmental data using the below. -enviro_data <- fZooMSS_CalculatePhytoParam(data.frame(cellID = 1, - sst = 15, - chlo = 0.5)) - -# Add delta time (years) -enviro_data$dt <- 0.01 - -# Set length of simulation (years) -enviro_data$tmax <- 50 - -# Setup jobname -jobname <- "DATE_JOBNAME" # This is the job name used on the HPC queue, and also to save the run: Recommend: YYYYMMDD_AbbrevExperimentName. -enviro_row <- 1 # Which row of the environmental data do you want to run if HPC=FALSE. - -HPC <- FALSE # Is this being run on a HPC for all cells or will we manually choose the row of the enviro_data to be used. -SaveTimeSteps <- TRUE # Should we save all time steps. This can be very large if tmax is large - - -Groups <- read.csv("TestGroups.csv", stringsAsFactors = FALSE) # Load in functional group information. This can be edited directly. - - -# No need to change anything below here. ---------------------------------- - -if (HPC == TRUE){ - ID <- as.integer(Sys.getenv('PBS_ARRAY_INDEX')) # Get the array run number on HPC - } else { - ID <- enviro_row - } - -ID_char <- sprintf("%04d",ID) # Set the ID as a 4 digit character so it will sort properly - -input_params <- enviro_data[ID,] -rm(enviro_data) - -out$model$model_runtime <- system.time( - out <- fZooMSS_Model(input_params, Groups, SaveTimeSteps) -) - -# Save the output if you want -saveRDS(out, file = paste0("RawOutput/", jobname, "_", ID_char,".RDS")) - - -# Plotting ---------------------------------------------------------------- - -source("fZooMSS_Plot.R") - -(ggPPMR <- fZooMSS_Plot_PPMR(out)) -(ggSizeSpec <- fZooMSS_Plot_SizeSpectra(out)) - -## If you have saved the timesteps you can plot the timeseries -(ggAbundTS <- fZooMSS_Plot_AbundTimeSeries(out)) -(ggGrowthTS <- fZooMSS_Plot_GrowthTimeSeries(out)) -(ggPredTS <- fZooMSS_Plot_PredTimeSeries(out)) - diff --git a/tests/testthat.R b/tests/testthat.R new file mode 100644 index 0000000..0d6e32b --- /dev/null +++ b/tests/testthat.R @@ -0,0 +1,12 @@ +# This file is part of the standard setup for testthat. +# It is recommended that you do not modify it. +# +# Where should you do additional test configuration? +# Learn more about the roles of various files in: +# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview +# * https://testthat.r-lib.org/articles/special-files.html + +library(testthat) +library(zoomss) + +test_check("zoomss") diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R new file mode 100644 index 0000000..a2c2099 --- /dev/null +++ b/tests/testthat/test-utils.R @@ -0,0 +1,115 @@ +library(testthat) +library(zoomss) +library(dplyr) +library(tibble) + +# Setup real model data once for all tests +enviro_data <- createEnviroData(n_years = 20) +groups <- getGroups() %>% + dplyr::filter(!Species %in% c("Apex_Fish", "Demersal_Fish", "Small_Pelagic_Fish")) + +# Create real model data with isave parameter for full functionality +mdl <- zoomss_model( + input_params = enviro_data, + Groups = groups, + isave = 50 # This is important for proper test results +) + +# Create a second model with zero abundance for edge case testing +mdl2 <- mdl +mdl2$abundance[] <- 0 + +# Tests for reduceSize() ------------------------------------------------- + +test_that("reduceSize reduces size dimension correctly", { + # Test with real model data + result <- reduceSize(mdl$abundance) + + # Check dimensions: should reduce last dimension (sizes) + expect_equal(dim(result), c(dim(mdl$abundance)[1], dim(mdl$abundance)[2])) + + # Check that values are sums across size dimension + manual_sum <- apply(mdl$abundance, c(1, 2), sum) + expect_equal(result, manual_sum) +}) + +test_that("reduceSize handles 2D arrays", { + # Test with 2D array (single time slice from model) + result <- reduceSize(mdl$abundance[1, , ]) + + # For 2D array, reduceSize returns the same array (no size dimension to reduce) + expect_equal(result, mdl$abundance[1, , ]) +}) + +# Tests for reduceSpecies() ---------------------------------------------- + +test_that("reduceSpecies reduces group dimension correctly", { + # Test with real model data + result <- reduceSpecies(mdl$abundance) + + # Check dimensions: should reduce middle dimension (groups) + expect_equal(dim(result), c(dim(mdl$abundance)[1], dim(mdl$abundance)[3])) + + # Check that values are sums across group dimension + manual_sum <- apply(mdl$abundance, c(1, 3), sum) + expect_equal(result, manual_sum) +}) + +test_that("reduceSpecies handles 2D arrays", { + # Test with 2D array (single time slice from model) + # reduceSpecies is designed for 3D arrays, so 2D should error + expect_error(reduceSpecies(mdl$abundance[1, , ]), "'MARGIN' does not match dim") +}) + +# Tests for reduceAll() -------------------------------------------------- + +test_that("reduceAll reduces all dimensions correctly", { + # Test with real model data + result <- reduceAll(mdl$abundance) + + # Should reduce to vector (time dimension only) + expect_true(is.vector(result)) + expect_equal(length(result), dim(mdl$abundance)[1]) + + # Check that values are sums across all but first dimension + manual_sum <- apply(mdl$abundance, 1, sum) + expect_equal(result, manual_sum) +}) + +# Tests for getBiomass() -------------------------------------------------- + +test_that("getBiomass converts abundance to wet weight biomass correctly", { + # Test with real model data + result <- getBiomass(mdl, units = "ww") + + # Check dimensions match input + expect_equal(dim(result), dim(mdl$abundance)) + + # Check that biomass = abundance * weight (approximately, allowing for rounding) + # Test a few specific cases + idx <- which(mdl$abundance > 0, arr.ind = TRUE)[seq_len(5), ] + for(i in seq_len(nrow(idx))) { + t_idx <- idx[i, 1] + g_idx <- idx[i, 2] + s_idx <- idx[i, 3] + expected_biomass <- mdl$abundance[t_idx, g_idx, s_idx] * mdl$param$w[s_idx] + expect_equal(result[t_idx, g_idx, s_idx], expected_biomass, tolerance = 1e-10) + } +}) + +# Tests for untibble() --------------------------------------------------- + +test_that("untibble converts tibble to data frame", { + # Create a test tibble + test_tibble <- tibble::tibble(x = 1:5, y = letters[1:5]) + + result <- untibble(test_tibble) + + # Check that result is a data frame, not a tibble + expect_true(is.data.frame(result)) + expect_false(tibble::is_tibble(result)) + + # Check that data is preserved + expect_equal(result$x, test_tibble$x) + expect_equal(result$y, test_tibble$y) +}) diff --git a/tests/testthat/test-utils_enviro.R b/tests/testthat/test-utils_enviro.R new file mode 100644 index 0000000..8849056 --- /dev/null +++ b/tests/testthat/test-utils_enviro.R @@ -0,0 +1,3 @@ +test_that("multiplication works", { + expect_equal(2 * 2, 4) +}) diff --git a/tests/testthat/test-zoomss_model.R b/tests/testthat/test-zoomss_model.R new file mode 100644 index 0000000..b984716 --- /dev/null +++ b/tests/testthat/test-zoomss_model.R @@ -0,0 +1,305 @@ +# Test suite for ZooMSS model functions +# Tests cover the main model workflow: zoomss_model, zoomss_params, zoomss_setup, zoomss_run +# Following tidyverse and R packages testing standards + +# Setup test data -------------------------------------------------------- + +env_data <- createEnviroData( + n_years = 20, + dt = 0.1, + seasonal = FALSE, + base_sst = 20, + base_chl = 1.0 +) + +# Get groups data +Groups <- getGroups() + +# Create mock model results for plotting tests +mdl <- zoomss_model(input_params = env_data, Groups = Groups, isave = 1) + +# Create minimal test groups data +non_default_groups <- data.frame( + Species = c("TestZoo1", "TestFish1"), + Type = c("Zooplankton", "Fish"), + FeedType = c("FilterFeeder", "Carnivore"), + Prop = c(1.0, NA), + W0 = c(-12.0, -6.0), # Use exact values that match w_log10 grid + Wmax = c(-6.0, 3.0), # Use exact values that match w_log10 grid + Wmat = c(-8.0, 0.0), # Use exact values that match w_log10 grid + SearchCoef = c(640, 640), + SearchExp = c(0.8, 0.8), + PPMRscale = c(1.0, 1.0), + PPMR = c(NA, 1000), + FeedWidth = c(2.0, 3.0), + GrossGEscale = c(2.5, 2.5), + Carbon = c(0.1, 0.1), + Repro = c(0.0, 0.0), + Fmort = c(0.0, 0.1), + Fmort_W0 = c(-8.0, 0.0), # Use exact values that match w_log10 grid + Fmort_Wmax = c(-6.0, 3.0), # Use exact values that match w_log10 grid + PlotColour = c("blue", "red"), + stringsAsFactors = FALSE + ) + + +# Tests for zoomss_model() ----------------------------------------------- + +test_that("zoomss_model runs with minimal input", { + # Create test data + + # Test basic model run + expect_no_error({ + result <- zoomss_model(env_data, non_default_groups, isave = 5) + }) + + # Test with default groups + expect_no_error({ + result <- zoomss_model(env_data, isave = 5) + }) +}) + +test_that("zoomss_model returns expected structure", { + + # Check that result is a list + expect_type(mdl, "list") + + # Check for expected components + expect_true("param" %in% names(mdl)) + expect_true("abundance" %in% names(mdl)) + expect_true("growth" %in% names(mdl)) + + # Check dimensions are reasonable + expect_true(is.array(mdl$abundance)) + expect_true(is.array(mdl$growth)) + expect_equal(length(dim(mdl$abundance)), 3) # time x groups x size_classes +}) + +test_that("zoomss_model validates input parameters", { + + # Test with missing environmental data + bad_input <- data.frame(time = 1:10) + + expect_error( + zoomss_model(bad_input, Groups), + "No environmental time series provided" + ) + + # Test with invalid groups + bad_groups <- data.frame(Species = "Test") + + expect_error( + zoomss_model(env_data, bad_groups), + "Missing required columns" + ) +}) + +# Tests for zoomss_params() ---------------------------------------------- + +test_that("zoomss_params creates valid parameter list", { + + params <- zoomss_params(Groups, env_data, isave = 5) + + # Check basic structure + expect_type(params, "list") + expect_true("Groups" %in% names(params)) + expect_true("ngrps" %in% names(params)) + expect_true("dt" %in% names(params)) + expect_true("tmax" %in% names(params)) + + # Check calculated values + expect_equal(params$ngrps, nrow(Groups)) + expect_equal(params$dt, 0.1) + expect_true(params$tmax > 0) + + # Check group indices + expect_true("zoo_grps" %in% names(params)) + expect_true("fish_grps" %in% names(params)) + expect_equal(length(params$zoo_grps), sum(Groups$Type == "Zooplankton")) + expect_equal(length(params$fish_grps), sum(Groups$Type == "Fish")) +}) + +test_that("zoomss_params calculates time parameters correctly", { + + # Test different time configurations + params1 <- zoomss_params(Groups, env_data, isave = 5) + expect_equal(params1$dt, 0.1) + expect_equal(params1$tmax, max(env_data$time)) + + # Test with different dt + env_data2 <- createEnviroData( + n_years = 20, + dt = 0.05, + seasonal = FALSE, + base_sst = 20, + base_chl = 1.0 + ) + + params2 <- zoomss_params(Groups, env_data2, isave = 10) + expect_equal(params2$dt, 0.05) + expect_equal(params2$tmax, max(env_data2$time)) +}) + +test_that("zoomss_params validates uniform time steps", { + + # Create non-uniform time steps + bad_time <- c(0, 0.1, 0.25, 0.3, 0.4) # Non-uniform steps + + expect_error( + createInputParams(bad_time, rep(15, 5), rep(2, 5)), + "Time steps are not uniform" + ) +}) + +# Tests for zoomss_setup() ----------------------------------------------- + +test_that("zoomss_setup creates model structure", { + + params <- zoomss_params(Groups, env_data, isave = 5) + model <- zoomss_setup(params) + + # Check model structure + expect_type(model, "list") + expect_true("param" %in% names(model)) + expect_identical(model$param, params) + + # Check for feeding kernels + kernel_names <- c("dynam_growthkernel", "dynam_diffkernel", + "dynam_dietkernel", "dynam_mortkernel", + "phyto_growthkernel", "phyto_diffkernel", "phyto_dietkernel") + + for (kernel in kernel_names) { + expect_true(kernel %in% names(model), info = paste("Missing kernel:", kernel)) + expect_true(is.array(model[[kernel]]), info = paste("Kernel not array:", kernel)) + } + + # Check abundance array - zoomss_stup is still working in N, Z, gg etc + expect_true("N" %in% names(model)) + expect_true(is.array(model$N)) + expect_equal(length(dim(model$N)), 3) # time x groups x size_classes +}) + +test_that("zoomss_setup initializes mortality and efficiency matrices", { + + params <- zoomss_params(Groups, env_data, isave = 5) + model <- zoomss_setup(params) + + # Check mortality matrices + expect_true("M_sb_base" %in% names(model)) + expect_true("fish_mort" %in% names(model)) + expect_true(is.matrix(model$M_sb_base)) + expect_true(is.matrix(model$fish_mort)) + + # Check efficiency matrix + expect_true("assim_eff" %in% names(model)) + expect_true(is.matrix(model$assim_eff)) + + # Check dimensions match groups and size classes + expect_equal(nrow(model$M_sb_base), params$ngrps) + expect_equal(nrow(model$fish_mort), params$ngrps) + expect_equal(nrow(model$assim_eff), params$ngrps) +}) + +# Tests for zoomss_run() ------------------------------------------------- + +test_that("zoomss_run executes model simulation", { + + params <- zoomss_params(Groups, env_data, isave = 5) + model <- zoomss_setup(params) + + expect_no_error({ + result <- zoomss_run(model) + }) + + # Check result structure - zoomss_run is still working in N, Z, gg etc + expect_type(result, "list") + expect_true("N" %in% names(result)) + expect_true("param" %in% names(result)) + + # Check that abundances are finite and non-negative + expect_true(all(is.finite(result$N))) + expect_true(all(result$N >= 0)) +}) + +test_that("zoomss_run produces time series output", { + + params <- zoomss_params(Groups, env_data, isave = 2) + model <- zoomss_setup(params) + result <- zoomss_run(model) + + # Check time series dimensions - zoomss_run is still working in N, Z, gg etc + expect_true(dim(result$N)[1] > 1) # Multiple time steps saved + expect_equal(dim(result$N)[2], nrow(Groups)) # Correct number of groups + expect_equal(dim(result$N)[3], params$ngrid) # Correct number of size classes + + # Check that we have reasonable output structure + time_steps_saved <- dim(result$N)[1] + expected_saves <- floor(params$itimemax / params$isave) + expect_true(time_steps_saved <= expected_saves + 1) # Allow for initial condition +}) + +# Integration tests ------------------------------------------------------- + +test_that("Full model workflow produces consistent results", { + # Run model twice with same inputs + + result1 <- zoomss_model(env_data, Groups, isave = 5) + result2 <- zoomss_model(env_data, Groups, isave = 5) + + # Results should be identical (deterministic model) + expect_equal(result1$abundance, result2$abundance) + expect_equal(result1$biomass, result2$biomass) +}) + +test_that("Model handles different group configurations", { + + # Test with minimal groups (1 zoo, 1 fish) + result_minimal <- zoomss_model(env_data, non_default_groups, isave = 5) + expect_equal(dim(result_minimal$abundance)[2], 2) # 2 groups + + # Test with default groups + result_default <- zoomss_model(env_data, isave = 5) + expect_true(dim(result_default$abundance)[2] > 2) # More groups in default +}) + + + +# Edge cases and error handling ------------------------------------------ + +test_that("Model handles edge cases gracefully", { + + # Very short simulation + env_data_short <- createEnviroData( + n_years = 5, + dt = 0.1, + seasonal = FALSE, + base_sst = 20, + base_chl = 1.0 + ) + + expect_no_error({ + result_short <- zoomss_model(env_data_short, Groups, isave = 1) + }) + + # Large isave parameter (save less frequently) + expect_no_error({ + result_sparse <- zoomss_model(env_data, Groups, isave = 50) + }) +}) + + +test_that("Parameter validation catches common errors", { + + # Test with groups missing required columns + bad_groups <- data.frame( + Species = "Test", + Type = "Zooplankton" + # Missing other required columns + ) + + expect_error( + zoomss_model(env_data, bad_groups), + "Missing required columns" + ) +}) + diff --git a/tests/testthat/test-zoomss_plotting.R b/tests/testthat/test-zoomss_plotting.R new file mode 100644 index 0000000..afaafed --- /dev/null +++ b/tests/testthat/test-zoomss_plotting.R @@ -0,0 +1,189 @@ +# Test suite for ZooMSS plotting functions +# Tests cover: plotPPMR, plotSizeSpectra, plotTimeSeries, plotEnvironment +# Following tidyverse and R packages testing standards + +# Setup test data -------------------------------------------------------- + +env_data <- createEnviroData( + n_years = 20, + dt = 0.1, + seasonal = FALSE, + base_sst = 20, + base_chl = 1.0 +) + +# Get groups data +Groups <- getGroups() + +# Create mock model results for plotting tests +mdl <- zoomss_model(input_params = env_data, Groups = Groups, isave = 1) + + +# Tests fosr plotPPMR() --------------------------------------------------- + +test_that("plotPPMR returns ggplot object", { + # Test that function returns a ggplot object + expect_no_error(plot_obj <- plotPPMR(mdl, idx = 1)) + expect_s3_class(plot_obj, "ggplot") +}) + +# test_that("plotPPMR handles model with all zooplankton groups", { +# +# mdl2 <- mdl +# +# # Remove fish groups (those with NA PPMRscale) +# fish_rows <- which(is.na(mdl2$param$Groups$PPMRscale)) +# if(length(fish_rows) > 0) { +# mdl2$param$Groups <- mdl2$param$Groups[-fish_rows, ] +# mdl2$abundance <- mdl2$abundance[, -fish_rows, ] +# # Also need to update diet array if it exists +# if(!is.null(mdl2$diet)) { +# # Diet array has groups as predators, so remove those rows +# mdl2$diet <- mdl2$diet[, -fish_rows, ] +# } +# } +# +# # This test may fail with bandwidth error if too few groups remain +# # In that case, we expect either success or a specific bandwidth error +# result <- tryCatch({ +# plot_obj <- plotPPMR(mdl2, idx = 1) +# expect_s3_class(plot_obj, "ggplot") +# TRUE +# }, error = function(e) { +# # Accept bandwidth errors as they're expected with few data points +# expect_true(grepl("bandwidth|points", e$message, ignore.case = TRUE)) +# TRUE +# }) +# +# expect_true(result) +# rm(mdl2) +# }) + +test_that("plotPPMR handles empty abundance data gracefully", { + mdl2 <- mdl + + # Set all abundances to zero + mdl2$abundance[] <- 0 + + expect_warning(plot_obj <- plotPPMR(mdl2, idx = 1), "Non-finite or zero total biomass") + expect_s3_class(plot_obj, "ggplot") + + rm(mdl2) +}) + +# Tests for plotSizeSpectra() -------------------------------------------- + +test_that("plotSizeSpectra returns ggplot object", { + expect_no_error(plot_obj <- plotSizeSpectra(mdl, n_years = 5)) + expect_s3_class(plot_obj, "ggplot") +}) + +test_that("plotSizeSpectra filters zero abundances", { + mdl2 <- mdl + + # Set some abundances to zero (time, groups, size) + mdl2$abundance[1, 1, 1:50] <- 0 + + expect_no_error(plot_obj <- plotSizeSpectra(mdl2, n_years = 5)) + expect_s3_class(plot_obj, "ggplot") + + rm(mdl2) +}) + +test_that("plotSizeSpectra handles all zero abundances", { + mdl2 <- mdl + + # Set all abundances to zero except one small value (time, groups, size) + mdl2$abundance[] <- 0 + mdl2$abundance[1, 1, 1] <- 0.001 + + expect_no_error(plot_obj <- plotSizeSpectra(mdl2, n_years = 5)) + expect_s3_class(plot_obj, "ggplot") + rm(mdl2) +}) + +# Tests for plotTimeSeries() --------------------------------------------- + +test_that("plotTimeSeries returns ggplot object for abundance", { + expect_no_error(plot_obj <- plotTimeSeries(mdl, by = "abundance")) + expect_s3_class(plot_obj, "ggplot") +}) + +test_that("plotTimeSeries returns ggplot object for biomass", { + expect_no_error(plot_obj <- plotTimeSeries(mdl, by = "biomass")) + expect_s3_class(plot_obj, "ggplot") +}) + +test_that("plotTimeSeries returns ggplot object for mortality", { + expect_no_error(plot_obj <- plotTimeSeries(mdl, by = "mortality")) + expect_s3_class(plot_obj, "ggplot") +}) + +test_that("plotTimeSeries returns ggplot object for growth", { + expect_no_error(plot_obj <- plotTimeSeries(mdl, by = "growth")) + expect_s3_class(plot_obj, "ggplot") +}) + +test_that("plotTimeSeries works with stacked biomass", { + expect_no_error(plot_obj <- plotTimeSeries(mdl, by = "biomass", type = "stack")) + expect_s3_class(plot_obj, "ggplot") +}) + +test_that("plotTimeSeries works with proportional biomass", { + expect_no_error(plot_obj <- plotTimeSeries(mdl, by = "biomass", type = "fill")) + expect_s3_class(plot_obj, "ggplot") +}) + +test_that("plotTimeSeries works with species filtering", { + expect_no_error(plot_obj <- plotTimeSeries(mdl, by = "abundance", species = c("Flagellates"))) + expect_s3_class(plot_obj, "ggplot") +}) + +test_that("plotTimeSeries handles invalid by parameter", { + expect_error(plotTimeSeries(mdl, by = "invalid"), "must be one of") +}) + +test_that("plotTimeSeries handles missing time series data", { + mdl2 <- mdl + mdl2$abundance <- NULL # Remove time series data + expect_error(plotTimeSeries(mdl2, by = "abundance"), "Time series data not available") +}) + +test_that("plotTimeSeries handles invalid species names", { + expect_error(plotTimeSeries(mdl, by = "abundance", species = c("InvalidSpecies")), + "All elements of 'species' must be in") +}) + +test_that("plotTimeSeries handles all invalid species names", { + expect_error(plotTimeSeries(mdl, by = "abundance", species = c("InvalidSpecies1", "InvalidSpecies2")), + "All elements of 'species' must be in") +}) + +# Tests for plotEnvironment() -------------------------------------------- + +test_that("plotEnvironment returns ggplot object or list", { + expect_no_error(plot_obj <- plotEnvironment(env_data)) + + # Should return either a ggplot (if patchwork available) or a list + expect_true(inherits(plot_obj, "ggplot") || is.list(plot_obj)) +}) + +test_that("plotEnvironment handles missing columns gracefully", { + + env_data2 <- dplyr::select(env_data, -chl) # Remove chl column + + # Missing chl column should cause error in pivot_longer + expect_error(plotEnvironment(env_data2)) + + rm(env_data2) +}) + +test_that("plotEnvironment works with small datasets", { + env_data2 <- env_data[1:5,] + + expect_no_error(plot_obj <- plotEnvironment(env_data2)) + expect_true(inherits(plot_obj, "ggplot") || is.list(plot_obj)) + + rm(env_data2) +}) + diff --git a/vignettes/.gitignore b/vignettes/.gitignore new file mode 100644 index 0000000..097b241 --- /dev/null +++ b/vignettes/.gitignore @@ -0,0 +1,2 @@ +*.html +*.R diff --git a/vignettes/zoomss.Rmd b/vignettes/zoomss.Rmd new file mode 100644 index 0000000..a3d7950 --- /dev/null +++ b/vignettes/zoomss.Rmd @@ -0,0 +1,103 @@ +--- +title: "Getting started with ZooMSS" +vignette: > + %\VignetteIndexEntry{zoomss} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +options(rmarkdown.html_vignette.check_title = FALSE) +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + +```{r message=FALSE, warning=FALSE} +library(zoomss) +library(ggplot2) +``` + +## Input Data + +ZooMSS requires two sets of input data: + +1. **Groups** - Contains all taxa-specific parameter values for each model group, including size ranges and functional group properties. + +2. **Environmental data** - A Time-series dataframe with time series of environmental conditions with `time`, `sst`, and `chl` columns. + +## Running the default Model + +Get the default published `Groups` dataframe using: + +```{r} +Groups <- getGroups() +``` + +Now create an environmental data time-series using the helper function. This time-series uses a constant sea surface temperature (`sst`) and chlorophyll *a* (`chl`) with a 0.1 yr-1 timestep (`dt`). + +```{r} +env_data <- createInputParams(time = seq(0, 100, by = 0.1) , + sst = 15, + chl = 0.15) + +``` + +We can look at the environment data and check everything is ok with: + +```{r} +plotEnvironment(env_data) +``` + + +Now we run ZooMSS and save every `isave` timestep to reduce storage requirements. +```{r} +mdl <- zoomss_model(input_params = env_data, Groups = Groups, isave = 2) + +``` + +## Plotting + +The model includes several built-in plotting functions for analysis and visualization. + + +### Time Series Analysis + +These plots display total abundance and mean growth/mortality across all size classes through time. + +```{r} + +library(patchwork) +p1 <- plotTimeSeries(mdl, by = "abundance", transform = "log10") # Plot abundance time series +p2 <- plotTimeSeries(mdl, by = "growth") # Plot growth rate time series +p3 <- plotTimeSeries(mdl, by = "mortality") # Plot predation mortality time series + +wrap_plots(p1, p2, p3, nrow = 3, guides = "collect") + +``` + + +We can also plot total biomass through time. + +```{r} +p4 <- plotTimeSeries(mdl, by = "biomass", transform = "log10") + theme(legend.position = "none") # Plot biomass +p5 <- plotTimeSeries(mdl, by = "biomass", type = "stack", transform = "log10") # Plot stacked biomass +p6 <- plotTimeSeries(mdl, by = "biomass", type = "fill") # Plot proportional stacked biomass + +wrap_plots(p4, p5, p6, nrow = 3, guides = "collect") + +``` + + +### Static Plots for a given model time point + +Plot mean species-resolved size spectra for the final `n_years`. +```{r} +plotSizeSpectra(mdl, n_years = 10) +``` + +Plot predator-prey mass ratios for the `idx` timestep +```{r message=FALSE, warning=FALSE} +plotPPMR(mdl, idx = 500) # Plot final timestep +``` diff --git a/zoomss.Rproj b/zoomss.Rproj new file mode 100644 index 0000000..69fafd4 --- /dev/null +++ b/zoomss.Rproj @@ -0,0 +1,22 @@ +Version: 1.0 + +RestoreWorkspace: No +SaveWorkspace: No +AlwaysSaveHistory: Default + +EnableCodeIndexing: Yes +UseSpacesForTab: Yes +NumSpacesForTab: 2 +Encoding: UTF-8 + +RnwWeave: Sweave +LaTeX: pdfLaTeX + +AutoAppendNewline: Yes +StripTrailingWhitespace: Yes +LineEndingConversion: Posix + +BuildType: Package +PackageUseDevtools: Yes +PackageInstallArgs: --no-multiarch --with-keep.source +PackageRoxygenize: rd,collate,namespace