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,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spatial-prioritization
|
|
3
|
+
description: "Solves systematic conservation planning problems using integer linear programming (prioritizr), Marxan, or Zonation for protected area design. Use this skill when the user mentions conservation planning, 30x30 targets, Marxan, Zonation, prioritizr, irreplaceability, boundary length modifier (BLM), minimum set problems, representation targets, systematic conservation, or protected area network design."
|
|
4
|
+
skill_version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Skill: spatial-prioritization
|
|
8
|
+
|
|
9
|
+
**Domain:** Conservation planning · prioritizr · Marxan · Zonation · Reserve design · 30×30
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Purpose
|
|
14
|
+
|
|
15
|
+
Guides the agent through systematic conservation planning to identify priority areas that efficiently represent biodiversity targets under cost constraints. Covers problem formulation (minimum-set, maximum-coverage), planning unit design, target definition, cost surface selection, connectivity penalties, and solving with integer linear programming. Produces priority maps, irreplaceability surfaces, and cost-effectiveness curves for decision-makers.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## When to Invoke
|
|
20
|
+
|
|
21
|
+
Invoke this skill when:
|
|
22
|
+
|
|
23
|
+
- The user requests conservation area prioritisation, gap analysis, or reserve design
|
|
24
|
+
- Systematic conservation planning (Marxan, Zonation, prioritizr) is needed
|
|
25
|
+
- Protected area network adequacy must be evaluated against biodiversity targets
|
|
26
|
+
- A 30×30 or other area-based conservation target must be spatially allocated
|
|
27
|
+
- Trade-offs between cost and biodiversity representation must be quantified
|
|
28
|
+
|
|
29
|
+
**trigger_keywords:** `conservation planning`, `protected areas`, `Marxan`, `Zonation`, `prioritizr`, `reserve design`, `systematic conservation`, `30x30`, `biodiversity target`, `irreplaceability`, `complementarity`, `gap analysis`, `cost-effectiveness`, `planning unit`, `boundary length modifier`
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Inputs
|
|
34
|
+
|
|
35
|
+
| Input | Format | Required |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| Species suitability or distribution stack | GeoTIFF (multiband) | Required |
|
|
38
|
+
| Cost surface raster | GeoTIFF | Required |
|
|
39
|
+
| Study area polygon | SHP or GPKG | Required |
|
|
40
|
+
| Conservation targets per species (%) | CSV | Recommended |
|
|
41
|
+
| Locked-in areas (existing protected areas) | SHP or GPKG | Optional |
|
|
42
|
+
| Locked-out areas (exclusion zones) | SHP or GPKG | Optional |
|
|
43
|
+
| Connectivity layer (habitat patches or resistance surface) | GeoTIFF or GPKG | Optional |
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Outputs
|
|
48
|
+
|
|
49
|
+
| Output | Description |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `priority_solution.tif` | Binary raster: 1 = selected planning unit, 0 = not selected |
|
|
52
|
+
| `irreplaceability.tif` | Selection frequency across portfolio of near-optimal solutions |
|
|
53
|
+
| `targets_achieved.csv` | % of target met per species/feature in the solution |
|
|
54
|
+
| `cost_effectiveness_curve.png` | Total cost vs. % targets achieved across budget levels |
|
|
55
|
+
| `solution_summary.md` | Narrative: total area, cost, targets met, connectivity score |
|
|
56
|
+
| `sensitivity_results.csv` | Solution metrics across BLM and target combinations |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Steps
|
|
61
|
+
|
|
62
|
+
1. **Define planning units**
|
|
63
|
+
Use the study area raster cells as planning units (pixel-based) or create a hexagonal
|
|
64
|
+
grid at the appropriate resolution. Confirm CRS matches all input layers.
|
|
65
|
+
Record planning unit size and type in `decision_log.md`.
|
|
66
|
+
|
|
67
|
+
2. **Prepare features (biodiversity layers)**
|
|
68
|
+
Load species suitability stack from `species-distribution-modeling` skill.
|
|
69
|
+
Optionally include ecosystem service layers from `ecosystem-services-assessment`.
|
|
70
|
+
Normalise all feature layers to [0, 1] if combining different units.
|
|
71
|
+
|
|
72
|
+
3. **Define targets**
|
|
73
|
+
Default: 30% of each species' total distribution within the study area.
|
|
74
|
+
If IUCN threat status data are available, apply higher targets for threatened species
|
|
75
|
+
(CR: 50%, EN: 40%, VU: 30%).
|
|
76
|
+
Save target table as `params/targets.csv`.
|
|
77
|
+
|
|
78
|
+
4. **Build and solve the prioritisation problem** *(invoke `run_prioritization.R`)*
|
|
79
|
+
Create problem with `prioritizr::problem()`, add targets, cost, and penalties.
|
|
80
|
+
Set locked-in (existing protected areas) and locked-out (excluded) zones.
|
|
81
|
+
Add connectivity penalty using `add_boundary_penalties(penalty = BLM)`.
|
|
82
|
+
Solve with `highs` solver (default) or `symphony` (fallback).
|
|
83
|
+
|
|
84
|
+
5. **Evaluate solution**
|
|
85
|
+
Check `targets_achieved.csv`: all features must reach ≥ 80% of target.
|
|
86
|
+
If any feature < 80%: budget is insufficient; run `prioritization_sensitivity.R`.
|
|
87
|
+
Calculate irreplaceability as selection frequency across 100 near-optimal solutions.
|
|
88
|
+
|
|
89
|
+
6. **Generate cost-effectiveness curve** *(invoke `prioritization_sensitivity.R`)*
|
|
90
|
+
Solve at 5 budget levels (50%, 75%, 100%, 125%, 150% of selected solution cost).
|
|
91
|
+
Plot cumulative targets achieved vs. total cost.
|
|
92
|
+
Present to decision-maker as trade-off summary.
|
|
93
|
+
|
|
94
|
+
7. **Validate and document**
|
|
95
|
+
Verify `priority_solution.tif` covers the expected % of study area.
|
|
96
|
+
Record solver used, BLM value, target definitions, and any infeasible scenarios
|
|
97
|
+
in `decision_log.md`.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Decision Points
|
|
102
|
+
|
|
103
|
+
| Condition | Diagnosis | Recommended Action |
|
|
104
|
+
|---|---|---|
|
|
105
|
+
| No feasible solution found in 1000 iterations | Budget too restrictive or targets unachievable | Relax targets (reduce by 5% increments) or increase budget; document trade-off |
|
|
106
|
+
| < 80% of targets achieved in solution | Budget insufficient for full representation | Present cost-effectiveness curve; let decision-maker choose acceptable representation level |
|
|
107
|
+
| Irreplaceability > 0.8 for a deforested area | Critical irreplaceable area is already lost | Escalate to restoration analysis; include in gap analysis narrative |
|
|
108
|
+
| BLM = 0 gives highly fragmented solution | Connectivity not enforced | Calibrate BLM: increase until solution compactness is acceptable without losing > 10% of targets |
|
|
109
|
+
| Existing protected areas already meet targets | No additional areas needed | Perform gap analysis only; report which species remain under-represented |
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Key Decisions to Document
|
|
114
|
+
|
|
115
|
+
Record the following in `decision_log.md` after running this skill:
|
|
116
|
+
|
|
117
|
+
- Planning unit type (pixel vs. hexagon), size, and CRS used
|
|
118
|
+
- Target percentages per feature and their justification (30×30, IUCN status, etc.)
|
|
119
|
+
- Cost surface used (area proxy, economic value, opportunity cost) and its source
|
|
120
|
+
- BLM value applied and how it was calibrated
|
|
121
|
+
- Solver used (highs, symphony, gurobi) and whether any scenarios were infeasible
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Tools and Libraries
|
|
126
|
+
|
|
127
|
+
**R**
|
|
128
|
+
```r
|
|
129
|
+
suppressPackageStartupMessages(library(prioritizr)) # conservation planning problem
|
|
130
|
+
suppressPackageStartupMessages(library(highs)) # HiGHS solver (recommended, free)
|
|
131
|
+
suppressPackageStartupMessages(library(terra)) # raster handling
|
|
132
|
+
suppressPackageStartupMessages(library(sf)) # vector handling
|
|
133
|
+
suppressPackageStartupMessages(library(dplyr)) # data manipulation
|
|
134
|
+
suppressPackageStartupMessages(library(ggplot2)) # cost-effectiveness plots
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Python** *(support layer only — core analysis in R)*
|
|
138
|
+
```python
|
|
139
|
+
import geopandas as gpd # spatial data inspection
|
|
140
|
+
import rasterio # raster inspection
|
|
141
|
+
import numpy as np # array operations
|
|
142
|
+
from pathlib import Path # file system
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Resources
|
|
148
|
+
|
|
149
|
+
- [`skills/spatial-prioritization/resources/prioritizr-formulation-guide.md`](resources/prioritizr-formulation-guide.md) — Problem types, planning units, targets, costs, BLM, solvers, and locked zones
|
|
150
|
+
- [`skills/spatial-prioritization/resources/marxan-vs-prioritizr-comparison.md`](resources/marxan-vs-prioritizr-comparison.md) — Comparison of Marxan, Zonation, prioritizr, and OPT; migration guide
|
|
151
|
+
- [`skills/spatial-prioritization/resources/cost-surface-reference.md`](resources/cost-surface-reference.md) — Cost proxy options, global data sources, normalisation, and sensitivity to cost
|
|
152
|
+
- [`skills/spatial-prioritization/resources/representation-targets-guide.md`](resources/representation-targets-guide.md) — 10%/17%/30% targets, species-level targets, fine-filter vs. coarse-filter approaches
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Notes
|
|
157
|
+
|
|
158
|
+
- **prioritizr requires a solver:** The `highs` package provides a free, high-performance solver sufficient for most problems. `gurobi` is faster for very large problems but requires an academic licence. Do not attempt to solve without an explicit solver; `prioritizr` will error.
|
|
159
|
+
- **Boundary length modifier (BLM) requires calibration:** BLM = 0 produces the cheapest but most fragmented solution. Too high a BLM increases cost dramatically. Calibrate by plotting cost vs. total boundary length across BLM values (built into `prioritization_sensitivity.R`).
|
|
160
|
+
- **Irreplaceability ≠ priority:** A planning unit with irreplaceability = 1.0 is selected in every near-optimal solution but may be inexpensive. A unit with irreplaceability = 0.3 is selected only in some solutions. Report both the solution map and irreplaceability map.
|
|
161
|
+
- **Planning unit size affects resolution and computation time:** 1 km² pixels for a country-scale analysis may produce millions of planning units, making ILP very slow. Aggregate to 10 km² for national-scale problems; use 1 km² only for regional scales.
|
|
162
|
+
- **Locked-in areas must be in the same CRS as planning units:** CRS mismatch between existing protected areas and planning units is a common error that causes protected areas to be ignored in the solution.
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill_id: spatial-prioritization
|
|
3
|
+
example_type: full_walkthrough
|
|
4
|
+
taxon: Multi-species (Atlantic Forest endemic vertebrates)
|
|
5
|
+
region: Southern Bahia, Brazil — Atlantic Forest hotspot
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Atlantic Forest Biodiversity Hotspot Prioritization — Full Walkthrough
|
|
9
|
+
|
|
10
|
+
## Study Context
|
|
11
|
+
|
|
12
|
+
**Location:** Southern Bahia, Brazil — one of the world's most biodiverse (and threatened) Atlantic Forest remnants
|
|
13
|
+
**Objective:** Design a minimum-cost protected area expansion to meet 30% representation targets for 85 endemic vertebrate species while maximising compactness (coridor potential)
|
|
14
|
+
**Planning units:** 5×5 km grid cells, n = 3,240 valid PUs
|
|
15
|
+
**Features:** 85 species SDM suitability layers (MaxEnt, continuous 0–1)
|
|
16
|
+
**Cost:** Opportunity cost surface based on agricultural land value (R$/ha/yr)
|
|
17
|
+
**Existing PAs:** 12 federal and state reserves (already locked in, covering ~8% of area)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Step 1 — Data Preparation
|
|
22
|
+
|
|
23
|
+
### Planning unit cost surface
|
|
24
|
+
|
|
25
|
+
```r
|
|
26
|
+
suppressPackageStartupMessages(library(terra))
|
|
27
|
+
suppressPackageStartupMessages(library(sf))
|
|
28
|
+
|
|
29
|
+
# Agricultural opportunity cost: sugarcane + cattle + timber
|
|
30
|
+
sugarcane <- rast("data/sugarcane_revenue_reais_ha.tif")
|
|
31
|
+
cattle <- rast("data/cattle_TLU_ha.tif") * 180 # R$/TLU/yr
|
|
32
|
+
timber <- rast("data/timber_potential_reais_ha.tif")
|
|
33
|
+
opp_cost <- max(sugarcane, cattle, timber, na.rm = TRUE)
|
|
34
|
+
opp_cost <- aggregate(opp_cost, fact = 5, fun = "mean") # resample to 5km
|
|
35
|
+
|
|
36
|
+
# Minimum floor
|
|
37
|
+
opp_cost[opp_cost < 1] <- 1
|
|
38
|
+
writeRaster(opp_cost, "data/pu_cost_5km.tif", overwrite = TRUE)
|
|
39
|
+
cat(sprintf("Cost range: %.0f – %.0f R$/ha/yr\n",
|
|
40
|
+
global(opp_cost, "min")[[1]], global(opp_cost, "max")[[1]]))
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Cost statistics:**
|
|
44
|
+
|
|
45
|
+
| Statistic | Value (R$/ha/yr) |
|
|
46
|
+
|-----------|-----------------|
|
|
47
|
+
| Min | 1.0 |
|
|
48
|
+
| Median | 845 |
|
|
49
|
+
| Mean | 1,240 |
|
|
50
|
+
| Q95 | 3,890 |
|
|
51
|
+
| Max | 8,750 |
|
|
52
|
+
|
|
53
|
+
**Decision:** Log-transform cost for analysis to reduce influence of 5 outlier PUs with costs > 7,000 R$/ha/yr. Decision logged with rationale.
|
|
54
|
+
|
|
55
|
+
### Feature layers preparation
|
|
56
|
+
|
|
57
|
+
```r
|
|
58
|
+
feat_files <- list.files("data/sdm_continuous/", pattern = ".tif$", full.names = TRUE)
|
|
59
|
+
features <- rast(feat_files)
|
|
60
|
+
features <- resample(features, rast("data/pu_cost_5km.tif"), method = "bilinear")
|
|
61
|
+
|
|
62
|
+
# Check feature distribution: remove features with < 5 PUs with suitability > 0.3
|
|
63
|
+
feat_sums <- global(features > 0.3, "sum", na.rm = TRUE)
|
|
64
|
+
low_feat <- names(features)[feat_sums[[1]] < 5]
|
|
65
|
+
cat(sprintf("Removing %d features with very restricted range.\n", length(low_feat)))
|
|
66
|
+
features <- features[[!names(features) %in% low_feat]]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Result:** 3 species removed (range < 5 PUs); 82 features retained.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Step 2 — Baseline Prioritization (Minimum Set, 30% Targets)
|
|
74
|
+
|
|
75
|
+
### Target computation (IUCN-based)
|
|
76
|
+
|
|
77
|
+
```r
|
|
78
|
+
species_meta <- read.csv("data/species_iucn_status.csv")
|
|
79
|
+
# Columns: species, iucn_category, current_protected_fraction
|
|
80
|
+
|
|
81
|
+
set_iucn_targets <- function(species_df) {
|
|
82
|
+
raw <- dplyr::case_when(
|
|
83
|
+
species_df$iucn_category == "CR" ~ 0.60,
|
|
84
|
+
species_df$iucn_category == "EN" ~ 0.50,
|
|
85
|
+
species_df$iucn_category == "VU" ~ 0.40,
|
|
86
|
+
species_df$iucn_category == "NT" ~ 0.30,
|
|
87
|
+
TRUE ~ 0.17
|
|
88
|
+
)
|
|
89
|
+
pmax(0, raw - species_df$current_protected_fraction)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
targets_df <- set_iucn_targets(species_meta)
|
|
93
|
+
# Distribution: CR: 0.42 median (gap after 18% already protected)
|
|
94
|
+
# EN: 0.35; VU: 0.28; NT: 0.22
|
|
95
|
+
write.csv(data.frame(feature_name = names(features), target = targets_df),
|
|
96
|
+
"data/iucn_targets.csv", row.names = FALSE)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Run baseline prioritization
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
Rscript run_prioritization.R \
|
|
103
|
+
data/pu_cost_5km.tif \
|
|
104
|
+
data/sdm_continuous/ \
|
|
105
|
+
outputs/baseline/ \
|
|
106
|
+
data/iucn_targets.csv \
|
|
107
|
+
data/existing_PAs_5km.tif \
|
|
108
|
+
data/excluded_urban_water.tif \
|
|
109
|
+
0 \
|
|
110
|
+
NA
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Baseline results:**
|
|
114
|
+
|
|
115
|
+
| Metric | Value |
|
|
116
|
+
|--------|-------|
|
|
117
|
+
| PUs selected | 487 / 3,240 (15.0%) |
|
|
118
|
+
| Total cost | R$ 234M/yr opportunity cost |
|
|
119
|
+
| Features with targets met | 79 / 82 (96.3%) |
|
|
120
|
+
| 3 features below target | *Diclidurus ingens* (CR, 0.41 vs 0.42 target), 2 VU bats |
|
|
121
|
+
|
|
122
|
+
**Action:** The 3 shortfall species have extremely restricted ranges. Manual inspection shows their key PUs are in a locked-out urban buffer. Decision: remove urban buffer restriction for those 3 PUs (no development plans confirmed) → re-run.
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Step 3 — Sensitivity Analysis
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
Rscript prioritization_sensitivity.R \
|
|
130
|
+
data/pu_cost_5km.tif \
|
|
131
|
+
data/sdm_continuous/ \
|
|
132
|
+
outputs/sensitivity/ \
|
|
133
|
+
data/iucn_targets.csv \
|
|
134
|
+
data/existing_PAs_5km.tif \
|
|
135
|
+
data/excluded_urban_water.tif
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### BLM calibration
|
|
139
|
+
|
|
140
|
+
| BLM | Cost (R$M/yr) | Boundary length | PUs selected |
|
|
141
|
+
|-----|--------------|-----------------|-------------|
|
|
142
|
+
| 0 | 234 | 18,240 | 487 |
|
|
143
|
+
| 0.001 | 238 | 15,120 | 492 |
|
|
144
|
+
| 0.01 | 251 | 11,880 | 508 |
|
|
145
|
+
| 0.05 | 279 | 8,640 | 531 |
|
|
146
|
+
| 0.1 | 312 | 7,200 | 565 |
|
|
147
|
+
|
|
148
|
+
**Decision:** BLM = 0.01 selected (elbow point — 7% cost increase reduces boundary by 35%). This creates significantly more compact, corridor-compatible solutions.
|
|
149
|
+
|
|
150
|
+
### Target sensitivity
|
|
151
|
+
|
|
152
|
+
| Target scaling | Mean target | Cost (R$M/yr) | Features met |
|
|
153
|
+
|---------------|-------------|--------------|-------------|
|
|
154
|
+
| 50% | 0.17 | 98 | 82/82 |
|
|
155
|
+
| 75% | 0.26 | 167 | 82/82 |
|
|
156
|
+
| 100% (baseline) | 0.35 | 251 | 82/82 |
|
|
157
|
+
| 125% | 0.44 | 389 | 80/82 |
|
|
158
|
+
| 150% | 0.52 | 521 | 76/82 |
|
|
159
|
+
|
|
160
|
+
**Finding:** Cost increases 3× from 50% to 150% target scaling. Targets above ~130% become infeasible for 2+ species given locked-out area constraints.
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Step 4 — Final Solution (BLM = 0.01)
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
Rscript run_prioritization.R \
|
|
168
|
+
data/pu_cost_5km.tif \
|
|
169
|
+
data/sdm_continuous/ \
|
|
170
|
+
outputs/final/ \
|
|
171
|
+
data/iucn_targets.csv \
|
|
172
|
+
data/existing_PAs_5km.tif \
|
|
173
|
+
data/excluded_urban_water.tif \
|
|
174
|
+
0.01 \
|
|
175
|
+
NA
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Final solution results:**
|
|
179
|
+
|
|
180
|
+
| Metric | Value |
|
|
181
|
+
|--------|-------|
|
|
182
|
+
| PUs selected | 508 (15.7%) |
|
|
183
|
+
| Total opportunity cost | R$ 251M/yr |
|
|
184
|
+
| Area selected | ~12,700 km² |
|
|
185
|
+
| Combined with existing PAs | ~14,600 km² (20.8% of study area) |
|
|
186
|
+
| Features with targets met | 82 / 82 (100%) |
|
|
187
|
+
| Gap to optimality (HiGHS) | 0.8% |
|
|
188
|
+
|
|
189
|
+
**Irreplaceability analysis:**
|
|
190
|
+
|
|
191
|
+
```r
|
|
192
|
+
irr <- rast("outputs/final/irreplaceability.tif")
|
|
193
|
+
# High-priority areas (top 10% irreplaceability, not yet in PA system)
|
|
194
|
+
high_irr_unprotected <- (irr >= quantile(values(irr), 0.90, na.rm = TRUE)) &
|
|
195
|
+
(rast("data/existing_PAs_5km.tif") == 0)
|
|
196
|
+
n_high_irr_unprotected <- sum(values(high_irr_unprotected) == 1, na.rm = TRUE)
|
|
197
|
+
cat(sprintf("High-irreplaceability, unprotected PUs: %d (%.0f km²)\n",
|
|
198
|
+
n_high_irr_unprotected, n_high_irr_unprotected * 25))
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Result:** 47 PUs (1,175 km²) have irreplaceability > 0.90 and are not currently protected. These are the highest-priority acquisition targets.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Step 5 — Portfolio Irreplaceability Map
|
|
206
|
+
|
|
207
|
+
```r
|
|
208
|
+
freq <- rast("outputs/sensitivity/portfolio_frequency.tif")
|
|
209
|
+
# Areas selected in > 75% of scenarios = robust priorities
|
|
210
|
+
robust_areas <- freq >= 0.75
|
|
211
|
+
robust_area_km2 <- sum(values(robust_areas) == 1, na.rm = TRUE) * 25
|
|
212
|
+
cat(sprintf("Robust priority areas (selected in >75%% scenarios): %.0f km²\n",
|
|
213
|
+
robust_area_km2))
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**Result:** 8,450 km² selected in > 75% of all scenarios. These areas are recommended as the highest-priority acquisition regardless of cost or target assumptions.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Step 6 — Final Outputs
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
outputs/
|
|
224
|
+
├── baseline/
|
|
225
|
+
│ ├── solution.tif # 487 PUs selected
|
|
226
|
+
│ ├── feature_representation.csv # 82 species, 79 met targets
|
|
227
|
+
│ ├── cost_summary.csv
|
|
228
|
+
│ └── irreplaceability.tif
|
|
229
|
+
├── final/ # BLM = 0.01
|
|
230
|
+
│ ├── solution.tif # 508 PUs, all 82 targets met
|
|
231
|
+
│ ├── feature_representation.csv
|
|
232
|
+
│ ├── irreplaceability.tif
|
|
233
|
+
│ └── prioritization_map.png
|
|
234
|
+
└── sensitivity/
|
|
235
|
+
├── blm_calibration.csv
|
|
236
|
+
├── blm_calibration_plot.png
|
|
237
|
+
├── target_sensitivity.csv
|
|
238
|
+
├── cost_scenario_sensitivity.csv
|
|
239
|
+
└── portfolio_frequency.tif # robust priorities (75% threshold)
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Summary Table
|
|
245
|
+
|
|
246
|
+
| Metric | Value |
|
|
247
|
+
|--------|-------|
|
|
248
|
+
| Planning units | 3,240 (5×5 km) |
|
|
249
|
+
| Features analysed | 82 Atlantic Forest endemics |
|
|
250
|
+
| Existing PA coverage | 8.0% (locked in) |
|
|
251
|
+
| Solution area | 15.7% (+ existing = 20.8%) |
|
|
252
|
+
| All targets met | Yes (82/82) |
|
|
253
|
+
| Opportunity cost | R$ 251M/yr |
|
|
254
|
+
| Gap to optimality | 0.8% |
|
|
255
|
+
| Robust priority area (>75% freq) | 8,450 km² |
|
|
256
|
+
| Irreplaceable unprotected area | 1,175 km² (47 PUs) |
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Decision Log
|
|
261
|
+
|
|
262
|
+
```yaml
|
|
263
|
+
- date: 2026-02-01
|
|
264
|
+
skill_id: spatial-prioritization
|
|
265
|
+
decision: "Log-transform cost; outlier PUs capped at 95th percentile"
|
|
266
|
+
rationale: "5 PUs with cost > 7000 R$/ha dominated solution; log-transform standard practice"
|
|
267
|
+
outputs: ["data/pu_cost_5km.tif"]
|
|
268
|
+
|
|
269
|
+
- date: 2026-02-02
|
|
270
|
+
skill_id: spatial-prioritization
|
|
271
|
+
decision: "BLM = 0.01 selected for final solution"
|
|
272
|
+
rationale: "Elbow of cost-compactness curve; 7% cost increase for 35% boundary reduction"
|
|
273
|
+
outputs: ["outputs/sensitivity/blm_calibration.csv"]
|
|
274
|
+
|
|
275
|
+
- date: 2026-02-03
|
|
276
|
+
skill_id: spatial-prioritization
|
|
277
|
+
decision: "Urban buffer exception for 3 CR bat species PUs"
|
|
278
|
+
rationale: "No confirmed development plans in those PUs; verified with municipal zoning"
|
|
279
|
+
outputs: ["outputs/final/solution.tif"]
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## References
|
|
285
|
+
|
|
286
|
+
- Hanson, J.O. et al. (2024). prioritizr: Systematic conservation prioritization in R. *Methods in Ecology and Evolution*, 15(8), 1337–1344. DOI: 10.1111/2041-210X.14376
|
|
287
|
+
- CBD (2022). *Kunming-Montreal Global Biodiversity Framework*, Target 3. COP15.
|
|
288
|
+
- Rodrigues, A.S.L. et al. (2004). Effectiveness of the global protected area network in representing species diversity. *Nature*, 428, 640–643. DOI: 10.1038/nature02422
|
|
289
|
+
- Wilson, K.A. et al. (2009). Conserving biodiversity efficiently: what to do, where, and when. *PLOS Biology*, 7(9), e1000175. DOI: 10.1371/journal.pbio.1000175
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill_id: spatial-prioritization
|
|
3
|
+
example_count: 5
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Spatial Prioritization — Example Prompts
|
|
7
|
+
|
|
8
|
+
## Scenario 1: 30×30 Target Achievement — Tropical Country
|
|
9
|
+
|
|
10
|
+
**Context:** A tropical nation needs to expand its protected area network from current 14% coverage to 30% by 2030 (Kunming-Montreal GBF Target 3).
|
|
11
|
+
|
|
12
|
+
**Prompt:**
|
|
13
|
+
> "I have SDM suitability layers for 120 species and an opportunity cost surface for a tropical country. Design a minimum-cost protected area network that achieves 30% representation for all species AND covers at least 30% of total land area. Lock in existing PAs."
|
|
14
|
+
|
|
15
|
+
**Expected workflow:**
|
|
16
|
+
1. Build feature layers (120 species SDM suitability rasters)
|
|
17
|
+
2. Set targets = 0.30 for all features; add area constraint via `add_min_set_objective`
|
|
18
|
+
3. Lock in WDPA existing PAs via `locked_in_raster`
|
|
19
|
+
4. `run_prioritization.R pu_cost.tif features/ outputs/ 0.30 wdpa.tif`
|
|
20
|
+
5. Check `feature_representation.csv` — verify all 120 features ≥ 30%
|
|
21
|
+
6. Map solution; compute % land area covered
|
|
22
|
+
|
|
23
|
+
**Key decision points:**
|
|
24
|
+
- If any species < 30% → check if its range is fully within locked-out areas
|
|
25
|
+
- If solution selects > 40% of land → check if some targets can be relaxed for LC species
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Scenario 2: Fixed Budget Conservation Planning
|
|
30
|
+
|
|
31
|
+
**Context:** NGO has USD 10M to acquire land in a biodiversity hotspot. Maximise conservation benefit within this budget.
|
|
32
|
+
|
|
33
|
+
**Prompt:**
|
|
34
|
+
> "With a budget of USD 10M, select the set of land parcels (planning units) that maximises the number of threatened species (IUCN CR, EN, VU) whose representation targets are met. Use IUCN-based targets (CR=60%, EN=50%, VU=40%)."
|
|
35
|
+
|
|
36
|
+
**Expected workflow:**
|
|
37
|
+
1. Compute IUCN targets via `set_iucn_targets()` from resource guide
|
|
38
|
+
2. Switch to `add_max_features_objective(budget = 10e6)`
|
|
39
|
+
3. `run_prioritization.R pu_cost.tif features/ outputs/ targets_iucn.csv NA NA 0 10000000`
|
|
40
|
+
4. Load `feature_representation.csv` → count species above/below target
|
|
41
|
+
5. Report cost-effectiveness: threatened species-targets met per million USD
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Scenario 3: Corridor Design Between Two National Parks
|
|
46
|
+
|
|
47
|
+
**Context:** Two national parks need to be connected by a wildlife corridor. Identify the minimum-cost land parcels connecting them while protecting 40% of corridor species.
|
|
48
|
+
|
|
49
|
+
**Prompt:**
|
|
50
|
+
> "Design a wildlife corridor connecting Park A and Park B. Select planning units that form a connected corridor while meeting 40% representation targets for 25 focal species. Lock in both parks; exclude urban areas."
|
|
51
|
+
|
|
52
|
+
**Expected workflow:**
|
|
53
|
+
1. Lock in both parks as locked_in_raster
|
|
54
|
+
2. Lock out urban + water as locked_out_raster
|
|
55
|
+
3. Set BLM = 0.05 to encourage compact, connected solution
|
|
56
|
+
4. `run_prioritization.R pu.tif features/ outputs/ 0.40 parks.tif urban_water.tif 0.05`
|
|
57
|
+
5. Verify solution forms a connected path (use igraph on solution raster)
|
|
58
|
+
6. Report total corridor length and width at narrowest point
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Scenario 4: Sensitivity Analysis for Policy Decision
|
|
63
|
+
|
|
64
|
+
**Context:** Government needs to defend a new protected area design to stakeholders. Show how the solution is robust to cost uncertainty and target choice.
|
|
65
|
+
|
|
66
|
+
**Prompt:**
|
|
67
|
+
> "Run a sensitivity analysis on the conservation solution: (1) BLM calibration to find the optimal compactness, (2) test target scalings from 50% to 150% of the baseline 30% target, (3) test cost uncertainty ±30%. Produce a portfolio irreplaceability map."
|
|
68
|
+
|
|
69
|
+
**Expected workflow:**
|
|
70
|
+
1. `prioritization_sensitivity.R pu.tif features/ outputs/ 0.30 locked_in.tif locked_out.tif`
|
|
71
|
+
2. Load `blm_calibration.csv` → plot cost-compactness tradeoff → select elbow BLM
|
|
72
|
+
3. Load `target_sensitivity.csv` → show cost doubles going from 50% to 150% scaling
|
|
73
|
+
4. Load `portfolio_frequency.tif` → map areas selected in > 75% of scenarios = robust priorities
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Scenario 5: Marine Protected Area Network
|
|
78
|
+
|
|
79
|
+
**Context:** Marine spatial planning for a coastal nation. Design an MPA network covering 30% of territorial waters while protecting key fish spawning areas and coral reefs.
|
|
80
|
+
|
|
81
|
+
**Prompt:**
|
|
82
|
+
> "I have marine biodiversity feature layers (fish spawning areas, coral, seagrass, endemic species SDMs) and a planning unit grid representing fishing revenue as opportunity cost. Design an MPA network meeting 30% targets for all features while minimising cost to fishers."
|
|
83
|
+
|
|
84
|
+
**Expected workflow:**
|
|
85
|
+
1. Planning units: 1 km² grid cells covering territorial waters; cost = annual fishing revenue
|
|
86
|
+
2. Features: spawning aggregations, coral cover, seagrass, endemic species suitability
|
|
87
|
+
3. Locked-out: shipping lanes (navigational requirement), oil/gas concessions
|
|
88
|
+
4. `run_prioritization.R marine_pu.tif marine_features/ outputs/ 0.30 NA shipping.tif 0.01`
|
|
89
|
+
5. Report: total fishing revenue lost in solution vs % marine area protected
|
|
90
|
+
|
|
91
|
+
**Key decision points:**
|
|
92
|
+
- If fishing revenue cost unavailable → use inverse of fishing effort as proxy
|
|
93
|
+
- If no-take zones are mandatory in PA regulations → add no-take constraint as binary feature layer
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
---
|
|
2
|
+
resource_id: cost-surface-reference
|
|
3
|
+
skill_id: spatial-prioritization
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Cost Surface Reference for Conservation Planning
|
|
7
|
+
|
|
8
|
+
## Types of Conservation Cost
|
|
9
|
+
|
|
10
|
+
| Cost type | Definition | Data source | Bias risk |
|
|
11
|
+
|-----------|-----------|-------------|-----------|
|
|
12
|
+
| **Land acquisition** | Market value of land | Cadastral databases, government assessments | Overvalues urban-adjacent land |
|
|
13
|
+
| **Opportunity cost** | Foregone income if land is protected | Crop productivity + livestock density | Ignores non-market values |
|
|
14
|
+
| **Management cost** | Annual monitoring, enforcement, restoration | Government agency budgets | Variable by governance context |
|
|
15
|
+
| **Transaction cost** | Legal, administrative negotiation costs | Expert estimate | Often ignored; can dominate |
|
|
16
|
+
| **Area (proxy)** | Equal cost per PU (1 per cell) | Always available | No economic information |
|
|
17
|
+
|
|
18
|
+
**Recommended hierarchy:** Opportunity cost > land acquisition cost > area proxy. Use area proxy only when no cost data is available.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Opportunity Cost Construction
|
|
23
|
+
|
|
24
|
+
```r
|
|
25
|
+
suppressPackageStartupMessages(library(terra))
|
|
26
|
+
|
|
27
|
+
# Components of agricultural opportunity cost
|
|
28
|
+
crop_value <- rast("data/crop_net_revenue_usd_ha.tif") # $/ha/yr
|
|
29
|
+
livestock_value <- rast("data/livestock_density_TLU_ha.tif") # TLU/ha → $/ha/yr
|
|
30
|
+
timber_value <- rast("data/timber_potential_usd_ha.tif") # $/ha
|
|
31
|
+
|
|
32
|
+
# Weight livestock by price per TLU (e.g., 200 USD/TLU/yr)
|
|
33
|
+
livestock_opp <- livestock_value * 200
|
|
34
|
+
|
|
35
|
+
# Total opportunity cost = max of competing land uses
|
|
36
|
+
opp_cost <- max(crop_value, livestock_opp, timber_value, na.rm = TRUE)
|
|
37
|
+
|
|
38
|
+
# Replace NA with low cost (not zero — zero cost attracts solver spuriously)
|
|
39
|
+
opp_cost[is.na(opp_cost)] <- 1
|
|
40
|
+
writeRaster(opp_cost, "data/opportunity_cost.tif", overwrite = TRUE)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Cost Normalisation
|
|
46
|
+
|
|
47
|
+
```r
|
|
48
|
+
# Option 1: Standardise to 0–1 (useful for comparing solutions across regions)
|
|
49
|
+
cost_norm <- (opp_cost - global(opp_cost, "min", na.rm = TRUE)[[1]]) /
|
|
50
|
+
(global(opp_cost, "max", na.rm = TRUE)[[1]] -
|
|
51
|
+
global(opp_cost, "min", na.rm = TRUE)[[1]])
|
|
52
|
+
|
|
53
|
+
# Option 2: Log-transform (reduces influence of outlier high-cost cells)
|
|
54
|
+
cost_log <- log1p(opp_cost)
|
|
55
|
+
|
|
56
|
+
# Option 3: Percentile cap (cap at 95th percentile to remove outliers)
|
|
57
|
+
q95 <- quantile(values(opp_cost), 0.95, na.rm = TRUE)
|
|
58
|
+
cost_capped <- min(opp_cost, q95)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Choose normalisation based on cost distribution.** If cost is approximately log-normal (common for land values), log-transform avoids a few high-cost cells dominating the solution.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Cost Surface Uncertainty
|
|
66
|
+
|
|
67
|
+
Cost data often has high uncertainty. Test prioritisation robustness:
|
|
68
|
+
|
|
69
|
+
```r
|
|
70
|
+
# Run prioritization under 3 cost scenarios
|
|
71
|
+
cost_low <- cost * 0.7 # -30% uncertainty
|
|
72
|
+
cost_base <- cost
|
|
73
|
+
cost_high <- cost * 1.3 # +30% uncertainty
|
|
74
|
+
|
|
75
|
+
run_scenario <- function(cost_raster, name) {
|
|
76
|
+
p <- problem(cost_raster, features) %>%
|
|
77
|
+
add_min_set_objective() %>%
|
|
78
|
+
add_relative_targets(targets) %>%
|
|
79
|
+
add_highs_solver(gap = 0.01) %>%
|
|
80
|
+
add_binary_decisions()
|
|
81
|
+
s <- solve(p)
|
|
82
|
+
data.frame(scenario = name,
|
|
83
|
+
cost = eval_cost_summary(p, s)$cost,
|
|
84
|
+
n_pu = sum(values(s), na.rm = TRUE))
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
scenarios <- lapply(list(cost_low, cost_base, cost_high),
|
|
88
|
+
list("low", "base", "high"),
|
|
89
|
+
function(c, n) run_scenario(c, n))
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Locked-In and Locked-Out Planning Units
|
|
95
|
+
|
|
96
|
+
| Category | Definition | R implementation |
|
|
97
|
+
|----------|-----------|-----------------|
|
|
98
|
+
| **Locked-in** | Must be selected (existing PAs, community reserves) | `add_locked_in_constraints(locked_in_raster)` |
|
|
99
|
+
| **Locked-out** | Cannot be selected (developed areas, water bodies, military) | `add_locked_out_constraints(locked_out_raster)` |
|
|
100
|
+
| **Semi-locked** | Selected only if budget allows | Remove from locked constraints; let solver decide |
|
|
101
|
+
|
|
102
|
+
```r
|
|
103
|
+
# Build locked-in raster from protected area shapefile
|
|
104
|
+
pas <- st_read("data/wdpa_protected_areas.shp", quiet = TRUE)
|
|
105
|
+
locked_in <- rasterize(vect(pas), cost, field = 1, background = 0)
|
|
106
|
+
locked_in[is.na(cost)] <- NA # match planning unit extent
|
|
107
|
+
|
|
108
|
+
# Build locked-out from urban and water polygons
|
|
109
|
+
excluded <- st_read("data/urban_water_excluded.shp", quiet = TRUE)
|
|
110
|
+
locked_out <- rasterize(vect(excluded), cost, field = 1, background = 0)
|
|
111
|
+
locked_out[is.na(cost)] <- NA
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Pitfalls
|
|
117
|
+
|
|
118
|
+
- **Zero-cost cells attracting all PUs:** If cost = 0 for some PUs, the solver trivially selects them. Use a minimum cost floor (e.g., 1) for all non-excluded PUs.
|
|
119
|
+
- **Cost misalignment with features:** If cost raster is at 10-km resolution but features at 1-km, resampling introduces spatial mismatch. Always build cost at the same resolution as the analysis.
|
|
120
|
+
- **Ignoring non-market values:** Pure opportunity cost undervalues inaccessible, culturally important, or wilderness areas. Consider supplementing with ecosystem service values.
|
|
121
|
+
- **Using area as cost when land access is the real constraint:** In many developing-country contexts, political access (community agreements, government willingness) is the real cost, not land value. Document which cost metric was used and why.
|
|
122
|
+
- **Static cost surface:** Land values change over time. For 30-year planning horizons, consider projected future opportunity cost (discounted NPV of land use revenues).
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## References
|
|
127
|
+
|
|
128
|
+
- Naidoo, R. & Iwamura, T. (2007). Global-scale mapping of economic benefits from agricultural lands. *Biological Conservation*, 140(1–2), 40–49. DOI: 10.1016/j.biocon.2007.07.025
|
|
129
|
+
- Polasky, S. et al. (2008). Where to put things? Spatial land management to sustain biodiversity and economic returns. *Biological Conservation*, 141(6), 1505–1524. DOI: 10.1016/j.biocon.2008.03.022
|
|
130
|
+
- Ferraro, P.J. (2003). Asymmetric information and contract design for payments for environmental services. *Ecological Economics*, 65(4), 810–821. DOI: 10.1016/j.ecolecon.2007.07.029
|