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.
Files changed (217) hide show
  1. package/AGENT_CONTEXT.md +191 -0
  2. package/CATALOG.md +329 -0
  3. package/LICENSE +692 -0
  4. package/README.md +347 -0
  5. package/bin/install.mjs +168 -0
  6. package/docs/comparison-with-alternatives.md +38 -0
  7. package/docs/global-examples-index.md +103 -0
  8. package/docs/repository-statistics.md +101 -0
  9. package/docs/theoretical-foundations.md +188 -0
  10. package/environment.yaml +106 -0
  11. package/examples/community/arctic_tundra_vegetation_example.md +247 -0
  12. package/examples/community/bird_landuse_example.md +63 -0
  13. package/examples/community/phytoplankton_reservoir_example.md +60 -0
  14. package/examples/community/reef_fish_indopacific_example.md +221 -0
  15. package/examples/impact/baci_road_example.md +57 -0
  16. package/examples/impact/ecosystem_services_atlantic_forest.md +83 -0
  17. package/examples/impact/forest_loss_borneo_timeseries_example.md +225 -0
  18. package/examples/occupancy/puma_camera_example.md +61 -0
  19. package/examples/occupancy/snow_leopard_himalayas_example.md +204 -0
  20. package/examples/reproducible/whittaker_biome_sdm_example.md +406 -0
  21. package/examples/sdm/anteater_cerrado_example.md +69 -0
  22. package/examples/sdm/jaguar_amazon_example.md +80 -0
  23. package/examples/sdm/koala_climate_change_example.md +170 -0
  24. package/examples/sdm/wolf_recolonization_europe_example.md +193 -0
  25. package/package.json +43 -0
  26. package/renv.lock +194 -0
  27. package/skills/SKILL_INDEX.json +1020 -0
  28. package/skills/acoustic-monitoring/SKILL.md +163 -0
  29. package/skills/acoustic-monitoring/examples/example-prompts.md +100 -0
  30. package/skills/acoustic-monitoring/examples/temperate_forest_birds_example.md +285 -0
  31. package/skills/acoustic-monitoring/resources/acoustic-indices-reference.md +93 -0
  32. package/skills/acoustic-monitoring/resources/soundscape-ecology-guide.md +90 -0
  33. package/skills/acoustic-monitoring/resources/species-id-tools-comparison.md +89 -0
  34. package/skills/acoustic-monitoring/scripts/batch_species_detection.py +360 -0
  35. package/skills/acoustic-monitoring/scripts/compute_acoustic_indices.R +235 -0
  36. package/skills/acoustic-monitoring/scripts/compute_acoustic_indices.py +374 -0
  37. package/skills/biostatistics-workbench/SKILL.md +140 -0
  38. package/skills/biostatistics-workbench/examples/example-prompts.md +39 -0
  39. package/skills/biostatistics-workbench/resources/effect-size-reference.md +81 -0
  40. package/skills/biostatistics-workbench/resources/glm-family-link-reference.md +47 -0
  41. package/skills/biostatistics-workbench/resources/test-selection-guide.md +93 -0
  42. package/skills/biostatistics-workbench/scripts/glm_pipeline.R +78 -0
  43. package/skills/biostatistics-workbench/scripts/glm_pipeline.py +210 -0
  44. package/skills/camera-trap-processing/SKILL.md +159 -0
  45. package/skills/camera-trap-processing/examples/example-prompts.md +103 -0
  46. package/skills/camera-trap-processing/examples/leopard_serengeti_example.md +231 -0
  47. package/skills/camera-trap-processing/resources/activity-patterns-reference.md +113 -0
  48. package/skills/camera-trap-processing/resources/camtrapR-workflow-guide.md +130 -0
  49. package/skills/camera-trap-processing/resources/detection-event-definition-guide.md +89 -0
  50. package/skills/camera-trap-processing/scripts/estimate_activity.R +169 -0
  51. package/skills/camera-trap-processing/scripts/process_camtrap_data.R +179 -0
  52. package/skills/camera-trap-processing/scripts/process_camtrap_data.py +192 -0
  53. package/skills/community-ecology-ordination/SKILL.md +133 -0
  54. package/skills/community-ecology-ordination/examples/example-prompts.md +35 -0
  55. package/skills/community-ecology-ordination/resources/dissimilarity-metric-guide.md +53 -0
  56. package/skills/community-ecology-ordination/resources/nmds-interpretation-guide.md +104 -0
  57. package/skills/community-ecology-ordination/scripts/__pycache__/community_analysis.cpython-311.pyc +0 -0
  58. package/skills/community-ecology-ordination/scripts/community_analysis.R +143 -0
  59. package/skills/community-ecology-ordination/scripts/community_analysis.py +231 -0
  60. package/skills/ecological-data-foundation/SKILL.md +129 -0
  61. package/skills/ecological-data-foundation/examples/example-prompts.md +40 -0
  62. package/skills/ecological-data-foundation/resources/coordinate-cleaning-flags.md +66 -0
  63. package/skills/ecological-data-foundation/resources/darwin-core-glossary.md +91 -0
  64. package/skills/ecological-data-foundation/resources/data-citation-guide.md +265 -0
  65. package/skills/ecological-data-foundation/resources/gbif-data-citation-guide.md +193 -0
  66. package/skills/ecological-data-foundation/resources/qa-checklist.md +83 -0
  67. package/skills/ecological-data-foundation/scripts/__pycache__/clean_occurrences.cpython-311.pyc +0 -0
  68. package/skills/ecological-data-foundation/scripts/__pycache__/download_from_ebird.cpython-311.pyc +0 -0
  69. package/skills/ecological-data-foundation/scripts/__pycache__/download_from_inat.cpython-311.pyc +0 -0
  70. package/skills/ecological-data-foundation/scripts/__pycache__/download_from_iucn.cpython-311.pyc +0 -0
  71. package/skills/ecological-data-foundation/scripts/__pycache__/download_from_obis.cpython-311.pyc +0 -0
  72. package/skills/ecological-data-foundation/scripts/clean_occurrences.R +230 -0
  73. package/skills/ecological-data-foundation/scripts/clean_occurrences.py +268 -0
  74. package/skills/ecological-data-foundation/scripts/download_from_ebird.R +251 -0
  75. package/skills/ecological-data-foundation/scripts/download_from_ebird.py +364 -0
  76. package/skills/ecological-data-foundation/scripts/download_from_gbif.R +315 -0
  77. package/skills/ecological-data-foundation/scripts/download_from_gbif.py +407 -0
  78. package/skills/ecological-data-foundation/scripts/download_from_inat.R +238 -0
  79. package/skills/ecological-data-foundation/scripts/download_from_inat.py +304 -0
  80. package/skills/ecological-data-foundation/scripts/download_from_iucn.R +273 -0
  81. package/skills/ecological-data-foundation/scripts/download_from_iucn.py +344 -0
  82. package/skills/ecological-data-foundation/scripts/download_from_obis.R +248 -0
  83. package/skills/ecological-data-foundation/scripts/download_from_obis.py +318 -0
  84. package/skills/ecological-impact-assessment/SKILL.md +123 -0
  85. package/skills/ecological-impact-assessment/examples/example-prompts.md +32 -0
  86. package/skills/ecological-impact-assessment/resources/baci-design-guide.md +55 -0
  87. package/skills/ecological-impact-assessment/resources/fragmentation-metrics-reference.md +86 -0
  88. package/skills/ecological-impact-assessment/resources/pressure-index-template.md +78 -0
  89. package/skills/ecological-impact-assessment/resources/study-design-guide.md +168 -0
  90. package/skills/ecological-impact-assessment/scripts/baci_analysis.R +161 -0
  91. package/skills/ecological-impact-assessment/scripts/fragmentation_analysis.py +141 -0
  92. package/skills/ecological-impact-assessment/scripts/power_analysis_baci.R +274 -0
  93. package/skills/ecosystem-services-assessment/SKILL.md +125 -0
  94. package/skills/ecosystem-services-assessment/examples/example-prompts.md +24 -0
  95. package/skills/ecosystem-services-assessment/resources/es-indicator-reference.md +45 -0
  96. package/skills/ecosystem-services-assessment/resources/invest-parameter-guide.md +86 -0
  97. package/skills/ecosystem-services-assessment/resources/rusle-coefficients.md +88 -0
  98. package/skills/ecosystem-services-assessment/scripts/__pycache__/compute_es.cpython-311.pyc +0 -0
  99. package/skills/ecosystem-services-assessment/scripts/compute_es.py +189 -0
  100. package/skills/ecosystem-services-assessment/scripts/tradeoff_analysis.R +161 -0
  101. package/skills/environmental-time-series/SKILL.md +125 -0
  102. package/skills/environmental-time-series/examples/example-prompts.md +33 -0
  103. package/skills/environmental-time-series/resources/anomaly-indices-reference.md +88 -0
  104. package/skills/environmental-time-series/resources/bfast-parameter-guide.md +69 -0
  105. package/skills/environmental-time-series/scripts/__pycache__/recovery_trajectory.cpython-311.pyc +0 -0
  106. package/skills/environmental-time-series/scripts/__pycache__/trend_analysis.cpython-311.pyc +0 -0
  107. package/skills/environmental-time-series/scripts/recovery_trajectory.R +305 -0
  108. package/skills/environmental-time-series/scripts/recovery_trajectory.py +178 -0
  109. package/skills/environmental-time-series/scripts/trend_analysis.R +192 -0
  110. package/skills/environmental-time-series/scripts/trend_analysis.py +184 -0
  111. package/skills/geoprocessing-for-ecology/SKILL.md +123 -0
  112. package/skills/geoprocessing-for-ecology/examples/example-prompts.md +32 -0
  113. package/skills/geoprocessing-for-ecology/resources/crs-reference.md +62 -0
  114. package/skills/geoprocessing-for-ecology/resources/global-predictor-sources.md +331 -0
  115. package/skills/geoprocessing-for-ecology/resources/resampling-methods.md +57 -0
  116. package/skills/geoprocessing-for-ecology/scripts/__pycache__/download_predictors.cpython-311.pyc +0 -0
  117. package/skills/geoprocessing-for-ecology/scripts/download_predictors.R +239 -0
  118. package/skills/geoprocessing-for-ecology/scripts/download_predictors.py +379 -0
  119. package/skills/geoprocessing-for-ecology/scripts/stack_and_extract.R +224 -0
  120. package/skills/geoprocessing-for-ecology/scripts/stack_and_extract.py +172 -0
  121. package/skills/landscape-connectivity/SKILL.md +170 -0
  122. package/skills/landscape-connectivity/examples/example-prompts.md +96 -0
  123. package/skills/landscape-connectivity/examples/jaguar_mesoamerica_corridor_example.md +271 -0
  124. package/skills/landscape-connectivity/resources/circuitscape-parameter-guide.md +155 -0
  125. package/skills/landscape-connectivity/resources/graph-theory-for-ecology.md +134 -0
  126. package/skills/landscape-connectivity/resources/resistance-surface-guide.md +141 -0
  127. package/skills/landscape-connectivity/scripts/connectivity_analysis.py +387 -0
  128. package/skills/landscape-connectivity/scripts/connectivity_metrics.R +274 -0
  129. package/skills/landscape-connectivity/scripts/resistance_surface.R +239 -0
  130. package/skills/model-validation-and-uncertainty/SKILL.md +131 -0
  131. package/skills/model-validation-and-uncertainty/examples/example-prompts.md +30 -0
  132. package/skills/model-validation-and-uncertainty/resources/extrapolation-risk-guide.md +236 -0
  133. package/skills/model-validation-and-uncertainty/resources/metric-selection-guide.md +52 -0
  134. package/skills/model-validation-and-uncertainty/resources/threshold-selection-guide.md +64 -0
  135. package/skills/model-validation-and-uncertainty/scripts/__pycache__/validate_model.cpython-311.pyc +0 -0
  136. package/skills/model-validation-and-uncertainty/scripts/extrapolation_risk.R +315 -0
  137. package/skills/model-validation-and-uncertainty/scripts/validate_model.py +226 -0
  138. package/skills/model-validation-and-uncertainty/scripts/validate_sdm.R +162 -0
  139. package/skills/occupancy-and-detection/SKILL.md +126 -0
  140. package/skills/occupancy-and-detection/examples/example-prompts.md +33 -0
  141. package/skills/occupancy-and-detection/resources/detection-history-format.md +100 -0
  142. package/skills/occupancy-and-detection/resources/occupancy-study-design.md +47 -0
  143. package/skills/occupancy-and-detection/scripts/__pycache__/occupancy_analysis.cpython-311.pyc +0 -0
  144. package/skills/occupancy-and-detection/scripts/occupancy_analysis.R +160 -0
  145. package/skills/occupancy-and-detection/scripts/occupancy_analysis.py +159 -0
  146. package/skills/population-viability-analysis/SKILL.md +161 -0
  147. package/skills/population-viability-analysis/examples/african_elephant_pva_example.md +266 -0
  148. package/skills/population-viability-analysis/examples/example-prompts.md +95 -0
  149. package/skills/population-viability-analysis/resources/extinction-risk-thresholds.md +128 -0
  150. package/skills/population-viability-analysis/resources/matrix-model-guide.md +139 -0
  151. package/skills/population-viability-analysis/resources/sensitivity-elasticity-reference.md +182 -0
  152. package/skills/population-viability-analysis/scripts/matrix_pva.R +258 -0
  153. package/skills/population-viability-analysis/scripts/pva_analysis.py +442 -0
  154. package/skills/population-viability-analysis/scripts/stochastic_pva.R +353 -0
  155. package/skills/predictive-modeling-best-practices/SKILL.md +136 -0
  156. package/skills/predictive-modeling-best-practices/examples/example-prompts.md +58 -0
  157. package/skills/predictive-modeling-best-practices/resources/collinearity-decision-tree.md +65 -0
  158. package/skills/predictive-modeling-best-practices/resources/sampling-bias-correction.md +267 -0
  159. package/skills/predictive-modeling-best-practices/resources/spatial-cv-guide.md +73 -0
  160. package/skills/predictive-modeling-best-practices/scripts/__pycache__/spatial_cv.cpython-311.pyc +0 -0
  161. package/skills/predictive-modeling-best-practices/scripts/collinearity_check.R +112 -0
  162. package/skills/predictive-modeling-best-practices/scripts/spatial_cv.py +182 -0
  163. package/skills/reproducible-ecology-pipeline/SKILL.md +139 -0
  164. package/skills/reproducible-ecology-pipeline/examples/example-prompts.md +35 -0
  165. package/skills/reproducible-ecology-pipeline/resources/directory-structure-template.md +94 -0
  166. package/skills/reproducible-ecology-pipeline/resources/params-yaml-template.yaml +84 -0
  167. package/skills/reproducible-ecology-pipeline/resources/reproducibility-checklist-template.md +66 -0
  168. package/skills/reproducible-ecology-pipeline/scripts/generate_file_manifest.py +110 -0
  169. package/skills/reproducible-ecology-pipeline/scripts/init_project.sh +53 -0
  170. package/skills/spatial-prioritization/SKILL.md +162 -0
  171. package/skills/spatial-prioritization/examples/biodiversity_hotspot_prioritization_example.md +289 -0
  172. package/skills/spatial-prioritization/examples/example-prompts.md +93 -0
  173. package/skills/spatial-prioritization/resources/cost-surface-reference.md +130 -0
  174. package/skills/spatial-prioritization/resources/marxan-vs-prioritizr-comparison.md +125 -0
  175. package/skills/spatial-prioritization/resources/prioritizr-formulation-guide.md +188 -0
  176. package/skills/spatial-prioritization/resources/representation-targets-guide.md +186 -0
  177. package/skills/spatial-prioritization/scripts/prioritization_sensitivity.R +320 -0
  178. package/skills/spatial-prioritization/scripts/run_prioritization.R +336 -0
  179. package/skills/species-distribution-modeling/SKILL.md +139 -0
  180. package/skills/species-distribution-modeling/examples/example-prompts.md +36 -0
  181. package/skills/species-distribution-modeling/resources/algorithm-comparison.md +25 -0
  182. package/skills/species-distribution-modeling/resources/calibration-area-guide.md +71 -0
  183. package/skills/species-distribution-modeling/resources/climate-scenario-preparation.md +170 -0
  184. package/skills/species-distribution-modeling/resources/maxent-calibration-guide.md +211 -0
  185. package/skills/species-distribution-modeling/resources/sdm-checklist.md +37 -0
  186. package/skills/species-distribution-modeling/scripts/predict_distribution.R +236 -0
  187. package/skills/species-distribution-modeling/scripts/predict_distribution.py +286 -0
  188. package/skills/species-distribution-modeling/scripts/prepare_future_layers.R +351 -0
  189. package/skills/species-distribution-modeling/scripts/project_scenarios.R +220 -0
  190. package/skills/species-distribution-modeling/scripts/run_ensemble_sdm.R +99 -0
  191. package/skills/species-distribution-modeling/scripts/sdm_pipeline.py +318 -0
  192. package/skills/species-distribution-modeling/scripts/tune_maxnet.R +344 -0
  193. package/templates/SKILL_TEMPLATE.md +225 -0
  194. package/templates/checklists/data-submission-checklist.md +38 -0
  195. package/templates/checklists/post-analysis-checklist.md +55 -0
  196. package/templates/checklists/pre-analysis-checklist.md +31 -0
  197. package/templates/prompts/debug-skill.md +47 -0
  198. package/templates/prompts/invoke-skill.md +34 -0
  199. package/templates/prompts/invoke-workflow.md +45 -0
  200. package/templates/reports/technical-report-template.md +80 -0
  201. package/templates/scripts/logger_setup.R +79 -0
  202. package/templates/scripts/logger_setup.py +119 -0
  203. package/templates/scripts/params_loader.R +28 -0
  204. package/templates/scripts/params_loader.py +38 -0
  205. package/workflows/analyze-community-structure/WORKFLOW.md +72 -0
  206. package/workflows/analyze-environmental-change/WORKFLOW.md +73 -0
  207. package/workflows/assess-ecological-impact/WORKFLOW.md +75 -0
  208. package/workflows/assess-ecosystem-services/WORKFLOW.md +68 -0
  209. package/workflows/assess-landscape-connectivity/WORKFLOW.md +84 -0
  210. package/workflows/build-fire-risk-map/WORKFLOW.md +79 -0
  211. package/workflows/produce-technical-report/WORKFLOW.md +113 -0
  212. package/workflows/run-camera-trap-occupancy/WORKFLOW.md +87 -0
  213. package/workflows/run-conservation-prioritization/WORKFLOW.md +89 -0
  214. package/workflows/run-multispecies-screening/WORKFLOW.md +197 -0
  215. package/workflows/run-occupancy-analysis/WORKFLOW.md +74 -0
  216. package/workflows/run-population-viability/WORKFLOW.md +90 -0
  217. package/workflows/run-sdm-study/WORKFLOW.md +99 -0
@@ -0,0 +1,331 @@
1
+ # Global Predictor Sources for Ecological Modelling
2
+
3
+ Reference guide for downloading environmental predictor layers used in Species Distribution Models (SDMs) and other ecological analyses. Each source includes access method, spatial resolution, temporal coverage, and recommended use cases.
4
+
5
+ ---
6
+
7
+ ## Summary Table
8
+
9
+ | Dataset | Type | Resolution | Coverage | Access | SDM Use |
10
+ |---------|------|-----------|----------|--------|---------|
11
+ | WorldClim v2.1 | Climate | 30s–10m | Global | Free | Bioclimatic variables (19 BIO) |
12
+ | CHELSA v2.1 | Climate | 30s | Global | Free | High-res bioclimatic variables |
13
+ | TerraClimate | Climate | ~4km | Global | Free | Monthly climate + water balance |
14
+ | ERA5-Land | Climate | ~9km | Global | Free (CDS) | Hourly/monthly reanalysis |
15
+ | MODIS | Remote sensing | 250m–1km | Global | Free (NASA) | NDVI, land cover, LST |
16
+ | Copernicus LC | Land cover | 100m | Global | Free | Land use / land cover |
17
+ | SoilGrids v2 | Soil | 250m | Global | Free | Soil properties (pH, SOC, clay) |
18
+ | MERIT DEM | Topography | ~90m | Global | Free | Elevation, slope, aspect |
19
+ | HydroSHEDS | Hydrology | 90m | Global | Free | River networks, catchments |
20
+ | GFW | Forest cover | 30m | Global | Free | Hansen tree cover change |
21
+ | ESA CCI LC | Land cover | 300m | Global | Free | Annual land cover 1992–2020 |
22
+ | Human Footprint | Anthropogenic | ~1km | Global | Free | Human pressure index |
23
+
24
+ ---
25
+
26
+ ## WorldClim v2.1
27
+
28
+ **URL**: https://worldclim.org/data/worldclim21.html
29
+ **DOI**: https://doi.org/10.1002/joc.5086
30
+ **Type**: Bioclimatic variables derived from temperature and precipitation
31
+ **Resolution**: 30 arc-seconds (~1 km), 2.5, 5, 10 arc-minutes
32
+ **Temporal coverage**: 1970–2000 (current); future SSP scenarios (CMIP6)
33
+ **Format**: GeoTIFF (.tif)
34
+
35
+ ### Download (R — geodata package)
36
+ ```r
37
+ library(geodata)
38
+ # 19 bioclimatic variables, 2.5 arc-minute resolution
39
+ bio <- worldclim_global(var = "bio", res = 2.5, path = "data/predictors/worldclim")
40
+ # Single variable: tmin, tmax, prec, srad, wind, vapr
41
+ tmax <- worldclim_global(var = "tmax", res = 2.5, path = "data/predictors/worldclim")
42
+ # Future scenario (CMIP6)
43
+ bio_fut <- cmip6_world(model = "MPI-ESM1-2-HR", ssp = "585", time = "2061-2080",
44
+ var = "bioc", res = 2.5, path = "data/predictors/worldclim")
45
+ ```
46
+
47
+ ### Download (Python — requests)
48
+ ```python
49
+ import requests
50
+ from pathlib import Path
51
+ url = "https://biogeo.ucdavis.edu/data/worldclim/v2.1/base/wc2.1_2.5m_bio.zip"
52
+ Path("data/predictors/worldclim").mkdir(parents=True, exist_ok=True)
53
+ r = requests.get(url, stream=True, timeout=300)
54
+ with open("data/predictors/worldclim/wc2.1_2.5m_bio.zip", "wb") as f:
55
+ for chunk in r.iter_content(chunk_size=65536):
56
+ f.write(chunk)
57
+ ```
58
+
59
+ **SDM guidance**: Use all 19 BIO variables, then apply collinearity screening (|r| > 0.7) to select non-redundant predictors. BIO1, BIO4, BIO12, BIO15 are often retained.
60
+
61
+ ---
62
+
63
+ ## CHELSA v2.1
64
+
65
+ **URL**: https://chelsa-climate.org/
66
+ **DOI**: https://doi.org/10.1038/s41597-021-01084-7
67
+ **Type**: High-resolution bioclimatic variables (superior to WorldClim in complex terrain)
68
+ **Resolution**: 30 arc-seconds (~1 km)
69
+ **Temporal coverage**: 1981–2010 (current); CMIP6 future scenarios
70
+ **Format**: NetCDF / GeoTIFF
71
+
72
+ ### Download (R — direct URL)
73
+ ```r
74
+ library(terra)
75
+ # CHELSA BIO1 (mean annual temperature)
76
+ url_bio1 <- "https://os.zhdk.cloud.switch.ch/envicloud/chelsa/chelsa_V2/GLOBAL/climatologies/1981-2010/bio/CHELSA_bio1_1981-2010_V.2.1.tif"
77
+ dir.create("data/predictors/chelsa", recursive = TRUE, showWarnings = FALSE)
78
+ download.file(url_bio1, destfile = "data/predictors/chelsa/CHELSA_bio1.tif",
79
+ mode = "wb", quiet = FALSE)
80
+ r <- terra::rast("data/predictors/chelsa/CHELSA_bio1.tif")
81
+ ```
82
+
83
+ ### Download (Python)
84
+ ```python
85
+ import requests
86
+ from pathlib import Path
87
+ base = "https://os.zhdk.cloud.switch.ch/envicloud/chelsa/chelsa_V2/GLOBAL/climatologies/1981-2010/bio"
88
+ out = Path("data/predictors/chelsa")
89
+ out.mkdir(parents=True, exist_ok=True)
90
+ for i in range(1, 20):
91
+ fname = f"CHELSA_bio{i}_1981-2010_V.2.1.tif"
92
+ r = requests.get(f"{base}/{fname}", stream=True, timeout=600)
93
+ r.raise_for_status()
94
+ (out / f"CHELSA_bio{i}.tif").write_bytes(r.content)
95
+ ```
96
+
97
+ **SDM guidance**: Prefer CHELSA over WorldClim in mountains, coastal areas, and tropical regions where topographic correction matters. CHELSA and WorldClim BIO variables are on the same scale and can substitute directly.
98
+
99
+ ---
100
+
101
+ ## TerraClimate
102
+
103
+ **URL**: https://www.climatologylab.org/terraclimate.html
104
+ **DOI**: https://doi.org/10.1038/sdata.2017.191
105
+ **Type**: Monthly climate and water balance (1958–present)
106
+ **Resolution**: ~4 km (1/24 degree)
107
+ **Format**: NetCDF
108
+
109
+ ### Download (R)
110
+ ```r
111
+ library(terra)
112
+ # Download monthly PDSI (Palmer Drought Severity Index), 2010
113
+ url <- "https://climate.northwestknowledge.net/TERRACLIMATE-DATA/TerraClimate_PDSI_2010.nc"
114
+ download.file(url, "data/predictors/terraclimate_PDSI_2010.nc", mode = "wb")
115
+ r <- terra::rast("data/predictors/terraclimate_PDSI_2010.nc")
116
+ ```
117
+
118
+ **Variables**: ppt (precip), tmax, tmin, aet, def, pdsi, pet, q, soil, srad, swe, vap, vpd, ws
119
+ **SDM guidance**: Useful for water-balance related species responses. Combine with WorldClim for multi-temporal analyses.
120
+
121
+ ---
122
+
123
+ ## ERA5-Land (Copernicus CDS)
124
+
125
+ **URL**: https://cds.climate.copernicus.eu/datasets/reanalysis-era5-land
126
+ **DOI**: https://doi.org/10.24381/cds.68d2bb30
127
+ **Type**: Monthly/hourly land surface reanalysis
128
+ **Resolution**: ~9 km (0.1 degree)
129
+ **Temporal coverage**: 1950–present
130
+ **Format**: NetCDF / GRIB
131
+
132
+ ### Download (Python — cdsapi)
133
+ ```python
134
+ import cdsapi
135
+ c = cdsapi.Client() # requires ~/.cdsapirc with key
136
+ c.retrieve(
137
+ "reanalysis-era5-land-monthly-means",
138
+ {
139
+ "variable": ["2m_temperature", "total_precipitation"],
140
+ "product_type": "monthly_averaged_reanalysis",
141
+ "year": [str(y) for y in range(1990, 2021)],
142
+ "month": [f"{m:02d}" for m in range(1, 13)],
143
+ "time": "00:00",
144
+ "format": "netcdf",
145
+ },
146
+ "data/predictors/era5_land_temp_precip.nc"
147
+ )
148
+ ```
149
+
150
+ **SDM guidance**: Best for recent time periods and when high temporal resolution is needed. Requires free Copernicus CDS account and cdsapi configuration.
151
+
152
+ ---
153
+
154
+ ## MODIS (NASA)
155
+
156
+ **URL**: https://lpdaac.usgs.gov/
157
+ **Type**: Remote sensing products (NDVI, EVI, land cover, LST, etc.)
158
+ **Resolution**: 250 m (NDVI/EVI), 500 m, 1 km (LST, land cover)
159
+ **Temporal coverage**: 2000–present (16-day composites)
160
+ **Format**: HDF / GeoTIFF
161
+
162
+ ### Download (R — MODIStsp / terra)
163
+ ```r
164
+ # MODIStsp for bulk MODIS download (requires NASA EarthData account)
165
+ # library(MODIStsp)
166
+ # MODIStsp() # interactive GUI
167
+
168
+ # Alternative: direct download via APPEEARS or terra/STAC
169
+ library(terra)
170
+ # MODIS NDVI via STAC (Microsoft Planetary Computer)
171
+ # See: https://planetarycomputer.microsoft.com/dataset/modis-13A1-061
172
+ ```
173
+
174
+ ### Download (Python — pystac)
175
+ ```python
176
+ import planetary_computer
177
+ import pystac_client
178
+ import stackstac
179
+ catalog = pystac_client.Client.open(
180
+ "https://planetarycomputer.microsoft.com/api/stac/v1",
181
+ modifier=planetary_computer.sign_inplace,
182
+ )
183
+ items = catalog.search(
184
+ collections=["modis-13A1-061"], # NDVI 500m 16-day
185
+ bbox=[-80, -15, -34, 5],
186
+ datetime="2020-01-01/2020-12-31",
187
+ ).item_collection()
188
+ stack = stackstac.stack(items, assets=["500m_16_days_NDVI"])
189
+ ```
190
+
191
+ **SDM guidance**: NDVI as a proxy for vegetation productivity. Use annual maximum NDVI or seasonal composites. Apply cloud-masking (QA layers) before use.
192
+
193
+ ---
194
+
195
+ ## Copernicus Global Land Cover
196
+
197
+ **URL**: https://lcviewer.vito.be/2019
198
+ **DOI**: https://doi.org/10.3390/rs12061044
199
+ **Type**: Annual global land cover
200
+ **Resolution**: 100 m
201
+ **Temporal coverage**: 2015–2019
202
+ **Format**: GeoTIFF
203
+
204
+ ### Download (Python)
205
+ ```python
206
+ # Available via Copernicus Land Service: https://land.copernicus.eu/global/products/lc
207
+ # Access requires free account; download per tile (20°x20°)
208
+ # Fractional cover layers: forest, shrub, grassland, cropland, urban, bare, water, permanent snow
209
+ ```
210
+
211
+ **SDM guidance**: Use fractional cover layers (0–100%) as continuous predictors rather than discrete class rasters. This retains more variation and improves model performance.
212
+
213
+ ---
214
+
215
+ ## SoilGrids v2.0
216
+
217
+ **URL**: https://soilgrids.org/
218
+ **DOI**: https://doi.org/10.1371/journal.pone.0169748
219
+ **Type**: Global soil property predictions at 6 standard depths
220
+ **Resolution**: 250 m
221
+ **Format**: GeoTIFF (Cloud-Optimised GeoTIFF via WCS/STAC)
222
+
223
+ ### Download (R — terra + WCS)
224
+ ```r
225
+ library(terra)
226
+ # pH at 0-5 cm depth (mean)
227
+ url_ph <- "https://maps.isric.org/mapserv?map=/map/phh2o.map&SERVICE=WCS&VERSION=2.0.1&REQUEST=GetCoverage&COVERAGEID=phh2o_0-5cm_mean&FORMAT=image/tiff&SUBSET=X(-8237000,-7196000)&SUBSET=Y(-1308000,-40000)&SUBSETTINGCRS=http://www.opengis.net/def/crs/EPSG/0/152160"
228
+ download.file(url_ph, "data/predictors/soilgrids_ph_0-5cm.tif", mode = "wb")
229
+ ```
230
+
231
+ **Variables**: clay, sand, silt content; soil organic carbon (SOC); pH (H₂O); bulk density; cation exchange capacity (CEC); available water content
232
+ **Depths**: 0–5, 5–15, 15–30, 30–60, 60–100, 100–200 cm
233
+ **SDM guidance**: Use surface horizon (0–5 cm) for most terrestrial SDMs. SOC and pH are the most ecologically meaningful for plant and invertebrate distributions.
234
+
235
+ ---
236
+
237
+ ## MERIT DEM
238
+
239
+ **URL**: http://hydro.iis.u-tokyo.ac.jp/~yamadai/MERIT_DEM/
240
+ **DOI**: https://doi.org/10.1029/2017WR021187
241
+ **Type**: Multi-Error-Removed Improved-Terrain DEM
242
+ **Resolution**: 3 arc-seconds (~90 m)
243
+ **Format**: GeoTIFF
244
+
245
+ ### Derived topographic variables (R)
246
+ ```r
247
+ library(terra)
248
+ dem <- terra::rast("data/predictors/merit_dem.tif")
249
+ slope <- terra::terrain(dem, v = "slope", unit = "degrees")
250
+ aspect <- terra::terrain(dem, v = "aspect", unit = "degrees")
251
+ tpi <- terra::terrain(dem, v = "TPI") # Topographic Position Index
252
+ tri <- terra::terrain(dem, v = "TRI") # Terrain Ruggedness Index
253
+ ```
254
+
255
+ **SDM guidance**: Elevation, slope, and aspect are key predictors for montane species. Topographic wetness index (TWI) can be derived using the `RSAGA` or `whitebox` packages.
256
+
257
+ ---
258
+
259
+ ## HydroSHEDS
260
+
261
+ **URL**: https://www.hydrosheds.org/
262
+ **DOI**: https://doi.org/10.1002/hyp.9936
263
+ **Type**: Hydrological datasets derived from SRTM
264
+ **Resolution**: 90 m (river network), 3 arc-min (basins)
265
+ **Format**: GeoTIFF / Shapefile
266
+
267
+ **Layers**: flow accumulation, flow direction, river network, sub-basins, catchments
268
+ **SDM guidance**: Essential for freshwater species SDMs. Use flow accumulation as a proxy for river size, and sub-basin polygons for spatial blocks in cross-validation.
269
+
270
+ ---
271
+
272
+ ## Global Forest Watch (Hansen)
273
+
274
+ **URL**: https://www.globalforestwatch.org/
275
+ **DOI**: https://doi.org/10.1126/science.1244693
276
+ **Type**: Annual forest cover change (2000–present)
277
+ **Resolution**: 30 m
278
+ **Format**: GeoTIFF (tiles)
279
+
280
+ ### Download (R — gfwr or direct tiles)
281
+ ```r
282
+ library(terra)
283
+ # Download canopy cover tile (e.g., 00N_070W)
284
+ url <- "https://storage.googleapis.com/earthenginepartners-hansen/GFC-2023-v1.11/Hansen_GFC-2023-v1.11_treecover2000_00N_070W.tif"
285
+ download.file(url, "data/predictors/hansen_treecover_00N_070W.tif", mode = "wb")
286
+ tc <- terra::rast("data/predictors/hansen_treecover_00N_070W.tif")
287
+ ```
288
+
289
+ **SDM guidance**: Use tree cover (%) as a continuous predictor. For change analyses, compute forest loss as cumulative annual loss to a given year. Threshold at 30% canopy cover for closed-canopy forest definition.
290
+
291
+ ---
292
+
293
+ ## ESA CCI Land Cover
294
+
295
+ **URL**: https://climate.esa.int/en/projects/land-cover/
296
+ **DOI**: https://doi.org/10.1016/j.rse.2017.07.028
297
+ **Type**: Annual global land cover classification
298
+ **Resolution**: 300 m
299
+ **Temporal coverage**: 1992–2020
300
+ **Format**: NetCDF
301
+
302
+ **SDM guidance**: Use for long time-series land cover change analyses. Reclassify the 37-class legend to broader categories meaningful for the taxon group. Consider using temporal stack for detectability analyses.
303
+
304
+ ---
305
+
306
+ ## Human Footprint Index
307
+
308
+ **URL**: https://wcshumanfootprint.org/
309
+ **DOI**: https://doi.org/10.1038/s41467-020-18509-4
310
+ **Type**: Cumulative human pressure index
311
+ **Resolution**: ~1 km
312
+ **Temporal coverage**: 2009, 2017
313
+ **Format**: GeoTIFF
314
+
315
+ **SDM guidance**: Strong predictor for threatened species with habitat sensitivity. Include in models for species with documented human disturbance responses. Standardise to [0,1] before use.
316
+
317
+ ---
318
+
319
+ ## Notes for SDM Use
320
+
321
+ 1. **Resolution matching**: Resample all layers to the same resolution (usually the coarsest) before stacking. Use bilinear interpolation for continuous variables, nearest-neighbour for categorical.
322
+
323
+ 2. **Collinearity**: Always run collinearity screening before modelling. Remove one variable from each pair with |r| > 0.7 (Spearman). Prefer variables with stronger ecological justification.
324
+
325
+ 3. **Extent**: Clip all layers to a consistent modelling extent before extraction. A buffer of 200–500 km around occurrence points is typical for regional SDMs.
326
+
327
+ 4. **Projection**: Reproject to a geographic CRS (WGS84 / EPSG:4326) for SDM unless the study area is small and a projected CRS is more appropriate.
328
+
329
+ 5. **Future projections**: Match the time period and SSP scenario of future climate layers to the same GCM used for baseline calibration. Use ensembles of ≥5 GCMs to quantify projection uncertainty.
330
+
331
+ 6. **Citation**: Always cite the specific dataset version and access date. Most datasets use DOI-based citation.
@@ -0,0 +1,57 @@
1
+ # Resampling Methods Reference
2
+
3
+ ## Method Descriptions
4
+
5
+ ### Nearest Neighbour (`near`)
6
+ - Assigns the value of the nearest source pixel
7
+ - **Use for:** Categorical data (land cover, soil type, administrative zones)
8
+ - **Avoid for:** Continuous data (creates blocky artefacts)
9
+ - GDAL flag: `-r near`
10
+
11
+ ### Bilinear (`bilinear`)
12
+ - Weighted average of the 4 nearest source pixels
13
+ - **Use for:** Continuous data (elevation, temperature, precipitation, NDVI)
14
+ - Avoids blocky artefacts; slightly smooths the data
15
+ - GDAL flag: `-r bilinear`
16
+
17
+ ### Cubic (`cubic`)
18
+ - Weighted average of the 16 nearest source pixels (bicubic spline)
19
+ - **Use for:** High-quality DEM processing, fine-resolution resampling
20
+ - Smoother than bilinear; may introduce slight ringing at edges
21
+ - GDAL flag: `-r cubic`
22
+
23
+ ### Average (`average`)
24
+ - Average of all source pixels overlapping the target pixel
25
+ - **Use for:** Downsampling (coarsening resolution); preserves mean values
26
+ - GDAL flag: `-r average`
27
+
28
+ ### Mode (`mode`)
29
+ - Most frequent value among source pixels
30
+ - **Use for:** Downsampling categorical data (land cover aggregation)
31
+ - GDAL flag: `-r mode`
32
+
33
+ ### Sum (`sum`)
34
+ - Sum of all source pixels overlapping the target pixel
35
+ - **Use for:** Count data aggregation (fire frequency, species count per cell)
36
+ - GDAL flag: `-r sum`
37
+
38
+ ## Decision Guide
39
+
40
+ ```
41
+ Is the data categorical?
42
+ YES → Use: nearest (upsampling) | mode (downsampling)
43
+ NO → Is high spatial precision critical?
44
+ YES → Use: cubic
45
+ NO → Are you downsampling (coarsening)?
46
+ YES → Use: average
47
+ NO → Use: bilinear
48
+ ```
49
+
50
+ ## Common Mistakes
51
+
52
+ | Mistake | Consequence | Fix |
53
+ |---------|-------------|-----|
54
+ | Bilinear on land cover | Creates fractional class values | Use nearest |
55
+ | Nearest on elevation | Blocky DEM, poor slope/aspect | Use bilinear or cubic |
56
+ | No resampling specified | GDAL defaults to nearest | Always specify `-r` |
57
+ | Mixing resolutions in stack | Spatial misalignment | Resample all to common grid first |
@@ -0,0 +1,239 @@
1
+ # ecological-agent-skills / Copyright (C) 2026 Francisco Diego Barros Barata
2
+ # SPDX-License-Identifier: GPL-3.0-or-later
3
+
4
+ # Usage: Rscript download_predictors.R <output_dir> [resolution] [extent_wkt] [source]
5
+
6
+ # ── Inline logger ─────────────────────────────────────────────────────────────
7
+ SKILL_NAME <- "geoprocessing-for-ecology"
8
+ .log_ts <- function() format(Sys.time(), "[%Y-%m-%d %H:%M:%S]")
9
+ log_info <- function(...) message(.log_ts(), " [INFO] ", sprintf(...))
10
+ log_warn <- function(...) message(.log_ts(), " [WARN] ", sprintf(...))
11
+ log_error<- function(...) message(.log_ts(), " [ERROR] ", sprintf(...))
12
+ log_step <- function(n, d) log_info("-- STEP %d: %s", n, d)
13
+ log_decision <- function(v, val, why) log_info("DECISION | %s = %s | %s", v, val, why)
14
+ dir.create("logs", recursive=TRUE, showWarnings=FALSE)
15
+
16
+ #
17
+ # Arguments:
18
+ # output_dir : Directory to write predictor rasters (created if absent)
19
+ # resolution : WorldClim resolution: 2.5, 5, or 10 (arc-minutes, default: 2.5)
20
+ # extent_wkt : WKT bounding box to clip outputs — e.g., "POLYGON((-80 -30,-80 10,-30 10,-30 -30,-80 -30))"
21
+ # If not provided, global layers are saved without clipping.
22
+ # source : Comma-separated list of sources to download: worldclim,chelsa,modis
23
+ # Default: "worldclim"
24
+ #
25
+ # Outputs:
26
+ # output_dir/worldclim/wc2.1_{res}m_bio_{1..19}.tif — WorldClim bioclimatic variables
27
+ # output_dir/chelsa/CHELSA_bio{1..19}.tif — CHELSA bioclimatic variables
28
+ # output_dir/predictor_metadata.csv — layer provenance and checksums
29
+ #
30
+ # References:
31
+ # WorldClim: Fick & Hijmans (2017) doi:10.1002/joc.5086
32
+ # CHELSA: Karger et al. (2021) doi:10.1038/s41597-021-01084-7
33
+
34
+ suppressPackageStartupMessages(library(terra))
35
+ suppressPackageStartupMessages(library(geodata))
36
+
37
+ # ── 1. Parse arguments ───────────────────────────────────────────────────────
38
+ log_step(1, "Analisar argumentos da linha de comando")
39
+ args <- commandArgs(trailingOnly = TRUE)
40
+
41
+ if (length(args) < 1) {
42
+ output_dir <- "data/predictors"
43
+ resolution <- 2.5
44
+ extent_wkt <- NULL
45
+ sources <- "worldclim"
46
+ log_warn("Nenhum argumento fornecido. Usando valores padrao.")
47
+ } else {
48
+ output_dir <- args[1]
49
+ resolution <- if (length(args) >= 2) as.numeric(args[2]) else 2.5
50
+ extent_wkt <- if (length(args) >= 3 && args[3] != "") args[3] else NULL
51
+ sources <- if (length(args) >= 4) args[4] else "worldclim"
52
+ }
53
+
54
+ sources_list <- trimws(strsplit(sources, ",")[[1]])
55
+
56
+ log_info("Script: download_predictors.R | Skill: %s", SKILL_NAME)
57
+ log_info("Output dir : %s", output_dir)
58
+ log_info("Resolution : %g arc-minutes", resolution)
59
+ log_info("Extent WKT : %s", ifelse(is.null(extent_wkt), "global (sem corte)", extent_wkt))
60
+ log_info("Sources : %s", paste(sources_list, collapse = ", "))
61
+
62
+ log_decision("resolution", resolution,
63
+ "2.5 arc-min (~4.5 km) e o equilibrio padrao entre detalhe e tamanho de arquivo")
64
+
65
+ if (!resolution %in% c(0.5, 2.5, 5, 10)) {
66
+ log_warn("Resolucao %g nao e um valor padrao do WorldClim (0.5, 2.5, 5, 10). Pode causar erro no download.", resolution)
67
+ }
68
+
69
+ # ── 2. Create output directory ───────────────────────────────────────────────
70
+ log_step(2, "Criar diretorio de saida")
71
+ dir.create(output_dir, recursive = TRUE, showWarnings = FALSE)
72
+
73
+ # ── 3. Parse extent ──────────────────────────────────────────────────────────
74
+ clip_extent <- NULL
75
+ if (!is.null(extent_wkt)) {
76
+ log_step(3, "Interpretar extensao WKT para corte de camadas")
77
+ tryCatch({
78
+ clip_extent <- terra::vect(extent_wkt, crs = "EPSG:4326")
79
+ log_info("Extensao de corte: %s", paste(as.vector(terra::ext(clip_extent)), collapse = ", "))
80
+ }, error = function(e) {
81
+ log_error(
82
+ "Falha ao interpretar extent_wkt: %s\nCausa provavel: WKT invalido.\nExemplo valido: POLYGON((-80 -30,-80 10,-30 10,-30 -30,-80 -30))\nSkill anterior: geoprocessing-for-ecology",
83
+ conditionMessage(e)
84
+ )
85
+ stop(e)
86
+ })
87
+ } else {
88
+ log_step(3, "Sem extensao de corte — camadas globais serao salvas integralmente")
89
+ }
90
+
91
+ # ── Helper: clip and save raster ─────────────────────────────────────────────
92
+ clip_and_save <- function(r, out_path, clip_ext) {
93
+ if (!is.null(clip_ext)) {
94
+ r <- tryCatch(
95
+ terra::crop(r, clip_ext),
96
+ error = function(e) {
97
+ log_warn("Falha ao cortar camada para extensao: %s. Salvando versao global.", conditionMessage(e))
98
+ r
99
+ }
100
+ )
101
+ }
102
+ dir.create(dirname(out_path), recursive = TRUE, showWarnings = FALSE)
103
+ terra::writeRaster(r, out_path, overwrite = TRUE)
104
+ log_info("Salvo: %s", out_path)
105
+ return(invisible(out_path))
106
+ }
107
+
108
+ # ── Helper: compute SHA256 checksum ──────────────────────────────────────────
109
+ sha256_file <- function(path) {
110
+ tryCatch({
111
+ digest::digest(file = path, algo = "sha256")
112
+ }, error = function(e) {
113
+ "N/A"
114
+ })
115
+ }
116
+
117
+ # ── Metadata accumulator ─────────────────────────────────────────────────────
118
+ meta_rows <- list()
119
+
120
+ # ── 4. Download WorldClim ────────────────────────────────────────────────────
121
+ if ("worldclim" %in% sources_list) {
122
+ log_step(4, "Baixar WorldClim v2.1 — variaveis bioclimaticas")
123
+ wc_dir <- file.path(output_dir, "worldclim")
124
+ dir.create(wc_dir, recursive = TRUE, showWarnings = FALSE)
125
+
126
+ log_decision("worldclim_var", "bio",
127
+ "19 variaveis bioclimaticas cobrem todos os aspectos de temperatura e precipitacao")
128
+
129
+ bio_stack <- tryCatch({
130
+ geodata::worldclim_global(var = "bio", res = resolution, path = wc_dir)
131
+ }, error = function(e) {
132
+ log_error(
133
+ "Falha ao baixar WorldClim: %s\nCausa provavel: sem conexao com a internet ou servidor WorldClim indisponivel.\nVerifique: https://worldclim.org/\nSkill anterior: geoprocessing-for-ecology",
134
+ conditionMessage(e)
135
+ )
136
+ stop(e)
137
+ })
138
+
139
+ log_info("WorldClim baixado: %d camadas", terra::nlyr(bio_stack))
140
+
141
+ # Save individual BIO layers
142
+ for (i in seq_len(terra::nlyr(bio_stack))) {
143
+ layer_name <- paste0("BIO", i)
144
+ out_path <- file.path(wc_dir, sprintf("wc2.1_%gm_bio_%d.tif", resolution, i))
145
+ r <- bio_stack[[i]]
146
+ clip_and_save(r, out_path, clip_extent)
147
+ meta_rows[[length(meta_rows) + 1]] <- list(
148
+ source = "WorldClim_v2.1",
149
+ variable = layer_name,
150
+ resolution = paste0(resolution, " arc-min"),
151
+ file = out_path,
152
+ citation = "Fick & Hijmans (2017) doi:10.1002/joc.5086",
153
+ licence = "CC BY 4.0",
154
+ download_date = format(Sys.Date(), "%Y-%m-%d")
155
+ )
156
+ }
157
+ log_info("WorldClim: todos os 19 BIO salvo em %s", wc_dir)
158
+ }
159
+
160
+ # ── 5. Download CHELSA ───────────────────────────────────────────────────────
161
+ if ("chelsa" %in% sources_list) {
162
+ log_step(5, "Baixar CHELSA v2.1 — variaveis bioclimaticas")
163
+ ch_dir <- file.path(output_dir, "chelsa")
164
+ dir.create(ch_dir, recursive = TRUE, showWarnings = FALSE)
165
+
166
+ chelsa_base <- "https://os.zhdk.cloud.switch.ch/envicloud/chelsa/chelsa_V2/GLOBAL/climatologies/1981-2010/bio"
167
+
168
+ for (i in 1:19) {
169
+ fname <- sprintf("CHELSA_bio%d_1981-2010_V.2.1.tif", i)
170
+ url <- paste0(chelsa_base, "/", fname)
171
+ out_path <- file.path(ch_dir, sprintf("CHELSA_bio%d.tif", i))
172
+
173
+ log_info("Baixando CHELSA BIO%d de: %s", i, url)
174
+ dl_ok <- tryCatch({
175
+ download.file(url, out_path, mode = "wb", quiet = TRUE)
176
+ TRUE
177
+ }, error = function(e) {
178
+ log_error(
179
+ "Falha ao baixar CHELSA BIO%d: %s\nCausa provavel: servidor CHELSA indisponivel ou sem conexao.\nVerifique: https://chelsa-climate.org/\nSkill anterior: geoprocessing-for-ecology",
180
+ i, conditionMessage(e)
181
+ )
182
+ FALSE
183
+ })
184
+
185
+ if (!dl_ok) next
186
+
187
+ # Apply clip if requested
188
+ if (!is.null(clip_extent)) {
189
+ tryCatch({
190
+ r <- terra::rast(out_path)
191
+ r <- terra::crop(r, clip_extent)
192
+ terra::writeRaster(r, out_path, overwrite = TRUE)
193
+ log_info("CHELSA BIO%d cortado para extensao de estudo.", i)
194
+ }, error = function(e) {
195
+ log_warn("Falha ao cortar CHELSA BIO%d: %s. Mantendo versao global.", i, conditionMessage(e))
196
+ })
197
+ }
198
+
199
+ log_info("CHELSA BIO%d salvo: %s", i, out_path)
200
+ meta_rows[[length(meta_rows) + 1]] <- list(
201
+ source = "CHELSA_v2.1",
202
+ variable = paste0("BIO", i),
203
+ resolution = "30 arc-sec (~1 km)",
204
+ file = out_path,
205
+ citation = "Karger et al. (2021) doi:10.1038/s41597-021-01084-7",
206
+ licence = "CC BY 4.0",
207
+ download_date = format(Sys.Date(), "%Y-%m-%d")
208
+ )
209
+ }
210
+ log_info("CHELSA: todos os 19 BIO processados em %s", ch_dir)
211
+ }
212
+
213
+ # ── 6. MODIS placeholder ─────────────────────────────────────────────────────
214
+ if ("modis" %in% sources_list) {
215
+ log_step(6, "MODIS: download requer conta NASA EarthData (nao automatizado)")
216
+ log_warn(
217
+ "Download automatizado de MODIS requer conta em https://urs.earthdata.nasa.gov/\n Use MODIStsp (R) ou AppEEARS (https://appeears.earthdatacloud.nasa.gov/) para downloads em lote.\n Alternativa Python: pystac com Microsoft Planetary Computer (nao requer conta).\n Consulte: skills/geoprocessing-for-ecology/resources/global-predictor-sources.md"
218
+ )
219
+ }
220
+
221
+ # ── 7. Save predictor metadata CSV ──────────────────────────────────────────
222
+ log_step(7, "Gravar metadata de preditores")
223
+ if (length(meta_rows) > 0) {
224
+ meta_df <- do.call(rbind, lapply(meta_rows, as.data.frame, stringsAsFactors = FALSE))
225
+ meta_path <- file.path(output_dir, "predictor_metadata.csv")
226
+ tryCatch({
227
+ write.csv(meta_df, meta_path, row.names = FALSE)
228
+ log_info("Metadata gravado: %s (%d camadas)", meta_path, nrow(meta_df))
229
+ }, error = function(e) {
230
+ log_error(
231
+ "Falha ao gravar metadata: %s\nSkill anterior: geoprocessing-for-ecology",
232
+ conditionMessage(e)
233
+ )
234
+ })
235
+ } else {
236
+ log_warn("Nenhuma camada baixada com sucesso. Arquivo de metadata nao criado.")
237
+ }
238
+
239
+ log_info("Download de preditores concluido. Verifique: %s", output_dir)