## ----setup, include=FALSE-----------------------------------------------------
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 7.5,
  fig.height = 4.8,
  warning = FALSE,
  message = FALSE
)

## ----install, eval=FALSE------------------------------------------------------
#  install.packages("remotes")
#  remotes::install_github("agimenezromero/demovuln-r", build_vignettes = TRUE)

## ----packages-----------------------------------------------------------------
library(demovuln)

if (!requireNamespace("ggplot2", quietly = TRUE)) {
  stop("This tutorial uses ggplot2 for plotting. Install it with install.packages('ggplot2').")
}
library(ggplot2)

## ----define-matrix------------------------------------------------------------
stage_names <- c("Juvenile", "Subadult", "Adult")

A <- matrix(
  c(
    0.00, 0.00, 1.60,
    0.35, 0.55, 0.05,
    0.00, 0.25, 0.86
  ),
  nrow = 3,
  byrow = TRUE,
  dimnames = list(
    destination = stage_names,
    source = stage_names
  )
)

A

## ----create-model-------------------------------------------------------------
model <- matrix_population_model(
  A,
  fecundity_rows = 1,
  adult_stages = 3,
  juvenile_stages = c(1, 2),
  name = "Example three-stage model"
)

model$lambda_
stable_stage_distribution(model)

## ----target-masks-------------------------------------------------------------
targets <- c("adult_survival", "juvenile_survival", "fecundity", "all")
target_labels <- c(
  adult_survival = "Adult survival",
  juvenile_survival = "Juvenile survival",
  fecundity = "Fecundity",
  all = "All parameters"
)

mask_to_data <- function(mask, target_label) {
  idx <- expand.grid(
    destination = seq_len(nrow(mask)),
    source = seq_len(ncol(mask))
  )
  idx$selected <- as.vector(mask)
  idx$target <- target_label
  idx
}

mask_table <- do.call(
  rbind,
  lapply(targets, function(target) {
    mask <- build_target_mask(model, target = target)
    mask_to_data(mask, target_labels[[target]])
  })
)

mask_table$source_stage <- factor(mask_table$source, labels = stage_names)
mask_table$destination_stage <- factor(mask_table$destination, labels = stage_names)

p_masks <- ggplot(mask_table, aes(x = source_stage, y = destination_stage, fill = selected)) +
  geom_tile(color = "grey70") +
  facet_wrap(~ target, nrow = 1) +
  scale_y_discrete(limits = rev(stage_names)) +
  scale_fill_manual(values = c(`FALSE` = "white", `TRUE` = "steelblue")) +
  labs(
    x = "Source stage at time t",
    y = "Destination stage at time t + 1",
    fill = "Perturbed",
    title = "Matrix entries selected by each demographic target"
  ) +
  theme_minimal(base_size = 11) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

p_masks

## ----survival-affects-fecundity-----------------------------------------------
B_with_fecundity <- apply_perturbation(
  model,
  target = "adult_survival",
  magnitude = 0.5,
  survival_affects_fecundity = TRUE
)

B_without_fecundity <- apply_perturbation(
  model,
  target = "adult_survival",
  magnitude = 0.5,
  survival_affects_fecundity = FALSE
)

B_with_fecundity
B_without_fecundity

## ----single-simulation--------------------------------------------------------
generation_time <- 20

sim_adult <- simulate_dynamics(
  model,
  target = "adult_survival",
  magnitude = 0.30,
  duration = 4,
  period = 10,
  t_max = 3 * generation_time,
  recovery_steps = 4 * generation_time,
  normalize_by_lambda = TRUE
)

sim_adult$reduction

## ----single-trajectory-plot---------------------------------------------------
trajectory_df <- data.frame(
  time = seq_along(sim_adult$abundance) - 1,
  time_generations = (seq_along(sim_adult$abundance) - 1) / generation_time,
  baseline = sim_adult$baseline_abundance,
  perturbed = sim_adult$abundance
)

trajectory_plot_df <- rbind(
  data.frame(
    time_generations = trajectory_df$time_generations,
    abundance = trajectory_df$baseline,
    scenario = "Unperturbed baseline"
  ),
  data.frame(
    time_generations = trajectory_df$time_generations,
    abundance = trajectory_df$perturbed,
    scenario = "Perturbed"
  )
)

p_single <- ggplot(trajectory_plot_df, aes(x = time_generations, y = abundance, linetype = scenario)) +
  geom_line(linewidth = 0.9) +
  labs(
    x = "Time (reference generations)",
    y = "Relative population size",
    linetype = NULL,
    title = "One temporally structured perturbation regime"
  ) +
  theme_minimal(base_size = 12)

p_single

## ----compare-target-trajectories----------------------------------------------
simulations <- lapply(
  c("adult_survival", "juvenile_survival", "fecundity"),
  function(target) {
    simulate_dynamics(
      model,
      target = target,
      magnitude = 0.30,
      duration = 4,
      period = 10,
      t_max = 3 * generation_time,
      recovery_steps = 4 * generation_time,
      normalize_by_lambda = TRUE
    )
  }
)
names(simulations) <- c("adult_survival", "juvenile_survival", "fecundity")

trajectory_panel_data <- do.call(
  rbind,
  lapply(names(simulations), function(target) {
    sim <- simulations[[target]]
    time <- seq_along(sim$abundance) - 1
    rbind(
      data.frame(
        time_generations = time / generation_time,
        abundance = sim$baseline_abundance,
        scenario = "Unperturbed baseline",
        target = target_labels[[target]]
      ),
      data.frame(
        time_generations = time / generation_time,
        abundance = sim$abundance,
        scenario = "Perturbed",
        target = target_labels[[target]]
      )
    )
  })
)

p_trajectories <- ggplot(
  trajectory_panel_data,
  aes(x = time_generations, y = abundance, linetype = scenario)
) +
  geom_line(linewidth = 0.85) +
  facet_wrap(~ target, nrow = 1) +
  labs(
    x = "Time (reference generations)",
    y = "Relative population size",
    linetype = NULL,
    title = "The same perturbation regime applied to different demographic targets"
  ) +
  theme_minimal(base_size = 11)

p_trajectories

## ----compare-target-reductions------------------------------------------------
regime_reductions <- data.frame(
  target = target_labels[names(simulations)],
  population_reduction = vapply(simulations, function(x) x$reduction, numeric(1))
)

regime_reductions

## ----direct-grid--------------------------------------------------------------
grid_direct <- perturbation_grid(
  magnitudes = seq(0, 0.8, by = 0.1),
  durations = seq(0, generation_time, by = 2),
  periods = c(5, 10, 20, 40)
)

grid_scenarios(grid_direct)[1:10, ]

## ----frequency-grid-----------------------------------------------------------
frequencies <- c(0.25, 0.5, 1, 2, 4)

grid <- perturbation_grid_from_frequencies(
  magnitudes = seq(0, 0.8, by = 0.1),
  durations = seq(0, generation_time, by = 2),
  frequencies = frequencies,
  generation_time = generation_time,
  rounding = "nearest"
)

frequency_period_table <- data.frame(
  frequency_per_generation = frequencies,
  period = pmax(1L, as.integer(round(generation_time / frequencies)))
)

frequency_period_table

## ----run-grid-one-target------------------------------------------------------
out_adult <- run_grid(
  model,
  target = "adult_survival",
  grid = grid,
  t_max = 3 * generation_time,
  recovery_steps = 4 * generation_time,
  normalize_by_lambda = TRUE,
  skip_infeasible = TRUE
)

out_adult$vulnerability
head(out_adult$table)

## ----run-grid-all-targets-----------------------------------------------------
grid_results <- lapply(targets, function(target) {
  run_grid(
    model,
    target = target,
    grid = grid,
    t_max = 3 * generation_time,
    recovery_steps = 4 * generation_time,
    normalize_by_lambda = TRUE,
    skip_infeasible = TRUE
  )
})
names(grid_results) <- targets

vulnerability_table <- data.frame(
  target = unname(target_labels[targets]),
  Phi = vapply(grid_results, function(x) x$vulnerability, numeric(1))
)

vulnerability_table

## ----vulnerability-barplot----------------------------------------------------
p_phi <- ggplot(vulnerability_table, aes(x = target, y = Phi)) +
  geom_col(width = 0.7, fill = "grey40") +
  labs(
    x = "Perturbed demographic target",
    y = expression(Phi),
    title = "Integrated vulnerability across demographic targets"
  ) +
  theme_minimal(base_size = 12) +
  theme(axis.text.x = element_text(angle = 25, hjust = 1))

p_phi

## ----grid-table-for-heatmaps--------------------------------------------------
grid_table <- do.call(
  rbind,
  lapply(targets, function(target) {
    tab <- grid_results[[target]]$table
    tab$target <- target_labels[[target]]
    tab
  })
)

heatmap_data <- subset(grid_table, feasible & period == generation_time)

p_heatmap <- ggplot(
  heatmap_data,
  aes(x = magnitude, y = duration, fill = population_reduction)
) +
  geom_tile() +
  facet_wrap(~ target, nrow = 2) +
  scale_fill_gradient(low = "white", high = "firebrick", limits = c(0, 100)) +
  labs(
    x = "Perturbation magnitude",
    y = "Perturbation duration (projection intervals)",
    fill = "Population\nreduction (%)",
    title = "Vulnerability surfaces at one event per reference generation"
  ) +
  theme_minimal(base_size = 11)

p_heatmap

## ----custom-target------------------------------------------------------------
custom_mask <- matrix(
  FALSE,
  nrow = nrow(A),
  ncol = ncol(A),
  dimnames = dimnames(A)
)
custom_mask["Adult", "Subadult"] <- TRUE
custom_mask["Adult", "Adult"] <- TRUE

custom_mask

A_custom_perturbed <- apply_perturbation(
  model,
  target = "custom",
  custom_mask = custom_mask,
  magnitude = 0.40
)

A_custom_perturbed

## ----custom-simulation--------------------------------------------------------
sim_custom <- simulate_dynamics(
  model,
  target = "custom",
  custom_mask = custom_mask,
  magnitude = 0.40,
  duration = 4,
  period = 10,
  t_max = 3 * generation_time,
  recovery_steps = 4 * generation_time,
  normalize_by_lambda = TRUE
)

sim_custom$reduction

## ----custom-grid--------------------------------------------------------------
out_custom <- run_grid(
  model,
  target = "custom",
  custom_mask = custom_mask,
  grid = grid,
  t_max = 3 * generation_time,
  recovery_steps = 4 * generation_time,
  normalize_by_lambda = TRUE
)

out_custom$vulnerability

## ----initial-state-example----------------------------------------------------
sim_initial_state <- simulate_dynamics(
  model,
  target = "adult_survival",
  magnitude = 0.30,
  duration = 4,
  period = 10,
  t_max = 3 * generation_time,
  recovery_steps = 4 * generation_time,
  initial_state = c(0.80, 0.15, 0.05),
  normalize_by_lambda = TRUE
)

sim_initial_state$reduction

## ----stage-vectors-example----------------------------------------------------
sim_stages <- simulate_dynamics(
  model,
  target = "juvenile_survival",
  magnitude = 0.30,
  duration = 4,
  period = 10,
  t_max = 3 * generation_time,
  recovery_steps = 4 * generation_time,
  return_stage_vectors = TRUE
)

head(sim_stages$stage_vectors)

## ----recovery-option-example--------------------------------------------------
sim_recovery_off <- simulate_dynamics(
  model,
  target = "adult_survival",
  magnitude = 0.30,
  duration = 4,
  period = 10,
  t_max = 3 * generation_time,
  recovery_steps = 4 * generation_time,
  force_during_recovery = FALSE
)

sim_recovery_on <- simulate_dynamics(
  model,
  target = "adult_survival",
  magnitude = 0.30,
  duration = 4,
  period = 10,
  t_max = 3 * generation_time,
  recovery_steps = 4 * generation_time,
  force_during_recovery = TRUE
)

c(
  perturbations_stop_before_recovery = sim_recovery_off$reduction,
  perturbations_continue_during_recovery = sim_recovery_on$reduction
)

## ----infeasible-example-------------------------------------------------------
grid_with_infeasible <- perturbation_grid(
  magnitudes = 0.5,
  durations = c(1, 4, 8),
  periods = c(2, 5)
)

out_with_infeasible <- run_grid(
  model,
  target = "adult_survival",
  grid = grid_with_infeasible,
  t_max = 30,
  skip_infeasible = FALSE
)

out_with_infeasible$table

## ----minimal-workflow, eval=FALSE---------------------------------------------
#  library(demovuln)
#  
#  A <- matrix(
#    c(
#      0.00, 0.00, 1.60,
#      0.35, 0.55, 0.05,
#      0.00, 0.25, 0.86
#    ),
#    nrow = 3,
#    byrow = TRUE
#  )
#  
#  model <- matrix_population_model(
#    A,
#    fecundity_rows = 1,
#    adult_stages = 3,
#    juvenile_stages = c(1, 2)
#  )
#  
#  generation_time <- 20
#  
#  grid <- perturbation_grid_from_frequencies(
#    magnitudes = seq(0, 0.8, by = 0.1),
#    durations = seq(0, generation_time, by = 2),
#    frequencies = c(0.25, 0.5, 1, 2, 4),
#    generation_time = generation_time
#  )
#  
#  out <- run_grid(
#    model,
#    target = "adult_survival",
#    grid = grid,
#    t_max = 3 * generation_time,
#    recovery_steps = 4 * generation_time
#  )
#  
#  out$vulnerability
#  head(out$table)

## ----session-info-------------------------------------------------------------
sessionInfo()

