[general]
name=SOLWEIG
qgisMinimumVersion=4.0
qgisMaximumVersion=4.99
description=Calculate Mean Radiant Temperature & UTCI thermal comfort using the SOLWEIG model.
version=0.1.0-beta95
author=SOLWEIG Development Team
email=gareth.simons@ucl.ac.uk

about=SOLWEIG (Solar and Longwave Environmental Irradiance Geometry) is a high-performance urban microclimate model for calculating Mean Radiant Temperature and thermal comfort indices.

    Features:
    - Single timestep and timeseries Tmrt calculations
    - UTCI (Universal Thermal Climate Index) computation
    - PET (Physiological Equivalent Temperature) computation
    - Sky View Factor (SVF) preprocessing
    - EPW & SUEWS weather file import
    - Support for large rasters via tiled processing and GPU

    Requirements:
    - The SOLWEIG Python library must be installed separately.
    - The plugin will offer to install it automatically on first use.
    - To install manually, run this in the QGIS Python Console:
      import pip; pip.main(["install", "solweig", "--no-deps"])

    Documentation: https://umep-dev.github.io/solweig/

    This plugin provides QGIS Processing algorithms that wrap the SOLWEIG Python library. This version of Solweig is currently in testing as a proof of concept for Rust + GPU + tiled processing to handle large rasters.

    Adapted from UMEP (Urban Multi-scale Environmental Predictor) by Fredrik Lindberg, Sue Grimmond, and contributors. If you use this plugin in research, please cite:

    Lindberg F, Grimmond CSB, Gabey A, Huang B, Kent CW, Sun T, Theeuwes N, Järvi L, Ward H, Capel-Timms I, Chang YY, Jonsson P, Krave N, Liu D, Meyer D, Olofson F, Tan JG, Wästberg D, Xue L, Zhang Z (2018) Urban Multi-scale Environmental Predictor (UMEP) - An integrated tool for city-based climate services. Environmental Modelling and Software 99, 70-87 https://doi.org/10.1016/j.envsoft.2017.09.020

tracker=https://github.com/UMEP-dev/solweig/issues
repository=https://github.com/UMEP-dev/solweig
homepage=https://umep-dev.github.io/solweig/

hasProcessingProvider=yes
tags=urban climate, thermal comfort, mean radiant temperature, UTCI, PET, microclimate, heat stress, urban planning

category=Analysis
icon=icon.png

experimental=True
deprecated=False

changelog=
    0.1.0-beta95
    - Fixes a Qt6 compatibility issue flagged by the plugin repository validator (unscoped enum in the EPW download utility). No behaviour change.
    0.1.0-beta94
    - The SOLWEIG_NO_GPU environment variable is now honoured on calculation runs that load precomputed SVF; previously it silently left the GPU enabled on that path.
    - Missing EPW path in EPW weather mode now raises a clear error instead of an assert (which python -O would strip).
    - Documentation: tutorials overview page with instructions for running the notebooks locally; the site and README state the package's positioning as an experimental compatibility-focused implementation, with UMEP as the reference.
    0.1.0-beta93
    - Fixes plugin loading: unescaped %% signs in this metadata file broke QGIS's parser, so the plugin failed to load with "Errors parsing metadata.txt".
    - Stale SVF caches are now caught at load time: a cache computed for a different raster is skipped (or reported with its path and both grid shapes) instead of surfacing later as a bare "Grid shape mismatch" error.
    0.1.0-beta92
    - Fixes an out-of-memory crash at the end of large tiled runs: the summary GeoTIFF export now caps in-flight write buffers at about 1 GB instead of writing all outputs at once.
    - Faster large-raster runs, with output unchanged on valid data: fully-nodata tiles skip computation, tiled GeoTIFF writes and next-tile reads overlap the computation, and the GVF geometry precompute runs on the GPU.
    - In tiled runs, shadow output over fully-nodata tiles is now NaN instead of a spurious sunlit value of 1.0.
    - Fixes a crash in isotropic mode when the valid-data crop was active.
    0.1.0-beta91
    - Library gains memory-bounded prepare() for large rasters (layer-sequential windowing; >50 Mpx cold-build peak RAM cut ~3x, from ~30 GB to ~10 GB on a 507 Mpx raster). No plugin UI or numerical change from b90.
    0.1.0-beta90
    - Library gains the opt-in UMEP 2026a ground-surface scheme (use_ground_scheme / use_outgoing_longwave; Python API only, not yet exposed in the plugin UI). Defaults off; plugin behaviour and numerical output unchanged from b89.
    - A field comparison of the opt-in scheme is documented in VALIDATION.md; the scheme is experimental and off by default.
    0.1.0-beta89
    - Correctness release from a full-repository review; numerical output changes for some runs (see VALIDATION.md).
    - Clearness-index pressure unit fixed (hPa was scaled as kPa): clear-sky irradiance was ~20-25%% underestimated for EPW/values-driven runs.
    - GVF source area fixed at non-1 m pixel sizes (marched 144 m instead of 36 m at 2 m pixels); new UMEP parity gate at 0.5/1/2 m. 1 m runs unchanged.
    - Cached GVF sunwall mask unified with UMEP semantics (fully sunlit walls only).
    - Tiled SVF preprocessing fixed (crashed with NameError after computing all tiles); cancelling SVF preprocessing no longer persists a partial cache — the plugin now stops gracefully via solweig.ComputationCancelled.
    - Plugin loads cleanly when solweig is not installed (per-algorithm import isolation); anisotropic-sky hint points at the correct toolbox algorithm.
    - EPW parsing uses per-field missing codes (RH 99%% and GHI 999 W/m2 are valid data again); ModelConfig.from_json actually reads legacy parameter files.
    - Stale shadow-matrix caches raise a clear error instead of aborting QGIS; SVF caches invalidate when the trunk layer changes; land-cover nodata maps to the nodata class instead of "paved".
    0.1.0-beta88
    - CI / test-categorisation only — zero plugin behaviour change.
    - Performance-timing benchmarks moved to a local-only `gpu_perf_gate` marker; CI keeps only the hardware-stable memory bench. Resolves a CI false positive on the aniso/iso ratio gate (calibrated against local M-series GPU; CI runs CPU-only Linux where the ratio is naturally ~3×).
    - Plugin functionality, public API, and numerical output unchanged from b87.
    0.1.0-beta87
    - Breaking: top-level solweig.extract_bounds / intersect_bounds / resample_to_grid / etc. (b85 DeprecationWarning shim) now raise AttributeError. Import from solweig.geospatial instead.
    - solweig.disable_gpu() now disables all three GPU paths (shadows, anisotropic sky, GVF) in a single call. Pre-b87 it only flipped shadows so "CPU-only" tests weren't actually CPU-only.
    - New solweig.enable_gpu() mirrors disable_gpu(). Fixed a lazy-init bug that silently re-enabled GPU after disable_gpu().
    - New GPU metrics: solweig.gpu_dispatch_count() / gpu_fallback_count() / reset_gpu_metrics(). Atomic counters at every Rust GPU dispatch site; lets tests assert "GPU path actually ran".
    - New shadow + SVF GPU/CPU parity tests + runtime-ratio benchmark. Documents a small known difference in svf_veg* edge pixels (<1%%, propagates to <0.5 °C Tmrt).
    - Plugin: no functional change.
    0.1.0-beta86
    - No numerical change (golden tests byte-identical, validation site numbers unchanged)
    - Hot-file decomposition: io.py / summary.py / models/weather.py / models/precomputed.py split below 700-line threshold (every public symbol re-exported, no caller changes)
    - models/surface.py further extracted (1731 lines now, down from 3037 at b85): surface_loading, surface_compute, surface_svf_tiled, surface_serialization, surface_views
    - Test coverage 75%% → 81%% (cleared the 80%% target) via +117 focused unit tests
    - solweig.Settings + solweig.ThermalState added to the top-level public surface (mkdocs API docs follow)
    - QGIS plugin: 349 LOC of dead create_surface_from_parameters chain removed; production path uses SurfaceData.prepare() directly
    - QGIS plugin metadata changelog trimmed (254 → 96 lines); older betas link to GitHub releases
    - Public docs: physics specs (SVF / shadows / GVF / radiation / ground temp / Tmrt / UTCI / PET) rendered in-site via mkdocs-include-markdown; dev docs (PRINCIPLES / INVARIANTS / ARCHITECTURE) moved to repo root; tutorial notebooks gain proper alt text via custom mkdocs hook
    - Audit script: 9th axis added (axis_canonical_docs) — validates that repo-root canonical docs exist, have inbound references, and have valid relative .md links
    - Performance gates tightened ~3–10× (matrix budgets 1.5–4.0 s → 0.5–0.85 s; ratio caps 5/4/6 → 2/2.5/2)
    - Memory benchmark re-measured at 377 B/px (Feb baseline 370; b85 refactors added under 2%%)
    0.1.0-beta85
    - Architecture stabilisation: no numerical change, golden tests byte-identical
    - Rust FFI bundling: compute_timestep drops from 43 args to 18 (SvfBundle + StateBundle)
    - StateBundle carries an FFI version field; mismatched Python/Rust pairings raise ValueError instead of silently mis-mapping
    - New solweig.geospatial submodule; top-level extract_bounds/intersect_bounds/resample_to_grid/etc emit DeprecationWarning
    - Settings dataclass replaces 50-line override block in calculate()
    - SurfaceData typed views (geometry/optical/auxiliary) used by the production compute path
    - Cache-key hardening: _arr_key includes witness bytes, catches in-place mutations
    - vegetation.rs panic surface 44 → 14 sites via documented contiguity helper
    - surface.py decomposed: serialization helpers extracted to models/surface_serialization.py
    - poe audit task + AUDIT.md (8 measured axes); new CI jobs (audit, test-slow); test-spec now includes slow tests
    - Foundation docs: PRINCIPLES.md + INVARIANTS.md (repo root)
    0.1.0-beta84
    - Rust wall-aspect kernel: promote internal math to f64, switch to banker's rounding to match numpy's np.round (closer to UMEP numerics; input/output arrays stay f32 so data memory is unchanged)
    - Delete Python Goodwin fallback from wallalgorithms.py; Rust kernel is now the single code path (same numerical behaviour for QGIS and pip users)
    - Public API additions on solweig/__init__.py: extract_bounds, intersect_bounds, resample_to_grid, namespace_to_dict, pixel_size_tag, compute_max_tile_pixels, looks_like_relative, wallalgorithms
    - QGIS plugin now uses only solweig's public API (no reaching into models/utils/loaders/physics/tiling/cache internals)
    - Plugin error wrapping: QgsProcessingException messages now expose SolweigError structured attributes (field/expected/got/reason/...)
    - Small cleanups: remove duplicate MIN_SUN_ELEVATION_DEG constant, standardize logging in api.py, remove dead xy_to_lnglat/rotate_array/cart2pol/get_ders, remove unimplemented poi_coords parameter
    0.1.0-beta83
    - Fix PVGIS TMY reference period docs (2005-2020 -> 2005-2023 for v5.3)
    - Clarify that TMY row timestamps legitimately span multiple years (each month is a real historical month)
    0.1.0-beta82
    - Fix silent scale convention inversion in Rust shadow caster (tan_altitude_by_scale operator)
    - Add DEM stair-step smoothing (auto-detects int16 1m quantization)
    - Add prepare() warm-run fast-path (100x speedup on cache hit with detailed mismatch logs)
    - Fix tile sizer buffer accounting (removes spurious "buffer exceeds limit" warning)
    - Optimize GridAccumulator.update() with in-place numpy ufuncs
    - Plugin metadata consolidation: delegate metadata.json write to SurfaceData.save_cleaned()
    0.1.0-beta80
    - Add NVIDIA VRAM detection on Linux via NVML
    0.1.0-beta79
    - Fix Windows PermissionError on memmap temp dir cleanup
    - Fix rasterio create_empty_raster not initializing with nodata
    0.1.0-beta77
    - Fix GPU OOM on large rasters
    0.1.0-beta74
    - Fix rasterio resampling pixel drift (from_bounds back-computed inexact pixel size)
    - Fix phantom vegetation shadows: QGIS load path preserved CDSM NaN markers
    - Add SurfaceData.load() API; eliminate QGIS/core loading duplication
    - Remove duplicate root-level SVF/raster saves from QGIS preprocessing
    - Fix progress bar regression: wall computation now reports progress
    0.1.0-beta73
    - Fix CDSM/TDSM preprocessing tests for sub-threshold NaN behaviour
    0.1.0-beta72
    - Handle CDSM reconciliation with DEM to prevent shadow artefacts on hills

    Older releases (0.1.0-beta1 .. 0.1.0-beta71):
    - See https://github.com/UMEP-dev/solweig/releases for the full version history.
