bluegreencity-ki

Configuration Reference: config/config.yaml

This document is the authoritative reference for every key in config/config.yaml. It is structured to mirror the file’s top-level sections so you can read them in parallel.

Table of Contents


Overview

config/config.yaml is the single configuration file that controls the entire BlueGreenCity-KI pipeline. It is loaded by bluegreencity_ki.core.config.load_config and passed as a plain Python dict to every module.

config/config.yaml
│
├── project           – CRS, run_date, backend, study areas
├── analytics         – Grafana read-only PostGIS analytics cache
├── inputs            – data sources (trees, rasters, roads, soil, …)
├── criteria          – list of risk criteria with weights and params
├── land_use          – land-use code → risk-score mapping
├── output            – GeoPackage / PostGIS output settings
├── integration       – optional API integrations
├── sustainability    – energy/CO₂ tracking
├── savings           – optional water/fuel/green-volume estimates
├── validation        – comparison against drought-damage ground truth
├── plausibility      – automated sanity checks
├── report            – artefact toggles (histograms, PNGs)
├── data_management   – PostGIS import and versioning metadata
├── climate           – DWD/Open-Meteo import settings
├── risk_products     – site vulnerability + irrigation action priority
├── irrigation_planning – deterministic irrigation draft planner
├── irrigation_review – local Taipy review UI settings
└── ml                – AutoGluon training and inference settings

The file ships with Hannover-specific defaults. All paths are relative to the project root unless stated otherwise or an absolute path is provided.


project

Global pipeline settings.

Key Type Default Description
crs string "EPSG:25832" Coordinate reference system used throughout the pipeline (ETRS89 / UTM zone 32N for Hannover).
run_date string "auto" Analysis reference date. "auto" uses today’s date; pass an ISO date string ("2025-06-01") to fix the date for reproducibility.
feature_reference_year int | null null Explicit reference year for year-aware criteria (age, groundwater, NDVI). When set, overrides the year derived from run_date. Use this to produce historical or panel snapshots (e.g. 2020). When run_date is "auto" and this key is set, run_date is automatically set to {feature_reference_year}-01-01.
backend string "osgeo" Spatial processing backend. Only "osgeo" (GeoPandas + GDAL) is supported in production.
scenario string "baseline" Scenario label stored in output metadata. Supports {feature_reference_year}. Change this when running alternative parameter scenarios.
neutral_score float 0.5 Score assigned when a criterion cannot compute a value (missing data). Range: 0–1.
raster_base_dir string (none) Base directory prepended to relative raster paths in inputs. Absolute raster paths always override this. If omitted, relative paths are resolved from the project root.
raster_sampling_cache mapping see below Optional persistent cache for raster sampling results across runs.

File output paths support {scenario}, {feature_reference_year}, {run_date} (YYYY-MM-DD), {run_date_underscore} (YYYY_MM_DD), {study_area} and {active_area}. For example, ./data/output/{run_date_underscore}_{scenario}/trees_at_risk.gpkg creates a readable run folder such as 2026_07_28_ml_operational_panel_2018_2023_predict_2024_validate_2025.

project.raster_sampling_cache

Persistent cache settings for expensive raster sampling (point/zonal).
The cache stores tree-level sampled values on disk and reuses them in later runs when the cache key matches.

Key Type Default Description
enabled bool false Enables persistent disk cache for raster sampling.
cache_dir string "./data/cache/raster_sampling" Directory where cache files are stored.
refresh bool false If true, bypasses existing cache entries for the current run and rewrites them.
version int | string 1 Manual cache namespace/version. Increase this to invalidate all existing entries after algorithm changes.

project.study_areas

Defines spatial regions for the analysis.

project:
  study_areas:
    active: "hannover_gesamt"      # Key of the currently active study area
    definitions:
      hannover_gesamt: { … }
      hannover_ml_training_2010: { … }

study_areas.active

Set this to the key of whichever study area definition should be used for the current run.

study_areas.definitions.<area_key>

Each study area definition can contain:

Key Type Required Description
name string yes Human-readable display name.
description string no Free-text description stored in run metadata.
bbox_source string yes "auto" (derive bounding box from tree data) or "manual" (use the bbox key below).
bbox list of 4 floats when bbox_source: manual [minlon, minlat, maxlon, maxlat] in EPSG:4326.
trees mapping yes Tree data source definition (see below).
trees sub-keys (CSV inventory)
trees:
  type: "csv_inventory"
  path: "./data/input/trees/Baum-2010-2025-v6_historisch_prod.csv"
  delimiter: ";"
  encoding: "utf-8"
  timestamp_column: "Zeitpunkt"
  timestamp_filter: "latest"     # or "2025-01-01" to pin a snapshot
  keep_invalid_geometry_rows: true
  exclude_from_analysis_statuses:
    - "removed_tree"
    - "tree_group_b"
    - "planned_tree_f"
    - "planned_not_planted"
    - "erroneous_record"
  geometry:
    x_column: "Rechtswert"
    y_column: "Hochwert"
    source_crs: "EPSG:25832"
    # Optional fallback (issue #216): rows without Rechtswert/Hochwert but with
    # valid WGS84 lat/lon get a point reprojected from EPSG:4326.
    lat_column: "Y (lat)"
    lon_column: "X (long)"
  column_mapping:
    "Baum ID": "objectid"
    "ID": "inventory_record_id"
    "Baumnummer": "baumnummer"
    "Weitere Hauptdaten Baumnummer (Typ)": "baumnummer_typ"
    "Gefällt am": "gefaellt_am"
    "Hauptdaten Pflanzjahr": "pflanzjahr"
    # … more column renames
  parse_leading_integer:
    - "vitalitaet"               # "2 noch befriedigend…" → 2
  id_field: "objectid"
  species_field: "ga_lang"
Key Type Description
type string "csv_inventory" for flat CSV files; "postgis" to read from PostgreSQL.
path string Path to the CSV file (relative to project root).
timestamp_column string Column that holds the snapshot date. Used with timestamp_filter.
timestamp_filter string "latest" selects the most recent snapshot; an ISO date selects a specific one.
timestamp_filter_mode string Controls per-group filtering when timestamp_filter is a date. "latest" (default) picks the single most recent row across all groups; "latest_on_or_before_per_group" picks the latest row per tree (identified by timestamp_group_column) on or before the filter date — useful for building historical panel snapshots where each tree should have its own most-recent-available record.
timestamp_group_column string Required when timestamp_filter_mode: "latest_on_or_before_per_group". Column that identifies individual trees across multiple snapshots (e.g. "ID").
keep_invalid_geometry_rows bool Keep rows with invalid coordinates as raw records with empty geometry. They remain available via ctx.vector["trees_raw"].
exclude_from_analysis_statuses list Inventory statuses that are excluded from criteria evaluation after loading.
geometry.x_column / geometry.y_column string CSV columns holding X (easting) and Y (northing) coordinates.
geometry.source_crs string CRS of the coordinate columns. Reprojected to project.crs automatically.
geometry.lat_column / geometry.lon_column string (optional, issue #216) WGS84 latitude/longitude columns used as a fallback for rows whose projected coordinates are missing or zero. The point is reprojected from EPSG:4326 to source_crs. Projected coordinates always take priority.
column_mapping map Renames long CSV headers to short pipeline-compatible names. Original columns are kept in the in-memory pipeline frame; on export (PostGIS/GPKG) redundant source columns — including legacy dot-separated variants from earlier CSV versions (e.g. Hauptdaten.Pflanzjahr) — are dropped when their mapped target is present.
parse_leading_integer list Columns where a leading integer is extracted from text before use (e.g. vitality stage).
row_filters map (optional) Filter rows by column value before loading. Useful to restrict to a single Objektart.
id_field string Column used as the tree identifier throughout the pipeline.
species_field string Column containing the species name (used by tolerance criteria).

The loader also derives a domain-level status model from the CSV, including inventory_status, exclude_from_analysis, and flags such as is_planned_not_planted, is_removed_tree, is_tree_group_b, is_planned_tree_f, is_erroneous_record, and has_valid_coordinates.

Historical CSV snapshot
trees:
  <<: *hannover_tree_inventory
  timestamp_filter: "2010-12-31"
  id_field: "objectid"

PostGIS tree inputs are no longer used. Historical study areas reuse the configured inventory CSV and select a fixed snapshot date.


analytics

Read-only PostGIS cache tables consumed by the Grafana dashboards. The active study area’s consolidated CSV remains the single source of truth for every rebuild.

analytics:
  ml_dashboard:
    schema: "bgcki"
    feature_source_table: "analysis_tree_risk_scores_ml_operational_panel"
    categorical_numeric_features: ["land_use_value"]
    files:            # annual-validation artifact layout
      feature_importance: "feature_importances/feature_importance_future_drought_damage_severe_t1.csv"
      leaderboard: "leaderboards/leaderboard_future_drought_damage_severe_t1.csv"
      shap_values: "shap/risk_classes_shap_values.csv"
      feature_values: "shap/risk_classes_feature_values.csv"
    operational_files:   # operational artifact layout (high-risk SHAP scope)
      feature_importance: "model/drought_risk_t1/explanation_feature_importance_training.csv"
      shap_values: "shap/high_risk_shap_values.csv"
      feature_values: "shap/high_risk_feature_values.csv"
    tables:
      feature_importance: "ml_feature_importance"
      leaderboard: "ml_model_leaderboard"
      shap_values: "ml_shap_value"
      correlation: "ml_feature_correlation"
      internal_validation: "ml_internal_validation"
      spatial_diagnostics: "ml_spatial_diagnostics"
  tree_inventory:
    schema: "bgcki"
    table: "tree_inventory_observation"
    chunk_size: 50000
    current:
      observed_at: "2026-09-11"
      source_columns: {…}   # v6 current-extract column mapping
    regular_care_areas: ["67.31.1", …, "67.31.7"]
    excluded_tree_number_types: ["freier Standort", …]
    source_columns: {…}     # historical CSV column mapping
  tree_year_analysis:
    schema: "bgcki"
    table: "tree_year_analysis"
    feature_source_table: "analysis_tree_risk_scores_ml_operational_panel"
    inventory_source_table: "tree_inventory_observation"
Key Description
ml_dashboard ML dashboard cache: feature source table, categorical_numeric_features, artifact file paths (files.* for the annual-validation layout, operational_files.* for the operational layout) and target tables.*. artifact_run_dir is auto-resolved from the newest annual-validation run; set it explicitly only to pin Grafana to a historical run.
tree_inventory Tree-inventory observation sync (table tree_inventory_observation, chunk_size: 50000). current.* maps the v6 current-extract columns (imported once per update as a single observation dated observed_at); source_columns maps the historical CSV columns; regular_care_areas and excluded_tree_number_types filter the sync.
tree_year_analysis Yearly per-tree analysis table (tree_year_analysis) built from the ML feature source table and the inventory observation table.

inputs

External data sources loaded before criteria run.

inputs.trees

Legacy shortcut for the tree source fields referenced from criteria modules. The actual data source is defined in the active study area.

inputs:
  trees:
    id_field: "objectid"
    species_field: "ga_lang"

inputs.enrichment

Spatial enrichment datasets are joined onto the tree inventory before any criteria are computed. All criteria automatically receive enriched attributes.

inputs.enrichment.obskh

Joins OBSkH crown data to the tree inventory via nearest-neighbour spatial join.

Key Type Default Description
enabled bool true Master switch for this enrichment layer.
path string — Path to the OBSkH point shapefile (relative to raster_base_dir or absolute).
join_tolerance_m float 3.0 Maximum join distance (metres).
crown_diameter_field string "krone" Column in the shapefile holding crown diameter (m).
crown_diameter_max_m float 35.0 Plausibility cap: values above this are set to NaN.

inputs.enrichment.citree

Loads the maintained Citree species-criteria catalog and joins it onto the inventory by species. Currently enabled (enabled: true); the catalog CSV lives under the repository (maintained via scripts/extract_citree_species_catalog.py), not under raster_base_dir.

Key Type Default Description
enabled bool true Master switch. When enabled, all citree_* columns are available to criteria (e.g. drought_tolerance, heat_tolerance).
path string "./data/derived/species/citree_species_criteria.csv" Path to the species catalog CSV (relative to project root).
species_field string "ga_lang" Tree column matched against the catalog species names.
columns map see config Catalog column → enriched citree_* column (14 columns, e.g. Trockenheitstoleranz → citree_trockenheitstoleranz).

inputs.roads

OSM road network used by the street_type and salt criteria.

Key Type Default Description
source string "osm" "osm" fetches via Overpass API and caches to PostGIS; "local" reads from the PostGIS table directly.
postgis_table string "context_osm_highways" PostGIS table where OSM roads are cached.
postgis_schema string "bgcki" PostGIS schema.
allowed list see config OSM highway types to include. Order matters for street_type risk scoring (first = highest risk).
buffer_m float 200.0 Bounding-box buffer (metres) added when fetching roads to ensure roads near the edge are fully captured.
overpass_endpoint string "https://overpass-api.de/…" Overpass API URL.
timeout_s int 180 Overpass request timeout in seconds.
refresh_days int 365 Cached OSM roads are re-fetched after this many days.

inputs.alkis_roads

ALKIS NAS WFS integration (LGLN Niedersachsen open data). Provides precise parcel-based street names for the salt criterion.

Key Type Description
wfs_url string LGLN WFS NAS endpoint URL.
wfs_version string WFS protocol version (e.g. "2.0.0").
flurstueck_layer string WFS layer name for parcels.
lagebezeichnung_layer string WFS layer name for parcel addresses.
street_names_csv_url string URL of the NDS street-name ZIP (CSV inside).
gemeinde_schluessel string 8-digit Gemeindeschlüssel identifying the municipality.
cache_dir string Local directory for the ALKIS GPKG cache.
cache_path string Full path to the cached GPKG file.
cache_layer string Layer name inside the cache GPKG.
refresh_days int Re-fetch from WFS after this many days.
bbox_wgs84 list of 4 floats [minlon, minlat, maxlon, maxlat] bounding box of the municipality in WGS84.
wfs_timeout int HTTP timeout per WFS request (seconds).
wfs_page_size int Features per WFS page (pagination).
landnutzung.gpkg_url string STAC download URL for ALKIS Landnutzung GPKG.
landnutzung.layer string Layer name for road surfaces inside the GPKG.
landnutzung.funktion_filter list of ints ALKIS Funktion codes to keep (carriageway surfaces only).

inputs.salt / inputs.salt_join

Configuration for the aha Winterdienst salt-exposure dataset.

inputs:
  salt:
    winterdienst_csv: "./data/derived/salt/winterdienst_strassenverzeichnis_2026.csv"
    winterdienst_name_field: "strassenname"
    winterdienst_class_field: "winterdienst"
    priority_field: "winterdienst"
  salt_join:
    max_distance: 50.0   # metres
Key Type Description
salt.winterdienst_csv string Path to the parsed Winterdienst street list CSV.
salt.winterdienst_name_field string Column with street name in the CSV.
salt.winterdienst_class_field string Column with priority class (W0, W1, W2).
salt.priority_field string Column forwarded to the criterion as the priority attribute.
salt_join.max_distance float Maximum tree-to-road distance (metres) for the spatial join.

inputs.osm_join

Optional cache for the tree–OSM-highway spatial join result.

Key Type Description
cache_path string Path to the joined GeoPackage cache file.
max_distance float Maximum search radius (metres) for nearest-road lookup.

Raster inputs

All raster entries follow a common structure:

<raster_key>:
  type: "file"     # or "tif"
  path: "…"        # relative to raster_base_dir, or absolute
  description: "…" # optional, metadata only
Config key Description
landuse_raster Land-use classification raster (Hannover Klimaanalyse 2022).
airtemp_raster_14h Daytime (14 h) air temperature raster (°C, 10 m resolution).
airtemp_raster_04h Night-time (04 h) air temperature raster (°C).
ndvi_raster NDVI raster from 2024 CIR aerial imagery.
ndvi_raster_2020 NDVI raster from 2020 for temporal comparison.
cold_air_kpr_raster Cold air production rate (KPR, m³/m²/h).
cold_air_kvs_raster Cold air volume flow (KVS, m³/m/s).
sky_view_factor_raster Sky View Factor (0–1, DGM + LOD2 buildings).
sunlit_hours_spring_raster Sunlit hours at spring equinox (March 20).
sunlit_hours_summer_raster Sunlit hours at summer solstice (June 21).
sunlit_hours_autumn_raster Sunlit hours at autumn equinox (September 22).
sunlit_hours_winter_raster Sunlit hours at winter solstice (December 21).
albedo_raster Surface albedo from UrbanGreenEye Sentinel-2 2024 (type: "file"; stores reflectance ×1000 — the albedo criterion scales it back with scale_factor: 0.001).
uhi_siedlungsraum_raster UHI night-temperature deviation (K) over settlement areas, GEONET Klimaanalyse 2022 (type: "file", 10 m).
uhi_verkehr_raster UHI night-temperature deviation (K) over traffic areas, GEONET Klimaanalyse 2022 (type: "file", 10 m).
dwsi_rasters UrbanGreenEye DWSI vitality rasters 2018–2025 (type: "file" per entry); a yearly_sources list with raster keys dwsi_2018 … dwsi_2025, used by the dwsi criterion.

inputs.groundwater

Groundwater monitoring data from LHH.

Key Type Description
type string "directory" – scans the folder for matching CSV files.
path string Path to the directory containing Flurabstand CSVs (relative to raster_base_dir).
file_pattern string Glob pattern to select CSVs inside the directory.
grimm_strele_path string Path to the Grimm-Strele 20-year trend shapefile.
well_id_field string Column with monitoring well ID.
x_field / y_field string Coordinate columns (Rechtswert / Hochwert, EPSG:25832).
flurabstand_field string Column with depth-to-groundwater value (m).
year_field string Column with the measurement year.

inputs.nfk_wfs

WFS source for NFK (usable field capacity) from the LBEG BK50 soil map.

Key Type Description
url string LBEG WFS endpoint.
typename string WFS layer name.
version string WFS protocol version.
srs_name string CRS of the WFS service.
bbox_wgs84 list [minlon, minlat, maxlon, maxlat] in WGS84.
nfk_value_field string Attribute with numeric NFKWE value (mm).
nfk_class_field string Attribute with NFKWE class (1–5).
cache_path string Path to the local GPKG cache.
refresh_days int Refresh interval in days.

inputs.gk25_wfs

WFS source for the GK25 geologic map (LBEG NIBIS cardomap, Detailkartierung, issue #166). The server ignores BBOX filters, so the loader performs a full GML download and clips client-side; cached.

Key Type Description
url / version string LBEG cardomap WFS endpoint (NodeId=201) and protocol version ("2.0.0").
typename string WFS layer ("cls:L160").
srs_name string Requested CRS ("EPSG:25832").
schichten_field / klartext_field string Attribute columns with the layer-sequence symbol string ("SCHICHTEN") and its text description ("KLARTEXT").
bbox_wgs84 list [minlon, minlat, maxlon, maxlat] client-side clip box.
cache_path string Local GPKG cache ("./data/derived/geology/gk25_hannover.gpkg").
refresh_days int Refresh interval (live: 365).

inputs.overture_transportation

Overture Maps transportation network filtered to subway tunnel segments (rail_classes: ["subway"], tunnel_only: true, issue #139); static infrastructure, therefore cached. Used by the subway_tunnel criterion.

Key Type Description
bbox_wgs84 list Query bounding box in WGS84.
rail_classes list Overture rail classes to fetch (live: ["subway"]).
tunnel_only bool Keep only is_tunnel segments.
cache_path string Local GPKG cache ("./data/derived/transport/subway_tunnels.gpkg").
refresh_days int Refresh interval (live: 365).

inputs.osm_construction

OSM construction sites (highway=construction, issue #139), fetched fresh from the Overpass API on every run — deliberately no cache, since construction sites are temporary. Used by the construction_sites criterion.

Key Type Description
bbox_wgs84 list Query bounding box in WGS84.

inputs.planting_sites

LHH “Baumumfeld” planting-site polygons (issue #194). Partial coverage and read fresh on every run — never cached. Used by land_use (surface-type score override) and planting_structure (trees in the same polygon).

Key Type Description
type string "file" — local GPKG (path relative to raster_base_dir).
path string "Baumumfeld/Baumumfeld_zusammengefasst.gpkg".
layer string GPKG layer name ("Baumumfeld_zusammengefasst").
surface_type_field string Polygon column holding the surface type ("kategorie").

inputs.seasonal_weather

Per-tree × per-year weather features from DWD HYRAS + FAO-ET0 (issue #213); used by the seasonal_weather criterion.

Key Type Description
type string "csv".
path string "data/derived/ml/tree_seasonal_weather.csv" (relative to project root).

criteria

The criteria key is a list of criterion entries. Each entry activates one criterion and assigns it a weight in the final risk score aggregation.

criteria:
  - name: "age"
    weight: 0.5
    params:       # optional, criterion-specific
      …
    normalizer_params:   # optional
      q_low: 0.05
      q_high: 0.95
      clip: true
Sub-key Type Description
name string Criterion identifier (must match a registered criterion in criteria_catalog).
weight float Relative weight in the weighted-average aggregation. All weights are normalized automatically; absolute values only matter relative to one another.
params map Criterion-specific parameters (see individual sections below).
normalizer_params map Parameters for the quantile normalizer (q_low, q_high, clip). Used by continuous criteria.

Order of criteria in the list does not affect the final score. Remove a criterion entry to exclude it from the run.


Criterion: salt

Evaluates road-salt exposure risk using aha Winterdienst priority classes.

- name: "salt"
  weight: 0.5
  params:
    mapping:
      "W1": 1.0    # highest priority (most salt) → highest risk
      "W2": 0.5
      "W0": 0.0    # not on Winterdienst route → no salt risk
Param Type Description
mapping map Maps Winterdienst class to risk score (0–1).

Criterion: street_type

Scores drought risk based on the OSM highway classification of the nearest road.

- name: "street_type"
  weight: 0.5

No params are required. The risk ordering is derived from the order of inputs.roads.allowed: the first entry in that list is highest risk, the last is lowest. Trees with no nearby road receive score 0.0.


Criterion: age

Estimates tree age and maps it to a risk score using quantile normalization.

- name: "age"
  weight: 0.5
  normalizer_params:
    q_low: 0.05
    q_high: 0.95
    clip: true

Age is determined in two stages:

  1. If pflanzjahr is available: age = feature_reference_year − pflanzjahr (uses feature_reference_year from project if set, otherwise falls back to run_date.year).
  2. If pflanzjahr is missing: piecewise estimate from stem circumference (st_umfang) using Stadt Hannover classification tables.
Normalizer param Type Default Description
q_low float 0.05 Lower quantile for normalization (clipped to 0.0).
q_high float 0.95 Upper quantile for normalization (clipped to 1.0).
clip bool true Clip scores outside [0, 1] to the boundary values.

Output extras: age_value (years), age_source ("pflanzjahr" | "circumference" | "missing"), age_reference_year (the year used for the age calculation — helpful when running historical panel snapshots).


Criterion: vitality

Maps the tree vitality stage (0–5) to a risk score.

- name: "vitality"
  weight: 0.5
  params:
    exclude_stages: [4, 5]   # dead / degenerating → score 0.0
    stage0_score: 0.5        # score for missing / stage-0 trees
Param Type Default Description
exclude_stages list of int [4, 5] Stages mapped to score 0.0 (watering exclusion semantics).
stage0_score float 0.5 Score assigned when vitality is 0 or missing.

Stages 1–3 are linearly scaled: score = stage / 3.0.


Criterion: planting_structure

Groups trees by proximity and scores isolated trees as higher risk.

- name: "planting_structure"
  weight: 0.5
  params:
    radius_m: 25.0
    mode: breaks
    neighbor_breaks: [0, 4, 9]
    neighbor_scores: [0.8, 0.5, 0.3, 0.1]
Param Type Default Description
radius_m float 25.0 Neighbourhood radius (metres) for counting nearby trees.
mode string "breaks" "breaks" (class-based) or "linear" (risk decreases continuously with neighbor count).
neighbor_breaks list of int [0, 4, 9] Class thresholds (for mode: breaks). Defines 4 classes: 0, 1–4, 5–9, ≥10.
neighbor_scores list of float [0.8, 0.5, 0.3, 0.1] Risk scores per class (must have one more entry than neighbor_breaks).
neighbor_min int auto Lower bound for linear scaling (for mode: linear).
neighbor_max int auto Upper bound for linear scaling (for mode: linear).

Criterion: air_temperature_day

Scores daytime drought risk from the 14 h air temperature raster.

- name: "air_temperature_day"
  weight: 0.5
  params:
    threshold_method: "tree_percentile"
    use_zonal_statistics: true
    low_percentile: 5
    high_percentile: 95
    temp_day_low: 20.0    # for static method
    temp_day_high: 30.0   # for static method
Param Type Description
threshold_method string "tree_percentile" (recommended), "spatial_percentile", or "static".
use_zonal_statistics bool When true, uses mean temperature over the crown buffer (requires OBSkH crown diameter); falls back to point sampling.
low_percentile / high_percentile int Percentile thresholds for adaptive methods.
temp_day_low / temp_day_high float Fixed temperature thresholds (°C) for static method.

Criterion: air_temperature_night

Scores nighttime heat stress from the 04 h air temperature raster.

- name: "air_temperature_night"
  weight: 0.5
  params:
    threshold_method: "tree_percentile"
    use_zonal_statistics: true
    low_percentile: 5
    high_percentile: 95
    temp_night_low: 15.0   # for static method
    temp_night_high: 22.0  # for static method

Parameters are identical in structure to air_temperature_day.


Criterion: uhi_intensity

Scores Urban Heat Island intensity as ΔT = T₁₄ₕ − T₀₄ₕ. A small ΔT means poor nocturnal cooling (strong UHI) → higher risk. The score is inverted: score = 1 − normalized(ΔT).

- name: "uhi_intensity"
  weight: 0.5
  params:
    threshold_method: "tree_percentile"
    use_zonal_statistics: true
    low_percentile: 5
    high_percentile: 95
    uhi_low: 5.0     # for static method (K)
    uhi_high: 10.0   # for static method (K)
Param Type Description
threshold_method string "tree_percentile" or "static".
uhi_low / uhi_high float Fixed ΔT thresholds in Kelvin for the static method.

Criterion: land_use

Samples the land-use raster at tree locations and looks up the risk score from the land_use mapping section.

- name: "land_use"
  weight: 0.5
  params:
    nodata_value: 28   # code to treat as NoData

Criterion: ndvi

Scores vegetation health from NDVI (Normalized Difference Vegetation Index). High NDVI = healthy vegetation = lower drought risk.

- name: "ndvi"
  weight: 0.5
  params:
    threshold_method: "sample_percentile"
    low_percentile: 5
    high_percentile: 95
    ndvi_low: 0.2    # for static method
    ndvi_high: 0.6   # for static method
    mode: "multi_temporal"
    raster_key_2: "ndvi_2020"
    change_weight: 0.0
    change_threshold: 0.1
Param Type Description
threshold_method string "sample_percentile" (from tree values), "spatial_percentile" (full raster, high RAM), or "static".
mode string "single_date" or "multi_temporal" (compares two NDVI rasters).
raster_key_2 string Config key for the second (older) NDVI raster when mode: multi_temporal.
change_weight float Weight of NDVI change in the final score (0 = change stored but not used).
change_threshold float NDVI change normalization range.
yearly_sources list (optional) Year-range-based raster selection for panel snapshots. When present, the raster used is determined by matching feature_reference_year (or run_date.year) against the defined ranges instead of using a single fixed raster key. See below for the entry structure.

ndvi.yearly_sources entries

Each entry defines a year range and the raster to use for it:

params:
  mode: "single_date"
  yearly_sources:
    - start_year: 2020
      end_year: 2023
      raster_key: "ndvi_2020"
      source_year: 2020
      output_column: "ndvi_value_2020"   # written to extras
    - start_year: 2024
      end_year: 2026
      raster_key: "ndvi"
      source_year: 2024
      output_column: "ndvi_value_2024"
Sub-key Type Description
start_year int First year (inclusive) for which this raster applies.
end_year int Last year (inclusive) for which this raster applies.
raster_key string Key in inputs pointing to the raster to sample from.
source_year int Stored in output as ndvi_source_year for provenance tracking.
output_column string Year-specific extras column written alongside the canonical ndvi_value_current.

When yearly_sources is configured, the criterion produces these dynamic output columns instead of the static ndvi_value:

Column Description
ndvi_value_current NDVI value from the matched raster (used for scoring and as the ML feature).
ndvi_source_year Calendar year of the raster used (for provenance).
ndvi_age_years feature_reference_year − ndvi_source_year (measures data freshness).
ndvi_available True/False – whether a valid NDVI value was found for this tree.
ndvi_value_<year> Year-specific column (e.g. ndvi_value_2024) for backwards-compat exports.

Criterion: albedo

Scores surface albedo sampled from the UrbanGreenEye Sentinel-2 raster (inputs.albedo_raster): low albedo = darker, heat-absorbing surroundings → higher drought stress risk.

- name: "albedo"
  weight: 0.015353
  params:
    threshold_method: "sample_percentile"
    scale_factor: 0.001      # raster stores integer reflectance × 1000
    valid_min: 0.0
    valid_max: 1.2
    low_percentile: 5
    high_percentile: 95
    albedo_low: 0.10         # for static method
    albedo_high: 0.22
Param Type Description
threshold_method string "sample_percentile" (live), "spatial_percentile", or "static".
scale_factor float Converts the stored integer reflectance to unitless albedo.
valid_min / valid_max float Valid physical range after scaling.
albedo_low / albedo_high float Fixed albedo thresholds for the static method.

Criterion: dwsi

Scores the UrbanGreenEye DWSI tree-vitality index sampled from yearly summer rasters (inputs.dwsi_rasters): negative values = vitality loss → higher drought risk; 5000 marks cloud-masked pixels.

- name: "dwsi"
  weight: 0.050970
  params:
    threshold_method: "sample_percentile"
    low_percentile: 5
    high_percentile: 95
    dwsi_low: -20.0          # for static method (percentage scale −100…+100)
    dwsi_high: 20.0
    valid_min: -100.0
    valid_max: 100.0
    cloud_mask_value: 5000
    yearly_sources:          # one entry per year: dwsi_2018 … dwsi_2025
      - {start_year: 2018, end_year: 2018, raster_key: "dwsi_2018", source_year: 2018}
Param Type Description
dwsi_low / dwsi_high float Static thresholds on the percentage scale (−100…+100).
cloud_mask_value int Raster value marking cloud-masked pixels.
yearly_sources list Year → dwsi_<year> raster selection (same structure as ndvi.yearly_sources).

Criterion: seasonal_weather

Joins per-tree × per-year weather features (DWD HYRAS + FAO-ET0, issue #213) from inputs.seasonal_weather. Pure ML context features — it does not contribute to the rule-based score (weight 0.0).

- name: "seasonal_weather"
  weight: 0.0
  params:
    path: "data/derived/ml/tree_seasonal_weather.csv"

Criterion: drought_tolerance

Maps drought-tolerance ratings from the enriched Citree tree fields to risk scores.

- name: "drought_tolerance"
  weight: 0.5
  params:
    source_column: "citree_trockenheitstoleranz"
    mapping:
      sehr tolerant: 0.1
      trockentolerant: 0.3
      mittel: 0.5
      empfindlich: 0.8
      vertraegt keine trockenheit: 0.8
      unbekannt: 0.5
      "": 0.5
Param Type Description
source_column string Enriched tree column containing the Citree drought tolerance label.
mapping map Text rating → risk score. Required – no built-in fallback.

Criterion: pit_size

Maps below-ground root space quality to risk scores using the inventory field Wurzel Wurzelraum.

- name: "pit_size"
  weight: 0.5
  params:
    mapping:
      "gesamter wurzelbereich versiegelt": 0.9
      "baumscheibe kleiner als 2 x 2 m": 0.8
      …
      "gesamter wurzelbereich unversiegelt": 0.1
      "nan": 0.5
      "": 0.5
Param Description
mapping German inventory text → risk score (0–1). Required.

Criterion: tree_disc

Maps above-ground tree disc cover type to risk scores using the inventory field Wurzel Baumscheibenbedeckung.

- name: "tree_disc"
  weight: 0.5
  params:
    mapping:
      "bewachsen": 0.1
      "undurchlässig (asphalt, etc.)": 0.9
      …
      "nan": 0.5
      "": 0.5

Structure identical to pit_size.


Criterion: heat_tolerance

Maps heat-tolerance ratings from the enriched Citree tree fields to risk scores.

- name: "heat_tolerance"
  weight: 0.5
  params:
    source_column: "citree_hitzevertraeglichkeit"
    mapping:
      gut: 0.1
      mittel: 0.4
      schwach: 0.7
      unbekannt: 0.5
      "": 0.5

Structure identical to drought_tolerance.


Criterion: cold_air

Combines cold air production rate (KPR) and volume flow (KVS) from the FITNAH climate model into a single microclimate cooling score. High cold air values → better cooling → lower drought risk (inverted score).

- name: "cold_air"
  weight: 0.5
  params:
    threshold_method: "sample_percentile"
    low_percentile: 5
    high_percentile: 95
    kpr_low: 5.0     # for static method
    kpr_high: 30.0
    kvs_low: 1.0
    kvs_high: 10.0
    kpr_weight: 0.5  # must sum to 1.0
    kvs_weight: 0.5
Param Type Description
threshold_method string "sample_percentile", "spatial_percentile", or "static".
kpr_low / kpr_high float KPR thresholds (m³/m²/h) for static method.
kvs_low / kvs_high float KVS thresholds (m³/m/s) for static method.
kpr_weight / kvs_weight float Weights for the combined score (must sum to 1.0).

Criterion: field_capacity

Scores water availability from NFK (usable field capacity, mm) from the LBEG BK50 soil map, with special handling for new plantings and inner-city trees.

- name: "field_capacity"
  weight: 0.5
  params:
    new_planting_year_threshold: 2015
    new_planting_year_score: 0.3
    new_planting_nfkwe_value: 170
    missing_score: 0.9
    breakpoints:
      0: 1.0
      50: 0.9
      90: 0.7
      120: 0.5
      160: 0.3
      250: 0.1
Param Type Description
new_planting_year_threshold int Trees planted after this year are treated as new plantings in engineered substrate.
new_planting_year_score float Fixed risk score for new plantings.
new_planting_nfkwe_value int Assumed NFKWE (mm) for new plantings (Hannover Typ 2 substrate).
missing_score float Risk score when no BK50 polygon covers the tree location (typically inner city).
breakpoints map NFKWE (mm) → risk score. Values between breakpoints are linearly interpolated. Required.

Criterion: gk25

Classifies the uppermost layer of the GK25 geologic map (inputs.gk25_wfs, issue #166) into a material class and maps it to a risk score. Weight 0.0: contributes the gk25_material_class extra / ML feature only, not to the weighted total, until the weights are recalibrated.

- name: "gk25"
  weight: 0.0
  params:
    material_scores:
      anthropogenic: 0.8
      water: 0.1
      rock: 0.6
      peat: 0.2
      clay: 0.4
      silt_loam: 0.3
      mixed_silt_sand: 0.5
      gravel: 0.8
      sand: 0.7
Param Description
material_scores Material class → risk score (drought stress via water storage / drainage).

Criterion: subway_tunnel

Scores proximity to underground Stadtbahn tunnel segments (inputs.overture_transportation, issue #139): tunnels limit soil volume and can lower the local groundwater table. Weight 0.0: contributes the subway_tunnel_dist_m extra / ML feature only, pending recalibration.

- name: "subway_tunnel"
  weight: 0.0
  params:
    distance_breaks: [15, 30]          # metres to nearest tunnel segment
    distance_scores: [0.8, 0.5, 0.1]   # ≤15 m → 0.8, ≤30 m → 0.5, else 0.1

Criterion: construction_sites

Scores proximity to active road construction sites (inputs.osm_construction, fetched fresh every run, issue #139). Weight 0.0: contributes the construction_dist_m extra / ML feature only, pending recalibration.

- name: "construction_sites"
  weight: 0.0
  params:
    distance_breaks: [25]              # metres to nearest construction way
    distance_scores: [0.7, 0.1]        # ≤25 m → 0.7, else 0.1

Criterion: groundwater

Scores drought risk from depth to groundwater (Flurabstand) using Ordinary Kriging interpolation (live default) from ~200 LHH monitoring wells; IDW is available as fallback via interpolation_method. An optional Grimm-Strele 20-year trend adjustment is configured but currently inactive (trend_enabled: false in the live config).

- name: "groundwater"
  weight: 0.5
  params:
    scoring_source: "median"   # "latest", "median", or "max"
    interpolation_method: "kriging"   # "kriging" (Ordinary Kriging) or "idw"
    variogram_model: "exponential"    # kriging only: exponential|spherical|gaussian|linear|power
    idw_power: 2                      # idw only
    max_distance_m: 5000
    min_neighbors: 3
    breakpoints:
      0.0: 0.1
      1.0: 0.2
      2.0: 0.4
      4.0: 0.6
      6.0: 0.8
      10.0: 0.95
    trend_enabled: false
    trend_adjustment:
      "stark steigend": -0.1
      "steigend": -0.05
      "gleich bleibend": 0.0
      "fallend": 0.05
      "stark fallend": 0.1
Param Type Description
scoring_source string Which temporal aggregation drives the risk score: "latest", "median", or "max".
interpolation_method string "kriging" (Ordinary Kriging, live default) or "idw" (fallback).
variogram_model string Variogram model for kriging (live: "exponential"; also spherical, gaussian, linear, power).
idw_power int IDW weighting exponent (higher = more local influence); used only when interpolation_method: "idw".
max_distance_m float Trees beyond this distance from any well receive the neutral score.
min_neighbors int Minimum number of wells for a valid interpolation.
breakpoints map Depth (m) → risk score. Linearly interpolated. Required.
trend_enabled bool Whether to apply the Grimm-Strele trend adjustment.
trend_adjustment map Trend label → additive score modifier.

When project.feature_reference_year is set, the groundwater criterion filters well data to measurements up to and including that year before aggregating. This ensures that panel snapshots for e.g. 2020 only use well readings ≤ 2020 and do not look ahead. The output extras include feature_reference_year and years_used_for_snapshot for provenance.


Criterion: sky_view_factor

Scores tree exposure from the Sky View Factor (SVF), which measures the fraction of sky visible from a point (0 = fully enclosed, 1 = open sky).

- name: "sky_view_factor"
  weight: 0.5
  params:
    threshold_method: "tree_percentile"
    interpretation: "shading_protection"
    low_percentile: 10
    high_percentile: 90
    svf_low: 0.3    # for static method
    svf_high: 0.7
Param Type Description
threshold_method string "tree_percentile", "spatial_percentile", or "static".
interpretation string "shading_protection" (lower SVF = more shade = less risk) or "exposure" (lower SVF = restricted light = more risk).
svf_low / svf_high float Fixed SVF thresholds for static method.

Criterion: sunlit_hours

Scores exposure risk from mean daily sunlit hours over selected seasons.

- name: "sunlit_hours"
  weight: 0.5
  params:
    threshold_method: "tree_percentile"
    seasons: ["spring", "summer", "autumn"]
    low_percentile: 10
    high_percentile: 90
    hours_low: 4.0    # for static method
    hours_high: 10.0
Param Type Description
seasons list Subset of ["spring", "summer", "autumn", "winter"] to include in the mean.
hours_low / hours_high float Fixed sunlit-hour thresholds for static method.

land_use mapping

Top-level section (not nested under criteria) that defines how land-use raster codes are translated to risk scores and labels.

Currently dead config. The criterion reads config["land_use"]["mapping"] (bluegreencity_ki/criteria/land_use.py), but in the live config the land_use: key contains no mapping — the block below sits at the top level, next to land_use:. The loader therefore silently falls back to its built-in default, which is identical to the top-level mapping: block. Editing that block changes nothing until it is moved under land_use:.

land_use:
mapping:
  28: {risk_score: 0.5, label: "Tagebau (NODATA)", description: "NoData value"}
  20: {risk_score: 0.9, label: "Gebäude", description: "Buildings"}
  9:  {risk_score: 0.1, label: "Freiland/Rasen", description: "Open land/grass"}
  …

Each entry has:

Sub-key Type Description
risk_score float Risk score (0–1) assigned to trees on this land-use type.
label string Short human-readable label (used in output and reports).
description string Longer description (metadata only).

Risk score conventions used in the Hannover dataset:

Score Interpretation
0.1 Low risk (water, open grassland)
0.3 Medium-low (tree over grass)
0.5 Neutral / NoData
0.7 Medium-high (tree over non-natural grass)
0.9 High risk (buildings, sealed surfaces, rail)

Codes not present in the mapping receive neutral_score and a warning is logged.


output

Controls where pipeline results are written.

output:
  format: "gpkg"
  path: "./data/output/trees_at_risk.gpkg"
  layer_points: "trees_at_risk_points"
  aggregated:
    enabled: true
    output_dir: "./data/output/aggregated"
    include_csv: true
    include_geojson: true
    include_json: true
    output_crs: "EPSG:4326"
    postgis:
      enabled: true
      schema: "bgcki"
      table_prefix: "analysis_tree_risk_scores"
      mode: "replace"
      add_metadata: true
    h3:
      enabled: true
      resolutions: [10, 11]
    a5:
      enabled: true
      resolutions: [15, 16]
    admin_areas:
      enabled: true

  postgis:
    enabled: true
    schema: "bgcki"
    table: "analysis_tree_risk_scores"
    mode: "replace"   # or "append"
    add_metadata: true

  species_counts:
    enabled: true
    # path: "./data/output/trees_species_counts.csv"  # optional override
Key Type Default Description
format string "gpkg" Output file format ("gpkg" = GeoPackage).
path string — Output file path.
layer_points string — Layer name inside the GeoPackage.
aggregated.enabled bool false unless configured Enables additional mean-aggregated polygon outputs for grid and administrative geographies.
aggregated.output_dir string ./data/output/aggregated Directory where aggregated GeoPackages and CSVs are written.
aggregated.include_csv bool true Whether to write a CSV version next to each aggregated GeoPackage.
aggregated.include_geojson bool false unless configured Whether to write a GeoJSON version next to each aggregated GeoPackage.
aggregated.include_json bool false unless configured Whether to also write a .json GeoJSON serialization next to each aggregated GeoPackage.
aggregated.output_crs string "EPSG:4326" Target CRS for aggregated polygon outputs. WGS84 is recommended for Superset map charts.
aggregated.postgis.enabled bool false unless configured Whether to additionally write aggregated layers to PostGIS.
aggregated.postgis.schema string postgis.schema or "bgcki" Target PostGIS schema for aggregated layers.
aggregated.postgis.table_prefix string postgis.table or "analysis_tree_risk_scores" Prefix used to derive aggregated PostGIS table names such as analysis_tree_risk_scores_h3_hex_mean_res8.
aggregated.postgis.mode string postgis.mode or "replace" Write mode for aggregated PostGIS tables.
aggregated.postgis.add_metadata bool postgis.add_metadata or true Whether to add run_date and created_at to aggregated PostGIS tables.
aggregated.h3.enabled bool true Enables H3-based mean aggregation over point outputs.
aggregated.h3.resolutions list[int] — H3 resolutions to export, e.g. [10, 11]. Each resolution is written to its own file.
aggregated.h3.filename_prefix string "h3_hex_mean" Suffix used in the generated H3 output filenames.
aggregated.h3.layer_name_prefix string "h3_hex_mean" Prefix used for GeoPackage layer names of H3 outputs.
aggregated.a5.enabled bool false unless configured Enables experimental A5 pentagonal grid aggregation using the Python module a5.
aggregated.a5.resolutions list[int] — A5 resolutions to export, e.g. [15, 16]. Each resolution is written to its own file.
aggregated.a5.filename_prefix string "a5_pentagon_mean" Suffix used in the generated A5 output filenames.
aggregated.a5.layer_name_prefix string "a5_pentagon_mean" Prefix used for GeoPackage layer names of A5 outputs.
aggregated.admin_areas.enabled bool true Enables mean aggregation against configured administrative polygon layers.
aggregated.admin_areas.spatial_predicate string "within" Spatial join predicate used to assign trees to polygons.
aggregated.admin_areas.<area>.path string area-specific Path to the polygon layer for stadtteile, stadtbezirke, or pflegebezirke.
aggregated.admin_areas.<area>.name_column string auto-detected Polygon name column used in the aggregate output.
aggregated.admin_areas.<area>.id_column string auto-detected Stable polygon identifier used for joining aggregated values back to geometry.
aggregated.admin_areas.<area>.filename_suffix string area-specific Suffix appended to the generated GeoPackage and CSV filenames.
aggregated.admin_areas.<area>.layer_name string area-specific GeoPackage layer name for the aggregated polygon output.
postgis.enabled bool true Whether to also write to PostGIS.
postgis.schema string "bgcki" Target PostGIS schema.
postgis.table string — Target PostGIS table.
postgis.mode string "replace" "replace" truncates the table before writing; "append" adds rows with run_date for historical tracking.
postgis.add_metadata bool true Whether to add run_date and scenario columns.
species_counts.enabled bool true Whether to export a species-count CSV alongside the main output.
species_counts.path string auto Override the CSV path; if omitted, written next to the main output file.

integration

Optional API integrations (currently not active in production).

integration:
  greenspace_api:
    enabled: false

sustainability

Tracks estimated energy consumption and CO₂ emissions per pipeline run and appends them to a run log CSV.

sustainability:
  enabled: true
  run_log: "./logs/run_log.csv"
  avg_power_watts: 45.0
  carbon_intensity_g_per_kwh: 420
  include_gpu: false
  active_profile: "shared_workstation"
  host_profiles:
    shared_workstation:
      avg_power_watts: 350.0
    workstation_laptop:
      avg_power_watts: 85.0
Key Type Description
enabled bool Master switch. When false, no tracking is done.
run_log string Path to the CSV run log.
avg_power_watts float Default power estimate when no matching host profile is found.
carbon_intensity_g_per_kwh float Carbon intensity factor for the electricity mix (g CO₂/kWh).
include_gpu bool Whether to add GPU power draw to the estimate.
active_profile string Key of the host profile to use (overrides avg_power_watts).
host_profiles.<name>.avg_power_watts float Machine-specific power estimate (W).

savings

Optional estimation of water and fuel savings achievable by risk-based watering optimization. Disabled by default.

savings:
  enabled: false
  water:
    liters_per_tree_per_event: 150
    baseline_events_per_season: 6
    optimized_events_per_season: 4
  fuel:
    fuel_liters_per_km: 0.12
    baseline_km_per_season: 1000
    optimized_km_per_season: 800
  green_volume:
    model: simple_growth
    annual_growth_kg_co2_per_tree: 5.0
    survival_gain_percent: 10.0

validation

Runs an optional validation step that compares pipeline risk scores against drought-damage ground truth labels from the tree inventory.

validation:
  enabled: true
  mode: "pipeline_monitoring"   # pipeline_monitoring | expert_validation | external_2025_2026
  gisid_column: "objectid"
  min_validation_matches: 50
  print_report: true
  primary_score_column: "drought_risk_ml"
  threshold: 0.5
  top_k_fractions: [0.05, 0.10, 0.20]
  baseline:
    enabled: true
    score_column: "drought_risk_rulebased"
Key Type Default Description
enabled bool true Master switch. Can also be disabled at runtime with --skip-validation.
mode string "pipeline_monitoring" Validation mode: "pipeline_monitoring" (live), "expert_validation", or "external_2025_2026".
gisid_column string "objectid" Tree ID column in the pipeline output (must match the ID column in the drought CSV).
min_validation_matches int 50 Minimum number of non-null labels required to run; below this, validation is skipped with status "skipped".
print_report bool true Print the validation report to the console.
primary_score_column string "drought_risk_ml" Primary score column compared against the labels.
threshold float 0.5 Threshold for the binary classification against the labels.
top_k_fractions list [0.05, 0.10, 0.20] Top-k fractions for the ranking analysis (top 5 %, 10 %, 20 %).
baseline.enabled / baseline.score_column bool / string true / "drought_risk_rulebased" Optional baseline comparison (live: the rule-based score as technical baseline).

plausibility

Automated sanity checks run after criteria computation. Covers numeric spot checks, monotonicity, spatial distribution, ML-based anomaly detection, and optional external list comparison.

plausibility:
  enabled: true
  spot_check_samples: 5
  spot_check_tolerance: 1.0e-6
  spot_check_criteria:
    - salt
    - street_type
    - age
    …

  visualizations:
    enabled: true

  monotonicity:
    tolerance: 0.02
    direction_overrides: {}

  spatial:
    group_column: "stadtteil"
    warn_std_threshold: 0.20
    stadtteile_path: "…/SKH20_Stadtteile.shp"
    stadtbezirke_path: "…/SKH20_Stadtbezirke.shp"
    stadtgrenze_path: "…/SKH20_Stadtgrenze.shp"

  ml:
    max_rows: 5000
    correlation_threshold: 0.85
    correlation_enabled: true
    pca_enabled: true
    cluster_enabled: true
    explainability_enabled: true
    species_cluster_count: 6
    species_min_samples: 5

  ampelliste:
    path:
    species_column_index: 0
    rating_column_index: 1
    high_discrepancy_threshold: 0.40
Key Type Description
enabled bool Master switch for all plausibility checks.
spot_check_samples int Number of trees to re-compute for numeric spot checks.
spot_check_tolerance float Acceptable floating-point deviation in spot checks.
spot_check_criteria list Criteria included in the spot check (lightweight criteria only recommended).
visualizations.enabled bool Whether to write PNG/CSV artefacts for plausibility results.
monotonicity.tolerance float Allowable monotonicity violation (fraction of tree pairs).
monotonicity.direction_overrides map Override the expected monotonicity direction per criterion.
spatial.group_column string Column used to group trees for spatial distribution checks.
spatial.warn_std_threshold float Standard deviation threshold above which a spatial warning is raised.
spatial.stadtteile_path string Path to district boundary shapefile (for visualizations).
ml.correlation_threshold float Pearson correlation above which two criteria are flagged as redundant.
ml.pca_enabled / ml.cluster_enabled bool Toggle PCA and clustering analysis (disabled by default for performance).
ml.explainability_enabled bool Toggle SHAP-based explainability.
ampelliste.path string Optional external species rating list for comparison.
ampelliste.high_discrepancy_threshold float Score difference above which a discrepancy is reported.

See validation/plausibility.md for a detailed description of each check type.


report

Controls which artefact files are written alongside the main output.

report:
  save_hist_png: true       # Score distribution histograms per criterion
  save_validation_png: true # Validation result plots

data_management

Metadata and versioning configuration for PostGIS data imports. The pipeline itself reads rasters from files; this section controls how import scripts register datasets in the data catalog.

data_management:
  raster_imports:
    ndvi_2024:
      input_key: "ndvi_raster"
      schema: "bgcki"
      table: "context_raster_ndvi"
      description: "NDVI from CIR aerial imagery 2024"
      version: "2024"
      source: "Aerial CIR imagery, Stadt Hannover"
      update_frequency: "irregular"
      notes: "…"

  vector_imports:
    tree_inventory:
      input_key: "trees"
      schema: "bgcki"
      table_template: "trees_inventory_{version}"
      description: "City street tree inventory"
      version: "2025_10"
      source: "Landeshauptstadt Hannover"
      update_frequency: "irregular"
      archive_old_versions: true

  versioning:
    strategy: "archive"    # "archive" or "replace"
    table_naming: "{table}_{version}"
    metadata_table:
      enabled: true
      schema: "public"
      table: "data_catalog"
    archive:
      auto_archive_on_new_version: true
      archive_schema: "archive"
      move_to_archive_schema: false

Each raster_imports or vector_imports entry uses these common keys:

Key Type Description
input_key string Key in inputs that resolves the source path.
schema string Target PostGIS schema.
table / table_template string Table name. Template supports {version} placeholder.
description string Human-readable dataset description.
version string Version tag (e.g. "2024", "2025_10").
source string Data provider.
url string Source URL (optional).
update_frequency string Qualitative update cadence ("annual", "irregular", …).
notes string Additional metadata, resolution, caveats.

climate

Configuration for importing climate data from DWD CDC and the Open-Meteo API.

climate:
  sources:
    dwd_primary: true
    openmeteo_fallback: true

  dwd:
    cache_dir: "data/cache/climate"
    preferred_dataset: "hostrada"   # "hyras" (daily 5km) or "hostrada" (hourly 1km)
    hyras_variables:
      - precipitation
      - temperature_mean
      - temperature_max
      - temperature_min
      - humidity
    hostrada_variables:
      - temperature
      - humidity
      - precipitation
      - radiation
      - wind_speed
    years: [2020, 2021, 2022, 2023, 2024]
    update_frequency: "annual"

  openmeteo:
    variables:
      - temperature_2m
      - precipitation
      - relative_humidity_2m
      - et0_fao_evapotranspiration
    resolution: "hourly"
    start_date: "2022-01-01"
    end_date: "2024-12-31"
    update_frequency: "weekly"

  water_balance:
    enabled: false
    mode: "local_observation"
    model_version: "swbm-v0.4"
    method: "fao56"
    et0_source: "openmeteo"
    forecast_days: 7
    soil_data_source: "nfk_polygons"
    execution:
      tree_features_path: "data/derived/water_balance/tree_features.gpkg"
      dwd_cache_dir: "data/cache/water_balance"
      write_batch_size: 5000
      write_postgis: true
      schedule_time: "04:00"
    parquet:
      daily_state_path: "data/derived/water_balance/daily_state.parquet"
      irrigation_event_path: "data/derived/water_balance/irrigation_events.parquet"
    postgis:
      schema: "bgcki"
      daily_state_table: "swbm_daily_state"
      irrigation_event_table: "irrigation_event"
    irrigation_event_import:
      enabled: false
      source: "local_csv"
      path: null
      timezone: "Europe/Berlin"
      write_postgis: true
      read_csv: {delimiter: ",", encoding: "utf-8"}
      columns:
        tree_id: null
        irrigated_at: null
        source_event_id: null
        observed_amount_liters: null
    irrigation:
      enabled: false
      trigger_soil_water_fraction_layer_1: 0.4
      target_field_capacity_fraction: 0.8
      typical_amount_liters: 150.0
      unknown_amount_strategy: "modeled_deficit"
      species_specific: true

  database:
    schema: "bgcki"
    dwd_table_prefix: "climate_dwd"
    openmeteo_table_prefix: "climate_openmeteo"
    create_time_index: true
    create_spatial_index: true

  quality:
    temperature_range: [-30, 45]
    precipitation_range: [0, 200]
    humidity_range: [0, 100]
    wind_speed_range: [0, 150]
    allow_missing: true
    max_missing_percent: 10

water_balance sub-keys not shown in the sample above

Key Live value (abridged) Description
meteorology source_quality: {dwd: 1.0, parquet: 1.0, openmeteo: 0.7}, default_quality: 0.5, elevation_m: 55.0; openmeteo_fallback.enabled: true; dwd_preprocessing (HYRAS 6-1, ET0 1.1) Meteorology source-quality weights plus DWD/Open-Meteo fetch settings.
forcing sunlit-hours fallbacks 8/14/10/4 h (spring/summer/autumn/winter), stem diameter 30.0 cm, unknown-SVF scenarios 0.3/0.6/0.9 Fallback values (each with a quality weight) used when forcing data is missing.
vegetation defaults: LAI allometry [1.50, 0.20], branch area index 0.35, transpiration fraction [0.80, 0.10], phenology [91, 145, 182, 305]; plus per-genus overrides Vegetation parameters (defaults + genus-specific).
soil field capacity 0.26, wilting point 0.07, drainage 0.35, interception 1.0 mm/LAI, runoff 0.1/0.15, infiltration 0.55, pit buffer 0.30 m Soil water-balance parameters.
capillary_rise enabled: true; source kriged_groundwater (kriging, exponential variogram, max_distance_m: 5000, min_neighbors: 3); lookup 5.0 → 0.1 mm/day Groundwater-driven capillary rise into the deepest root-zone layer.
profile_imputation unknown age → young 5 / mature 20 / old 40 years; crown: per-species means (enabled: true, 1–35 m) Imputation for missing tree-age and crown inputs.
hda_validation gate budgets: median demand diff ≤ 1.0 %, p95 ≤ 10.0 %; reports to docs/validation Output-vs-output validation against the h_da standalone historical exports.

See data_maintenance/Climate_Data_Import.md for the climate import workflow and data_maintenance/Soil_Water_Balance_Integration.md for the current SWBM integration boundary.


risk_products

Composite products derived from criterion scores, used by the Lagebild and the irrigation planner.

risk_products:
  site_vulnerability:
    enabled: true
    groups:
      water_soil:
        weight: 0.2
        components:
          groundwater_risk: 0.45
          field_capacity_risk: 0.45
          gk25_risk: 0.1
      root_site:
        weight: 0.2
        components:
          pit_size_risk: 0.3
          tree_disc_risk: 0.15
          land_use_risk: 0.3
          planting_structure_risk: 0.25
      exposure:
        weight: 0.2
        components:
          sky_view_factor_risk: 0.2
          sunlit_hours_risk: 0.15
          air_temperature_day_risk: 0.15
          air_temperature_night_risk: 0.1
          uhi_intensity_risk: 0.15
          cold_air_risk: 0.15
          albedo_risk: 0.1
      species_resilience:
        weight: 0.2
        components:
          drought_tolerance_risk: 0.5
          heat_tolerance_risk: 0.5
      chronic_load:
        weight: 0.2
        components:
          salt_risk: 0.25
          street_type_risk: 0.35
          subway_tunnel_risk: 0.4
  action_priority:
    weights:
      swbm: 0.5
      ml_damage: 0.3
      site_vulnerability: 0.2
Key Description
site_vulnerability Five equally weighted groups (water_soil, root_site, exposure, species_resilience, chronic_load) combined into the site_vulnerability_rulebased score. gk25_risk is deliberately down-weighted to 0.1 (2026-08-30, Plan C.3).
action_priority.weights Staged-cascade weights for the irrigation action priority: stage 1 is a hard gate (irrigation_demand_liters > 0); stages 2–4 rank the trees that need water by swbm: 0.5, ml_damage: 0.3, site_vulnerability: 0.2.

irrigation_planning

Configuration for the deterministic draft irrigation planner. It is enabled in the live config: the CLI refuses to run while it is false, and the daily cycle only calls the planner when it is true (live since the Phase 3 smoke run on 2026-09-24, issue #227). inputs.risk_path and inputs.daily_state_path are PostGIS schema.table pointers (bgcki.operational_tree_product / bgcki.swbm_daily_state); file paths (parquet/gpkg/csv) keep working for local runs.

irrigation_planning:
  enabled: true
  swbm_model_version: null
  inputs:
    daily_state_path: "bgcki.swbm_daily_state"
    risk_path: "bgcki.operational_tree_product"
    irrigation_event_path: "data/derived/water_balance/irrigation_events.parquet"
    weather_forecast_path: null
  outputs:
    parquet_path: "data/derived/irrigation_planning/plan_decisions.parquet"
    write_postgis: true
    postgis: {schema: "bgcki", table: "irrigation_plan_decision"}
  columns:
    state_tree_id: "tree_id"
    risk_tree_id: "objectid"
    event_tree_id: "tree_id"
    state_date: "state_date"
    model_version: "model_version"
    demand_liters: "irrigation_demand_liters"
    stress_today: "soil_water_stress_today"
    forecast_stress: "soil_water_stress_forecast_max_7d"
    trigger_date: "irrigation_trigger_date"
    avoidable_by_rain: "irrigation_avoidable_by_rain"
    data_quality: "data_quality"
    rulebased_risk: "drought_risk_rulebased"
    ml_risk: "drought_risk_ml"
    site_vulnerability: "site_vulnerability_rulebased"
    risk_date: "run_date"
    irrigated_at: "irrigated_at"
    strategic_value: null
    heat_vulnerability: null
    service_minutes: null
  candidate_preparation:
    rulebased_risk_weight: 0.0
    ml_risk_weight: 1.0
    default_strategic_value: 0.5
    default_heat_vulnerability: 0.5
    default_service_minutes: 8
    state_scenario_strategy: "conservative_max"
    minimum_risk_join_fraction: 0.95
  policy:
    version: "irrigation-policy-v0.1"
    horizon_days: 7
    risk_threshold: 0.7
    urgent_stress_threshold: 0.8
    min_irrigation_interval_days: 3
    solver_time_limit_seconds: 30.0
    priority_levels: {critical: 0.8, high: 0.6, medium: 0.4}
    priority_weights:
      risk: 0.3
      current_stress: 0.0
      forecast_stress: 0.5
      strategic_value: 0.0
      site_vulnerability: 0.2
      data_quality: 0.0
    heatwave:
      threshold_c: 30.0
      minimum_consecutive_days: 3
      priority_boost: 0.1
  resources:
    daily_water_liters: 108000.0
    team_count: 9
    team_hours_per_day: 8.0
    shift: "night"
    shift_hours: {night: 8.0, day: 7.0}
    vehicle_count: 9
    max_jobs_per_vehicle: 60

The columns: sub-map names the source column in each input (daily state, risk product, irrigation events) for every planner field; null entries are optional fields with defaults.

All policy values are versioned initial assumptions. Change policy.version whenever behavior changes. See data_maintenance/Irrigation_Planning.md for inputs, execution, output semantics, and current boundaries.


irrigation_review

Local-only Phase 3 Taipy review and execution settings:

irrigation_review:
  enabled: false
  draft_limit: 1000
  postgis_schema: "bgcki"
  gui:
    host: "127.0.0.1"
    port: 5000
  inputs:
    state_path: "data/derived/water_balance/dwd_fullcity_v4_2025-07-15.parquet"
    risk_path: "data/output/<YYYY_MM_DD>_ml_operational_train_<START>_<END>_predict_<YEAR>/hannover_gesamt/trees_at_risk_hannover_gesamt.gpkg"
    weather_path: null

inputs.risk_path is maintained automatically along two paths, both going through the single writer in bluegreencity_ki.core.risk_pointer (issue #231, Options B + C):

  1. After overnight ML refreshes: Step 6 of scripts/run_ml_refresh_overnight.ps1 invokes scripts/update_operational_risk_pointer.py and points the pointer at the newest data/output/<YYYY_MM_DD>_ml_operational_train_* GPKG.
  2. Daily at 04:00: scripts/run_scheduled_water_balance.ps1 runs the same script in --check mode before the Lagebild refresh resolves the config paths. A stale pointer (e.g. after a manual operational run via run_ml_path.py operational-current, such as a tree-cadastre switch) is logged and self-healed, so the Lagebild of the same day already reflects the new run — no manual pointer update needed.

    PostGIS table pointers are out of scope. A pointer value of the form schema.table (e.g. irrigation_planning.inputs.risk_path → bgcki.operational_tree_product, issue #227 Phase 2) is a canonical PostGIS source, not a GPKG file pointer. Its freshness is managed by the daily operational product refresh, and the check skips it. Without this rule the check would treat the table name as a stale GPKG pointer and self-heal it back to the newest training-run GPKG — silently overriding the Phase 2 design (incident 26.09.2026).

Check exit codes: 0 = up to date, healed, or skipped (risk_path: null or a PostGIS schema.table pointer); 1 = pointer unusable (missing file and no candidate run) — the daily refresh aborts, leaving the Lagebild at its previous state. The self-heal writes to config/config.yaml but never commits; pick the change up with the next regular commit (the log line says so).

The UI remains disabled and bound to localhost by default. See data_maintenance/Irrigation_Review_Taipy.md for installation, migration, and audit semantics.


ml

Configuration for AutoGluon-based machine learning drought risk prediction.

For the stable reference benchmark and the documented ablation runs, see risk_assessment_ml/reports/stable_ablation_report_2026-04-03.md.

ml:
  enabled: true
  dataset_mode: "operational_panel"   # "operational_panel" | "single_snapshot"
  training_data: "data/derived/ml/training_dataset_v6_operational_panel_2018_2024.csv"
  drought_csv: "data/input/trees/Baum-2010-2025-v6_historisch_prod.csv"

  labeling:
    strategy: "operational_panel_drought_damage"  # or "future_drought_damage" | "historical_drought_damage"
    snapshot_year: 2025
    label_horizon_years: 1
    target_label: "future_drought_damage_severe_t1"

  operational_panel:
    start_year: 2018
    end_year: 2024
    feature_query_mode: "snapshot_year"
    feature_year_column: "snapshot_year"

  training:
    model_path: "data/models/autogluon"
    features_table: "bgcki.analysis_tree_risk_scores_ml_operational_panel"
    presets: "best_quality"
    time_limit: 3600
    eval_metric: "roc_auc"
    num_bag_folds: 5
    num_bag_sets: 1
    num_stack_levels: 1
    feature_columns:
      - "ga_lang"
      - "age_value"
      - "vitality_value"
      …
    excluded_columns:
      - "objectid"
      - "snapshot_year"
      - "label_year"
      …

  labels:
    - "future_drought_damage_severe_t1"

  inference:
    label: "future_drought_damage_severe_t1"
    feature_aliases: {}   # optional: map missing features to known synonyms

  thresholds:
    critical: 0.85
    high: 0.30
    medium: 0.10
    low: 0.00

  output:
    leaderboards: "data/models/autogluon/leaderboards"
    feature_importances: "data/models/autogluon/feature_importances"
    shap_explanations: "data/models/autogluon/shap"
    predictions: "data/output/{run_date_underscore}_{scenario}/ml_predictions.csv"
    postgis: {enabled: true, schema: "bgcki", table_prefix: "{scenario}", mode: "replace"}
Key Type Description
enabled bool Whether to run ML scoring in the pipeline. Requires a trained model.
dataset_mode string "operational_panel" – multi-year panel approach (one row per tree×year, recommended); "single_snapshot" – legacy single snapshot.
training_data string Path to the training dataset CSV.
drought_csv string Raw inventory CSV used to extract drought labels.
labeling.strategy string Label extraction strategy: "operational_panel_drought_damage" (panel, one snapshot per year), "future_drought_damage" (predicts next-year damage from reference year), "historical_drought_damage" (legacy window approach).
labeling.snapshot_year int Reference year for "future_drought_damage" strategy: labels are extracted strictly after this year.
labeling.label_horizon_years int How many years ahead the label looks. Default 1 means next-year damage.
labeling.target_label string Column name of the target label (e.g. "future_drought_damage_severe_t1"). Must match a column produced by the label extractor.
operational_panel.start_year int First year (inclusive) of the multi-year panel.
operational_panel.end_year int Last year (inclusive) of the multi-year panel. Also drives the training window: train_end = end_year - 1, prediction_year = end_year.
operational_panel.feature_query_mode string How features are fetched per snapshot: "snapshot_year" (reads feature_year_column from the features table).
operational_panel.feature_year_column string Column in the features table that holds the snapshot year for the panel query.
operational_panel.snapshot_years list (optional) Explicit list of snapshot years. When set, it overrides start_year/end_year for the panel build only. The training window still derives from end_year, so you can extend the feature panel (e.g. add 2025 for the Baumkataster) without changing what the model trains on.
annual_validation.output_dir string Base directory for the annual validation model ("data/models/autogluon/annual_validation"); each (re-)training creates a timestamped <YYYY_MM>/train_…__predict_…__validate_… run directory. Also export_gpkg: true and drift_watch.metric_delta: 0.05 (warns when ROC-AUC drops / Brier increases vs. the previous month’s run).
operational.output_dir string Base directory for the operational (refit-final) model ("data/models/autogluon/operational").
shap map SHAP explanation settings (live: scope: "high-risk", high_risk_max_rows: 25, background_sample_size: 50, batch_size: 50, waterfall_limit: 10); the risk-classes mode stratifies risk_classes_max_rows_per_class: 50 rows per class.
grouped_cv map Grouped cross-validation (live: n_splits: 5, group_columns: ["objectid", "h3_res8"], threshold: 0.5, random_state: 42) plus spatial diagnostics (Zone-AUC + Moran’s I around the city center, zone_radius_m: 5000, n_permutations: 999).
rolling_validation map Rolling-origin validation (live: min_train_years: 4, group_column: "objectid", threshold: 0.5, per-species via species_column: "ga_lang").
training.presets string AutoGluon quality preset: "best_quality", "high_quality", "medium_quality", "good_quality".
training.time_limit int AutoGluon time budget per label (seconds).
training.eval_metric string Evaluation metric (e.g. "roc_auc").
training.hyperparameters map Per-family AutoGluon hyperparameter sets (GBM/CAT/XGB/RF/XT/NN_TORCH). Tree ensembles run with num_gpus: 0; NN_TORCH with num_gpus: 1 and min_time_limit: 300 so it can compete within the budget.
training.num_gpus int AutoGluon GPU count (live: 1).
training.features_table string schema.table in PostGIS from which features are read for each panel snapshot during training dataset construction. This table must be materialized first, e.g. via scripts/ml/build_operational_panel_snapshots.py.
training.feature_columns list Allowlist of features used in training. The operative list has 54 features (the correlation-cleaned “Modell Hannover” base plus the 2026-10 spatial / SWBM / A-B-bundle additions); it is defined in config/config.yaml; see risk_assessment_ml/automl_features.md for the feature documentation of the current (October 2026) model, and the archive for superseded snapshots (e.g. the 17-feature April 2026 generation).
training.excluded_columns list Technical exclusion list (IDs, label columns, panel metadata that must not leak into features).
training.spatial_features map Spatial features (Bundle 2026-10, enabled: true): H3 cell categories (cell_resolutions: [7, 8]), raw UTM coordinates, and a res-8 ring aggregation (self-excluded mean) over m_svf_value / m_air_temp_14h_value. The spatial_block 2×3 grid is a grouping key only, not a model feature.
training.swbm_features map SWBM soil-water features (enabled: true), strictly from the snapshot year: table bgcki.swbm_daily_state, scenario irrigation-lower, dry season 05-01…10-31, reference dates jul15/aug15, stress_days_threshold: 0.5.
training.spatial_cv map Spatial groups for model selection (group_column: "spatial_block", max_groups: 10); live enabled: false (2026-10-07 ablation: spatial groups in training hurt external holdout AUC).
training.class_weight_positive float Sample-weight multiplier for positive rows (live: 1.0 = off).
labels list Target label column(s) to train.
inference.label string Which trained model is used for pipeline scoring.
inference.feature_aliases map (optional) Maps missing feature names to known synonyms. Useful when a feature was renamed between training and inference (e.g. {"ndvi_value_2024": "ndvi_value_current"}).
local_explainability map Per-tree local explanations (live: enabled: true, scope: "all", top_k: 3, batch_size: 500); the extreme_groups / none scopes exist for faster debug runs.
calibration map Platt calibration of the raw AutoGluon probabilities (live: enabled: true, method: platt); fitted on the external holdout per validation run and applied at inference → drought_risk_ml_calibrated.
thresholds map Probability → risk class mapping. First matching threshold wins (descending). Current operative values: critical: 0.85, high: 0.30, medium: 0.10, low: 0.00 — they apply to the calibrated score drought_risk_ml_calibrated (Issue #253, 2026-10-08). The ML run stamps the class with its active thresholds, but the daily operational refresh re-derives the class from the score + this config, so a change takes effect at the next refresh.
swbm_irrigation_map map Color bands for the “Bewässerungsbetrieb” Grafana map: SWBM demand bands ≤150 / ≤400 / ≤1000 l (blue shades) and planned-amount bands ≤20 / ≤50 / ≤150 l, plus high_risk_no_demand_color: "#d7263d" for high-risk trees without demand.
output.leaderboards / output.feature_importances string Artefact directories (live: under data/models/autogluon/).
output.shap_explanations string SHAP artefact directory (live: "data/models/autogluon/shap").
output.predictions string Prediction CSV pattern (live: "data/output/{run_date_underscore}_{scenario}/ml_predictions.csv").
output.postgis map PostGIS export of the ML results (live: enabled: true, schema bgcki, table_prefix: "{scenario}", mode: "replace").

Run-Configs (generated, not hand-edited)

config/config.yaml is the single source of truth. The per-run configs in data/derived/ml/run_configs/ are generated artifacts, not hand-maintained files. They are produced by scripts/run_ml_path.py from the base config via bluegreencity_ki/ml/run_profiles.py and are git-ignored (data/derived/).

Generated file Profile Scenario Writes to
validation.yaml validation ml_validation_train_<a>_<b>_predict_<p>_validate_<v> analysis_tree_risk_scores_validation_<p>
operational_current.yaml operational-current ml_operational_train_<a>_<b>_predict_<p> analysis_tree_risk_scores_operational_current
operational_current_provisional.yaml operational-current --provisional …_provisional_existing_model analysis_tree_risk_scores_operational_current_provisional

Regenerate (and optionally run) a profile:

# Write the run config only (no pipeline run)
conda run -n bgcki_wesemann python scripts/run_ml_path.py validation --write-config-only
conda run -n bgcki_wesemann python scripts/run_ml_path.py operational-current --write-config-only

# Write + run (add --shap risk-classes, --train, --refit-final, --grouped-cv as needed)
conda run -n bgcki_wesemann python scripts/run_ml_path.py operational-current --shap risk-classes

Do not edit the generated files directly – change config/config.yaml (or pass CLI flags) and regenerate. See how_to_run.md for the full run workflow.

The same ml configuration block is also used by the grouped cross-validation runner scripts/ml/evaluate_grouped_cv.py. That workflow writes panel-aware validation artefacts to the validation run directory (<run_dir>/grouped_cv, derived from the annual-validation run layout) and is documented in risk_assessment_ml/reports/operational_panel_grouped_cv_report_2026-09-16.md.

See risk_assessment_ml/ml_risk_scoring_guide.md for methodology details and risk_assessment_ml/automl_features.md for the current operative feature set.


Common Patterns

Adding a new study area

  1. Add a new entry under project.study_areas.definitions.
  2. Set bbox_source: "manual" and provide a bbox in WGS84, or use bbox_source: "auto" to derive the bounding box from the tree data.
  3. Point trees to the correct data source.
  4. Change project.study_areas.active to the new key.
project:
  study_areas:
    active: "my_district"
    definitions:
      my_district:
        name: "My District"
        bbox_source: "manual"
        bbox: [9.72, 52.36, 9.80, 52.41]
        trees:
          type: "postgis"
          schema: "bgcki"
          table: "trees_inventory"
          id_field: "objectid"

Adjusting criterion weights

Change the weight value next to the criterion name. Weights are normalized automatically so only relative values matter.

criteria:
  - name: "vitality"
    weight: 2.0          # twice as influential as a weight-1 criterion
  - name: "age"
    weight: 0.5

Switching between threshold methods

Most raster-based criteria support three threshold methods. Use tree_percentile (the default) for production runs:

params:
  threshold_method: "tree_percentile"   # recommended
  low_percentile: 5
  high_percentile: 95

Switch to static for reproducible, version-independent scoring:

params:
  threshold_method: "static"
  temp_day_low: 20.0
  temp_day_high: 30.0

Disabling a criterion

Remove the criterion’s entry from the criteria list, or set its weight to 0. Removing it is cleaner and avoids unnecessary computation.