solweig 0.1.0b3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- solweig-0.1.0b3/PKG-INFO +326 -0
- solweig-0.1.0b3/README.md +291 -0
- solweig-0.1.0b3/pyproject.toml +179 -0
- solweig-0.1.0b3/pysrc/solweig/__init__.py +199 -0
- solweig-0.1.0b3/pysrc/solweig/api.py +464 -0
- solweig-0.1.0b3/pysrc/solweig/buffers.py +246 -0
- solweig-0.1.0b3/pysrc/solweig/bundles.py +271 -0
- solweig-0.1.0b3/pysrc/solweig/cache.py +187 -0
- solweig-0.1.0b3/pysrc/solweig/components/__init__.py +17 -0
- solweig-0.1.0b3/pysrc/solweig/components/ground.py +137 -0
- solweig-0.1.0b3/pysrc/solweig/components/gvf.py +269 -0
- solweig-0.1.0b3/pysrc/solweig/components/radiation.py +456 -0
- solweig-0.1.0b3/pysrc/solweig/components/shadows.py +180 -0
- solweig-0.1.0b3/pysrc/solweig/components/svf_resolution.py +188 -0
- solweig-0.1.0b3/pysrc/solweig/components/tmrt.py +102 -0
- solweig-0.1.0b3/pysrc/solweig/computation.py +759 -0
- solweig-0.1.0b3/pysrc/solweig/constants.py +82 -0
- solweig-0.1.0b3/pysrc/solweig/data/default_materials.json +221 -0
- solweig-0.1.0b3/pysrc/solweig/data/default_params.json +56 -0
- solweig-0.1.0b3/pysrc/solweig/data/physics_defaults.json +31 -0
- solweig-0.1.0b3/pysrc/solweig/errors.py +123 -0
- solweig-0.1.0b3/pysrc/solweig/io.py +1328 -0
- solweig-0.1.0b3/pysrc/solweig/loaders.py +257 -0
- solweig-0.1.0b3/pysrc/solweig/metadata.py +137 -0
- solweig-0.1.0b3/pysrc/solweig/models/__init__.py +37 -0
- solweig-0.1.0b3/pysrc/solweig/models/config.py +233 -0
- solweig-0.1.0b3/pysrc/solweig/models/precomputed.py +681 -0
- solweig-0.1.0b3/pysrc/solweig/models/results.py +322 -0
- solweig-0.1.0b3/pysrc/solweig/models/state.py +152 -0
- solweig-0.1.0b3/pysrc/solweig/models/surface.py +1832 -0
- solweig-0.1.0b3/pysrc/solweig/models/weather.py +700 -0
- solweig-0.1.0b3/pysrc/solweig/parametersforsolweig.json +221 -0
- solweig-0.1.0b3/pysrc/solweig/physics/Kup_veg_2015a.py +33 -0
- solweig-0.1.0b3/pysrc/solweig/physics/Perez_v3.py +313 -0
- solweig-0.1.0b3/pysrc/solweig/physics/__init__.py +0 -0
- solweig-0.1.0b3/pysrc/solweig/physics/clearnessindex_2013b.py +88 -0
- solweig-0.1.0b3/pysrc/solweig/physics/create_patches.py +68 -0
- solweig-0.1.0b3/pysrc/solweig/physics/cylindric_wedge.py +109 -0
- solweig-0.1.0b3/pysrc/solweig/physics/daylen.py +22 -0
- solweig-0.1.0b3/pysrc/solweig/physics/diffusefraction.py +47 -0
- solweig-0.1.0b3/pysrc/solweig/physics/morphology.py +188 -0
- solweig-0.1.0b3/pysrc/solweig/physics/patch_radiation.py +373 -0
- solweig-0.1.0b3/pysrc/solweig/physics/sun_distance.py +20 -0
- solweig-0.1.0b3/pysrc/solweig/physics/sun_position.py +1061 -0
- solweig-0.1.0b3/pysrc/solweig/physics/sunlit_shaded_patches.py +38 -0
- solweig-0.1.0b3/pysrc/solweig/physics/wallalgorithms.py +214 -0
- solweig-0.1.0b3/pysrc/solweig/postprocess.py +356 -0
- solweig-0.1.0b3/pysrc/solweig/progress.py +245 -0
- solweig-0.1.0b3/pysrc/solweig/solweig_logging.py +189 -0
- solweig-0.1.0b3/pysrc/solweig/tiling.py +420 -0
- solweig-0.1.0b3/pysrc/solweig/timeseries.py +394 -0
- solweig-0.1.0b3/pysrc/solweig/utils.py +309 -0
- solweig-0.1.0b3/pysrc/solweig/walls.py +59 -0
- solweig-0.1.0b3/rust/Cargo.lock +1395 -0
- solweig-0.1.0b3/rust/Cargo.toml +20 -0
- solweig-0.1.0b3/rust/src/emissivity_models.rs +28 -0
- solweig-0.1.0b3/rust/src/gpu/mod.rs +6 -0
- solweig-0.1.0b3/rust/src/gpu/shadow_gpu.rs +1941 -0
- solweig-0.1.0b3/rust/src/gpu/shadow_propagation.wgsl +346 -0
- solweig-0.1.0b3/rust/src/gpu/shadow_to_u8.wgsl +69 -0
- solweig-0.1.0b3/rust/src/gpu/svf_accumulation.wgsl +76 -0
- solweig-0.1.0b3/rust/src/ground.rs +491 -0
- solweig-0.1.0b3/rust/src/gvf.rs +586 -0
- solweig-0.1.0b3/rust/src/gvf_geometry.rs +355 -0
- solweig-0.1.0b3/rust/src/lib.rs +188 -0
- solweig-0.1.0b3/rust/src/morphology.rs +100 -0
- solweig-0.1.0b3/rust/src/patch_radiation.rs +254 -0
- solweig-0.1.0b3/rust/src/pet.rs +400 -0
- solweig-0.1.0b3/rust/src/pipeline.rs +1061 -0
- solweig-0.1.0b3/rust/src/shadowing.rs +819 -0
- solweig-0.1.0b3/rust/src/sky.rs +843 -0
- solweig-0.1.0b3/rust/src/skyview.rs +925 -0
- solweig-0.1.0b3/rust/src/sun.rs +526 -0
- solweig-0.1.0b3/rust/src/sunlit_shaded_patches.rs +33 -0
- solweig-0.1.0b3/rust/src/tmrt.rs +216 -0
- solweig-0.1.0b3/rust/src/utci.rs +364 -0
- solweig-0.1.0b3/rust/src/vegetation.rs +1004 -0
- solweig-0.1.0b3/rust/src/wall_aspect.rs +435 -0
solweig-0.1.0b3/PKG-INFO
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: solweig
|
|
3
|
+
Version: 0.1.0b3
|
|
4
|
+
Classifier: Development Status :: 3 - Alpha
|
|
5
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
6
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
7
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
10
|
+
Classifier: Programming Language :: Rust
|
|
11
|
+
Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
13
|
+
Requires-Dist: numpy>=1.26.0
|
|
14
|
+
Requires-Dist: pyproj>=3.6.0
|
|
15
|
+
Requires-Dist: scipy>=1.13.0
|
|
16
|
+
Requires-Dist: shapely>=2.0.1
|
|
17
|
+
Requires-Dist: geopandas>=1.0.1 ; extra == 'full'
|
|
18
|
+
Requires-Dist: rasterio>=1.3.0 ; extra == 'full'
|
|
19
|
+
Requires-Dist: tqdm>=4.67.1 ; extra == 'full'
|
|
20
|
+
Requires-Dist: pillow>=9.0.0 ; extra == 'full'
|
|
21
|
+
Provides-Extra: full
|
|
22
|
+
Provides-Extra: qgis
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Summary: High-performance SOLWEIG urban microclimate model (Rust + Python)
|
|
25
|
+
Keywords: python3,geographical-information-system,spatial-data,spatial-data-analysis,urban-climate,urban-heat-island,urban-meteorology,urban-microclimate,urban-planning,urban-sustainability,urban-thermal-comfort,urban-thermal-environment,urban-thermal-mapping,urban-thermal-modelling,urban-thermal-simulation,urban-thermal-sustainability
|
|
26
|
+
Author: UMEP Developers
|
|
27
|
+
Maintainer: UMEP Developers
|
|
28
|
+
License: AGPL-3.0
|
|
29
|
+
Requires-Python: >=3.9, <3.14
|
|
30
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
31
|
+
Project-URL: documentation, https://github.com/UMEP-dev/solweig
|
|
32
|
+
Project-URL: homepage, https://github.com/UMEP-dev/solweig
|
|
33
|
+
Project-URL: repository, https://github.com/UMEP-dev/solweig
|
|
34
|
+
|
|
35
|
+
# SOLWEIG
|
|
36
|
+
|
|
37
|
+
High-performance urban microclimate model for computing Mean Radiant Temperature (Tmrt) and thermal comfort indices (UTCI, PET).
|
|
38
|
+
|
|
39
|
+
**Rust + Python** performance-critical algorithms with GPU and tiled processing support.
|
|
40
|
+
|
|
41
|
+
> This package is currently in testing as a proof of concept. Please open an issue if you have any feedback or suggestions.
|
|
42
|
+
|
|
43
|
+
## Documentation
|
|
44
|
+
|
|
45
|
+
- [Quick Start Guide](docs/getting-started/quick-start.md) - Detailed tutorial
|
|
46
|
+
- [API Reference](docs/) - Full documentation site (MkDocs, 25 pages)
|
|
47
|
+
- [Physics Specifications](specs/) - Scientific documentation (10 specs)
|
|
48
|
+
- [ROADMAP.md](ROADMAP.md) - Development priorities
|
|
49
|
+
|
|
50
|
+
## Original Code
|
|
51
|
+
|
|
52
|
+
This package is adapted from the GPLv3-licensed [UMEP-processing](https://github.com/UMEP-dev/UMEP-processing) by Fredrik Lindberg, Ting Sun, Sue Grimmond, Yihao Tang, and Nils Wallenberg.
|
|
53
|
+
|
|
54
|
+
Licensed under GNU General Public License v3.0. See [LICENSE](LICENSE) for details.
|
|
55
|
+
|
|
56
|
+
**Citation:**
|
|
57
|
+
|
|
58
|
+
Adapted from UMEP (Urban Multi-scale Environmental Predictor) by Fredrik Lindberg, Sue Grimmond, and contributors. If you use this plugin in research, please cite:
|
|
59
|
+
|
|
60
|
+
> 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](https://doi.org/10.1016/j.envsoft.2017.09.020)
|
|
61
|
+
|
|
62
|
+
## Installation
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Clone and install
|
|
66
|
+
git clone https://github.com/UMEP-dev/solweig.git
|
|
67
|
+
cd solweig
|
|
68
|
+
uv sync # Install Python dependencies
|
|
69
|
+
maturin develop # Build Rust extension
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Quick Start
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
import solweig
|
|
76
|
+
from datetime import datetime
|
|
77
|
+
|
|
78
|
+
# Create surface from DSM array
|
|
79
|
+
surface = solweig.SurfaceData(dsm=my_dsm_array, pixel_size=1.0)
|
|
80
|
+
|
|
81
|
+
# Define location and weather
|
|
82
|
+
location = solweig.Location(latitude=57.7, longitude=12.0)
|
|
83
|
+
weather = solweig.Weather(
|
|
84
|
+
datetime=datetime(2024, 7, 15, 12, 0),
|
|
85
|
+
ta=25.0, # Air temperature (°C)
|
|
86
|
+
rh=50.0, # Relative humidity (%)
|
|
87
|
+
global_rad=800.0 # Global radiation (W/m²)
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# Calculate Tmrt
|
|
91
|
+
result = solweig.calculate(surface, location, weather)
|
|
92
|
+
print(f"Tmrt: {result.tmrt.mean():.1f}°C")
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Loading from GeoTIFFs
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
import solweig
|
|
99
|
+
|
|
100
|
+
# Load and prepare surface data (auto-computes walls/SVF)
|
|
101
|
+
surface = solweig.SurfaceData.prepare(
|
|
102
|
+
dsm="data/dsm.tif",
|
|
103
|
+
working_dir="cache/", # Walls/SVF cached here
|
|
104
|
+
cdsm="data/cdsm.tif", # Optional: vegetation
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# Load weather from EPW file
|
|
108
|
+
weather_list = solweig.Weather.from_epw(
|
|
109
|
+
"data/weather.epw",
|
|
110
|
+
start="2023-07-01",
|
|
111
|
+
end="2023-07-03",
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# Calculate timeseries
|
|
115
|
+
results = solweig.calculate_timeseries(
|
|
116
|
+
surface=surface,
|
|
117
|
+
weather_series=weather_list,
|
|
118
|
+
output_dir="output/",
|
|
119
|
+
)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Post-Processing (UTCI/PET)
|
|
123
|
+
|
|
124
|
+
Thermal comfort indices can be computed directly from results:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
# Single timestep: compute directly from result
|
|
128
|
+
result = solweig.calculate(surface, location, weather)
|
|
129
|
+
utci = result.compute_utci(weather) # Fast polynomial
|
|
130
|
+
pet = result.compute_pet(weather) # Slower iterative solver
|
|
131
|
+
|
|
132
|
+
# Batch processing: from saved Tmrt files
|
|
133
|
+
solweig.compute_utci(tmrt_dir="output/", weather_series=weather_list, output_dir="utci/")
|
|
134
|
+
solweig.compute_pet(tmrt_dir="output/", weather_series=weather_list, output_dir="pet/")
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Input Validation
|
|
138
|
+
|
|
139
|
+
Validate inputs before expensive calculations:
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
try:
|
|
143
|
+
warnings = solweig.validate_inputs(surface, location, weather)
|
|
144
|
+
for w in warnings:
|
|
145
|
+
print(f"Warning: {w}")
|
|
146
|
+
result = solweig.calculate(surface, location, weather)
|
|
147
|
+
except solweig.GridShapeMismatch as e:
|
|
148
|
+
print(f"Grid mismatch: {e.field}")
|
|
149
|
+
except solweig.MissingPrecomputedData as e:
|
|
150
|
+
print(f"Missing data: {e}")
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Demos
|
|
154
|
+
|
|
155
|
+
Complete working examples are in the [demos/](demos/) folder:
|
|
156
|
+
|
|
157
|
+
- [demos/athens-demo.py](demos/athens-demo.py) - Full workflow with GeoTIFFs
|
|
158
|
+
- [demos/solweig_gbg_test.py](demos/solweig_gbg_test.py) - Gothenburg test data
|
|
159
|
+
|
|
160
|
+
## QGIS Plugin
|
|
161
|
+
|
|
162
|
+
SOLWEIG is available as a QGIS Processing plugin for interactive spatial analysis:
|
|
163
|
+
|
|
164
|
+
1. Open QGIS → **Plugins** → **Manage and Install Plugins**
|
|
165
|
+
2. Go to **Settings** tab → Check **"Show also experimental plugins"**
|
|
166
|
+
3. Search for **"SOLWEIG"** in the **All** tab
|
|
167
|
+
4. Click **Install Plugin**
|
|
168
|
+
|
|
169
|
+
See [qgis_plugin/](qgis_plugin/) for source code and development details.
|
|
170
|
+
|
|
171
|
+
## Build & Test
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
maturin develop # Build Rust extension
|
|
175
|
+
pytest tests/ # Run all 353 tests
|
|
176
|
+
poe verify_project # Full verification (format, lint, test)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Development
|
|
182
|
+
|
|
183
|
+
### Project Structure
|
|
184
|
+
|
|
185
|
+
```text
|
|
186
|
+
pysrc/solweig/ # Python source (modular architecture)
|
|
187
|
+
api.py # Public API re-exports
|
|
188
|
+
models/ # Dataclass package (~3,080 lines)
|
|
189
|
+
components/ # Modular component functions
|
|
190
|
+
computation.py # Core orchestration logic
|
|
191
|
+
timeseries.py # Batch time series processing
|
|
192
|
+
tiling.py # Large raster tiling support
|
|
193
|
+
rust/ # Rust extensions via maturin
|
|
194
|
+
qgis_plugin/ # QGIS Processing plugin
|
|
195
|
+
tests/ # 353 tests (100% pass rate)
|
|
196
|
+
golden/ # Reference data validation
|
|
197
|
+
spec/ # Physical property tests
|
|
198
|
+
docs/ # MkDocs documentation site
|
|
199
|
+
specs/ # Markdown specifications
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Development Setup
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
# Install dependencies
|
|
206
|
+
uv sync
|
|
207
|
+
|
|
208
|
+
# Build Rust extension for development
|
|
209
|
+
maturin develop
|
|
210
|
+
|
|
211
|
+
# Run tests with coverage
|
|
212
|
+
pytest tests/ --cov=pysrc/solweig
|
|
213
|
+
|
|
214
|
+
# Format and lint
|
|
215
|
+
ruff format pysrc/ tests/
|
|
216
|
+
ruff check pysrc/ tests/ --fix
|
|
217
|
+
|
|
218
|
+
# Type checking
|
|
219
|
+
ty pysrc/
|
|
220
|
+
|
|
221
|
+
# Full verification pipeline
|
|
222
|
+
poe verify_project
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Building Documentation
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
# Serve docs locally
|
|
229
|
+
mkdocs serve
|
|
230
|
+
|
|
231
|
+
# Build static site
|
|
232
|
+
mkdocs build
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### QGIS Plugin Bundle Preparation
|
|
236
|
+
|
|
237
|
+
To prepare the QGIS plugin for distribution:
|
|
238
|
+
|
|
239
|
+
#### 1. Update Plugin Metadata
|
|
240
|
+
|
|
241
|
+
Edit `qgis_plugin/metadata.txt`:
|
|
242
|
+
|
|
243
|
+
```ini
|
|
244
|
+
[general]
|
|
245
|
+
name=SOLWEIG
|
|
246
|
+
version=0.1.0 # Increment version
|
|
247
|
+
experimental=True # Set to False when stable
|
|
248
|
+
description=Urban microclimate model for thermal comfort analysis
|
|
249
|
+
qgisMinimumVersion=3.0
|
|
250
|
+
author=Your Name
|
|
251
|
+
email=your.email@example.com
|
|
252
|
+
repository=https://github.com/UMEP-dev/solweig
|
|
253
|
+
tracker=https://github.com/UMEP-dev/solweig/issues
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
#### 2. Create Distribution ZIP
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
# Create a clean build directory
|
|
260
|
+
cd /Users/gareth/dev/umep/solweig
|
|
261
|
+
mkdir -p build/solweig
|
|
262
|
+
|
|
263
|
+
# Copy plugin files (excluding build artifacts)
|
|
264
|
+
cp -r qgis_plugin/* build/solweig/
|
|
265
|
+
|
|
266
|
+
# Create ZIP with correct structure
|
|
267
|
+
cd build
|
|
268
|
+
zip -r solweig.zip solweig/ -x "*.pyc" -x "*__pycache__*" -x "*.DS_Store"
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
#### 3. Test Plugin Locally
|
|
272
|
+
|
|
273
|
+
Before uploading, test the plugin in QGIS:
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
# Copy to QGIS plugins directory (macOS)
|
|
277
|
+
cp -r build/solweig ~/Library/Application\ Support/QGIS/QGIS3/profiles/default/python/plugins/
|
|
278
|
+
|
|
279
|
+
# Or use symlink for development
|
|
280
|
+
ln -s /Users/gareth/dev/umep/solweig/qgis_plugin ~/Library/Application\ Support/QGIS/QGIS3/profiles/default/python/plugins/solweig
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Then:
|
|
284
|
+
|
|
285
|
+
1. Open QGIS
|
|
286
|
+
2. **Plugins** → **Manage and Install Plugins** → **Installed**
|
|
287
|
+
3. Enable **SOLWEIG**
|
|
288
|
+
4. Test in **Processing Toolbox** → **SOLWEIG**
|
|
289
|
+
|
|
290
|
+
#### 4. Upload to QGIS Plugin Repository
|
|
291
|
+
|
|
292
|
+
1. Register at <https://plugins.qgis.org/>
|
|
293
|
+
2. Log in → **My Plugins** → **Upload a plugin**
|
|
294
|
+
3. Select `build/solweig.zip`
|
|
295
|
+
4. Check **"Experimental"** for pre-release versions
|
|
296
|
+
5. Add changelog/release notes
|
|
297
|
+
6. Click **Upload**
|
|
298
|
+
|
|
299
|
+
Review typically takes 1-3 days.
|
|
300
|
+
|
|
301
|
+
### Release Checklist
|
|
302
|
+
|
|
303
|
+
- [ ] Version incremented in `qgis_plugin/metadata.txt`
|
|
304
|
+
- [ ] All tests passing (`pytest tests/`)
|
|
305
|
+
- [ ] Documentation updated
|
|
306
|
+
- [ ] CHANGELOG.md updated
|
|
307
|
+
- [ ] Plugin tested in QGIS locally
|
|
308
|
+
- [ ] ZIP bundle created and validated
|
|
309
|
+
- [ ] Uploaded to plugins.qgis.org
|
|
310
|
+
|
|
311
|
+
### Tooling Preferences
|
|
312
|
+
|
|
313
|
+
| Tool | Use For | Instead Of |
|
|
314
|
+
| -------- | ---------------------- | ---------------------------- |
|
|
315
|
+
| **uv** | Package management | pip, poetry, pipenv |
|
|
316
|
+
| **ruff** | Linting and formatting | black, isort, flake8, pylint |
|
|
317
|
+
| **ty** | Type checking | mypy, pyright |
|
|
318
|
+
|
|
319
|
+
### Code Metrics
|
|
320
|
+
|
|
321
|
+
- **api.py**: 403 lines (simplified from 3,976)
|
|
322
|
+
- **models/ package**: ~3,080 lines (6 modules)
|
|
323
|
+
- **Component functions**: All ≤ 455 lines
|
|
324
|
+
- **Test count**: 353 tests (100% pass rate)
|
|
325
|
+
- **Legacy code removed**: 6,100 lines
|
|
326
|
+
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# SOLWEIG
|
|
2
|
+
|
|
3
|
+
High-performance urban microclimate model for computing Mean Radiant Temperature (Tmrt) and thermal comfort indices (UTCI, PET).
|
|
4
|
+
|
|
5
|
+
**Rust + Python** performance-critical algorithms with GPU and tiled processing support.
|
|
6
|
+
|
|
7
|
+
> This package is currently in testing as a proof of concept. Please open an issue if you have any feedback or suggestions.
|
|
8
|
+
|
|
9
|
+
## Documentation
|
|
10
|
+
|
|
11
|
+
- [Quick Start Guide](docs/getting-started/quick-start.md) - Detailed tutorial
|
|
12
|
+
- [API Reference](docs/) - Full documentation site (MkDocs, 25 pages)
|
|
13
|
+
- [Physics Specifications](specs/) - Scientific documentation (10 specs)
|
|
14
|
+
- [ROADMAP.md](ROADMAP.md) - Development priorities
|
|
15
|
+
|
|
16
|
+
## Original Code
|
|
17
|
+
|
|
18
|
+
This package is adapted from the GPLv3-licensed [UMEP-processing](https://github.com/UMEP-dev/UMEP-processing) by Fredrik Lindberg, Ting Sun, Sue Grimmond, Yihao Tang, and Nils Wallenberg.
|
|
19
|
+
|
|
20
|
+
Licensed under GNU General Public License v3.0. See [LICENSE](LICENSE) for details.
|
|
21
|
+
|
|
22
|
+
**Citation:**
|
|
23
|
+
|
|
24
|
+
Adapted from UMEP (Urban Multi-scale Environmental Predictor) by Fredrik Lindberg, Sue Grimmond, and contributors. If you use this plugin in research, please cite:
|
|
25
|
+
|
|
26
|
+
> 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](https://doi.org/10.1016/j.envsoft.2017.09.020)
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Clone and install
|
|
32
|
+
git clone https://github.com/UMEP-dev/solweig.git
|
|
33
|
+
cd solweig
|
|
34
|
+
uv sync # Install Python dependencies
|
|
35
|
+
maturin develop # Build Rust extension
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
import solweig
|
|
42
|
+
from datetime import datetime
|
|
43
|
+
|
|
44
|
+
# Create surface from DSM array
|
|
45
|
+
surface = solweig.SurfaceData(dsm=my_dsm_array, pixel_size=1.0)
|
|
46
|
+
|
|
47
|
+
# Define location and weather
|
|
48
|
+
location = solweig.Location(latitude=57.7, longitude=12.0)
|
|
49
|
+
weather = solweig.Weather(
|
|
50
|
+
datetime=datetime(2024, 7, 15, 12, 0),
|
|
51
|
+
ta=25.0, # Air temperature (°C)
|
|
52
|
+
rh=50.0, # Relative humidity (%)
|
|
53
|
+
global_rad=800.0 # Global radiation (W/m²)
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# Calculate Tmrt
|
|
57
|
+
result = solweig.calculate(surface, location, weather)
|
|
58
|
+
print(f"Tmrt: {result.tmrt.mean():.1f}°C")
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Loading from GeoTIFFs
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import solweig
|
|
65
|
+
|
|
66
|
+
# Load and prepare surface data (auto-computes walls/SVF)
|
|
67
|
+
surface = solweig.SurfaceData.prepare(
|
|
68
|
+
dsm="data/dsm.tif",
|
|
69
|
+
working_dir="cache/", # Walls/SVF cached here
|
|
70
|
+
cdsm="data/cdsm.tif", # Optional: vegetation
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Load weather from EPW file
|
|
74
|
+
weather_list = solweig.Weather.from_epw(
|
|
75
|
+
"data/weather.epw",
|
|
76
|
+
start="2023-07-01",
|
|
77
|
+
end="2023-07-03",
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# Calculate timeseries
|
|
81
|
+
results = solweig.calculate_timeseries(
|
|
82
|
+
surface=surface,
|
|
83
|
+
weather_series=weather_list,
|
|
84
|
+
output_dir="output/",
|
|
85
|
+
)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Post-Processing (UTCI/PET)
|
|
89
|
+
|
|
90
|
+
Thermal comfort indices can be computed directly from results:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
# Single timestep: compute directly from result
|
|
94
|
+
result = solweig.calculate(surface, location, weather)
|
|
95
|
+
utci = result.compute_utci(weather) # Fast polynomial
|
|
96
|
+
pet = result.compute_pet(weather) # Slower iterative solver
|
|
97
|
+
|
|
98
|
+
# Batch processing: from saved Tmrt files
|
|
99
|
+
solweig.compute_utci(tmrt_dir="output/", weather_series=weather_list, output_dir="utci/")
|
|
100
|
+
solweig.compute_pet(tmrt_dir="output/", weather_series=weather_list, output_dir="pet/")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Input Validation
|
|
104
|
+
|
|
105
|
+
Validate inputs before expensive calculations:
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
try:
|
|
109
|
+
warnings = solweig.validate_inputs(surface, location, weather)
|
|
110
|
+
for w in warnings:
|
|
111
|
+
print(f"Warning: {w}")
|
|
112
|
+
result = solweig.calculate(surface, location, weather)
|
|
113
|
+
except solweig.GridShapeMismatch as e:
|
|
114
|
+
print(f"Grid mismatch: {e.field}")
|
|
115
|
+
except solweig.MissingPrecomputedData as e:
|
|
116
|
+
print(f"Missing data: {e}")
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Demos
|
|
120
|
+
|
|
121
|
+
Complete working examples are in the [demos/](demos/) folder:
|
|
122
|
+
|
|
123
|
+
- [demos/athens-demo.py](demos/athens-demo.py) - Full workflow with GeoTIFFs
|
|
124
|
+
- [demos/solweig_gbg_test.py](demos/solweig_gbg_test.py) - Gothenburg test data
|
|
125
|
+
|
|
126
|
+
## QGIS Plugin
|
|
127
|
+
|
|
128
|
+
SOLWEIG is available as a QGIS Processing plugin for interactive spatial analysis:
|
|
129
|
+
|
|
130
|
+
1. Open QGIS → **Plugins** → **Manage and Install Plugins**
|
|
131
|
+
2. Go to **Settings** tab → Check **"Show also experimental plugins"**
|
|
132
|
+
3. Search for **"SOLWEIG"** in the **All** tab
|
|
133
|
+
4. Click **Install Plugin**
|
|
134
|
+
|
|
135
|
+
See [qgis_plugin/](qgis_plugin/) for source code and development details.
|
|
136
|
+
|
|
137
|
+
## Build & Test
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
maturin develop # Build Rust extension
|
|
141
|
+
pytest tests/ # Run all 353 tests
|
|
142
|
+
poe verify_project # Full verification (format, lint, test)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Development
|
|
148
|
+
|
|
149
|
+
### Project Structure
|
|
150
|
+
|
|
151
|
+
```text
|
|
152
|
+
pysrc/solweig/ # Python source (modular architecture)
|
|
153
|
+
api.py # Public API re-exports
|
|
154
|
+
models/ # Dataclass package (~3,080 lines)
|
|
155
|
+
components/ # Modular component functions
|
|
156
|
+
computation.py # Core orchestration logic
|
|
157
|
+
timeseries.py # Batch time series processing
|
|
158
|
+
tiling.py # Large raster tiling support
|
|
159
|
+
rust/ # Rust extensions via maturin
|
|
160
|
+
qgis_plugin/ # QGIS Processing plugin
|
|
161
|
+
tests/ # 353 tests (100% pass rate)
|
|
162
|
+
golden/ # Reference data validation
|
|
163
|
+
spec/ # Physical property tests
|
|
164
|
+
docs/ # MkDocs documentation site
|
|
165
|
+
specs/ # Markdown specifications
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Development Setup
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# Install dependencies
|
|
172
|
+
uv sync
|
|
173
|
+
|
|
174
|
+
# Build Rust extension for development
|
|
175
|
+
maturin develop
|
|
176
|
+
|
|
177
|
+
# Run tests with coverage
|
|
178
|
+
pytest tests/ --cov=pysrc/solweig
|
|
179
|
+
|
|
180
|
+
# Format and lint
|
|
181
|
+
ruff format pysrc/ tests/
|
|
182
|
+
ruff check pysrc/ tests/ --fix
|
|
183
|
+
|
|
184
|
+
# Type checking
|
|
185
|
+
ty pysrc/
|
|
186
|
+
|
|
187
|
+
# Full verification pipeline
|
|
188
|
+
poe verify_project
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Building Documentation
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
# Serve docs locally
|
|
195
|
+
mkdocs serve
|
|
196
|
+
|
|
197
|
+
# Build static site
|
|
198
|
+
mkdocs build
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### QGIS Plugin Bundle Preparation
|
|
202
|
+
|
|
203
|
+
To prepare the QGIS plugin for distribution:
|
|
204
|
+
|
|
205
|
+
#### 1. Update Plugin Metadata
|
|
206
|
+
|
|
207
|
+
Edit `qgis_plugin/metadata.txt`:
|
|
208
|
+
|
|
209
|
+
```ini
|
|
210
|
+
[general]
|
|
211
|
+
name=SOLWEIG
|
|
212
|
+
version=0.1.0 # Increment version
|
|
213
|
+
experimental=True # Set to False when stable
|
|
214
|
+
description=Urban microclimate model for thermal comfort analysis
|
|
215
|
+
qgisMinimumVersion=3.0
|
|
216
|
+
author=Your Name
|
|
217
|
+
email=your.email@example.com
|
|
218
|
+
repository=https://github.com/UMEP-dev/solweig
|
|
219
|
+
tracker=https://github.com/UMEP-dev/solweig/issues
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
#### 2. Create Distribution ZIP
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
# Create a clean build directory
|
|
226
|
+
cd /Users/gareth/dev/umep/solweig
|
|
227
|
+
mkdir -p build/solweig
|
|
228
|
+
|
|
229
|
+
# Copy plugin files (excluding build artifacts)
|
|
230
|
+
cp -r qgis_plugin/* build/solweig/
|
|
231
|
+
|
|
232
|
+
# Create ZIP with correct structure
|
|
233
|
+
cd build
|
|
234
|
+
zip -r solweig.zip solweig/ -x "*.pyc" -x "*__pycache__*" -x "*.DS_Store"
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
#### 3. Test Plugin Locally
|
|
238
|
+
|
|
239
|
+
Before uploading, test the plugin in QGIS:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
# Copy to QGIS plugins directory (macOS)
|
|
243
|
+
cp -r build/solweig ~/Library/Application\ Support/QGIS/QGIS3/profiles/default/python/plugins/
|
|
244
|
+
|
|
245
|
+
# Or use symlink for development
|
|
246
|
+
ln -s /Users/gareth/dev/umep/solweig/qgis_plugin ~/Library/Application\ Support/QGIS/QGIS3/profiles/default/python/plugins/solweig
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Then:
|
|
250
|
+
|
|
251
|
+
1. Open QGIS
|
|
252
|
+
2. **Plugins** → **Manage and Install Plugins** → **Installed**
|
|
253
|
+
3. Enable **SOLWEIG**
|
|
254
|
+
4. Test in **Processing Toolbox** → **SOLWEIG**
|
|
255
|
+
|
|
256
|
+
#### 4. Upload to QGIS Plugin Repository
|
|
257
|
+
|
|
258
|
+
1. Register at <https://plugins.qgis.org/>
|
|
259
|
+
2. Log in → **My Plugins** → **Upload a plugin**
|
|
260
|
+
3. Select `build/solweig.zip`
|
|
261
|
+
4. Check **"Experimental"** for pre-release versions
|
|
262
|
+
5. Add changelog/release notes
|
|
263
|
+
6. Click **Upload**
|
|
264
|
+
|
|
265
|
+
Review typically takes 1-3 days.
|
|
266
|
+
|
|
267
|
+
### Release Checklist
|
|
268
|
+
|
|
269
|
+
- [ ] Version incremented in `qgis_plugin/metadata.txt`
|
|
270
|
+
- [ ] All tests passing (`pytest tests/`)
|
|
271
|
+
- [ ] Documentation updated
|
|
272
|
+
- [ ] CHANGELOG.md updated
|
|
273
|
+
- [ ] Plugin tested in QGIS locally
|
|
274
|
+
- [ ] ZIP bundle created and validated
|
|
275
|
+
- [ ] Uploaded to plugins.qgis.org
|
|
276
|
+
|
|
277
|
+
### Tooling Preferences
|
|
278
|
+
|
|
279
|
+
| Tool | Use For | Instead Of |
|
|
280
|
+
| -------- | ---------------------- | ---------------------------- |
|
|
281
|
+
| **uv** | Package management | pip, poetry, pipenv |
|
|
282
|
+
| **ruff** | Linting and formatting | black, isort, flake8, pylint |
|
|
283
|
+
| **ty** | Type checking | mypy, pyright |
|
|
284
|
+
|
|
285
|
+
### Code Metrics
|
|
286
|
+
|
|
287
|
+
- **api.py**: 403 lines (simplified from 3,976)
|
|
288
|
+
- **models/ package**: ~3,080 lines (6 modules)
|
|
289
|
+
- **Component functions**: All ≤ 455 lines
|
|
290
|
+
- **Test count**: 353 tests (100% pass rate)
|
|
291
|
+
- **Legacy code removed**: 6,100 lines
|