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.0b25.tar.gz (255.8 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.0b25-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.5 MB view details)

Uploaded PyPymanylinux: glibc 2.17+ x86-64

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

Uploaded PyPymanylinux: glibc 2.17+ ARM64

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

Uploaded PyPymanylinux: glibc 2.17+ ARM64

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

Uploaded CPython 3.9+Windows x86-64

solweig-0.1.0b25-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.0b25-cp39-abi3-musllinux_1_2_aarch64.whl (3.6 MB view details)

Uploaded CPython 3.9+musllinux: musl 1.2+ ARM64

solweig-0.1.0b25-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.5 MB view details)

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

solweig-0.1.0b25-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.0b25-cp39-abi3-macosx_11_0_arm64.whl (2.8 MB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

solweig-0.1.0b25-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.0b25.tar.gz.

File metadata

  • Download URL: solweig-0.1.0b25.tar.gz
  • Upload date:
  • Size: 255.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for solweig-0.1.0b25.tar.gz
Algorithm Hash digest
SHA256 fb4cdf7d8fc74228c551b66b7fdd097cd56b79c3728d4e4847fc6d89d4dbbe3e
MD5 5bb3c6c40758028f4c9f229d71339353
BLAKE2b-256 3a65bd2fe9072865634b4e39c7e2bee69add716ed541309279e453cbc6901359

See more details on using hashes here.

Provenance

The following attestation bundles were made for solweig-0.1.0b25.tar.gz:

Publisher: python-publish.yml on UMEP-dev/solweig

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

File hashes

Hashes for solweig-0.1.0b25-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 f01cb4f41a8ac3fc107548703c4c76871baee7045450738dbeb935d0d3348488
MD5 19d99dad764e84c4bb14dc94d454a9c9
BLAKE2b-256 2ddaec611cbb03f6242d9dd9a3350e6d4ed925dd0277bdf5f6a33390e5195cff

See more details on using hashes here.

Provenance

The following attestation bundles were made for solweig-0.1.0b25-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: python-publish.yml on UMEP-dev/solweig

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

File hashes

Hashes for solweig-0.1.0b25-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 5e79b899d024e00e2e14766e22e538a01fe733a0f3a0bd2ad61d0e175192bcc3
MD5 1d02650dfd9578a3cee5750b4fc66f07
BLAKE2b-256 feb30cebfcfb6a48f7ddea5eae9da9c0649090c1189669a6b4f8d8da6c4e0bba

See more details on using hashes here.

Provenance

The following attestation bundles were made for solweig-0.1.0b25-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: python-publish.yml on UMEP-dev/solweig

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

File hashes

Hashes for solweig-0.1.0b25-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 6516ea6c0c418521e8177d9e6f690ae3ed56e7466d5916777780ac908d69b158
MD5 9d834052c1722f16c0287c92611d3dae
BLAKE2b-256 c637cab942146c295ec87d090c9e842981c11682a7bea519edbffab04a2bf597

See more details on using hashes here.

Provenance

The following attestation bundles were made for solweig-0.1.0b25-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: python-publish.yml on UMEP-dev/solweig

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

  • Download URL: solweig-0.1.0b25-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: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for solweig-0.1.0b25-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 ab1ca284e85c2d59371f51b8596d9022c6f3394c3801c12204a26292bdde9590
MD5 e773bcd2193a548977af5d1bbe70f751
BLAKE2b-256 9bf6a898e75f6eae8b7a5877e741075b0087170a0be8236cc7705fcd1517cf5a

See more details on using hashes here.

Provenance

The following attestation bundles were made for solweig-0.1.0b25-cp39-abi3-win_amd64.whl:

Publisher: python-publish.yml on UMEP-dev/solweig

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

File hashes

Hashes for solweig-0.1.0b25-cp39-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 ad74ea7907b6918d1e696acefb53389b5a08c50caabefb89d59be116aa9ea56c
MD5 97af4d617507789e4ba1d643372b1b44
BLAKE2b-256 32fbc6466c13ae67a63eaae01882ea6cf94910dad4fd0eacbf7ba4fa8a88114b

See more details on using hashes here.

Provenance

The following attestation bundles were made for solweig-0.1.0b25-cp39-abi3-musllinux_1_2_x86_64.whl:

Publisher: python-publish.yml on UMEP-dev/solweig

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

File hashes

Hashes for solweig-0.1.0b25-cp39-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 63432ed81a860fb48e41a1327e29a091a91a82563c9590138242f0e9c1ef0acf
MD5 640a040336bffca4202533019bdc137c
BLAKE2b-256 1510df2fc0b0b61a8527d42f43cf3cc1df6370e7bf3867e5a4723f9d79babafa

See more details on using hashes here.

Provenance

The following attestation bundles were made for solweig-0.1.0b25-cp39-abi3-musllinux_1_2_aarch64.whl:

Publisher: python-publish.yml on UMEP-dev/solweig

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

File hashes

Hashes for solweig-0.1.0b25-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 ba6196923811573263db80bd2cdeb288d2ac14c8cb25c9ac4be032b94f606990
MD5 e49fab3eac909634d5d0bd3a4e8ae774
BLAKE2b-256 afd914e22fed81767947da4be557e645cdafbc026fdf6e40919f8e7f5356ec55

See more details on using hashes here.

Provenance

The following attestation bundles were made for solweig-0.1.0b25-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: python-publish.yml on UMEP-dev/solweig

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

File hashes

Hashes for solweig-0.1.0b25-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 88b103883667679aeee5f6980ff563c350b4afbc999e18ddd380ca8d208b7681
MD5 f7cd3c77add43f86f5d140b54228dd6a
BLAKE2b-256 0f480f7f7a43995d17a097469d18a2fab7d55fc9f0bcf82fcedc4a1abb745a1e

See more details on using hashes here.

Provenance

The following attestation bundles were made for solweig-0.1.0b25-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: python-publish.yml on UMEP-dev/solweig

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

File hashes

Hashes for solweig-0.1.0b25-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 21365d60b411820ed69bb50b5e933c53a93330fabf7ba21fcc6f190188a06067
MD5 b3cab657659367683b16b1cb17166869
BLAKE2b-256 a608621f959456477a27fece755b408606d7f21f0eb0d37f1a6781c13563480f

See more details on using hashes here.

Provenance

The following attestation bundles were made for solweig-0.1.0b25-cp39-abi3-macosx_11_0_arm64.whl:

Publisher: python-publish.yml on UMEP-dev/solweig

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

File hashes

Hashes for solweig-0.1.0b25-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 12c0bd012bc2d0b043822892f32b52e5537cf2cdb9fffc42e0d674e79078004d
MD5 e678523cc4680cca3294e68f9e16047d
BLAKE2b-256 cd1cd05a3f43c303b6574f741d7cc7ae8108cacc04ad4a83317f562a24ccfb22

See more details on using hashes here.

Provenance

The following attestation bundles were made for solweig-0.1.0b25-cp39-abi3-macosx_10_12_x86_64.whl:

Publisher: python-publish.yml on UMEP-dev/solweig

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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