_results/fig5.R

# start ----


# load packages and get helper functions
source("_results/_preamble.R")

# whether to re-do simulations (use rds files otherwise)
.REDO_SIMS <- FALSE
# whether to re-save plots
.RESAVE_PLOTS <- FALSE





spp <- function(.n, .x = 0, .y = 1) {
    rnds <- runif(.n, min = .x, max = .y)
    M <- unname(rbind(rnds, rep(0, .n)))
    M[,1:(.n %/% 2)] <- M[2:1,1:(.n %/% 2)]
    M <- M[,sample.int(.n)]
    return(M)
}

# Takes ~1 min
t0 <- Sys.time()
excl_sims <- mapply(.dp = c(0.1, 0.9), .big_seed = c(464714778, 1632530173),
                    FUN = function(.dp, .big_seed) {
                        set.seed(.big_seed)
                        ex_seeds <- sample.int(2^31-1, 1000)
                        ex_sims <- mclapply(1:1000, function(.r) {
                            set.seed(ex_seeds[.r])
                            tibble(eta = 0.6, d1 = -0.5, d2 = .dp,
                                   final_t = 20e3, spp_gap_t = 5e3L,
                                   save_every = 0L,
                                   V0 = list(spp(20))) %>%
                                run_determ_1rep() %>%
                                select(c(spp, N, V1, V2)) %>%
                                unnest(c(spp, N, V1, V2)) %>%
                                mutate(rep = .r, seed = ex_seeds[.r])
                        }) %>%
                            do.call(what = bind_rows)
                        ex_sims$dp <- .dp
                        return(ex_sims)
                    },
                    SIMPLIFY = FALSE) %>%
    do.call(what = bind_rows) %>%
    select(dp, rep, seed, everything())
t1 <- Sys.time()
t1 - t0
# excl_sims


excl_p_df <- excl_sims %>%
    group_by(dp, rep) %>%
    summarize(v1 = sum(V1 > 0),
              v2 = sum(V2 > 0),
              n_spp = n(),
              .groups = "drop") %>%
    {group_by(., dp) %>% summarize(p1 = mean(v1 / n_spp)) %>% print(); .} %>%
    {.[["v1"]] %>% table() %>% print(); .} %>%
    {.[["n_spp"]] %>% table() %>% print(); .} %>%
    # group_by(dp, n_spp) %>%
    # summarize(across(c(v1), list(mean_p = ~ mean(.x / n_spp),
    #                              mean_n = ~ mean(.x),
    #                                  min_n = ~ min(.x),
    #                                  max_n = ~ max(.x))),
    #           n = n())
    group_by(dp, n_spp, v1) %>%
    summarize(count = n(),
              .groups = "drop") %>%
    group_by(dp, n_spp) %>%
    mutate(p = count / sum(count)) %>%
    ungroup() %>%
    mutate(p1 = v1 / n_spp, dp = factor(dp))

excl_p_df %>%
    ggplot(aes(n_spp, p1)) +
    geom_hline(yintercept = 0.5, linetype = "22", color = "gray70") +
    # geom_bar(aes(fill = v1), position="stack", stat="identity") +
    geom_point(aes(size = count)) +
    # geom_point(data = excl_p_df %>%
    #               group_by(dp, n_spp) %>%
    #               summarize(p1 = sum(p1 * p), .groups = "drop"),
    #           color = "red") +
    # stat_summary(fun = mean, geom = "line") +
    xlab("Number of surviving species") +
    ylab("Proportion investing in conflict traits") +
    facet_wrap(~ dp)



exc_sims %>% filter(rep == 1)

set.seed(643327297)
tibble(eta = 0.6, d1 = -0.5, d2 = .dp,
       final_t = 10e3, spp_gap_t = 5e3L,
       save_every = 0L,
       V0 = list(spp(10))) %>%
    run_determ_1rep() %>%
    select(c(spp, N, V1, V2)) %>%
    unnest(c(spp, N, V1, V2))







# ----------------------------------------------------------------------------*
# ----------------------------------------------------------------------------*
# ----------------------------------------------------------------------------*
# ----------------------------------------------------------------------------*
# ----------------------------------------------------------------------------*
# ----------------------------------------------------------------------------*








#'
#' Simulate 2-species equilibrium community.
#'
one_dx_dp_equil_sim <- function(.dx, .dp, .final_t = 30e3L) {

    # .dx = 0.6; .dp = 0.6
    # rm(sim0, raw_sim0, .V0_0, .d_vec, .dx, .dp)
    .d_vec <- c(- .dx, .dp)
    .V0_0 <- rbind(cos(c(6, 84) * pi / 180) * 1,
                   sin(c(6, 84) * pi / 180) * 1) %>%
        list()
    raw_sim0 <- tibble(eta = 0, d1 = .d_vec[1], d2 = .d_vec[2],
                       final_t = .final_t, spp_gap_t = 0L, save_every = 1L,
                       V0 = .V0_0) %>%
        run_determ_1rep()
    # Stable equilibrium?
    if (!equil_check(raw_sim0)) {
        stop("\nDidn't reach equilibrium for `.d_vec` = ",
             paste(.d_vec, collapse = ", "))
    }
    if ((max(Re(raw_sim0[["eig"]][[1]])) - 1) > 1e-6) {
        stop("\nEquilibrium not (neutrally) stable for `.d_vec` = ",
             paste(.d_vec, collapse = ", "))
    }
    sim0 <- raw_sim0 %>%
        select(spp, time, N, V1, V2) %>%
        unnest(c(spp, time, N, V1, V2)) %>%
        filter(time == max(time)) %>%
        mutate(Omega = calc_omega(., d_vec = .d_vec)) %>%
        select(-time) %>%
        mutate(invest = sqrt(V1^2 + V2^2))
    if (nrow(sim0) != ncol(.V0_0[[1]])) {
        stop("\nNot all species survived initial sim for `.d_vec` = ",
             paste(.d_vec, collapse = ", "))
    }
    out <- tibble(dx = .dx, dp = .dp, sim0 = list(sim0))

    return(out)
}


#' Simulations for effects on conflicter's investment.
#' Takes ~90 sec
# invest_d_sims <- crossing(.dx = seq(0.1, 1.5, 0.1) %>% round(1),
#                           .dp = seq(0.1, 1.5, 0.05) %>% round(2)) %>%
#     as.list() %>%
#     c(list(FUN = one_dx_dp_equil_sim, SIMPLIFY = FALSE)) %>%
#     do.call(what = mcmapply) %>%
#     do.call(what = bind_rows) %>%
#     mutate(invest_c = map_dbl(sim0, ~ .x$invest[[1]]),
#            invest_p = map_dbl(sim0, ~ .x$invest[[2]]))
# saveRDS(invest_d_sims, "_results/results-rds/invest_d_sims.rds")

invest_d_sims <- readRDS("_results/results-rds/invest_d_sims.rds")



#'
#' How does investment by the conflict / partitioning investor change
#' as we change dp and dx?
#'
dp_invest_p <- invest_d_sims %>%
    filter(dx %in% c(0.3, 0.5, 0.7, 0.9)) %>%
    filter(dp <= 0.9) %>%
    ggplot(aes(dp, invest_c, color = factor(dx))) +
    geom_hline(yintercept = 0, color = "gray70", size = 0.5) +
    geom_line(size = 0.5) +
    geom_point(size = 1) +
    geom_line(aes(y = invest_p), size = 0.5, linetype = "21") +
    geom_point(aes(y = invest_p), size = 1, shape = 15) +
    geom_text(data = tibble(dp = c(0.1, 0.85),
                            invest_c = c(0.55, 1.1),
                            lab = c("conflicter", "partitioner")),
              aes(label = lab), hjust = c(0, 1), vjust = 1, color = "black") +
    scale_color_manual(expression(d[x]),
                       values = c("gray80", "gray60", "gray40", "black")) +
    scale_x_continuous(expression(d[p]), breaks = c(1,5,9)/10) +
    scale_y_continuous("Equilibrium investment", breaks = 0.5 * 0:2,
                       limits = c(0, 1.35)) +
    NULL

dp_omega_p <- invest_d_sims %>%
    filter(dx %in% c(0.3, 0.5, 0.7, 0.9)) %>%
    filter(dp <= 0.9) %>%
    mutate(omega_c = map_dbl(sim0, ~ .x$Omega[[1]]),
           omega_p = map_dbl(sim0, ~ .x$Omega[[2]])) %>%
    ggplot(aes(dp, omega_c, color = factor(dx))) +
    geom_hline(yintercept = 0, color = "gray70", size = 0.5) +
    geom_line(size = 0.5) +
    geom_point(size = 1) +
    geom_line(aes(y = omega_p), size = 0.5, linetype = "21") +
    geom_point(aes(y = omega_p), size = 1, shape = 15) +
    scale_color_manual(expression(d[x]),
                       values = c("gray80", "gray60", "gray40", "black")) +
    scale_x_continuous(expression(d[p]), breaks = c(1,5,9)/10) +
    scale_y_continuous("Equilibrium ECN", breaks = 2500 * 0:2,
                       limits = c(0, 6000)) +
    NULL



dp_abund_p <- invest_d_sims %>%
    filter(dx %in% c(0.3, 0.5, 0.7, 0.9)) %>%
    filter(dp <= 0.9) %>%
    mutate(N_c = map_dbl(sim0, ~ .x$N[[1]]),
           N_p = map_dbl(sim0, ~ .x$N[[2]])) %>%
    ggplot(aes(dp, N_c, color = factor(dx))) +
    geom_line(size = 0.5) +
    geom_point(size = 1) +
    geom_line(aes(y = N_p), size = 0.5, linetype = "21") +
    geom_point(aes(y = N_p), size = 1, shape = 15) +
    scale_color_manual(expression(d[x]),
                       values = c("gray80", "gray60", "gray40", "black")) +
    scale_x_continuous(expression(d[p]), breaks = c(1,5,9)/10) +
    scale_y_continuous("Equilibrium abundance", breaks = 1000 * 2:4,
                       limits = c(1900, 4305)) +
    NULL


dp_invest_abund_p <- dp_invest_p + dp_omega_p + dp_abund_p +
    plot_annotation(tag_levels = "A") +
    plot_layout(ncol = 1, guides = "collect")

# if (.RESAVE_PLOTS) save_plot(dp_invest_abund_p, 4, 8, .prefix = "S4-")


#' These are similar to plots above, except that dx == 0.5 for simplicity,
#' plus they're simpler overall bc they'll be put together with others
#' to make Figure 5 using Illustrator.
#'
invest_d_p <- invest_d_sims %>%
    filter(dx == 0.5) %>%
    filter(dp <= 0.9) %>%
    select(-sim0) %>%
    pivot_longer(starts_with("invest"), names_to = "spp",
                 values_to = "invest") %>%
    mutate(spp = ifelse(str_ends(spp, "_c"), "conflicter", "partitioner") %>%
               factor(levels = c("conflicter", "partitioner"))) %>%
    ggplot(aes(dp, invest, color = spp)) +
    # geom_vline(xintercept = c(0.3, 0.7), size = 0.5, color = "gray70",
    #            linetype = "22") +
    geom_hline(yintercept = 0, color = "gray70", size = 0.5) +
    geom_line(size = 0.5) +
    geom_point(size = 1.5) +
    scale_color_manual(values = plasma(100)[c(1, 85, 65)][-3]) +
    scale_x_continuous(expression(d[p]), breaks = c(1,3,5,7,9)/10) +
    scale_y_continuous("Equilibrium investment", breaks = 0.5 * 0:2,
                       limits = c(0, 1.35)) +
    theme(axis.title = element_blank(),
          axis.text = element_blank(),
          legend.position = "none",
          plot.margin = margin(0,0,0,0)) +
    NULL

if (.RESAVE_PLOTS) save_plot(invest_d_p, 1.75, 1,
                             .name = "fig5_sub-plots/invest_d_p")


abund_d_p <- invest_d_sims %>%
    filter(dx == 0.5) %>%
    filter(dp <= 0.9) %>%
    mutate(N_c = map_dbl(sim0, ~ .x$N[[1]]),
           N_p = map_dbl(sim0, ~ .x$N[[2]])) %>%
    select(-sim0, -starts_with("invest")) %>%
    pivot_longer(starts_with("N"), names_to = "spp",
                 values_to = "N") %>%
    mutate(spp = ifelse(str_ends(spp, "_c"), "conflicter", "partitioner") %>%
               factor(levels = c("conflicter", "partitioner"))) %>%
    ggplot(aes(dp, N, color = spp)) +
    # geom_vline(xintercept = c(0.3, 0.7), size = 0.5, color = "gray70",
    #            linetype = "22") +
    geom_line(size = 0.5) +
    geom_point(size = 1.5) +
    scale_color_manual(values = plasma(100)[c(1, 85, 65)][-3]) +
    scale_x_continuous(expression(d[p]), breaks = c(1,3,5,7,9)/10) +
    scale_y_continuous("Equilibrium abundance", breaks = 2400 + 800 * 0:2,
                       limits = c(2400, 4305)) +
    theme(axis.title = element_blank(),
          axis.text = element_blank(),
          legend.position = "none",
          plot.margin = margin(0,0,0,0)) +
    NULL

if (.RESAVE_PLOTS) save_plot(abund_d_p, 1.75, 1,
                             .name = "fig5_sub-plots/abund_d_p")



#'
#' Simulate invaders into a 2-species community.
#'
one_dx_dp_inv_sim <- function(.dx, .dp, .sim0, .sim_max_t) {

    # .dx = 0.6; .dp = 0.6; .sim_max_t = 10e3L
    # rm(out, survs, x_vals, O_inv, sim0, raw_sim0, .V0_0, .d_vec,
    #    .dx, .dp, .sim_max_t)
    stopifnot(!inherits(.sim0, "list"))
    .d_vec <- c(- .dx, .dp)

    O_inv <- with(.sim0, sum(N * exp(- .d_vec[1] * V1^2 - .d_vec[2] * V2^2)))

    x_vals <- seq(0.1, 2.5, 0.1) %>%
        round(1)

    survs <- x_vals %>%
        map(function(.x) {
            #' No point in doing simulation if we know the invader's fitness
            #' will be < 1
            f0 <- with(formals(quant_gen), {
                exp(r0 - f * .x^2 - a0 - a0 * exp(-.x^2) * O_inv)
            })
            if (f0 < 1) return(c(rep(1L, nrow(.sim0)), 0L))

            .N0 <- c(.sim0$N, 1)
            .V0 <- cbind(rbind(.sim0$V1, .sim0$V2), c(.x, 0)) %>%
                list()

            raw_sim1 <- tibble(eta = 0, d1 = .d_vec[1], d2 = .d_vec[2],
                               final_t = .sim_max_t, spp_gap_t = 0L,
                               save_every = 1L,
                               V0 = .V0, N0 = list(.N0)) %>%
                run_determ_1rep()
            surv_spp <- raw_sim1 %>%
                select(spp, time, N, V1, V2) %>%
                unnest(c(spp, time, N, V1, V2)) %>%
                filter(time == max(time)) %>%
                .[["spp"]] %>%
                as.integer()
            surv_vec <- as.integer(1:(nrow(.sim0)+1) %in% surv_spp)
            # Stable equilibrium?
            if (!equil_check(raw_sim1)) {
                warning("\nDidn't reach equilibrium at `x` = ", .x,
                     " for `.d_vec` = ",
                     paste(.d_vec, collapse = ", "))
                surv_vec[surv_vec == 1] <- NA_integer_
            }
            if ((max(Re(raw_sim1[["eig"]][[1]])) - 1) > 1e-6) {
                warning("\nEquilibrium unstable at `x` = ", .x,
                     " for `.d_vec` = ",
                     paste(.d_vec, collapse = ", "))
                surv_vec[surv_vec == 1] <- NA_integer_
            }

            return(surv_vec)
        })

    out <- cbind(x_vals, do.call(rbind, survs)) %>%
        as.data.frame() %>%
        set_names(c("x", "spp1", "spp2", "spp3")) %>%
        as_tibble() %>%
        mutate(dx = .dx, dp = .dp) %>%
        select(dx, dp, everything())

    return(out)
}



# # Takes ~9 min
# dx_dp_sims <- invest_d_sims %>%
#     select(dx, dp, sim0) %>%
#     rename_with(~ paste0(".", .x)) %>%
#     # Some combos need to be run longer to reach equilibrium:
#     mutate(.sim_max_t = case_when(.dp >= 0.7 & .dp <= 0.85 & .dx >= 0.7 ~ 30e3L,
#                                   .dp >= 0.7 & .dp <= 0.85 & .dx > 0.6 ~ 20e3L,
#                                   .dp >= 0.7 & .dp <= 0.85 & .dx >= 0.2 ~ 30e3L,
#                                   TRUE ~ 10e3L)) %>%
#     # head() %>%
#     as.list() %>%
#     c(list(FUN = one_dx_dp_inv_sim, SIMPLIFY = FALSE)) %>%
#     do.call(what = mcmapply) %>%
#     do.call(what = bind_rows)
# saveRDS(dx_dp_sims, "_results/results-rds/dx_dp_sims.rds")

dx_dp_sims <- readRDS("_results/results-rds/dx_dp_sims.rds")

#' This should return no rows bc it checks for any reps not reaching an
#' equilibrium or reach an unstable equilibrium
dx_dp_sims %>%
    filter(if_any(starts_with("spp"), is.na))

#' Only 4 possible outcomes:
#'   1. both residents persist, invader excluded
#'   2. species 1 excluded, invader and species 2 coexist
#'   3. all 3 species persist
#'   4. both residents excluded, invader persists
dx_dp_sims %>%
    mutate(outcome = paste0(spp1, spp2, spp3)) %>%
    distinct(outcome)





dx_dp_sims %>% filter(dx == 0.5 & (dp == 0.3 | dp == 0.7) & x == 1)

invest_d_comm_p <- invest_d_sims %>%
    filter(dx == 0.5, dp %in% c(0.3, 0.7)) %>%
    arrange(dp) %>%
    .[["sim0"]] %>%
    map(function(dd) {
        dd %>%
            ggplot(aes(V1, V2, color = spp))+
            geom_abline(slope = 1, intercept = 0,
                        linetype = 2, color = "gray70") +
            geom_hline(yintercept = 0, color = "gray70", size = 0.5) +
            geom_vline(xintercept = 0, color = "gray70", size = 0.5) +
            geom_point(shape = 19, size = 3) +
            scale_color_manual(values = plasma(100)[c(1, 85)], guide = "none") +
            scale_y_continuous("Partitioning investment", breaks = 0.5 * 0:2) +
            scale_x_continuous("Conflict investment", breaks = 0.5 * 0:2) +
            coord_equal(xlim = c(-0.05, 1.3), ylim = c(-0.05, 1.3),
                        clip = "off") +
            theme(panel.background = element_blank(),
                  axis.title = element_blank(),
                  axis.text.x = element_blank(),
                  axis.text.y = element_blank(),
                  plot.margin = margin(0,0,0,0)) +
            NULL
    })

if (.RESAVE_PLOTS) {
    save_plot(invest_d_comm_p[[1]], 0.8, 0.8, .name = "fig5_sub-plots/comm_0.3")
    save_plot(invest_d_comm_p[[2]], 0.8, 0.8, .name = "fig5_sub-plots/comm_0.7")
}



invade_dp <- function(.dp, .inv_x = 1) {
    # .dp = 0.7; .inv_x = 1
    # rm(.dx, .dp, .inv_x, equil, raw_sim1, prequel, out)
    .dx <- 0.5
    stopifnot(length(.dp) == 1 && is.numeric(.dp) && .dp > 0)
    stopifnot(length(.inv_x) == 1 && is.numeric(.inv_x) && .inv_x > 0)
    equil <- invest_d_sims %>%
        filter(dx == .dx, dp == .dp) %>%
        .[["sim0"]] %>%
        .[[1]]

    raw_sim1 <- tibble(eta = 0, d1 = -.dx, d2 = .dp,
                       final_t = 10e3L, spp_gap_t = 0L,
                       save_every = 1L,
                       V0 = list(rbind(c(equil$V1, .inv_x),
                                       c(equil$V2, 0))),
                       N0 = list(c(equil$N, 1))) %>%
            run_determ_1rep() %>%
        select(spp, time, N, V1, V2) %>%
        unnest(c(spp, time, N, V1, V2)) %>%
        mutate(Omega = calc_omega(., d_vec = c(-.dx, .dp)),
               invest = sqrt(V1^2 + V2^2),
               dp = .dp)
    prequel <- equil %>% mutate(dp = .dp, time = -1L)
    out <- bind_rows(prequel, raw_sim1) %>%
        select(dp, everything())
    return(out)
}


invade_dp_df <- map_dfr(c(0.3, 0.7), invade_dp)


invade_dp_p_list <- sort(unique(invade_dp_df$dp)) %>%
    map(function(.dp) {
        .dd <- invade_dp_df %>% filter(dp == .dp)
        ext_df <- .dd %>%
            group_by(spp) %>%
            filter(time == max(time)) %>%
            ungroup() %>%
            filter(time < max(time))

        y_scales <- list(invest = scale_y_continuous("Total investment",
                                                     limits = c(-0.16, 1.6),
                                                     breaks = c(0, 0.7, 1.4)),
                         Omega = scale_y_continuous("ECN",
                                                    limits = c(-1100, 11000),
                                                    breaks = 5e3*0:2),
                         N = scale_y_continuous("Abundance",
                                                limits = c(-410, 4100),
                                                breaks = 2e3*0:2))
        plots <- imap(y_scales, function(y_scale, y_var) {
            .dd %>%
                filter(time < 350) %>%
                mutate(time = ifelse(time < 0, time * 100, time)) %>%
                ggplot(aes(time, !!sym(y_var), color = spp)) +
                geom_vline(xintercept = 0, color = "gray70", size = 0.5) +
                geom_hline(yintercept = 0, color = "gray70", size = 0.5) +
                geom_line(size = 0.75) +
                geom_point(data = ext_df, size = 2, shape = 4) +
                scale_color_manual(values = plasma(100)[c(1, 85, 65)],
                                   guide = "none") +
                scale_x_continuous("Time", breaks = 100 * 0:3) +
                y_scale +
                theme(axis.title = element_blank(),
                      axis.text.y = element_blank(),
                      axis.text.x = element_blank(),
                      plot.margin = margin(0,0,0,0)) +
                coord_cartesian(xlim = c(-50, NA), expand = FALSE)
        })
        p <- wrap_plots(plots, ncol = 1) &
            theme(plot.margin = margin(0,0,0,0))
        return(p)
    })


# wrap_plots(invade_dp_p_list, ncol = 2)


if (.RESAVE_PLOTS) {
    save_plot(invade_dp_p_list[[1]], 2, 1.75, .name = "fig5_sub-plots/invade_0.3")
    save_plot(invade_dp_p_list[[2]], 2, 1.75, .name = "fig5_sub-plots/invade_0.7")
}










# =============================================================================*
# =============================================================================*

# Full outcomes

# =============================================================================*
# =============================================================================*

d_outcome_p <- dx_dp_sims %>%
    mutate(outcome = case_when(spp1 == 1 & spp3 == 1 ~ "3-spp coexist",
                               spp1 == 1 & spp3 == 0 ~ "invader excluded",
                               spp1 == 0 & spp2 == 1 & spp3 == 1 ~ "conflict resident excluded",
                               spp1 == 0 & spp2 == 0 & spp3 == 1 ~ "both residents excluded",
                               TRUE ~ NA_character_) %>%
               factor(levels = c("both residents excluded",
                                 "conflict resident excluded",
                                 "3-spp coexist",
                                 "invader excluded"))) %>%
    mutate(dx_f = factor(dx, levels = sort(unique(dx)),
                         labels = paste("d[x] ==", sort(unique(dx))))) %>%
    ggplot(aes(dp, x)) +
    geom_raster(aes(fill = outcome)) +
    scale_fill_manual(NULL, values = c("gray80", plasma(100)[c(70, 40, 20)])) +
    scale_y_continuous(expression("Invader" ~ x[0]), breaks = 0:2) +
    scale_x_continuous(expression(d[p]), breaks = c(2,8,14)/10) +
    facet_wrap(~ dx_f, labeller = label_parsed, nrow = 3) +
    guides(fill = guide_legend(ncol = 1)) +
    theme(legend.position = "right") +
    NULL

if (.RESAVE_PLOTS) save_plot(d_outcome_p, 6, 4, .prefix = "S5-", .png = TRUE)



dx_dp_minx <- dx_dp_sims %>%
    split(interaction(.$dx, .$dp)) %>%
    map_dfr(function(.d) {
        .res_excl <- .d %>%
            filter(spp1 == 0 & spp3 == 1)
        if (nrow(.res_excl) == 0) {
            .min_x <- 100
        } else {
            .min_x  <- min(.res_excl$x)
        }
        out <- select(.d[1,], dx, dp) %>%
            mutate(min_x = .min_x)
        return(out)
    }) %>%
    mutate(inf = factor(min_x == 100),
           min_x = ifelse(min_x == 100, 2.2, min_x))





dp_minx_p <- dx_dp_minx %>%
    filter(dx %in% (c(3, 5, 7, 9) / 10)) %>%
    filter(dp <= 0.9) %>%
    group_by(dx) %>%
    filter(inf == "FALSE" | dp ==
               if (any(inf == "TRUE")) max(dp[inf == "TRUE"]) else -Inf) %>%
    ungroup() %>%
    ggplot(aes(dp, min_x)) +
    geom_hline(yintercept = 0.1, color = "gray70", size = 0.5) +
    geom_hline(yintercept = 2.2, color = "gray70", size = 0.5) +
    geom_line(aes(color = factor(dx)), size = 0.5) +
    geom_point(aes(shape = inf, color = factor(dx)), size = 1.5) +
    scale_shape_manual(values = c(19, 1), guide = "none") +
    # scale_color_viridis_d(expression(d[x]), begin = 0.2, end = 0.8) +
    scale_color_manual(values = c("gray80", "gray60", "gray40", "black")) +
    scale_x_continuous(expression(d[p]), breaks = c(1,5,9)/10) +
    scale_y_continuous(expression(x[inv]), breaks = 0:2) +
    theme(axis.title = element_blank(),
          axis.text = element_blank(),
          legend.position = "none",
          plot.margin = margin(0,0,0,0)) +
    NULL


if (.RESAVE_PLOTS) save_plot(dp_minx_p, 2, 1.75,
                             .name = "fig5_sub-plots/dp_minx")




paired_invasions <- function(.dx, .dp, .steps = c(-0.15, 0.15)) {
    # .dx = 0.7; .dp = 0.6; .step = 0.15
    # rm(.d_vec, .min_x, .x_vec, equil, out_list, out, i, .x, raw_sim1, prequel)
    stopifnot(length(.steps) == 2 && is.numeric(.steps) &&
                  .steps[1] < 0 && .steps[2] > 0)
    .d_vec = c(- abs(.dx), abs(.dp))
    .min_x <- dx_dp_minx %>%
        filter(dx == abs(.d_vec[1]), dp == .d_vec[2]) %>%
        .[["min_x"]]
    .x_vec <- .min_x + .steps
    equil <- invest_d_sims %>%
        filter(dx == abs(.d_vec[1]), dp == .d_vec[2]) %>%
        .[["sim0"]] %>%
        .[[1]]

    out_list <- rep(list(NA), 2)
    for (i in 1:length(.x_vec)) {
        .x = .x_vec[i]
        raw_sim1 <- tibble(eta = 0, d1 = .d_vec[1], d2 = .d_vec[2],
                           final_t = 10e3L, spp_gap_t = 0L,
                           save_every = 1L,
                           V0 = list(rbind(c(equil$V1, .x),
                                           c(equil$V2, 0))),
                           N0 = list(c(equil$N, 1))) %>%
            run_determ_1rep()
        # Stable equilibrium?
        if (!equil_check(raw_sim1)) {
            stop("\nDidn't reach equilibrium at `x` = ", .x,
                 " for `.d_vec` = ",
                 paste(.d_vec, collapse = ", "))
        }
        if ((max(Re(raw_sim1[["eig"]][[1]])) - 1) > 1e-6) {
            stop("\nEquilibrium unstable at `x` = ", .x,
                 " for `.d_vec` = ",
                 paste(.d_vec, collapse = ", "))
        }
        out <- raw_sim1 %>%
            select(spp, time, N, V1, V2) %>%
            unnest(c(spp, time, N, V1, V2)) %>%
            mutate(Omega = calc_omega(., d_vec = .d_vec),
                   invest = sqrt(V1^2 + V2^2),
                   x_inv = .x) %>%
            select(x_inv, everything())
        prequel <- equil %>% mutate(x_inv = .x, time = -1L)
        out_list[[i]] <- bind_rows(prequel, out)
    }
    do.call(bind_rows, out_list)
}



# The below code shows plots of the weird edge case issue in Figure S5.
# x <- paired_invasions(0.1, 1.35, .steps = c(-2, 0.5)) %>%
#     filter(x_inv == min(x_inv))
# y <- paired_invasions(0.3, 1.35, .steps = c(-0.01, 0.4)) %>%
#     filter(x_inv == max(x_inv))
# # The problem one:
# z <- paired_invasions(0.2, 1.35, .steps = c(-0.6, 0.9)) %>%
#     filter(x_inv == min(x_inv))
#
# problem_plot <- function(.d, .dx, y_var, .max, .leg = TRUE) {
#     p <- .d %>%
#             ggplot(aes(time, !!sym(y_var), color = spp)) +
#             ggtitle(sprintf("dx = %.2f", .dx)) +
#             geom_line() +
#             scale_y_continuous(limits = c(0, .max)) +
#             scale_color_manual(values = plasma(100)[c(1, 85, 65)])
#     if (!.leg) p <- p +
#             theme(legend.position = "none")
#     return(p)
# }
#
#
# problem_plot(x, 0.1, "invest", 1.4) +
#     problem_plot(z, 0.2, "invest", 1.4) +
#     problem_plot(y, 0.3, "invest", 1.4) +
#     problem_plot(x, 0.1, "Omega", 7000) +
#     problem_plot(z, 0.2, "Omega", 7000) +
#     problem_plot(y, 0.3, "Omega", 7000) +
#     problem_plot(x, 0.1, "N", 4700) +
#     problem_plot(z, 0.2, "N", 4700) +
#     problem_plot(y, 0.3, "N", 4700) +
#     plot_layout(ncol = 3, byrow = TRUE, guides = "collect")




paired_inv_df <- paired_invasions(0.5, 0.6, .steps = c(-0.9, 0.1))


paired_inv_p <- sort(unique(paired_inv_df$x_inv)) %>%
    map(function(xinv) {
        .dd <- paired_inv_df %>% filter(x_inv == xinv)
        ext_df <- .dd %>%
            group_by(spp) %>%
            filter(time == max(time)) %>%
            ungroup() %>%
            filter(time < max(time))

        y_scales <- list(invest = scale_y_continuous("Total investment",
                                                     limits = c(-0.17, 1.7),
                                                     breaks = c(0, 0.8, 1.6)),
                         Omega = scale_y_continuous("ECN",
                                                    limits = c(-900, 9000),
                                                    breaks = 4e3*0:2),
                         N = scale_y_continuous("Abundance",
                                                limits = c(-410, 4100),
                                                breaks = 2e3*0:2))
        plots <- imap(y_scales, function(y_scale, y_var) {
            .dd %>%
                filter(time < 400) %>%
                mutate(time = ifelse(time < 0, time * 100, time)) %>%
                ggplot(aes(time, !!sym(y_var), color = spp)) +
                geom_vline(xintercept = 0, color = "gray70", size = 0.5) +
                geom_hline(yintercept = 0, color = "gray70", size = 0.5) +
                geom_line(size = 0.75) +
                geom_point(data = ext_df, size = 2, shape = 4) +
                scale_color_manual(values = plasma(100)[c(1, 85, 65)],
                                   guide = "none") +
                scale_x_continuous("Time", breaks = 100 * 0:3) +
                y_scale +
                theme(axis.title = element_blank(),
                      axis.text.y = element_blank(),
                      axis.text.x = element_blank(),
                      plot.margin = margin(0,0,0,0)) +
                coord_cartesian(xlim = c(-50, NA), expand = FALSE)
        })
        p <- wrap_plots(plots, ncol = 1) &
            theme(plot.margin = margin(0,0,0,0))
        return(p)
    })

# wrap_plots(paired_inv_p, ncol = 2)


if (.RESAVE_PLOTS) {
    save_plot(paired_inv_p[[1]], 2, 1.75, .name = "fig5_sub-plots/under")
    save_plot(paired_inv_p[[2]], 2, 1.75, .name = "fig5_sub-plots/over")
}


paired_inv_comm_p <- invest_d_sims %>%
    filter(dx == 0.5, dp == 0.6) %>%
    .[["sim0"]] %>%
    .[[1]] %>%
    ggplot(aes(V1, V2, color = spp))+
    geom_abline(slope = 1, intercept = 0,
                linetype = 2, color = "gray70") +
    geom_hline(yintercept = 0, color = "gray70", size = 0.5) +
    geom_vline(xintercept = 0, color = "gray70", size = 0.5) +
    geom_point(shape = 19, size = 3) +
    # geom_point(shape = 19, size = 3, alpha = 0.75) +
    # geom_point(shape = 1, size = 3) +
    geom_segment(y = -0.05, yend = 0.05,
                 x = dx_dp_minx %>%
                     filter(dx == 0.5, dp == 0.6) %>%
                     .[["min_x"]],
                 xend = dx_dp_minx %>%
                     filter(dx == 0.5, dp == 0.6) %>%
                     .[["min_x"]], color = "black", size = 0.5) +
    scale_color_manual(values = plasma(100)[c(1, 85)], guide = "none") +
    scale_y_continuous("Partitioning investment", breaks = 0:2) +
    scale_x_continuous("Conflict investment", breaks = 0:2) +
    coord_equal(xlim = c(-0.025, 2), ylim = c(-0.025, 2), clip = "off") +
    theme(panel.background = element_blank(),
          axis.title = element_blank(),
          axis.ticks = element_blank(),
          axis.text.x = element_blank(),
          axis.text.y = element_blank(),
          plot.margin = margin(0,0,0,0))



paired_inv_comm_p_invasion <-
    list("min", "max") %>%
    set_names() %>%
    map(~ eval(parse(text = .x))) %>%
    map(function(.f) {
            .dd <- filter(paired_inv_df, time == 0, spp == 3) %>%
                filter(V1 == .f(V1))
            p <- paired_inv_comm_p +
                geom_point(data = .dd,
                           shape = 19, size = 3, color = plasma(100)[c(65)])
            gt <- ggplot_gtable(ggplot_build(p))
            gt$layout$z[grepl("^panel", gt$layout$name)] <- max(gt$layout$z) + 1
            gt
        })

if (.RESAVE_PLOTS) {
    save_plot(paired_inv_comm_p, 1, 1, .name = "fig5_sub-plots/comm")
    save_plot(function() {grid.newpage(); grid.draw(paired_inv_comm_p_invasion$max)},
              0.8, 0.8, .name = "fig5_sub-plots/comm-above")
    save_plot(function() {grid.newpage(); grid.draw(paired_inv_comm_p_invasion$min)},
              0.8, 0.8, .name = "fig5_sub-plots/comm-below")
}
lucasnell/evo_alt_states documentation built on Aug. 17, 2022, 5:34 a.m.