bluegreencity-ki

Irrigation Planning

Status

Produktiv seit 2026-09-24 (issue #227, Phase 3 Smoke-Lauf verifiziert: 89.280 Kandidaten, 84 ausgewählte Entwürfe, 3.395 L am Planungstag, Policy irrigation-policy-v0.1; Grafana-Dashboard „Bewässerungsbetrieb” liest die Decisions live). Der tägliche 04:00-Zyklus ruft den Planner ab enabled: true auf; die Policy-Versionierung und Kalibrierung (#223, v0.2) laufen parallel und ändern die live-Values ohne Rewrite.

Phase 2 provides a deterministic, UI-independent draft planner. It combines the latest Phase 1 soil-water state with the ML damage score and stable site vulnerability and allocates complete irrigation demands across a configurable multi-day resource horizon.

The result is a draft decision, not an automatically released work order. Taipy review, overrides, and approval belong to Phase 3.

Decision Logic

Candidates are eligible when either their combined risk reaches the configured threshold or their forecast SWBM stress reaches the urgent threshold. The planner excludes zero demand, irrigation avoidable by forecast rain (irrigation_avoidable_by_rain, see swbm_7_day_forecast.md section 7), and dates inside the minimum irrigation interval.

The canonical products remain separate:

Action priority is a staged cascade, not a blend of three equally ranked models (design: internal planning note “Kaskade: Label & Feature-Reduktion”, 2026-08-30, Block A):

  1. Gate (hard): a tree without modeled water demand (irrigation_demand_liters <= 0, i.e. SWBM layer-1 available water still above the 0.4 trigger from the original SWBM script) gets priority 0, regardless of ML score or site vulnerability.
  2. Urgency (soft): among the trees that need water, the SWBM forecast stress (weight 0.5) is the dominant ranking signal.
  3. Damage risk: the ML t+1 damage score (weight 0.3) refines the ranking.
  4. Site importance: the stable site vulnerability (weight 0.2) refines it further.

Stages 2-4 are a weighted sum; stage 1 multiplies the result by the demand gate. This makes the SWBM the first-class selection criterion instead of one factor among three, and prevents a vulnerable site or high ML score from creating an irrigation action without a current modeled water deficit.

The SciPy MILP solver maximizes total selected priority under daily constraints for water volume, team minutes, vehicle-derived job count, trigger dates, and minimum irrigation intervals. It may therefore select several smaller jobs instead of one large higher-ranked job when their total priority is greater.

Current defaults for strategic value, heat vulnerability, service time, weights, and thresholds are transparent starting assumptions. They are not scientifically or operationally calibrated values.

Inputs

The planner only runs when irrigation_planning.enabled: true in config/config.yaml; the CLI and the daily cycle both refuse to plan while it is false (issue #227).

Input sources may be file paths (Parquet, GeoPackage, GeoJSON, CSV) or PostGIS schema.table references. The canonical production setup reads from PostGIS:

Optional:

Legacy inputs may still map drought_risk_ml to the ML component. Missing required priority products exclude the affected trees during input preparation and are counted in the CLI summary.

Phase 1 may emit several profile/forcing scenarios for one tree. The default conservative_max strategy creates one deterministic envelope from the latest day: maximum demand and stress, earliest trigger, minimum data quality, and rain avoidance only when every scenario agrees. Set the strategy to error to reject ambiguous scenario inputs instead.

The default stable-ID overlap gate requires at least 95% of latest SWBM trees to match the risk input. This deliberately rejects older pipeline artefacts whose objectid contains a year-coded inventory-record ID instead of stable Baum ID.

Capacity model (fleet calibration, 26.09.2026 — issues #227/#246)

The daily constraints come from irrigation_planning.resources. The current values are a raw estimate (Rohschätzung), not a calibrated value — the config comments carry the derivation: 9 fleet units (1× 10,000 L and 8× 3,000 L watering trucks, each operated by 1 driver) with max_jobs_per_vehicle: 60 jobs → 540 jobs/day. The shift switch selects the effective shift length from shift_hours (night = 8 h without traffic, day = 7 h with traffic), which scales the team-minute budget; daily_water_liters: 108000 is the raw daily water estimate. Reference measurement from the LHH: 62 trees/day/driver (LHH Kick-Off 07/2025); per-tree amounts come from the SWBM. Open LHH questions (tank counters, refill frequency, hydrant throughput, IBC reserve vehicles) are tracked in issue #246.

Run Locally

Set the real risk path and resource assumptions in config/config.yaml, or provide paths explicitly:

conda run -n bgcki_wesemann python scripts/run_irrigation_planning.py `
  --config config/config.yaml `
  --planning-date 2026-08-04 `
  --state-path data/derived/water_balance/daily_state.parquet `
  --risk-path data/output/<run>/hannover_gesamt/trees_at_risk_hannover_gesamt.gpkg `
  --no-postgis

--no-postgis writes only the configured Parquet history. Without it, apply sql/migrations/2026-08-04_create_irrigation_planning_tables.sql first; the same decisions are then upserted to bgcki.irrigation_plan_decision.

Outputs

One auditable record is written per eligible candidate and policy run:

The primary key (tree_id, planning_run_date, policy_version) makes reruns idempotent. Changing policy behavior requires a new policy version.

Validation

The deterministic planner was benchmarked with 61,193 synthetic candidates, seven daily capacity windows, and the configured 30-second solver limit. It selected 588 feasible assignments in 16.05 seconds. This validates the full-city computational scale, not the scientific policy values.

A real Phase 1 state file contains 91,585 profile/forcing scenarios for 61,193 stable tree IDs. The scenario envelope reduces these deterministically to one candidate per tree. The available 2026-08-02 risk GeoPackage cannot be used for an operational join: its objectid values are year-coded inventory-record IDs and overlap 0% with stable SWBM IDs. The 95% gate rejects it explicitly. A fresh risk pipeline output created after the stable-ID correction is required for the first real full-city planning run.

Literature Basis (Kalibrierung, s. Issue #223)

The policy values above are starting assumptions. The following sources are the literature basis for locally calibrating triggers, amounts, young-tree rules, and exclusions. Retrieved via Consensus, 22.09.2026.

Trigger thresholds (when to irrigate):

Amounts and frequency:

Young-tree special rules:

Exclusions (waterlogging / groundwater):

Documentation and feedback loop:

Agricultural context (method transfer only): Luketich et al. 2019 PLoS ONE, Marchionni et al. 2021 Landscape & Urban Planning, Young et al. 2026 Sustainability, Mohamadzade et al. 2021 UFIG, Korjenic 2025 Sensors, Waldburger et al. 2025 Agr. Water Manage. (dendrometer automation saves 38–45 % water), Domínguez-Niño et al. 2020 Agr. Water Manage.

Gap: no strong direct source for “watering deeper than 50 cm promotes deeper rooting” was found in the Consensus search; the local Vico et al. 2013 (Ecohydrology of street trees design and irrigation requirements) already covers this topic.

Zotero library round (22.09.2026, second round)

Additional sources from the BlueGreenCity-KI Zotero library. Zotero cite keys in parentheses; full metadata in Zotero.

Local calibration data (highest priority for #223):

Triggers and monitoring:

Amounts and frequency:

Young trees and species:

Control and planning (methodological relatives of the MILP planner):

Current Boundary

Resources are currently aggregate daily capacities: water litres, team hours, vehicle count, and maximum jobs per vehicle. Source-specific water quality, depots, refilling, street-network travel times, route sequencing, field approval, and mobile completion reporting are intentionally not fabricated. They require reliable operational inputs and are later extensions around the same planning API.