# Author: anonymised for review
# R version: 2023.03.0
# Packages required: lme4, car, pROC, DHARMa

# Load packages
library(lme4)
library(car)
library(pROC)
library(DHARMa)

# Load the dataset
df <- read.csv("dataset.csv")

# Ensure correct variable types
df$species <- as.factor(df$species)
df$flight_cat <- as.numeric(df$flight_cat)
df$tag_to_body_weight_ratio <- as.numeric(df$tag_to_body_weight_ratio)

# Check assumptions
# Dichotomous outcome
table(df$flight_cat)

# No perfect separation
table(df$flight_cat, cut(df$tag_to_body_weight_ratio, 5))

# Linearity of the logit (Box-Tidwell)
boxTidwell(flight_cat ~ tag_to_body_weight_ratio, data = df)

# Fit GLMM
model <- glmer(flight_cat ~ tag_to_body_weight_ratio + (1 | species),
               data = df,
               family = binomial)

# Model summary
summary(model)

# DHARMa residual diagnostics
simres <- simulateResiduals(model)
plot(simres)
testDispersion(simres)

# Distribution of random intercepts
qqnorm(ranef(model)$species[,1])
qqline(ranef(model)$species[,1])

# ROC analysis and threshold determination
probs <- predict(model, type = "response")
roc_obj <- roc(response = df$flight_cat, predictor = probs)

# Optimal threshold (Youden index)
p_opt <- coords(roc_obj, "best", ret = "threshold")
p_thr <- as.numeric(p_opt)
b0 <- fixef(model)["(Intercept)"]
b1 <- fixef(model)["tag_to_body_weight_ratio"]
x_opt <- (qlogis(p_thr) - b0) / b1

# Output model threshold
print(x_opt)

# Optional: AUC
auc(roc_obj)

# Optional: alternative model with random slope and OLRE
df$obs <- 1:nrow(df)
model2 <- glmer(flight_cat ~ scale(tag_to_body_weight_ratio) +
                  (1 + scale(tag_to_body_weight_ratio) | species) +
                  (1 | obs),
                data = df,
                family = binomial)

# Model comparison
AIC(model, model2)
BIC(model, model2)


###########################################################################################################

#Extended flight capacity was analyzed with a cumulative link mixed model (CLMM, package ordinal) using tag-to-body-weight ratio as a fixed effect and species as a random effect.

library(ordinal)

# 1) Keep only individuals with a value in flight_capacity_total
df_use <- subset(df, !is.na(flight_capacity_total))

# 2) Define the response variable as an ordered factor (5 categories: 1 < 2 < 3 < 4 < 5)
df_use$flight_capacity_total <- ordered(df_use$flight_capacity_total,
                                        levels = c(1, 2, 3, 4, 5))

# 3) Fit CLMM: fixed effect = tag-to-body-weight ratio, random intercept = species
mod_clmm <- clmm(flight_capacity_total ~ tag_to_body_weight_ratio + (1 | species),
                 data = df_use,
                 link = "logit",
                 Hess = TRUE,
                 nAGQ = 10)

# 4) Results
summary(mod_clmm)
confint(mod_clmm, parm = "tag_to_body_weight_ratio", method = "Wald")
AIC(mod_clmm)


#################################################################################################################

#binomial logistic models predicting initial flight capacity using either tag-to-body-weight ratio or tag-to-wing-loading ratio

# Function: run models for a given genus
run_models <- function(data, genus_pattern) {
  cat("\n====================\n", genus_pattern, "\n====================\n\n")
  
  # Filter: only chosen genus, only one study site, and only individuals with forewing length
  df_sp <- data %>%
    filter(grepl(genus_pattern, species)) %>%
    filter(location == "biosphaere_potsdam") %>%
    filter(!is.na(forewing_length_mm))
  
  # Calculate variables
  df_sp <- df_sp %>%
    mutate(
      tag_weight_g       = est_weight_g * (tag_to_body_weight_ratio / 100),
      wing_loading       = est_weight_g / (forewing_length_mm^2),
      tag_to_wingloading = tag_weight_g / wing_loading
    )
  
  # Logistic regression with tag-to-body-weight ratio
  m_bw <- glm(
    flight_cat ~ scale(tag_to_body_weight_ratio),
    data   = df_sp,
    family = binomial
  )
  print(summary(m_bw))
  
  # Logistic regression with tag-to-wing-loading ratio
  m_wl <- glm(
    flight_cat ~ scale(tag_to_wingloading),
    data   = df_sp,
    family = binomial
  )
  print(summary(m_wl))
  
  # Compare AIC
  cat("\nAIC Comparison:\n")
  print(AIC(m_bw, m_wl))
}

# Run models for Caligo
run_models(df, "Caligo")

# Run models for Morpho
run_models(df, "Morpho")