ecological-agent-skills 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENT_CONTEXT.md +191 -0
- package/CATALOG.md +329 -0
- package/LICENSE +692 -0
- package/README.md +347 -0
- package/bin/install.mjs +168 -0
- package/docs/comparison-with-alternatives.md +38 -0
- package/docs/global-examples-index.md +103 -0
- package/docs/repository-statistics.md +101 -0
- package/docs/theoretical-foundations.md +188 -0
- package/environment.yaml +106 -0
- package/examples/community/arctic_tundra_vegetation_example.md +247 -0
- package/examples/community/bird_landuse_example.md +63 -0
- package/examples/community/phytoplankton_reservoir_example.md +60 -0
- package/examples/community/reef_fish_indopacific_example.md +221 -0
- package/examples/impact/baci_road_example.md +57 -0
- package/examples/impact/ecosystem_services_atlantic_forest.md +83 -0
- package/examples/impact/forest_loss_borneo_timeseries_example.md +225 -0
- package/examples/occupancy/puma_camera_example.md +61 -0
- package/examples/occupancy/snow_leopard_himalayas_example.md +204 -0
- package/examples/reproducible/whittaker_biome_sdm_example.md +406 -0
- package/examples/sdm/anteater_cerrado_example.md +69 -0
- package/examples/sdm/jaguar_amazon_example.md +80 -0
- package/examples/sdm/koala_climate_change_example.md +170 -0
- package/examples/sdm/wolf_recolonization_europe_example.md +193 -0
- package/package.json +43 -0
- package/renv.lock +194 -0
- package/skills/SKILL_INDEX.json +1020 -0
- package/skills/acoustic-monitoring/SKILL.md +163 -0
- package/skills/acoustic-monitoring/examples/example-prompts.md +100 -0
- package/skills/acoustic-monitoring/examples/temperate_forest_birds_example.md +285 -0
- package/skills/acoustic-monitoring/resources/acoustic-indices-reference.md +93 -0
- package/skills/acoustic-monitoring/resources/soundscape-ecology-guide.md +90 -0
- package/skills/acoustic-monitoring/resources/species-id-tools-comparison.md +89 -0
- package/skills/acoustic-monitoring/scripts/batch_species_detection.py +360 -0
- package/skills/acoustic-monitoring/scripts/compute_acoustic_indices.R +235 -0
- package/skills/acoustic-monitoring/scripts/compute_acoustic_indices.py +374 -0
- package/skills/biostatistics-workbench/SKILL.md +140 -0
- package/skills/biostatistics-workbench/examples/example-prompts.md +39 -0
- package/skills/biostatistics-workbench/resources/effect-size-reference.md +81 -0
- package/skills/biostatistics-workbench/resources/glm-family-link-reference.md +47 -0
- package/skills/biostatistics-workbench/resources/test-selection-guide.md +93 -0
- package/skills/biostatistics-workbench/scripts/glm_pipeline.R +78 -0
- package/skills/biostatistics-workbench/scripts/glm_pipeline.py +210 -0
- package/skills/camera-trap-processing/SKILL.md +159 -0
- package/skills/camera-trap-processing/examples/example-prompts.md +103 -0
- package/skills/camera-trap-processing/examples/leopard_serengeti_example.md +231 -0
- package/skills/camera-trap-processing/resources/activity-patterns-reference.md +113 -0
- package/skills/camera-trap-processing/resources/camtrapR-workflow-guide.md +130 -0
- package/skills/camera-trap-processing/resources/detection-event-definition-guide.md +89 -0
- package/skills/camera-trap-processing/scripts/estimate_activity.R +169 -0
- package/skills/camera-trap-processing/scripts/process_camtrap_data.R +179 -0
- package/skills/camera-trap-processing/scripts/process_camtrap_data.py +192 -0
- package/skills/community-ecology-ordination/SKILL.md +133 -0
- package/skills/community-ecology-ordination/examples/example-prompts.md +35 -0
- package/skills/community-ecology-ordination/resources/dissimilarity-metric-guide.md +53 -0
- package/skills/community-ecology-ordination/resources/nmds-interpretation-guide.md +104 -0
- package/skills/community-ecology-ordination/scripts/__pycache__/community_analysis.cpython-311.pyc +0 -0
- package/skills/community-ecology-ordination/scripts/community_analysis.R +143 -0
- package/skills/community-ecology-ordination/scripts/community_analysis.py +231 -0
- package/skills/ecological-data-foundation/SKILL.md +129 -0
- package/skills/ecological-data-foundation/examples/example-prompts.md +40 -0
- package/skills/ecological-data-foundation/resources/coordinate-cleaning-flags.md +66 -0
- package/skills/ecological-data-foundation/resources/darwin-core-glossary.md +91 -0
- package/skills/ecological-data-foundation/resources/data-citation-guide.md +265 -0
- package/skills/ecological-data-foundation/resources/gbif-data-citation-guide.md +193 -0
- package/skills/ecological-data-foundation/resources/qa-checklist.md +83 -0
- package/skills/ecological-data-foundation/scripts/__pycache__/clean_occurrences.cpython-311.pyc +0 -0
- package/skills/ecological-data-foundation/scripts/__pycache__/download_from_ebird.cpython-311.pyc +0 -0
- package/skills/ecological-data-foundation/scripts/__pycache__/download_from_inat.cpython-311.pyc +0 -0
- package/skills/ecological-data-foundation/scripts/__pycache__/download_from_iucn.cpython-311.pyc +0 -0
- package/skills/ecological-data-foundation/scripts/__pycache__/download_from_obis.cpython-311.pyc +0 -0
- package/skills/ecological-data-foundation/scripts/clean_occurrences.R +230 -0
- package/skills/ecological-data-foundation/scripts/clean_occurrences.py +268 -0
- package/skills/ecological-data-foundation/scripts/download_from_ebird.R +251 -0
- package/skills/ecological-data-foundation/scripts/download_from_ebird.py +364 -0
- package/skills/ecological-data-foundation/scripts/download_from_gbif.R +315 -0
- package/skills/ecological-data-foundation/scripts/download_from_gbif.py +407 -0
- package/skills/ecological-data-foundation/scripts/download_from_inat.R +238 -0
- package/skills/ecological-data-foundation/scripts/download_from_inat.py +304 -0
- package/skills/ecological-data-foundation/scripts/download_from_iucn.R +273 -0
- package/skills/ecological-data-foundation/scripts/download_from_iucn.py +344 -0
- package/skills/ecological-data-foundation/scripts/download_from_obis.R +248 -0
- package/skills/ecological-data-foundation/scripts/download_from_obis.py +318 -0
- package/skills/ecological-impact-assessment/SKILL.md +123 -0
- package/skills/ecological-impact-assessment/examples/example-prompts.md +32 -0
- package/skills/ecological-impact-assessment/resources/baci-design-guide.md +55 -0
- package/skills/ecological-impact-assessment/resources/fragmentation-metrics-reference.md +86 -0
- package/skills/ecological-impact-assessment/resources/pressure-index-template.md +78 -0
- package/skills/ecological-impact-assessment/resources/study-design-guide.md +168 -0
- package/skills/ecological-impact-assessment/scripts/baci_analysis.R +161 -0
- package/skills/ecological-impact-assessment/scripts/fragmentation_analysis.py +141 -0
- package/skills/ecological-impact-assessment/scripts/power_analysis_baci.R +274 -0
- package/skills/ecosystem-services-assessment/SKILL.md +125 -0
- package/skills/ecosystem-services-assessment/examples/example-prompts.md +24 -0
- package/skills/ecosystem-services-assessment/resources/es-indicator-reference.md +45 -0
- package/skills/ecosystem-services-assessment/resources/invest-parameter-guide.md +86 -0
- package/skills/ecosystem-services-assessment/resources/rusle-coefficients.md +88 -0
- package/skills/ecosystem-services-assessment/scripts/__pycache__/compute_es.cpython-311.pyc +0 -0
- package/skills/ecosystem-services-assessment/scripts/compute_es.py +189 -0
- package/skills/ecosystem-services-assessment/scripts/tradeoff_analysis.R +161 -0
- package/skills/environmental-time-series/SKILL.md +125 -0
- package/skills/environmental-time-series/examples/example-prompts.md +33 -0
- package/skills/environmental-time-series/resources/anomaly-indices-reference.md +88 -0
- package/skills/environmental-time-series/resources/bfast-parameter-guide.md +69 -0
- package/skills/environmental-time-series/scripts/__pycache__/recovery_trajectory.cpython-311.pyc +0 -0
- package/skills/environmental-time-series/scripts/__pycache__/trend_analysis.cpython-311.pyc +0 -0
- package/skills/environmental-time-series/scripts/recovery_trajectory.R +305 -0
- package/skills/environmental-time-series/scripts/recovery_trajectory.py +178 -0
- package/skills/environmental-time-series/scripts/trend_analysis.R +192 -0
- package/skills/environmental-time-series/scripts/trend_analysis.py +184 -0
- package/skills/geoprocessing-for-ecology/SKILL.md +123 -0
- package/skills/geoprocessing-for-ecology/examples/example-prompts.md +32 -0
- package/skills/geoprocessing-for-ecology/resources/crs-reference.md +62 -0
- package/skills/geoprocessing-for-ecology/resources/global-predictor-sources.md +331 -0
- package/skills/geoprocessing-for-ecology/resources/resampling-methods.md +57 -0
- package/skills/geoprocessing-for-ecology/scripts/__pycache__/download_predictors.cpython-311.pyc +0 -0
- package/skills/geoprocessing-for-ecology/scripts/download_predictors.R +239 -0
- package/skills/geoprocessing-for-ecology/scripts/download_predictors.py +379 -0
- package/skills/geoprocessing-for-ecology/scripts/stack_and_extract.R +224 -0
- package/skills/geoprocessing-for-ecology/scripts/stack_and_extract.py +172 -0
- package/skills/landscape-connectivity/SKILL.md +170 -0
- package/skills/landscape-connectivity/examples/example-prompts.md +96 -0
- package/skills/landscape-connectivity/examples/jaguar_mesoamerica_corridor_example.md +271 -0
- package/skills/landscape-connectivity/resources/circuitscape-parameter-guide.md +155 -0
- package/skills/landscape-connectivity/resources/graph-theory-for-ecology.md +134 -0
- package/skills/landscape-connectivity/resources/resistance-surface-guide.md +141 -0
- package/skills/landscape-connectivity/scripts/connectivity_analysis.py +387 -0
- package/skills/landscape-connectivity/scripts/connectivity_metrics.R +274 -0
- package/skills/landscape-connectivity/scripts/resistance_surface.R +239 -0
- package/skills/model-validation-and-uncertainty/SKILL.md +131 -0
- package/skills/model-validation-and-uncertainty/examples/example-prompts.md +30 -0
- package/skills/model-validation-and-uncertainty/resources/extrapolation-risk-guide.md +236 -0
- package/skills/model-validation-and-uncertainty/resources/metric-selection-guide.md +52 -0
- package/skills/model-validation-and-uncertainty/resources/threshold-selection-guide.md +64 -0
- package/skills/model-validation-and-uncertainty/scripts/__pycache__/validate_model.cpython-311.pyc +0 -0
- package/skills/model-validation-and-uncertainty/scripts/extrapolation_risk.R +315 -0
- package/skills/model-validation-and-uncertainty/scripts/validate_model.py +226 -0
- package/skills/model-validation-and-uncertainty/scripts/validate_sdm.R +162 -0
- package/skills/occupancy-and-detection/SKILL.md +126 -0
- package/skills/occupancy-and-detection/examples/example-prompts.md +33 -0
- package/skills/occupancy-and-detection/resources/detection-history-format.md +100 -0
- package/skills/occupancy-and-detection/resources/occupancy-study-design.md +47 -0
- package/skills/occupancy-and-detection/scripts/__pycache__/occupancy_analysis.cpython-311.pyc +0 -0
- package/skills/occupancy-and-detection/scripts/occupancy_analysis.R +160 -0
- package/skills/occupancy-and-detection/scripts/occupancy_analysis.py +159 -0
- package/skills/population-viability-analysis/SKILL.md +161 -0
- package/skills/population-viability-analysis/examples/african_elephant_pva_example.md +266 -0
- package/skills/population-viability-analysis/examples/example-prompts.md +95 -0
- package/skills/population-viability-analysis/resources/extinction-risk-thresholds.md +128 -0
- package/skills/population-viability-analysis/resources/matrix-model-guide.md +139 -0
- package/skills/population-viability-analysis/resources/sensitivity-elasticity-reference.md +182 -0
- package/skills/population-viability-analysis/scripts/matrix_pva.R +258 -0
- package/skills/population-viability-analysis/scripts/pva_analysis.py +442 -0
- package/skills/population-viability-analysis/scripts/stochastic_pva.R +353 -0
- package/skills/predictive-modeling-best-practices/SKILL.md +136 -0
- package/skills/predictive-modeling-best-practices/examples/example-prompts.md +58 -0
- package/skills/predictive-modeling-best-practices/resources/collinearity-decision-tree.md +65 -0
- package/skills/predictive-modeling-best-practices/resources/sampling-bias-correction.md +267 -0
- package/skills/predictive-modeling-best-practices/resources/spatial-cv-guide.md +73 -0
- package/skills/predictive-modeling-best-practices/scripts/__pycache__/spatial_cv.cpython-311.pyc +0 -0
- package/skills/predictive-modeling-best-practices/scripts/collinearity_check.R +112 -0
- package/skills/predictive-modeling-best-practices/scripts/spatial_cv.py +182 -0
- package/skills/reproducible-ecology-pipeline/SKILL.md +139 -0
- package/skills/reproducible-ecology-pipeline/examples/example-prompts.md +35 -0
- package/skills/reproducible-ecology-pipeline/resources/directory-structure-template.md +94 -0
- package/skills/reproducible-ecology-pipeline/resources/params-yaml-template.yaml +84 -0
- package/skills/reproducible-ecology-pipeline/resources/reproducibility-checklist-template.md +66 -0
- package/skills/reproducible-ecology-pipeline/scripts/generate_file_manifest.py +110 -0
- package/skills/reproducible-ecology-pipeline/scripts/init_project.sh +53 -0
- package/skills/spatial-prioritization/SKILL.md +162 -0
- package/skills/spatial-prioritization/examples/biodiversity_hotspot_prioritization_example.md +289 -0
- package/skills/spatial-prioritization/examples/example-prompts.md +93 -0
- package/skills/spatial-prioritization/resources/cost-surface-reference.md +130 -0
- package/skills/spatial-prioritization/resources/marxan-vs-prioritizr-comparison.md +125 -0
- package/skills/spatial-prioritization/resources/prioritizr-formulation-guide.md +188 -0
- package/skills/spatial-prioritization/resources/representation-targets-guide.md +186 -0
- package/skills/spatial-prioritization/scripts/prioritization_sensitivity.R +320 -0
- package/skills/spatial-prioritization/scripts/run_prioritization.R +336 -0
- package/skills/species-distribution-modeling/SKILL.md +139 -0
- package/skills/species-distribution-modeling/examples/example-prompts.md +36 -0
- package/skills/species-distribution-modeling/resources/algorithm-comparison.md +25 -0
- package/skills/species-distribution-modeling/resources/calibration-area-guide.md +71 -0
- package/skills/species-distribution-modeling/resources/climate-scenario-preparation.md +170 -0
- package/skills/species-distribution-modeling/resources/maxent-calibration-guide.md +211 -0
- package/skills/species-distribution-modeling/resources/sdm-checklist.md +37 -0
- package/skills/species-distribution-modeling/scripts/predict_distribution.R +236 -0
- package/skills/species-distribution-modeling/scripts/predict_distribution.py +286 -0
- package/skills/species-distribution-modeling/scripts/prepare_future_layers.R +351 -0
- package/skills/species-distribution-modeling/scripts/project_scenarios.R +220 -0
- package/skills/species-distribution-modeling/scripts/run_ensemble_sdm.R +99 -0
- package/skills/species-distribution-modeling/scripts/sdm_pipeline.py +318 -0
- package/skills/species-distribution-modeling/scripts/tune_maxnet.R +344 -0
- package/templates/SKILL_TEMPLATE.md +225 -0
- package/templates/checklists/data-submission-checklist.md +38 -0
- package/templates/checklists/post-analysis-checklist.md +55 -0
- package/templates/checklists/pre-analysis-checklist.md +31 -0
- package/templates/prompts/debug-skill.md +47 -0
- package/templates/prompts/invoke-skill.md +34 -0
- package/templates/prompts/invoke-workflow.md +45 -0
- package/templates/reports/technical-report-template.md +80 -0
- package/templates/scripts/logger_setup.R +79 -0
- package/templates/scripts/logger_setup.py +119 -0
- package/templates/scripts/params_loader.R +28 -0
- package/templates/scripts/params_loader.py +38 -0
- package/workflows/analyze-community-structure/WORKFLOW.md +72 -0
- package/workflows/analyze-environmental-change/WORKFLOW.md +73 -0
- package/workflows/assess-ecological-impact/WORKFLOW.md +75 -0
- package/workflows/assess-ecosystem-services/WORKFLOW.md +68 -0
- package/workflows/assess-landscape-connectivity/WORKFLOW.md +84 -0
- package/workflows/build-fire-risk-map/WORKFLOW.md +79 -0
- package/workflows/produce-technical-report/WORKFLOW.md +113 -0
- package/workflows/run-camera-trap-occupancy/WORKFLOW.md +87 -0
- package/workflows/run-conservation-prioritization/WORKFLOW.md +89 -0
- package/workflows/run-multispecies-screening/WORKFLOW.md +197 -0
- package/workflows/run-occupancy-analysis/WORKFLOW.md +74 -0
- package/workflows/run-population-viability/WORKFLOW.md +90 -0
- package/workflows/run-sdm-study/WORKFLOW.md +99 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Occupancy Study Design Reference
|
|
2
|
+
|
|
3
|
+
## Minimum Survey Requirements
|
|
4
|
+
|
|
5
|
+
### Rule of Thumb
|
|
6
|
+
- **Sites:** ≥ 30 sites (≥ 50 recommended for covariate estimation)
|
|
7
|
+
- **Surveys per site:** ≥ 3 repeat visits within a closed season
|
|
8
|
+
- **Detection probability:** If p > 0.3, fewer sites needed; if p < 0.1, many more required
|
|
9
|
+
|
|
10
|
+
### MacKenzie & Royle (2005) Guidelines
|
|
11
|
+
|
|
12
|
+
For 95% confidence that all sites with ψ > threshold are detected with K surveys:
|
|
13
|
+
|
|
14
|
+
| ψ (occupancy) | p (detection) | Sites needed | Surveys/site |
|
|
15
|
+
|--------------|--------------|-------------|-------------|
|
|
16
|
+
| 0.5 | 0.5 | 20 | 3 |
|
|
17
|
+
| 0.5 | 0.3 | 30 | 5 |
|
|
18
|
+
| 0.3 | 0.5 | 35 | 3 |
|
|
19
|
+
| 0.3 | 0.3 | 50 | 5 |
|
|
20
|
+
| 0.1 | 0.5 | 100 | 3 |
|
|
21
|
+
| 0.1 | 0.3 | 150 | 5 |
|
|
22
|
+
|
|
23
|
+
### Confirming Absence
|
|
24
|
+
Minimum surveys to confirm absence with confidence 1−α:
|
|
25
|
+
|
|
26
|
+
K ≥ log(α) / log(1 − p)
|
|
27
|
+
|
|
28
|
+
Example: p = 0.3, α = 0.05 → K ≥ log(0.05)/log(0.7) ≈ 8.4 → 9 surveys
|
|
29
|
+
|
|
30
|
+
## Closure Assumption
|
|
31
|
+
|
|
32
|
+
The population must be **closed** (no births, deaths, immigration, emigration) within a season. Practical guidelines:
|
|
33
|
+
- Mammals: typically 1–4 weeks per season
|
|
34
|
+
- Birds (breeding): 2–6 weeks
|
|
35
|
+
- Amphibians (breeding): days to 2 weeks
|
|
36
|
+
- If closure is uncertain: use dynamic (multi-season) model or robust design
|
|
37
|
+
|
|
38
|
+
## Common Protocols by Taxa
|
|
39
|
+
|
|
40
|
+
| Taxa | Protocol | Primary p covariate |
|
|
41
|
+
|------|---------|-------------------|
|
|
42
|
+
| Large mammals | Camera trap | Trap-nights (effort) |
|
|
43
|
+
| Birds | Point count | Observer, time of day |
|
|
44
|
+
| Amphibians | Acoustic survey | Temperature, rainfall |
|
|
45
|
+
| Reptiles | Visual encounter | Temperature, time of day |
|
|
46
|
+
| Bats | Acoustic detector | Night, temperature |
|
|
47
|
+
| Plants | Plot survey | Surveyor, season |
|
|
Binary file
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# ecological-agent-skills / Copyright (C) 2026 Francisco Diego Barros Barata
|
|
2
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
3
|
+
|
|
4
|
+
# Usage: Rscript occupancy_analysis.R <detection_history.csv> <site_covariates.csv> <output_dir>
|
|
5
|
+
# Single-season occupancy analysis with model selection
|
|
6
|
+
# Usage: Rscript occupancy_analysis.R <detection_history_csv> <site_cov_csv> <output_dir>
|
|
7
|
+
# Requires: unmarked, dplyr
|
|
8
|
+
|
|
9
|
+
# ── Inline logger ─────────────────────────────────────────────────────────────
|
|
10
|
+
SKILL_NAME <- "occupancy-and-detection"
|
|
11
|
+
.log_ts <- function() format(Sys.time(), "[%Y-%m-%d %H:%M:%S]")
|
|
12
|
+
log_info <- function(...) message(.log_ts(), " [INFO] ", sprintf(...))
|
|
13
|
+
log_warn <- function(...) message(.log_ts(), " [WARN] ", sprintf(...))
|
|
14
|
+
log_error<- function(...) message(.log_ts(), " [ERROR] ", sprintf(...))
|
|
15
|
+
log_step <- function(n, d) log_info("-- STEP %d: %s", n, d)
|
|
16
|
+
log_decision <- function(v, val, why) log_info("DECISION | %s = %s | %s", v, val, why)
|
|
17
|
+
dir.create("logs", recursive=TRUE, showWarnings=FALSE)
|
|
18
|
+
|
|
19
|
+
suppressPackageStartupMessages({
|
|
20
|
+
library(unmarked)
|
|
21
|
+
library(dplyr)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
args <- commandArgs(trailingOnly = TRUE)
|
|
25
|
+
dh_file <- ifelse(length(args) >= 1, args[1], "data/detection_history.csv")
|
|
26
|
+
sc_file <- ifelse(length(args) >= 2, args[2], "data/site_covariates.csv")
|
|
27
|
+
output_dir <- ifelse(length(args) >= 3, args[3], "outputs/occupancy")
|
|
28
|
+
|
|
29
|
+
log_step(1, "Validate inputs")
|
|
30
|
+
if (!file.exists(dh_file)) {
|
|
31
|
+
log_error(
|
|
32
|
+
"Falha em validate inputs: arquivo de historico de deteccao nao encontrado: %s\nCausa provavel: caminho incorreto ou arquivo nao gerado\nVerifique: o argumento detection_history_csv e o diretorio de trabalho\nSkill anterior: data-cleaning",
|
|
33
|
+
dh_file
|
|
34
|
+
)
|
|
35
|
+
stop("Detection history file not found.")
|
|
36
|
+
}
|
|
37
|
+
if (!file.exists(sc_file)) {
|
|
38
|
+
log_error(
|
|
39
|
+
"Falha em validate inputs: arquivo de covariadas de sitio nao encontrado: %s\nCausa provavel: caminho incorreto ou arquivo nao gerado\nVerifique: o argumento site_cov_csv e o diretorio de trabalho\nSkill anterior: data-cleaning",
|
|
40
|
+
sc_file
|
|
41
|
+
)
|
|
42
|
+
stop("Site covariates file not found.")
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
dir.create(output_dir, recursive = TRUE, showWarnings = FALSE)
|
|
46
|
+
|
|
47
|
+
log_step(2, "Load detection history and site covariates")
|
|
48
|
+
tryCatch({
|
|
49
|
+
dh <- as.matrix(read.csv(dh_file, row.names = 1))
|
|
50
|
+
sc <- read.csv(sc_file, row.names = 1)
|
|
51
|
+
}, error = function(e) {
|
|
52
|
+
log_error(
|
|
53
|
+
"Falha em load data: %s\nCausa provavel: CSV malformado ou sem coluna de rownames\nVerifique: estrutura dos arquivos (primeira coluna deve ser site ID)\nSkill anterior: data-cleaning",
|
|
54
|
+
conditionMessage(e)
|
|
55
|
+
)
|
|
56
|
+
stop(e)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
log_info("Sites: %d | Survey occasions: %d", nrow(dh), ncol(dh))
|
|
60
|
+
|
|
61
|
+
n_all_na <- sum(apply(is.na(dh), 1, all))
|
|
62
|
+
if (n_all_na > 0) {
|
|
63
|
+
log_warn("%d sites have all-NA detection histories. These will cause issues in unmarked. Consider removing them.", n_all_na)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
valid_vals <- dh[!is.na(dh)]
|
|
67
|
+
if (any(!valid_vals %in% c(0, 1))) {
|
|
68
|
+
log_warn("Detection history contains values other than 0, 1, or NA. Check your input data for coding errors.")
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
naive_occ <- mean(rowSums(dh, na.rm=TRUE) > 0)
|
|
72
|
+
log_info("Naive occupancy: %.3f", naive_occ)
|
|
73
|
+
if (naive_occ < 0.05) {
|
|
74
|
+
log_warn("Naive occupancy = %.3f is very low (<5%%). Occupancy models may have poor identifiability.", naive_occ)
|
|
75
|
+
}
|
|
76
|
+
if (naive_occ > 0.95) {
|
|
77
|
+
log_warn("Naive occupancy = %.3f is very high (>95%%). Consider whether species is truly absent from any sites.", naive_occ)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
log_step(3, "Standardise site covariates")
|
|
81
|
+
log_decision("covariate_scaling", "z-score (scale())", "standardisation improves model convergence and coefficient comparability")
|
|
82
|
+
tryCatch({
|
|
83
|
+
sc_std <- sc |> mutate(across(where(is.numeric), scale))
|
|
84
|
+
log_info("Covariates standardised: %s", paste(names(sc_std), collapse = ", "))
|
|
85
|
+
}, error = function(e) {
|
|
86
|
+
log_error(
|
|
87
|
+
"Falha em standardise covariates: %s\nCausa provavel: covariadas nao numericas ou com NA\nVerifique: tipos de dados e completude do arquivo de covariadas\nSkill anterior: data-cleaning",
|
|
88
|
+
conditionMessage(e)
|
|
89
|
+
)
|
|
90
|
+
stop(e)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
log_step(4, "Build unmarkedFrameOccu")
|
|
94
|
+
tryCatch({
|
|
95
|
+
umf <- unmarkedFrameOccu(y = dh, siteCovs = sc_std)
|
|
96
|
+
log_info("unmarkedFrameOccu built successfully.")
|
|
97
|
+
}, error = function(e) {
|
|
98
|
+
log_error(
|
|
99
|
+
"Falha em unmarkedFrameOccu: %s\nCausa provavel: numero de sites diverge entre dh e sc, ou valores invalidos em dh\nVerifique: que dh e sc tem o mesmo numero de linhas e mesmos site IDs\nSkill anterior: data-cleaning",
|
|
100
|
+
conditionMessage(e)
|
|
101
|
+
)
|
|
102
|
+
stop(e)
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
log_step(5, "Fit candidate occupancy models")
|
|
106
|
+
tryCatch({
|
|
107
|
+
m0 <- occu(~1 ~1, data = umf)
|
|
108
|
+
log_info("Null model fitted.")
|
|
109
|
+
|
|
110
|
+
# Add your candidate models here:
|
|
111
|
+
# m1 <- occu(~effort ~forest_cover, data = umf)
|
|
112
|
+
# m2 <- occu(~effort ~forest_cover + dist_road, data = umf)
|
|
113
|
+
}, error = function(e) {
|
|
114
|
+
log_error(
|
|
115
|
+
"Falha em occu() fitting: %s\nCausa provavel: dados insuficientes, covariadas com NA, ou singularidade numerica\nVerifique: numero de sitios detectados vs nao detectados e completude de covariadas\nSkill anterior: occupancy-and-detection (data formatting)",
|
|
116
|
+
conditionMessage(e)
|
|
117
|
+
)
|
|
118
|
+
stop(e)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
log_step(6, "Model selection")
|
|
122
|
+
tryCatch({
|
|
123
|
+
model_list <- fitList(null = m0)
|
|
124
|
+
ms <- modSel(model_list)
|
|
125
|
+
log_info("Model selection table:\n%s", paste(capture.output(ms), collapse = "\n"))
|
|
126
|
+
write.csv(as(ms, "data.frame"), file.path(output_dir, "model_selection_table.csv"))
|
|
127
|
+
log_info("Model selection table saved.")
|
|
128
|
+
}, error = function(e) {
|
|
129
|
+
log_error(
|
|
130
|
+
"Falha em model selection: %s\nCausa provavel: nenhum modelo ajustado com sucesso\nVerifique: etapa de fitting para mensagens de erro anteriores\nSkill anterior: occupancy-and-detection (fitting)",
|
|
131
|
+
conditionMessage(e)
|
|
132
|
+
)
|
|
133
|
+
stop(e)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
log_step(7, "Summarise best model and back-predict occupancy")
|
|
137
|
+
tryCatch({
|
|
138
|
+
log_info("Null model summary:\n%s", paste(capture.output(print(m0)), collapse = "\n"))
|
|
139
|
+
|
|
140
|
+
psi_pred <- predict(m0, type = "state")
|
|
141
|
+
p_pred <- predict(m0, type = "det")
|
|
142
|
+
log_info("Mean occupancy (psi): %.3f 95%% CI [%.3f, %.3f]",
|
|
143
|
+
mean(psi_pred$Predicted), mean(psi_pred$lower), mean(psi_pred$upper))
|
|
144
|
+
log_info("Mean detection (p): %.3f 95%% CI [%.3f, %.3f]",
|
|
145
|
+
mean(p_pred$Predicted), mean(p_pred$lower), mean(p_pred$upper))
|
|
146
|
+
|
|
147
|
+
if (mean(psi_pred$Predicted) < 0.1) {
|
|
148
|
+
log_warn("Estimated occupancy = %.3f is very low. Verify species is not cryptic or camera placement is adequate.", mean(psi_pred$Predicted))
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
write.csv(psi_pred, file.path(output_dir, "occupancy_estimates.csv"), row.names = FALSE)
|
|
152
|
+
write.csv(p_pred, file.path(output_dir, "detection_estimates.csv"), row.names = FALSE)
|
|
153
|
+
log_info("Outputs written to: %s", output_dir)
|
|
154
|
+
}, error = function(e) {
|
|
155
|
+
log_error(
|
|
156
|
+
"Falha em predict/summary: %s\nCausa provavel: modelo nao convergiu ou objeto umf invalido\nVerifique: avisos de convergencia do unmarked durante o fitting\nSkill anterior: occupancy-and-detection (fitting)",
|
|
157
|
+
conditionMessage(e)
|
|
158
|
+
)
|
|
159
|
+
stop(e)
|
|
160
|
+
})
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# ecological-agent-skills / Copyright (C) 2026 Francisco Diego Barros Barata
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
occupancy_analysis.py
|
|
7
|
+
Single-season occupancy analysis scaffold.
|
|
8
|
+
For full occupancy modelling in Python, interface with JAGS or use pyoccupancy.
|
|
9
|
+
This script demonstrates data formatting and naive occupancy computation.
|
|
10
|
+
Usage: python occupancy_analysis.py <detection_history_csv> <output_dir>
|
|
11
|
+
Requires: pandas, numpy
|
|
12
|
+
"""
|
|
13
|
+
import logging
|
|
14
|
+
import sys
|
|
15
|
+
from datetime import datetime
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
SKILL_NAME = "occupancy-and-detection"
|
|
19
|
+
_LOG_DIR = Path("logs")
|
|
20
|
+
_LOG_DIR.mkdir(parents=True, exist_ok=True)
|
|
21
|
+
_log_file = _LOG_DIR / f"skill_{SKILL_NAME}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
|
|
22
|
+
logging.basicConfig(
|
|
23
|
+
level=logging.INFO,
|
|
24
|
+
format="[%(asctime)s] [%(levelname)s] [" + SKILL_NAME + "] %(message)s",
|
|
25
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
|
26
|
+
handlers=[
|
|
27
|
+
logging.StreamHandler(sys.stdout),
|
|
28
|
+
logging.FileHandler(_log_file, encoding="utf-8"),
|
|
29
|
+
],
|
|
30
|
+
)
|
|
31
|
+
logger = logging.getLogger(SKILL_NAME)
|
|
32
|
+
|
|
33
|
+
def log_step(n: int, desc: str) -> None:
|
|
34
|
+
logger.info("-- STEP %d: %s", n, desc)
|
|
35
|
+
|
|
36
|
+
def log_decision(var: str, val, why: str) -> None:
|
|
37
|
+
logger.info("DECISION | %s = %s | %s", var, val, why)
|
|
38
|
+
|
|
39
|
+
import numpy as np
|
|
40
|
+
import pandas as pd
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def compute_naive_occ(dh: np.ndarray) -> float:
|
|
44
|
+
detected = np.nansum(dh, axis=1) > 0
|
|
45
|
+
return detected.sum() / len(detected)
|
|
46
|
+
|
|
47
|
+
def detection_summary(dh: np.ndarray) -> pd.DataFrame:
|
|
48
|
+
return pd.DataFrame({
|
|
49
|
+
"occasion": [f"occ{i+1}" for i in range(dh.shape[1])],
|
|
50
|
+
"n_surveyed": [np.sum(~np.isnan(dh[:, i])) for i in range(dh.shape[1])],
|
|
51
|
+
"n_detections": [int(np.nansum(dh[:, i])) for i in range(dh.shape[1])],
|
|
52
|
+
"detection_rate": [round(np.nanmean(dh[:, i]), 3) for i in range(dh.shape[1])],
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
def validate_detection_history(dh: np.ndarray) -> None:
|
|
56
|
+
valid = np.isin(dh[~np.isnan(dh)], [0, 1])
|
|
57
|
+
if not valid.all():
|
|
58
|
+
raise ValueError("Detection history contains values other than 0, 1, or NA.")
|
|
59
|
+
all_na = np.all(np.isnan(dh), axis=1)
|
|
60
|
+
if all_na.any():
|
|
61
|
+
raise ValueError(f"{all_na.sum()} sites have all-NA detection histories. Remove them.")
|
|
62
|
+
|
|
63
|
+
def main():
|
|
64
|
+
dh_file = sys.argv[1] if len(sys.argv) > 1 else "data/detection_history.csv"
|
|
65
|
+
output_dir = Path(sys.argv[2]) if len(sys.argv) > 2 else Path("outputs/occupancy")
|
|
66
|
+
|
|
67
|
+
log_step(1, "Validate inputs")
|
|
68
|
+
if not Path(dh_file).exists():
|
|
69
|
+
logger.error(
|
|
70
|
+
"Detection history file not found: %s\n"
|
|
71
|
+
"Causa provavel: caminho incorreto ou arquivo nao gerado\n"
|
|
72
|
+
"Verifique: o argumento detection_history_csv e o diretorio de trabalho\n"
|
|
73
|
+
"Skill anterior: data-cleaning",
|
|
74
|
+
dh_file
|
|
75
|
+
)
|
|
76
|
+
sys.exit(1)
|
|
77
|
+
|
|
78
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
79
|
+
|
|
80
|
+
log_step(2, "Load detection history")
|
|
81
|
+
try:
|
|
82
|
+
dh_df = pd.read_csv(dh_file, index_col=0)
|
|
83
|
+
dh = dh_df.values.astype(float)
|
|
84
|
+
except Exception as e:
|
|
85
|
+
logger.error(
|
|
86
|
+
"Unexpected error in load data: %s\n"
|
|
87
|
+
"Causa provavel: CSV malformado, valores nao numericos, ou ausencia de rownames\n"
|
|
88
|
+
"Verifique: estrutura do arquivo (primeira coluna = site ID, restantes = ocasioes)\n"
|
|
89
|
+
"Skill anterior: data-cleaning",
|
|
90
|
+
e
|
|
91
|
+
)
|
|
92
|
+
raise
|
|
93
|
+
|
|
94
|
+
logger.info("Sites: %d | Occasions: %d", dh.shape[0], dh.shape[1])
|
|
95
|
+
|
|
96
|
+
log_step(3, "Validate detection history structure")
|
|
97
|
+
try:
|
|
98
|
+
validate_detection_history(dh)
|
|
99
|
+
logger.info("Detection history validation passed.")
|
|
100
|
+
except ValueError as e:
|
|
101
|
+
logger.error(
|
|
102
|
+
"Unexpected error in validate_detection_history: %s\n"
|
|
103
|
+
"Causa provavel: valores invalidos (nao 0/1/NA) ou sitios com historico todo NA\n"
|
|
104
|
+
"Verifique: codificacao dos dados (apenas 0, 1, ou NA sao permitidos)\n"
|
|
105
|
+
"Skill anterior: data-cleaning",
|
|
106
|
+
e
|
|
107
|
+
)
|
|
108
|
+
raise
|
|
109
|
+
|
|
110
|
+
log_step(4, "Compute naive occupancy")
|
|
111
|
+
naive = compute_naive_occ(dh)
|
|
112
|
+
logger.info("Naive occupancy: %.3f (%d/%d sites)", naive, int(naive * dh.shape[0]), dh.shape[0])
|
|
113
|
+
|
|
114
|
+
if naive < 0.05:
|
|
115
|
+
logger.warning(
|
|
116
|
+
"Naive occupancy = %.3f is very low (<5%%). "
|
|
117
|
+
"Occupancy models may have poor identifiability with so few detections.",
|
|
118
|
+
naive
|
|
119
|
+
)
|
|
120
|
+
if naive > 0.95:
|
|
121
|
+
logger.warning(
|
|
122
|
+
"Naive occupancy = %.3f is very high (>95%%). "
|
|
123
|
+
"Consider whether species is truly absent from any surveyed sites.",
|
|
124
|
+
naive
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
log_step(5, "Compute detection summary per occasion")
|
|
128
|
+
try:
|
|
129
|
+
det_summary = detection_summary(dh)
|
|
130
|
+
det_summary.to_csv(output_dir / "detection_summary.csv", index=False)
|
|
131
|
+
logger.info("Detection summary:\n%s", det_summary.to_string(index=False))
|
|
132
|
+
|
|
133
|
+
low_occ = det_summary[det_summary["detection_rate"] < 0.05]
|
|
134
|
+
if not low_occ.empty:
|
|
135
|
+
logger.warning(
|
|
136
|
+
"Occasions with detection rate < 5%%: %s. "
|
|
137
|
+
"Low-effort occasions may reduce model precision.",
|
|
138
|
+
list(low_occ["occasion"])
|
|
139
|
+
)
|
|
140
|
+
except Exception as e:
|
|
141
|
+
logger.error(
|
|
142
|
+
"Unexpected error in detection summary: %s\n"
|
|
143
|
+
"Causa provavel: matriz com dimensoes invalidas ou valores inesperados\n"
|
|
144
|
+
"Verifique: estrutura do historico de deteccao\n"
|
|
145
|
+
"Skill anterior: occupancy-and-detection (data loading)",
|
|
146
|
+
e
|
|
147
|
+
)
|
|
148
|
+
raise
|
|
149
|
+
|
|
150
|
+
# For full occupancy modelling, use R (unmarked) or JAGS via pyjags.
|
|
151
|
+
# Example JAGS model call:
|
|
152
|
+
# import pyjags
|
|
153
|
+
# model_code = open("scripts/occu_model.jags").read()
|
|
154
|
+
# model = pyjags.Model(model_code, data={...}, chains=3)
|
|
155
|
+
logger.info("For full occupancy modelling, use scripts/occupancy_analysis.R (unmarked package).")
|
|
156
|
+
logger.info("Outputs written to: %s", output_dir)
|
|
157
|
+
|
|
158
|
+
if __name__ == "__main__":
|
|
159
|
+
main()
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: population-viability-analysis
|
|
3
|
+
description: "Builds matrix population models (Leslie/Lefkovitch) and runs stochastic PVA simulations to assess extinction risk and IUCN criteria. Use this skill when the user mentions PVA, population viability, lambda growth rate, Leslie or Lefkovitch matrices, quasi-extinction thresholds, elasticity or sensitivity analysis, stochastic population projections, minimum viable population (MVP), or IUCN Criterion E assessment."
|
|
4
|
+
skill_version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Skill: population-viability-analysis
|
|
8
|
+
|
|
9
|
+
**Domain:** PVA · Leslie matrix · Demographic stochasticity · Extinction risk · IUCN criteria
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Purpose
|
|
14
|
+
|
|
15
|
+
Guides the agent through population viability analysis using deterministic matrix models and stochastic simulations. Covers construction of Leslie or Lefkovitch stage-structured matrices, computation of population growth rate (λ), sensitivity and elasticity analysis, stochastic projection with demographic and environmental variance, and estimation of extinction probability and mean time to extinction (MTE) for IUCN Red List assessment.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## When to Invoke
|
|
20
|
+
|
|
21
|
+
Invoke this skill when:
|
|
22
|
+
|
|
23
|
+
- The user requests a population viability analysis or extinction risk assessment
|
|
24
|
+
- A Leslie or Lefkovitch matrix must be built from vital rate data
|
|
25
|
+
- Population growth rate (λ) and its sensitivity to demographic parameters are needed
|
|
26
|
+
- Stochastic population projections are requested with extinction probability curves
|
|
27
|
+
- IUCN criteria A–E must be evaluated using modelled population trajectories
|
|
28
|
+
|
|
29
|
+
**trigger_keywords:** `PVA`, `population viability`, `extinction risk`, `minimum viable population`, `Leslie matrix`, `Lefkovitch matrix`, `population projection`, `lambda`, `demographic analysis`, `IUCN criterion`, `quasi-extinction`, `stochastic simulation`, `vital rates`, `survival rate`, `fecundity`
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Inputs
|
|
34
|
+
|
|
35
|
+
| Input | Format | Required |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| Vital rates table (survival, growth, fecundity by stage/age) | CSV | Required |
|
|
38
|
+
| Number of projection years | Integer (default: 100) | Required |
|
|
39
|
+
| Number of stochastic simulations | Integer (default: 1000) | Recommended |
|
|
40
|
+
| Quasi-extinction threshold (Ne) | Integer (default: 50) | Recommended |
|
|
41
|
+
| Coefficient of variation for vital rates (stochastic variance) | CSV or floats | Recommended |
|
|
42
|
+
| Initial population size and stage distribution | CSV or vector | Optional |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Outputs
|
|
47
|
+
|
|
48
|
+
| Output | Description |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `lambda_estimates.csv` | Dominant eigenvalue λ with bootstrap 95% CI |
|
|
51
|
+
| `sensitivity_matrix.csv` | Partial derivatives ∂λ/∂a_ij for each matrix element |
|
|
52
|
+
| `elasticity_matrix.csv` | Proportional sensitivity e_ij for each matrix element |
|
|
53
|
+
| `population_projection.png` | Deterministic N(t) trajectory over projection years |
|
|
54
|
+
| `extinction_probability.csv` | P(extinction) and P(quasi-extinction) by year |
|
|
55
|
+
| `mte_estimate.csv` | Mean time to extinction with 95% CI |
|
|
56
|
+
| `stochastic_trajectories.png` | Fan plot of 1000 stochastic population trajectories |
|
|
57
|
+
| `extinction_curve.png` | Cumulative extinction probability over time |
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Steps
|
|
62
|
+
|
|
63
|
+
1. **Build the projection matrix**
|
|
64
|
+
Read vital rates from CSV. Confirm all survival rates are in (0, 1] and fecundity ≥ 0.
|
|
65
|
+
Construct Leslie (age-structured) or Lefkovitch (stage-structured) matrix.
|
|
66
|
+
If stage boundaries are ambiguous, document choice in `decision_log.md`.
|
|
67
|
+
|
|
68
|
+
2. **Compute λ and confidence interval** *(invoke `matrix_pva.R`)*
|
|
69
|
+
Calculate dominant eigenvalue λ = Re(eigen(A)$values[1]).
|
|
70
|
+
Bootstrap vital rates (1000 resamples) to obtain 95% CI for λ.
|
|
71
|
+
If λ < 1.0: population declining. If λ < 0.95: high extinction risk.
|
|
72
|
+
|
|
73
|
+
3. **Sensitivity and elasticity analysis**
|
|
74
|
+
Compute sensitivity matrix S and elasticity matrix E.
|
|
75
|
+
Identify which vital rate (survival, growth, fecundity) most affects λ.
|
|
76
|
+
High elasticity for adult survival → management interventions should target adults.
|
|
77
|
+
|
|
78
|
+
4. **Deterministic projection**
|
|
79
|
+
Project N(t) = A^t × N(0) over `n_years`.
|
|
80
|
+
If CV of vital rates > 0.30, note that deterministic projection underestimates variance.
|
|
81
|
+
Plot projection with initial population size.
|
|
82
|
+
|
|
83
|
+
5. **Stochastic simulation** *(invoke `stochastic_pva.R`)*
|
|
84
|
+
Draw vital rates from Beta (survival) and Poisson/Normal (fecundity) distributions
|
|
85
|
+
each time step using CV from input table.
|
|
86
|
+
Run `n_simulations` replicates. Track N(t) for each.
|
|
87
|
+
Calculate P(N(t) < Ne) for each year to produce extinction probability curve.
|
|
88
|
+
|
|
89
|
+
6. **Compute MTE and IUCN assessment**
|
|
90
|
+
Mean time to extinction = mean year of first crossing Ne across simulations.
|
|
91
|
+
Classify against IUCN criteria:
|
|
92
|
+
- P(extinction in 100 yr) > 50% → Critically Endangered (criterion E)
|
|
93
|
+
- > 20% → Endangered; > 10% → Vulnerable.
|
|
94
|
+
|
|
95
|
+
7. **Validate and document**
|
|
96
|
+
Check λ from step 2 is consistent with stochastic simulation trend.
|
|
97
|
+
Record all vital rate sources, CV assumptions, and IUCN classification rationale
|
|
98
|
+
in `decision_log.md`.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Decision Points
|
|
103
|
+
|
|
104
|
+
| Condition | Diagnosis | Recommended Action |
|
|
105
|
+
|---|---|---|
|
|
106
|
+
| Vital rate data from < 3 years | High parametric uncertainty | Run sensitivity analysis across wide range; report P(extinction) as range, not point estimate |
|
|
107
|
+
| λ < 0.95 in deterministic model | Rapid deterministic decline | Calculate MTE even without stochasticity; management urgency is high |
|
|
108
|
+
| CV of vital rates > 0.30 | Environmental stochasticity dominates | Stochastic model is mandatory; deterministic λ is insufficient |
|
|
109
|
+
| N_initial < 50 | Below minimum viable population | Allee effects may apply; consider demographic stochasticity separately |
|
|
110
|
+
| Bootstrap CI for λ crosses 1.0 | λ not significantly different from 1 | Report both scenarios (λ > 1 and λ < 1); do not claim stability without longer monitoring |
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Key Decisions to Document
|
|
115
|
+
|
|
116
|
+
Record the following in `decision_log.md` after running this skill:
|
|
117
|
+
|
|
118
|
+
- Source of vital rate estimates (literature, field data, expert elicitation) and associated uncertainty
|
|
119
|
+
- Choice of Leslie vs. Lefkovitch structure and age/stage class boundaries
|
|
120
|
+
- Quasi-extinction threshold (Ne) and its biological justification
|
|
121
|
+
- Distribution assumptions for stochastic vital rate draws (Beta, Poisson, Normal)
|
|
122
|
+
- Whether IUCN criterion E classification was performed and the result
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Tools and Libraries
|
|
127
|
+
|
|
128
|
+
**R**
|
|
129
|
+
```r
|
|
130
|
+
suppressPackageStartupMessages(library(popbio)) # matrix PVA: lambda, sensitivity, elasticity
|
|
131
|
+
suppressPackageStartupMessages(library(dplyr)) # data manipulation
|
|
132
|
+
suppressPackageStartupMessages(library(tidyr)) # reshaping
|
|
133
|
+
suppressPackageStartupMessages(library(ggplot2)) # plotting trajectories and curves
|
|
134
|
+
suppressPackageStartupMessages(library(boot)) # bootstrapping vital rates
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Python**
|
|
138
|
+
```python
|
|
139
|
+
import numpy as np # eigenvalue computation, matrix multiplication
|
|
140
|
+
import pandas as pd # vital rate tables
|
|
141
|
+
import matplotlib.pyplot as plt # trajectory plots
|
|
142
|
+
from pathlib import Path # file system
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Resources
|
|
148
|
+
|
|
149
|
+
- [`skills/population-viability-analysis/resources/matrix-model-guide.md`](resources/matrix-model-guide.md) — Leslie vs. Lefkovitch matrices, λ computation, sensitivity and elasticity reference table
|
|
150
|
+
- [`skills/population-viability-analysis/resources/extinction-risk-thresholds.md`](resources/extinction-risk-thresholds.md) — IUCN criteria A–E, quasi-extinction thresholds, MVP concept and literature values
|
|
151
|
+
- [`skills/population-viability-analysis/resources/sensitivity-elasticity-reference.md`](resources/sensitivity-elasticity-reference.md) — Published elasticities by taxon group and management implications
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Notes
|
|
156
|
+
|
|
157
|
+
- **λ from a single matrix ignores temporal variation:** A single matrix built from pooled data produces a long-run average λ. If vital rates vary strongly between years (drought, disease outbreaks), the stochastic geometric mean growth rate (λ_s) will be lower than the deterministic λ.
|
|
158
|
+
- **Sensitivity vs. elasticity are complementary:** Sensitivity identifies which matrix element has the largest absolute effect on λ; elasticity identifies the proportional effect. For management, elasticity is more interpretable because it accounts for the natural scale of each vital rate.
|
|
159
|
+
- **Small-population effects are not captured by matrix models:** Inbreeding depression, Allee effects, and demographic stochasticity in very small populations (N < 20) require individual-based models (IBM) that are beyond this skill's scope.
|
|
160
|
+
- **Do not extrapolate beyond data range:** If only 5 years of demographic data exist, projections to 100 years carry enormous uncertainty. Report CIs from bootstrapping and note the data limitation explicitly.
|
|
161
|
+
- **IUCN criterion E requires peer-reviewed vital rates:** Self-collected data with < 3 years of monitoring should not be used as the sole basis for an IUCN listing under criterion E without independent validation.
|