Skip to content

Commit fcc482a

Browse files
committed
Added more versions of keystoness. Ranges still off so I tried creating my own MTI function. Made no difference
1 parent ff46431 commit fcc482a

8 files changed

Lines changed: 195 additions & 62 deletions

File tree

.Rhistory

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
ks <- neusRpath::keystoneness("GB")
2+
ks <- neusRpath::keystoneness("GB")
3+
neusRpath::plot_keystoneness(ks, top_n = 10)
4+
export(plot_keystoneness)
5+
devtools::document()
6+
devtools::install()
7+
# To run keystoneness function, EPU required as input
8+
neusRpath::keystoneness("MAB")
9+
remove.packages("neusRpath")
10+
devtools::install()
11+
# To run keystoneness function, EPU required as input
12+
neusRpath::keystoneness("MAB")
13+
# To run plot_keystoneness, need to first run and save keystoneness. Then tell it how many to plot
14+
ks <- neusRpath::keystoneness("GB")
15+
neusRpath::plot_keystoneness(ks, top_n = 10)
16+
range(ks$keystoneness)
17+
# To run plot_keystoneness, need to first run and save keystoneness. Then tell it how many to plot
18+
ks <- neusRpath::keystoneness("MAB")
19+
neusRpath::plot_keystoneness(ks, top_n = 10)
20+
range(ks$keystoneness)
21+
# To run plot_keystoneness, need to first run and save keystoneness. Then tell it how many to plot
22+
ks <- neusRpath::keystoneness("GOM")
23+
neusRpath::plot_keystoneness(ks, top_n = 10)
24+
range(ks$keystoneness)
25+
View(ks)
26+
devtools::document()
27+
devtools::install()
28+
# To run plot_keystoneness, need to first run and save keystoneness. Then tell it how many to plot
29+
ks <- neusRpath::keystoneness("GB")
30+
neusRpath::plot_keystoneness(ks, top_n = 10)
31+
# To run keystoneness function, EPU required as input
32+
neusRpath::keystoneness("MAB")
33+
# To run plot_keystoneness, need to first run and save keystoneness. Then tell it how many to plot
34+
ks <- neusRpath::keystoneness("GB")
35+
neusRpath::plot_keystoneness(ks, top_n = 10)

NAMESPACE

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Generated by roxygen2: do not edit by hand
22

3-
export(keystoneness)
3+
export(MTI)
4+
export(keystoneness_all)
45
export(plot_keystoneness)

R/MTI.R

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#' Calculate Mixed Trophic Impact (MTI)
2+
#'
3+
#' @param Rpath Rpath object
4+
#' @param Rpath.params Rpath parameter object
5+
#' @param increase Logical; if TRUE, assumes marginal increase
6+
#'
7+
#' @return MTI matrix
8+
#' @export
9+
MTI <- function(Rpath, Rpath.params, increase = TRUE) {
10+
# --- Step 0: prepare ---
11+
x <- Rpath.params
12+
y <- Rpath
13+
14+
all_groups <- x$model$Group
15+
n_groups <- length(all_groups)
16+
17+
# --- Step 1: Build diet composition (DC) matrix ---
18+
DC_full <- matrix(0, nrow = n_groups, ncol = n_groups,
19+
dimnames = list(all_groups, all_groups))
20+
21+
preds <- x$diet$Group
22+
prey_cols <- colnames(x$diet)[-1]
23+
24+
for(i in seq_along(preds)) {
25+
predator <- preds[i]
26+
if(!predator %in% all_groups) next
27+
28+
prey_vals <- as.numeric(dplyr::select(x$diet[i, ], dplyr::all_of(prey_cols)))
29+
30+
# keep only prey that exist in all_groups
31+
valid_idx <- which(prey_cols %in% all_groups)
32+
valid_preys <- prey_cols[valid_idx]
33+
valid_vals <- prey_vals[valid_idx]
34+
35+
# replace NA with 0
36+
valid_vals[is.na(valid_vals)] <- 0
37+
38+
DC_full[predator, valid_preys] <- valid_vals
39+
}
40+
41+
# --- Step 2: Compute fraction of prey consumed by predator (FC) ---
42+
bio <- y$BB # biomass
43+
QB <- y$QB # consumption/biomass
44+
BQB <- bio * QB # production consumed
45+
46+
# Tij = consumption of prey j by predator i
47+
Tij <- DC_full * matrix(BQB, nrow = n_groups, ncol = n_groups, byrow = TRUE)
48+
49+
Tim <- rowSums(Tij, na.rm = TRUE) # handle NAs
50+
FCij <- matrix(0, nrow = n_groups, ncol = n_groups)
51+
52+
for(i in 1:n_groups) {
53+
if(!is.na(Tim[i]) && Tim[i] > 0) {
54+
FCij[i, ] <- Tij[i, ] / Tim[i]
55+
}
56+
}
57+
58+
FCji <- t(FCij)
59+
60+
# --- Step 3: Net impact ---
61+
net_impact <- DC_full - FCji
62+
63+
# --- Step 4: MTI ---
64+
MTI <- MASS::ginv(diag(n_groups) - net_impact) - diag(n_groups)
65+
66+
return(MTI)
67+
}

R/keystoneness.R

Lines changed: 39 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,73 @@
1-
#' Calculate keystoneness for a Northeast U.S. Rpath model
1+
#' Calculate keystoneness indices
22
#'
3-
#' Calculates the keystoneness index (KSi) for a given ecosystem model
4-
#' following Libralato et al. 2006:
5-
#' KSi = log[epsilon_i * (1 - p_i)],
6-
#' where epsilon_i is the total impact of group i (from the MTI matrix excluding self-effects)
7-
#' and p_i is the proportion of total system biomass.
3+
#' Computes Keystone index #1, #2, #3 and Relative Total Impact (raw and normalized)
4+
#' for a Northeast U.S. Rpath model, excluding detritus and fleet groups.
85
#'
96
#' @param epu Character. Ecosystem production unit: "GB", "GOM", or "MAB".
107
#' @return A data.frame with ecological groups, biomass, proportion biomass,
11-
#' total impact, and keystoneness index.
8+
#' raw and normalized Relative Total Impact, and keystone indices.
129
#' @examples
13-
#' keystoneness("GB")
10+
#' keystoneness_all("GB")
1411
#' @export
15-
keystoneness <- function(epu = c("GB", "GOM", "MAB")) {
12+
keystoneness_all <- function(epu = c("GB", "GOM", "MAB")) {
1613

1714
epu <- match.arg(epu)
1815

1916
# --- STEP 1: load model and balanced parameters ---
20-
data(list = paste0(epu)) # loads GB, GOM, or MAB model into environment
17+
data(list = epu)
2118
model <- get(epu)
2219

23-
# load balanced parameters
2420
params_name <- paste0(epu, "_balanced_params")
2521
data(list = params_name)
2622
params <- get(params_name)
2723

28-
# --- STEP 2: Mixed trophic impact matrix ---
29-
mti_mat <- Rpath::MTI(Rpath = model, Rpath.params = params)
24+
# --- STEP 2: compute MTI matrix using local MTI function ---
25+
mti_mat <- MTI(Rpath = model, Rpath.params = params)
3026

31-
# --- STEP 3: assign group names (ecological groups only) ---
27+
# --- STEP 3: filter for living ecological groups only ---
28+
eco_rows <- which(params$model$Type < 2) # living groups only
29+
mti_mat <- mti_mat[eco_rows, eco_rows, drop = FALSE]
30+
31+
biomass <- model$Biomass[eco_rows]
32+
prop_biomass <- biomass / sum(biomass, na.rm = TRUE)
33+
34+
# Group names
35+
group_names <- model$Group[eco_rows]
3236
if (!is.null(rownames(model$DC))) {
33-
group_names <- rownames(model$DC)
34-
} else if (!is.null(model$Group)) {
35-
group_names <- model$Group
36-
} else {
37-
group_names <- paste0("Group", seq_len(nrow(mti_mat)))
37+
group_names <- rownames(model$DC)[eco_rows]
3838
}
3939

40-
# exclude fishing gear groups
41-
n_eco <- nrow(mti_mat) - model$NUM_GEARS
42-
mti_mat <- mti_mat[1:n_eco, 1:n_eco]
43-
group_names <- group_names[1:n_eco]
40+
# --- STEP 4: Relative Total Impact (RTI) ---
41+
total_effect <- rowSums(abs(mti_mat), na.rm = TRUE)
42+
self_effect <- diag(abs(mti_mat))
43+
rti_raw <- total_effect - self_effect
44+
rti_norm <- rti_raw / max(rti_raw, na.rm = TRUE)
4445

45-
# --- STEP 4: compute proportional biomass ---
46-
biomass <- model$Biomass[1:n_eco]
47-
prop_biomass <- biomass / sum(biomass)
46+
# --- STEP 5: Keystone index #1 (Libralato 2006) ---
47+
KS1 <- log(rti_raw * (1 - prop_biomass))
4848

49-
# --- STEP 5: compute total impacts excluding self-effects ---
50-
total_effect <- apply(abs(mti_mat), 1, sum)
51-
self_effect <- diag(abs(mti_mat))
52-
epsilon <- total_effect - self_effect
49+
# --- STEP 6: Keystone index #2 (Valls 2015) ---
50+
predator_impacts <- rowSums(abs(mti_mat * (mti_mat < 0)), na.rm = TRUE)
51+
prey_impacts <- rowSums(abs(mti_mat * (mti_mat > 0)), na.rm = TRUE)
52+
KS2 <- (predator_impacts + prey_impacts) / biomass
5353

54-
# --- STEP 6: keystoneness (Libralato et al. 2006) ---
55-
KS_index <- log(epsilon * (1 - prop_biomass))
54+
# --- STEP 7: Keystone index #3 (Valls 2015) ---
55+
KS3 <- predator_impacts / biomass
5656

57-
# --- STEP 7: tidy output ---
57+
# --- STEP 8: tidy output ---
5858
results <- data.frame(
5959
group = group_names,
6060
biomass = biomass,
6161
prop_biomass = prop_biomass,
62-
impact = epsilon,
63-
keystoneness = KS_index,
62+
RTI_raw = rti_raw,
63+
RTI_normalized = rti_norm,
64+
`Keystone index #1` = KS1,
65+
`Keystone index #2` = KS2,
66+
`Keystone index #3` = KS3,
6467
stringsAsFactors = FALSE
6568
)
6669

67-
# Attach EPU label as an attribute
70+
# Attach EPU label as attribute
6871
attr(results, "epu") <- switch(epu,
6972
GB = "Georges Bank",
7073
GOM = "Gulf of Maine",

data-raw/test_runs.R

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,12 @@ neusRpath::keystoneness("MAB")
55
ks <- neusRpath::keystoneness("GB")
66
neusRpath::plot_keystoneness(ks, top_n = 10)
77

8+
9+
# testing once MTI.R was added
10+
# From the root of your repo
11+
source("R/MTI.R")
12+
source("R/keystoneness.R")
13+
14+
# Test your function
15+
results <- keystoneness_all("GB")
16+
head(results)

man/MTI.Rd

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/keystoneness.Rd

Lines changed: 0 additions & 25 deletions
This file was deleted.

man/keystoneness_all.Rd

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)