R/15.1-analysis-extraction.R

Defines functions create_result_summary analyze_feeding_performance analyze_energy_budget analyze_growth_patterns

Documented in analyze_energy_budget analyze_feeding_performance analyze_growth_patterns create_result_summary

#' Basic Analysis and Extraction Functions for FB4 Results
#'
#' @description
#' Functions for basic analysis and extraction of FB4 simulation results.
#' These functions build on the core extraction functions to provide
#' meaningful biological interpretations and statistical summaries.
#' Exported functions include \code{analyze_growth_patterns},
#' \code{analyze_energy_budget}, \code{analyze_feeding_performance},
#' and \code{create_result_summary}.
#'
#' @references
#' Deslauriers, D., Chipps, S.R., Breck, J.E., Rice, J.A. and Madenjian, C.P.
#' (2017). Fish Bioenergetics 4.0: An R-based modeling application.
#' \emph{Fisheries}, 42(11), 586–596. \doi{10.1080/03632415.2017.1377558}
#'
#' @return No return value; this page documents the result extraction and summary functions. See individual function documentation for return values.
#' @name analysis-extraction
#' @aliases analysis-extraction
NULL

# ============================================================================
# GROWTH ANALYSIS FUNCTIONS
# ============================================================================

#' Analyze growth patterns from FB4 results
#'
#' @description
#' Extracts and analyzes growth patterns from FB4 simulation results.
#' Calculates growth rates, efficiency metrics, and provides uncertainty
#' estimates when available.
#'
#' @param result FB4 result object
#' @param individual_id Individual ID for hierarchical models (NULL for population/single individual)
#' @param confidence_level Confidence level for intervals (default 0.95)
#' @return A named list with at minimum \code{method} (character),
#'   \code{has_uncertainty} (logical), \code{individual_id}, and
#'   \code{initial_weight} (numeric, g). The following growth metrics are
#'   included as sub-lists each with \code{estimate}, \code{se}, \code{ci_lower},
#'   and \code{ci_upper}: \code{final_weight} (g), \code{total_growth} (g),
#'   and \code{relative_growth} (\%). When simulation duration is available,
#'   \code{daily_growth_rate} (g/day) and \code{specific_growth_rate}
#'   (\%/day) are appended. For fitted methods a \code{p_value} sub-list
#'   (\code{estimate}, \code{se}) is also included; for hierarchical
#'   population-level calls, \code{n_individuals} (integer) is added.
#' @export
#'
#' @examples
#' \donttest{
#' data(fish4_parameters)
#' sp   <- fish4_parameters[["Oncorhynchus tshawytscha"]]$life_stages$adult
#' info <- fish4_parameters[["Oncorhynchus tshawytscha"]]$species_info
#' bio  <- Bioenergetic(
#'   species_params     = sp,
#'   species_info       = info,
#'   environmental_data = list(
#'     temperature = data.frame(Day = 1:30, Temperature = rep(12, 30))
#'   ),
#'   diet_data = list(
#'     proportions = data.frame(Day = 1:30, Prey1 = 1.0),
#'     energies    = data.frame(Day = 1:30, Prey1 = 5000),
#'     prey_names  = "Prey1"
#'   ),
#'   simulation_settings = list(initial_weight = 100, duration = 30)
#' )
#' bio$species_params$predator$ED_ini <- 5000
#' bio$species_params$predator$ED_end <- 5500
#' result <- run_fb4(bio, strategy = "direct", p_value = 0.5, verbose = FALSE)
#' growth <- analyze_growth_patterns(result)
#' }
analyze_growth_patterns <- function(result, individual_id = NULL, confidence_level = 0.95) {
  
  if (!is.fb4_result(result)) {
    stop("Input must be an fb4_result object")
  }
  
  result_type <- detect_result_type(result)
  method <- result_type$method
  has_uncertainty <- result_type$has_uncertainty
  
  # Get basic growth information
  growth_info <- list(
    method = method,
    has_uncertainty = has_uncertainty,
    individual_id = individual_id
  )
  
  # Extract growth metrics based on method
  if (method == "hierarchical") {
    
    if (is.null(individual_id)) {
      # Population mean
      pop_results <- get_population_results(result, confidence_level)
      
      growth_info$initial_weight <- result$summary$initial_weight %||% NA
      growth_info$final_weight <- list(
        estimate = pop_results$mean_final_weight_est %||% NA,
        se = pop_results$mean_final_weight_se %||% NA,
        ci_lower = pop_results$mean_final_weight_ci_lower %||% NA,
        ci_upper = pop_results$mean_final_weight_ci_upper %||% NA
      )
      
      growth_info$total_growth <- list(
        estimate = pop_results$mean_total_growth_est %||% NA,
        se = pop_results$mean_total_growth_se %||% NA,
        ci_lower = pop_results$mean_total_growth_ci_lower %||% NA,
        ci_upper = pop_results$mean_total_growth_ci_upper %||% NA
      )
      
      growth_info$relative_growth <- list(
        estimate = pop_results$mean_relative_growth_est %||% NA,
        se = pop_results$mean_relative_growth_se %||% NA,
        ci_lower = pop_results$mean_relative_growth_ci_lower %||% NA,
        ci_upper = pop_results$mean_relative_growth_ci_upper %||% NA
      )
      
      growth_info$n_individuals <- pop_results$n_individuals
      
    } else {
      # Individual result
      ind_results <- get_individual_results(result, confidence_level)
      
      if (individual_id > nrow(ind_results)) {
        stop("Individual ID ", individual_id, " not found. Available: 1-", nrow(ind_results))
      }
      
      ind_data <- ind_results[individual_id, ]
      
      growth_info$initial_weight <- result$summary$initial_weight %||% NA  # Same for all individuals
      growth_info$final_weight <- list(
        estimate = ind_data$final_weight_est %||% NA,
        se = ind_data$final_weight_se %||% NA,
        ci_lower = ind_data$final_weight_ci_lower %||% NA,
        ci_upper = ind_data$final_weight_ci_upper %||% NA
      )
      
      growth_info$total_growth <- list(
        estimate = ind_data$total_growth_est %||% NA,
        se = ind_data$total_growth_se %||% NA,
        ci_lower = ind_data$total_growth_ci_lower %||% NA,
        ci_upper = ind_data$total_growth_ci_upper %||% NA
      )
      
      growth_info$relative_growth <- list(
        estimate = ind_data$relative_growth_est %||% NA,
        se = ind_data$relative_growth_se %||% NA,
        ci_lower = ind_data$relative_growth_ci_lower %||% NA,
        ci_upper = ind_data$relative_growth_ci_upper %||% NA
      )
      
      growth_info$p_value <- list(
        estimate = ind_data$p_estimate %||% NA,
        se = ind_data$p_se %||% NA
      )
    }
    
  } else {
    # Non-hierarchical methods
    growth_info$initial_weight <- result$summary$initial_weight %||% NA
    
    if (method == "mle" && result$model_info$backend == "tmb") {
      # MLE with TMB - has uncertainty
      tmb_unc <- result$method_data$tmb_uncertainty
      
      growth_info$final_weight <- list(
        estimate = tmb_unc$final_weight_est %||% result$summary$predicted_weight %||% NA,
        se = tmb_unc$final_weight_se %||% NA,
        ci_lower = NA,
        ci_upper = NA
      )
      
      growth_info$total_growth <- list(
        estimate = tmb_unc$total_growth_est %||% NA,
        se = tmb_unc$total_growth_se %||% NA,
        ci_lower = NA,
        ci_upper = NA
      )
      
      growth_info$relative_growth <- list(
        estimate = tmb_unc$relative_growth_est %||% NA,
        se = tmb_unc$relative_growth_se %||% NA,
        ci_lower = NA,
        ci_upper = NA
      )
      
      # Calculate CIs if we have estimates and SEs
      z <- z_score(confidence_level)
      for (metric in c("final_weight", "total_growth", "relative_growth")) {
        est <- growth_info[[metric]]$estimate
        se <- growth_info[[metric]]$se
        if (!is.na(est) && !is.na(se)) {
          growth_info[[metric]]$ci_lower <- est - z * se
          growth_info[[metric]]$ci_upper <- est + z * se
        }
      }
      
    } else {
      # Traditional methods or MLE without full uncertainty
      final_weight <- result$summary$final_weight %||% result$summary$predicted_weight %||% NA
      
      growth_info$final_weight <- list(
        estimate = final_weight,
        se = NA,
        ci_lower = NA,
        ci_upper = NA
      )
      
      if (!is.na(final_weight) && !is.na(growth_info$initial_weight)) {
        total_growth <- final_weight - growth_info$initial_weight
        relative_growth <- (final_weight / growth_info$initial_weight - 1) * 100
        
        growth_info$total_growth <- list(
          estimate = total_growth,
          se = NA,
          ci_lower = NA,
          ci_upper = NA
        )
        
        growth_info$relative_growth <- list(
          estimate = relative_growth,
          se = NA,
          ci_lower = NA,
          ci_upper = NA
        )
      }
    }
    
    # Add p_value information for fitted methods
    if (method %in% c("mle", "binary_search", "optim")) {
      growth_info$p_value <- list(
        estimate = result$summary$p_estimate %||% result$summary$p_value %||% NA,
        se = result$method_data$sigma_se %||% NA
      )
    }
  }
  
  # Calculate derived metrics
  duration <- result$summary$simulation_days %||% NA
  if (!is.na(duration) && !is.na(growth_info$total_growth$estimate)) {
    # Daily growth rate (absolute)
    growth_info$daily_growth_rate <- list(
      estimate = growth_info$total_growth$estimate / duration,
      se = if (!is.na(growth_info$total_growth$se)) growth_info$total_growth$se / duration else NA,
      ci_lower = if (!is.na(growth_info$total_growth$ci_lower)) growth_info$total_growth$ci_lower / duration else NA,
      ci_upper = if (!is.na(growth_info$total_growth$ci_upper)) growth_info$total_growth$ci_upper / duration else NA
    )
    
    # Specific growth rate (% per day)
    if (!is.na(growth_info$initial_weight) && !is.na(growth_info$final_weight$estimate)) {
      sgr <- log(growth_info$final_weight$estimate / growth_info$initial_weight) / duration * 100
      growth_info$specific_growth_rate <- list(
        estimate = sgr,
        se = NA,  # Would need delta method for proper SE
        ci_lower = NA,
        ci_upper = NA
      )
    }
  }
  
  return(growth_info)
}

# ============================================================================
# ENERGY BUDGET ANALYSIS FUNCTIONS
# ============================================================================

#' Analyze energy budget from FB4 results
#'
#' @description
#' Analyzes energy budget components from FB4 simulation results.
#' Calculates proportional allocation to different processes with
#' uncertainty propagation when available.
#'
#' @param result FB4 result object
#' @param individual_id Individual ID for hierarchical models (NULL for population/single individual)
#' @param confidence_level Confidence level for intervals (default 0.95)
#' @return A named list with four elements:
#'   \describe{
#'     \item{energy_components}{The list returned by
#'       \code{\link{get_energy_budget_uncertainty}}, containing six component
#'       sub-lists each with \code{estimate}, \code{se}, \code{ci_lower}, and
#'       \code{ci_upper}.}
#'     \item{proportions}{Named list of proportional allocations
#'       (\code{prop_respiration}, \code{prop_egestion}, \code{prop_excretion},
#'       \code{prop_sda}, \code{prop_net}), each a sub-list with \code{estimate},
#'       \code{se}, \code{ci_lower}, and \code{ci_upper}. \code{NULL} when
#'       consumption energy is zero or unavailable.}
#'     \item{summary_metrics}{Named list with \code{gross_growth_efficiency},
#'       \code{metabolic_scope}, and \code{assimilation_efficiency} sub-lists
#'       (each \code{estimate} + \code{se}). \code{NULL} when proportions are
#'       unavailable.}
#'     \item{balance_check}{Named list with \code{consumption_energy},
#'       \code{total_allocated}, \code{balance_error}, and
#'       \code{relative_error} (all numeric) to verify mass-balance closure.}
#'   }
#'   Plus the context scalars \code{method}, \code{has_uncertainty}, and
#'   \code{individual_id}.
#' @export
#' @examples
#' \donttest{
#' data(fish4_parameters)
#' sp   <- fish4_parameters[["Oncorhynchus tshawytscha"]]$life_stages$adult
#' info <- fish4_parameters[["Oncorhynchus tshawytscha"]]$species_info
#' bio  <- Bioenergetic(
#'   species_params     = sp,
#'   species_info       = info,
#'   environmental_data = list(
#'     temperature = data.frame(Day = 1:30, Temperature = rep(12, 30))
#'   ),
#'   diet_data = list(
#'     proportions = data.frame(Day = 1:30, Prey1 = 1.0),
#'     energies    = data.frame(Day = 1:30, Prey1 = 5000),
#'     prey_names  = "Prey1"
#'   ),
#'   simulation_settings = list(initial_weight = 100, duration = 30)
#' )
#' bio$species_params$predator$ED_ini <- 5000
#' bio$species_params$predator$ED_end <- 5500
#' result <- run_fb4(bio, strategy = "direct", p_value = 0.5, verbose = FALSE)
#' budget <- analyze_energy_budget(result)
#' }
analyze_energy_budget <- function(result, individual_id = NULL, confidence_level = 0.95) {
  
  if (!is.fb4_result(result)) {
    stop("Input must be an fb4_result object")
  }
  
  result_type <- detect_result_type(result)
  method <- result_type$method
  has_uncertainty <- result_type$has_uncertainty
  
  # Get energy budget components
  budget <- get_energy_budget_uncertainty(result, individual_id, confidence_level)
  
  # Initialize analysis result
  budget_analysis <- list(
    method = method,
    has_uncertainty = has_uncertainty,
    individual_id = individual_id,
    energy_components = budget
  )
  
  # Calculate energy proportions if consumption energy is available
  consumption_est <- budget$consumption_energy$estimate
  
  if (!is.na(consumption_est) && consumption_est > 0) {
    
    # Calculate proportions
    components <- c("respiration_energy", "egestion_energy", "excretion_energy", "sda_energy", "net_energy")
    
    budget_analysis$proportions <- list()
    
    for (component in components) {
      comp_est <- budget[[component]]$estimate
      comp_se <- budget[[component]]$se
      
      if (!is.na(comp_est)) {
        prop_est <- comp_est / consumption_est
        
        # Approximate SE for proportion using delta method
        prop_se <- NA
        if (!is.na(comp_se) && !is.na(budget$consumption_energy$se)) {
          # Delta method for ratio: Var(Y/X) ~ (Y/X)^2 * [Var(Y)/Y^2 + Var(X)/X^2 - 2*Cov(X,Y)/(X*Y)]
          # Assuming independence: Cov(X,Y) = 0
          cv_comp <- comp_se / comp_est
          cv_cons <- budget$consumption_energy$se / consumption_est
          prop_se <- prop_est * sqrt(cv_comp^2 + cv_cons^2)
        }
        
        prop_name <- gsub("_energy", "", component)
        budget_analysis$proportions[[paste0("prop_", prop_name)]] <- list(
          estimate = prop_est,
          se = prop_se,
          ci_lower = if (!is.na(prop_se)) prop_est - z_score(confidence_level) * prop_se else NA,
          ci_upper = if (!is.na(prop_se)) prop_est + z_score(confidence_level) * prop_se else NA
        )
      }
    }
    
    # Calculate summary metrics
    prop_respiration <- budget_analysis$proportions$prop_respiration$estimate %||% 0
    prop_sda <- budget_analysis$proportions$prop_sda$estimate %||% 0
    prop_net <- budget_analysis$proportions$prop_net$estimate %||% 0
    
    budget_analysis$summary_metrics <- list(
      gross_growth_efficiency = list(
        estimate = prop_net,
        se = budget_analysis$proportions$prop_net$se %||% NA
      ),
      metabolic_scope = list(
        estimate = prop_respiration + prop_sda,
        se = NA  # Would need covariance for proper SE
      ),
      assimilation_efficiency = list(
        estimate = 1 - (budget_analysis$proportions$prop_egestion$estimate %||% 0),
        se = budget_analysis$proportions$prop_egestion$se %||% NA
      )
    )
    
    # Energy balance check
    total_allocated <- sum(vapply(components, function(x) budget[[x]]$estimate %||% 0, numeric(1)))
    budget_analysis$balance_check <- list(
      consumption_energy = consumption_est,
      total_allocated = total_allocated,
      balance_error = abs(total_allocated - consumption_est),
      relative_error = abs(total_allocated - consumption_est) / consumption_est * 100
    )
    
  } else {
    budget_analysis$proportions <- NULL
    budget_analysis$summary_metrics <- NULL
    budget_analysis$balance_check <- list(
      consumption_energy = consumption_est,
      error = "Consumption energy not available or zero"
    )
  }
  
  return(budget_analysis)
}

# ============================================================================
# FEEDING ANALYSIS FUNCTIONS
# ============================================================================

#' Analyze feeding performance from FB4 results
#'
#' @description
#' Analyzes feeding-related metrics including consumption rates,
#' feeding efficiency, and p_value estimates with uncertainty.
#'
#' @param result FB4 result object
#' @param individual_id Individual ID for hierarchical models (NULL for population/single individual)
#' @param confidence_level Confidence level for intervals (default 0.95)
#' @return A named list with at minimum \code{method} (character),
#'   \code{has_uncertainty} (logical), and \code{individual_id}. Additional
#'   elements present when the relevant data are available:
#'   \describe{
#'     \item{total_consumption}{The list returned by
#'       \code{\link{get_consumption_uncertainty}} (\code{estimate}, \code{se},
#'       \code{ci_lower}, \code{ci_upper}, plus context scalars).}
#'     \item{daily_consumption}{Sub-list (\code{estimate}, \code{se},
#'       \code{ci_lower}, \code{ci_upper}) for the daily consumption rate
#'       (g/day).}
#'     \item{specific_consumption}{Sub-list (same four slots) for the
#'       specific consumption rate (g consumption / g fish / day).}
#'     \item{p_value}{Structure depends on method: for hierarchical it contains
#'       \code{population_mean}, \code{population_se}, \code{population_sd}, and
#'       \code{n_individuals}; for single-individual methods it contains
#'       \code{estimate}, \code{se}, \code{ci_lower}, and \code{ci_upper}.}
#'     \item{feeding_efficiency}{Sub-list (\code{estimate}, \code{se},
#'       \code{ci_lower}, \code{ci_upper}) for the ratio of total growth to
#'       total consumption (dimensionless).}
#'   }
#' @export
#' @examples
#' \donttest{
#' data(fish4_parameters)
#' sp   <- fish4_parameters[["Oncorhynchus tshawytscha"]]$life_stages$adult
#' info <- fish4_parameters[["Oncorhynchus tshawytscha"]]$species_info
#' bio  <- Bioenergetic(
#'   species_params     = sp,
#'   species_info       = info,
#'   environmental_data = list(
#'     temperature = data.frame(Day = 1:30, Temperature = rep(12, 30))
#'   ),
#'   diet_data = list(
#'     proportions = data.frame(Day = 1:30, Prey1 = 1.0),
#'     energies    = data.frame(Day = 1:30, Prey1 = 5000),
#'     prey_names  = "Prey1"
#'   ),
#'   simulation_settings = list(initial_weight = 100, duration = 30)
#' )
#' bio$species_params$predator$ED_ini <- 5000
#' bio$species_params$predator$ED_end <- 5500
#' result <- run_fb4(bio, strategy = "direct", p_value = 0.5, verbose = FALSE)
#' feeding <- analyze_feeding_performance(result)
#' }
analyze_feeding_performance <- function(result, individual_id = NULL, confidence_level = 0.95) {
  
  if (!is.fb4_result(result)) {
    stop("Input must be an fb4_result object")
  }
  
  result_type <- detect_result_type(result)
  method <- result_type$method
  
  # Get consumption data
  consumption <- get_consumption_uncertainty(result, individual_id, confidence_level)
  
  # Initialize feeding analysis
  feeding_analysis <- list(
    method = method,
    has_uncertainty = consumption$has_uncertainty,
    individual_id = individual_id
  )
  
  # Basic consumption metrics
  feeding_analysis$total_consumption <- consumption

  # Calculate consumption rates
  z               <- z_score(confidence_level)
  initial_weight  <- result$summary$initial_weight  %||% NA
  simulation_days <- result$summary$simulation_days %||% NA

  if (!is.na(consumption$estimate) && !is.na(initial_weight) && !is.na(simulation_days)) {

    # Daily consumption rate (g/day)
    daily_consumption    <- consumption$estimate / simulation_days
    daily_consumption_se <- if (!is.na(consumption$se)) consumption$se / simulation_days else NA

    feeding_analysis$daily_consumption <- list(
      estimate = daily_consumption,
      se       = daily_consumption_se,
      ci_lower = if (!is.na(daily_consumption_se)) daily_consumption - z * daily_consumption_se else NA,
      ci_upper = if (!is.na(daily_consumption_se)) daily_consumption + z * daily_consumption_se else NA
    )

    # Specific consumption rate (g consumption / g fish / day)
    specific_consumption    <- daily_consumption / initial_weight
    specific_consumption_se <- if (!is.na(daily_consumption_se)) daily_consumption_se / initial_weight else NA

    feeding_analysis$specific_consumption <- list(
      estimate = specific_consumption,
      se       = specific_consumption_se,
      ci_lower = if (!is.na(specific_consumption_se)) specific_consumption - z * specific_consumption_se else NA,
      ci_upper = if (!is.na(specific_consumption_se)) specific_consumption + z * specific_consumption_se else NA
    )
  }
  
  # p_value analysis (feeding rate)
  if (method == "hierarchical") {
    if (is.null(individual_id)) {
      # Population parameters
      pop_results <- get_population_results(result, confidence_level)
      feeding_analysis$p_value <- list(
        population_mean = pop_results$mu_p_estimate %||% NA,
        population_se = pop_results$mu_p_se %||% NA,
        population_sd = pop_results$sigma_p_estimate %||% NA,
        n_individuals = pop_results$n_individuals
      )
    } else {
      # Individual p_value
      ind_results <- get_individual_results(result, confidence_level)
      if (individual_id <= nrow(ind_results)) {
        feeding_analysis$p_value <- list(
          estimate = ind_results$p_estimate[individual_id] %||% NA,
          se = ind_results$p_se[individual_id] %||% NA
        )
      }
    }
  } else if (method %in% c("mle", "binary_search", "optim")) {
    # Single p_value estimate
    feeding_analysis$p_value <- list(
      estimate = result$summary$p_estimate %||% result$summary$p_value %||% NA,
      se = result$method_data$sigma_se %||% NA,
      ci_lower = result$method_data$confidence_intervals$p_ci_lower %||% NA,
      ci_upper = result$method_data$confidence_intervals$p_ci_upper %||% NA
    )
  }
  
  # Feeding efficiency (if growth data available)
  growth <- analyze_growth_patterns(result, individual_id, confidence_level)
  
  if (!is.na(growth$total_growth$estimate) && !is.na(consumption$estimate)) {
    feeding_efficiency <- growth$total_growth$estimate / consumption$estimate
    
    # Approximate SE using delta method
    feeding_efficiency_se <- NA
    if (!is.na(growth$total_growth$se) && !is.na(consumption$se)) {
      cv_growth <- growth$total_growth$se / growth$total_growth$estimate
      cv_consumption <- consumption$se / consumption$estimate
      feeding_efficiency_se <- feeding_efficiency * sqrt(cv_growth^2 + cv_consumption^2)
    }
    
    feeding_analysis$feeding_efficiency <- list(
      estimate = feeding_efficiency,
      se       = feeding_efficiency_se,
      ci_lower = if (!is.na(feeding_efficiency_se)) feeding_efficiency - z * feeding_efficiency_se else NA,
      ci_upper = if (!is.na(feeding_efficiency_se)) feeding_efficiency + z * feeding_efficiency_se else NA
    )
  }
  
  return(feeding_analysis)
}

# ============================================================================
# SUMMARY STATISTICS FUNCTIONS
# ============================================================================

#' Comprehensive post-simulation analysis summary
#'
#' @description
#' **Post-hoc analysis function** — takes a finished \code{fb4_result} object
#' and bundles growth, feeding, and energy-budget analyses into a single list.
#' Useful when you need all major metrics in one call.
#'
#' This is different from the internal \code{$summary} slot (built automatically
#' during result construction by \code{create_unified_summary()}). This function
#' re-derives richer metrics from \code{daily_output} and supports uncertainty
#' propagation for MLE / bootstrap / hierarchical results.
#'
#' @param result An \code{fb4_result} object returned by \code{run_fb4()}
#' @param individual_id For hierarchical models: individual ID to extract
#'   (\code{NULL} returns population-level summary)
#' @param confidence_level Confidence level for uncertainty intervals, default 0.95
#' @return Named list with \code{model_info}, \code{growth}, \code{feeding},
#'   \code{energy_budget}, and \code{model_fit} sections
#' @seealso \code{\link{analyze_growth_patterns}}, \code{\link{analyze_feeding_performance}},
#'   \code{\link{analyze_energy_budget}}
#' @export
create_result_summary <- function(result, individual_id = NULL, confidence_level = 0.95) {
  
  if (!is.fb4_result(result)) {
    stop("Input must be an fb4_result object")
  }
  
  # Get all major analyses
  growth <- analyze_growth_patterns(result, individual_id, confidence_level)
  feeding <- analyze_feeding_performance(result, individual_id, confidence_level)
  budget <- analyze_energy_budget(result, individual_id, confidence_level)
  
  summary_result <- list(
    # Model information
    model_info = list(
      method = result$summary$method,
      backend = result$model_info$backend,
      has_uncertainty = growth$has_uncertainty,
      individual_id = individual_id,
      confidence_level = confidence_level
    ),
    
    # Growth metrics
    growth = list(
      initial_weight = growth$initial_weight,
      final_weight = growth$final_weight,
      total_growth = growth$total_growth,
      relative_growth = growth$relative_growth,
      daily_growth_rate = growth$daily_growth_rate,
      specific_growth_rate = growth$specific_growth_rate
    ),
    
    # Feeding metrics
    feeding = list(
      total_consumption = feeding$total_consumption,
      daily_consumption = feeding$daily_consumption,
      specific_consumption = feeding$specific_consumption,
      p_value = feeding$p_value,
      feeding_efficiency = feeding$feeding_efficiency
    ),
    
    # Energy budget
    energy_budget = list(
      components = budget$energy_components,
      proportions = budget$proportions,
      summary_metrics = budget$summary_metrics,
      balance_check = budget$balance_check
    ),
    
    # Model fit (for statistical methods)
    model_fit = if (result$summary$method %in% c("mle", "hierarchical")) {
      list(
        converged = result$summary$converged,
        log_likelihood = result$method_data$model_fit$log_likelihood %||% result$method_data$log_likelihood,
        aic = result$method_data$model_fit$aic %||% result$method_data$aic,
        bic = result$method_data$model_fit$bic %||% result$method_data$bic
      )
    } else {
      list(
        converged = result$summary$converged %||% TRUE
      )
    }
  )
  
  return(summary_result)
}

Try the fb4package package in your browser

Any scripts or data that you put into this service are public.

fb4package documentation built on May 8, 2026, 1:07 a.m.