Skip to main content

High-performance SOLWEIG urban microclimate model (Rust + Python)

Project description

SOLWEIG

High-performance urban microclimate model for computing Mean Radiant Temperature (Tmrt) and thermal comfort indices (UTCI, PET).

Rust + Python performance-critical algorithms with GPU and tiled processing support.

This package is currently in testing as a proof of concept. Please open an issue if you have any feedback or suggestions.

Documentation

Original Code

This package is adapted from the GPLv3-licensed UMEP-processing by Fredrik Lindberg, Ting Sun, Sue Grimmond, Yihao Tang, and Nils Wallenberg.

Licensed under GNU General Public License v3.0. See LICENSE for details.

Citation:

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 doi:10.1016/j.envsoft.2017.09.020

Installation

# Clone and install
git clone https://github.com/UMEP-dev/solweig.git
cd solweig
uv sync                  # Install Python dependencies
maturin develop          # Build Rust extension

Quick Start

import solweig
from datetime import datetime

# Create surface from DSM array
surface = solweig.SurfaceData(dsm=my_dsm_array, pixel_size=1.0)

# Define location and weather
location = solweig.Location(latitude=57.7, longitude=12.0)
weather = solweig.Weather(
    datetime=datetime(2024, 7, 15, 12, 0),
    ta=25.0,        # Air temperature (°C)
    rh=50.0,        # Relative humidity (%)
    global_rad=800.0  # Global radiation (W/m²)
)

# Calculate Tmrt
result = solweig.calculate(surface, location, weather)
print(f"Tmrt: {result.tmrt.mean():.1f}°C")

Loading from GeoTIFFs

import solweig

# Load and prepare surface data (auto-computes walls/SVF)
surface = solweig.SurfaceData.prepare(
    dsm="data/dsm.tif",
    working_dir="cache/",       # Walls/SVF cached here
    cdsm="data/cdsm.tif",       # Optional: vegetation
)

# Load weather from EPW file
weather_list = solweig.Weather.from_epw(
    "data/weather.epw",
    start="2023-07-01",
    end="2023-07-03",
)

# Calculate timeseries
results = solweig.calculate_timeseries(
    surface=surface,
    weather_series=weather_list,
    output_dir="output/",
)

Post-Processing (UTCI/PET)

Thermal comfort indices can be computed directly from results:

# Single timestep: compute directly from result
result = solweig.calculate(surface, location, weather)
utci = result.compute_utci(weather)  # Fast polynomial
pet = result.compute_pet(weather)    # Slower iterative solver

# Batch processing: from saved Tmrt files
solweig.compute_utci(tmrt_dir="output/", weather_series=weather_list, output_dir="utci/")
solweig.compute_pet(tmrt_dir="output/", weather_series=weather_list, output_dir="pet/")

Input Validation

Validate inputs before expensive calculations:

try:
    warnings = solweig.validate_inputs(surface, location, weather)
    for w in warnings:
        print(f"Warning: {w}")
    result = solweig.calculate(surface, location, weather)
except solweig.GridShapeMismatch as e:
    print(f"Grid mismatch: {e.field}")
except solweig.MissingPrecomputedData as e:
    print(f"Missing data: {e}")

Demos

Complete working examples are in the demos/ folder:

QGIS Plugin

SOLWEIG is available as a QGIS Processing plugin for interactive spatial analysis:

  1. Open QGIS → PluginsManage and Install Plugins
  2. Go to Settings tab → Check "Show also experimental plugins"
  3. Search for "SOLWEIG" in the All tab
  4. Click Install Plugin

See qgis_plugin/ for source code and development details.

Build & Test

maturin develop          # Build Rust extension
pytest tests/            # Run all 353 tests
poe verify_project       # Full verification (format, lint, test)

Development

Project Structure

pysrc/solweig/              # Python source (modular architecture)
  api.py                    # Public API re-exports
  models/                   # Dataclass package (~3,080 lines)
  components/               # Modular component functions
  computation.py            # Core orchestration logic
  timeseries.py             # Batch time series processing
  tiling.py                 # Large raster tiling support
rust/                       # Rust extensions via maturin
qgis_plugin/                # QGIS Processing plugin
tests/                      # 353 tests (100% pass rate)
  golden/                   # Reference data validation
  spec/                     # Physical property tests
docs/                       # MkDocs documentation site
specs/                      # Markdown specifications

Development Setup

# Install dependencies
uv sync

# Build Rust extension for development
maturin develop

# Run tests with coverage
pytest tests/ --cov=pysrc/solweig

# Format and lint
ruff format pysrc/ tests/
ruff check pysrc/ tests/ --fix

# Type checking
ty pysrc/

# Full verification pipeline
poe verify_project

Building Documentation

# Serve docs locally
mkdocs serve

# Build static site
mkdocs build

QGIS Plugin Bundle Preparation

The easiest way is to let GitHub Actions build the package — push a version tag (e.g. v0.1.0) or trigger the workflow manually. Download the universal ZIP from the release artifacts and upload it to the QGIS Plugin Repository.

The plugin source lives in qgis_plugin/solweig_qgis/ and is built using the qgis_plugin/build_plugin.py script, which compiles the Rust extension, bundles it with the Python library, and creates a distributable ZIP.

1. Update Plugin Metadata

Edit qgis_plugin/solweig_qgis/metadata.txt and increment the version.

2. Build the Plugin

# Build for current platform (builds Rust extension + bundles Python library)
python qgis_plugin/build_plugin.py

# Build and create a distributable ZIP for the current platform
python qgis_plugin/build_plugin.py --package

# Create a universal multi-platform ZIP from pre-built wheels in dist/
# (this is what GitHub Actions uses)
python qgis_plugin/build_plugin.py --universal

3. Test Plugin Locally

# Symlink for development (macOS)
ln -s "$(pwd)/qgis_plugin/solweig_qgis" ~/Library/Application\ Support/QGIS/QGIS3/profiles/default/python/plugins/solweig_qgis

Then:

  1. Open QGIS
  2. PluginsManage and Install PluginsInstalled
  3. Enable SOLWEIG
  4. Test in Processing ToolboxSOLWEIG

4. Upload to QGIS Plugin Repository

  1. Register at https://plugins.qgis.org/
  2. Log in → My PluginsUpload a plugin
  3. Select the ZIP from qgis_plugin/solweig-qgis-*-universal.zip
  4. Check "Experimental" for pre-release versions
  5. Add changelog/release notes
  6. Click Upload

Release Checklist

  • Version incremented in qgis_plugin/solweig_qgis/metadata.txt
  • All tests passing (pytest tests/)
  • Documentation updated
  • CHANGELOG.md updated
  • Plugin tested in QGIS locally
  • ZIP bundle created and validated
  • Uploaded to plugins.qgis.org

Tooling Preferences

Tool Use For Instead Of
uv Package management pip, poetry, pipenv
ruff Linting and formatting black, isort, flake8, pylint
ty Type checking mypy, pyright

Code Metrics

  • api.py: 403 lines (simplified from 3,976)
  • models/ package: ~3,080 lines (6 modules)
  • Component functions: All ≤ 455 lines
  • Test count: 353 tests (100% pass rate)
  • Legacy code removed: 6,100 lines

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

solweig-0.1.0b7.tar.gz (218.1 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

solweig-0.1.0b7-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.4 MB view details)

Uploaded PyPymanylinux: glibc 2.17+ x86-64

solweig-0.1.0b7-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.4 MB view details)

Uploaded PyPymanylinux: glibc 2.17+ ARM64

solweig-0.1.0b7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.4 MB view details)

Uploaded PyPymanylinux: glibc 2.17+ ARM64

solweig-0.1.0b7-cp39-abi3-win_amd64.whl (3.3 MB view details)

Uploaded CPython 3.9+Windows x86-64

solweig-0.1.0b7-cp39-abi3-musllinux_1_2_x86_64.whl (3.7 MB view details)

Uploaded CPython 3.9+musllinux: musl 1.2+ x86-64

solweig-0.1.0b7-cp39-abi3-musllinux_1_2_aarch64.whl (3.6 MB view details)

Uploaded CPython 3.9+musllinux: musl 1.2+ ARM64

solweig-0.1.0b7-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.4 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ x86-64

solweig-0.1.0b7-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.4 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ ARM64

solweig-0.1.0b7-cp39-abi3-macosx_11_0_arm64.whl (2.7 MB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

solweig-0.1.0b7-cp39-abi3-macosx_10_12_x86_64.whl (2.8 MB view details)

Uploaded CPython 3.9+macOS 10.12+ x86-64

File details

Details for the file solweig-0.1.0b7.tar.gz.

File metadata

  • Download URL: solweig-0.1.0b7.tar.gz
  • Upload date:
  • Size: 218.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: maturin/1.11.5

File hashes

Hashes for solweig-0.1.0b7.tar.gz
Algorithm Hash digest
SHA256 81318c0328ad0f8f8df939939d4cba1743ba9864876375c1d6984d1567a5c959
MD5 8869c83f97419510bb8b62bfdd908ce0
BLAKE2b-256 4d66e6e29f9f805740620d1e4b17de7b2b92a3885286d92b81e54314d66bbd04

See more details on using hashes here.

File details

Details for the file solweig-0.1.0b7-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for solweig-0.1.0b7-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 cca332630d87ee2ddfdc791f2e2b4c4899d80e99239abadc8a253542857499d3
MD5 5762db602baf969e091cc99ad5703afb
BLAKE2b-256 54ac6321b1b1fbe62e46561bd83dca49bebabe5f409206ad36f29536bbd559a8

See more details on using hashes here.

File details

Details for the file solweig-0.1.0b7-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for solweig-0.1.0b7-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 d6d383cbff616fab4bcbad87d54ab6f265e312834c9896177006d0646b353e2d
MD5 8e9e789a3353a4abfc4effd1b1d4e341
BLAKE2b-256 53784c81c4016f98b2734395f4f9ec9ab735335452d60ff348ca1b26574426f4

See more details on using hashes here.

File details

Details for the file solweig-0.1.0b7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for solweig-0.1.0b7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 edefa54e0e46a9ea0b6aba8200f896e2e92b9edda097fa17bd1e3d4ba4fa1dac
MD5 bbd94eb3c8a9647b18995bc26194758b
BLAKE2b-256 fe424b22cc2ee068f56995d8da673f52db184e323385818cf1b926c949c77162

See more details on using hashes here.

File details

Details for the file solweig-0.1.0b7-cp39-abi3-win_amd64.whl.

File metadata

  • Download URL: solweig-0.1.0b7-cp39-abi3-win_amd64.whl
  • Upload date:
  • Size: 3.3 MB
  • Tags: CPython 3.9+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: maturin/1.11.5

File hashes

Hashes for solweig-0.1.0b7-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 a9db3c01649c08787b265ad8bbef4971ca8d745ffdcbac45ace7da0ed1d2bb40
MD5 6a62e5e26a8aaa08388e278d4bedb28b
BLAKE2b-256 563d51a24946dcfb9d687ecf37a68bfdb7f5a07e6f1897bc62c7956fbf5c95b7

See more details on using hashes here.

File details

Details for the file solweig-0.1.0b7-cp39-abi3-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for solweig-0.1.0b7-cp39-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 b0f2bf9ae094f0a04d44ab7182272f735d7a74bc65ec281d79c1ef79d5b5d4dc
MD5 104dd55415a2d362fb10e5ffdc3e78da
BLAKE2b-256 c6985f0087dde674f35954f3c582f8d4c5caf29a8c32859aff061eb9f02123c1

See more details on using hashes here.

File details

Details for the file solweig-0.1.0b7-cp39-abi3-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for solweig-0.1.0b7-cp39-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 67be789f4bb89ae10811bfcd9a56fdcbd18cd02b40ef7c4e0087ac2508d470cd
MD5 16b1b570538d343f55b2d284261d10d2
BLAKE2b-256 373b51c15b9bd22046d93df9f6c8329f4389e43488b969f55a492ec65e3b8f2f

See more details on using hashes here.

File details

Details for the file solweig-0.1.0b7-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for solweig-0.1.0b7-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 6e47b96d3b84e67e323c67fc0c0d43cd0d83a46ce449ce8aa3e8b62f9dd5791a
MD5 f68a49e6a94b24f7f861249a5f9a7858
BLAKE2b-256 6bd8a6ea7aa10341ec657bea3da1b1285a3a4d6f4ed73eef6e3c7ce86ba42084

See more details on using hashes here.

File details

Details for the file solweig-0.1.0b7-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for solweig-0.1.0b7-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 cd4b129ff7ad51b9d7917b4d057c49b065c2219edc2bd7f3be9ac0d39e4f2672
MD5 916388509e08852dce9dba06973eb09c
BLAKE2b-256 d44ab438794b5e5130eaa08f3fe593896ebfe4a96ea201861498044be47f4d2e

See more details on using hashes here.

File details

Details for the file solweig-0.1.0b7-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for solweig-0.1.0b7-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 cc7df878d6a1a0f80c5298ef71a1854cc15927a9c1cf07b7fd133cbe0f2c10df
MD5 a6be3c2450ab86455ff3adc262028cfc
BLAKE2b-256 8433d968770b816deb66a2760166602ff1feff18233c1edf25640365d88d90f1

See more details on using hashes here.

File details

Details for the file solweig-0.1.0b7-cp39-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for solweig-0.1.0b7-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 eadf8b9f40d9068d114140150cca6a9a9d39f35b0721b9ddbfd9dbbc5b9f5f9d
MD5 57886cdfecd7558511b9142128b6e9a4
BLAKE2b-256 fa1088391090a70dba5bf92f7a37337f51d65171f084004180159ef86d586c04

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page