Geospatial foundation models enable data-efficient tree species mapping in temperate mountain forests
Code for the paper (preprint).
Authors: James GC Ball, Jana Annika Wicklein, Zhengpeng Feng, Jovana Knezevic, Sadiq Jaffer, Anil Madhavapeddy, Clement Atzberger, Michele Dalponte, David Coomes
Data: Zenodo (10.5281/zenodo.18877941)
This repository contains all code for classifying 18 tree species and species groups at 10 m resolution across the Autonomous Province of Trento (Italian Alps) using geospatial foundation-model embeddings (AlphaEarth, Tessera) compared against conventional Sentinel-1/2 composites.
trentino-trees/
├── src/
│ ├── common/ Shared utilities (data loading, fold generation, metrics)
│ ├── model/ MLP classifiers, fraction/purity curves, temporal transfer
│ ├── preprocessing/ NPZ export, parcel merging, fractions lookup
│ ├── evaluation/ Cross-year transfer evaluation
│ ├── plotting/ UMAP, fraction curves, purity curves, temporal transfer plots
│ └── data_acquisition/ Google Earth Engine scripts, raster download utilities
├── scripts/ Experiment launchers and figure generation scripts
├── environment.yml Conda environment specification
└── LICENSE
git clone https://github.com/PatBall1/trentino-trees
cd trentino-trees
conda env create -f environment.yml
conda activate trent
export PYTHONPATH="$(pwd):$PYTHONPATH"Download the data from Zenodo.
Place the NPZ files into data/labels_merged/, renaming to remove the data__ prefix:
data__pre_distilled_labels_tessera2018.npz → data/labels_merged/pre_distilled_labels_tessera2018.npz
data__parcel_fractions_lookup.npz → data/labels_merged/parcel_fractions_lookup.npz
data__class_registry_jana.csv → data/labels_jana/class_registry_jana.csv
bash scripts/rerun_fraction_curves_v2.sh
python scripts/plot_fraction_curve_comparison_v3.pypython -m src.model.mlp_nested_cv_sklearn \
--npz data/labels_merged/pre_distilled_labels_tessera2018.npz \
--out results/mlp_nested_cv_sklearn/tessera_merged_balancedRepeat for each representation NPZ.
bash scripts/rerun_hard_label_purity_curves_v5.sh
python scripts/plot_purity_curve_comparison.pybash scripts/rerun_temporal_transfer_v3.shpython scripts/predict_landscape_combined.pyNot required if using the Zenodo NPZ files, but for full end-to-end reproducibility:
- Sentinel composites: Run
src/data_acquisition/s1s2annual.jsandsrc/data_acquisition/s1s2seasonal.jsin the Google Earth Engine Code Editor - AlphaEarth embeddings: Run
src/data_acquisition/alphaearth.jsin the GEE Code Editor - Tessera embeddings: Download via
src/data_acquisition/geotessera_pull.sh - NPZ generation from rasters:
python -m src.preprocessing.export_label_raster_npz --feature-raster <raster.tif> --parcel-path <parcels.gpkg> --out-npz <output.npz>
If you use this code, please cite the accompanying preprint and dataset:
@article{ball2026geospatial,
title={Geospatial foundation models enable data-efficient tree species mapping
in temperate mountain forests},
author={Ball, James GC and Wicklein, Jana Annika and Feng, Zhengpeng and
Knezevic, Jovana and Jaffer, Sadiq and Madhavapeddy, Anil and
Atzberger, Clement and Dalponte, Michele and Coomes, David},
journal={bioRxiv},
year={2026},
doi={10.64898/2026.02.23.707022}
}MIT