Core Functions¶
calculate¶
solweig.calculate(surface, weather, location=None, *, output_dir, config=None, human=None, precomputed=None, use_anisotropic_sky=None, conifer=False, physics=None, materials=None, wall_material=None, max_shadow_distance_m=None, tile_size=None, outputs=None, heat_thresholds_day=None, heat_thresholds_night=None, progress_callback=None)
¶
Calculate mean radiant temperature (Tmrt).
Single entry point for all SOLWEIG calculations. SVF and shadow matrices
must already be on surface (via :meth:SurfaceData.prepare) or in
precomputed. The anisotropic sky model is on by default.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
surface
|
SurfaceData
|
Prepared surface data from :meth: |
required |
weather
|
Weather | list[Weather]
|
One or more Weather objects. A single Weather is auto-wrapped. |
required |
location
|
Location | None
|
Geographic location. If None, extracted from surface CRS. |
None
|
config
|
ModelConfig | None
|
Model settings. Explicit keyword args override config values. |
None
|
human
|
HumanParams | None
|
Human body parameters (posture, absorption, etc.). |
None
|
precomputed
|
PrecomputedData | None
|
Alternative source for SVF/shadow matrices (advanced). |
None
|
use_anisotropic_sky
|
bool | None
|
Anisotropic (True) or uniform (False) sky diffuse radiation. Default True. |
None
|
conifer
|
bool
|
Treat vegetation as evergreen (always leaf-on). |
False
|
physics
|
SimpleNamespace | None
|
Physics parameters from load_physics(). |
None
|
materials
|
SimpleNamespace | None
|
Material properties from load_materials(). |
None
|
wall_material
|
str | None
|
Wall material type ("brick", "concrete", "wood", "cobblestone"). |
None
|
max_shadow_distance_m
|
float | None
|
Maximum shadow reach in metres (default 1000.0). |
None
|
tile_size
|
int | None
|
Core tile side in pixels for tiled processing. If None (default), auto-calculated from available resources. Minimum 256. |
None
|
output_dir
|
str | Path
|
Working directory for all output. Summary grids are always
saved to |
required |
outputs
|
list[str] | None
|
Which per-timestep outputs to save as GeoTIFFs
(e.g., |
None
|
heat_thresholds_day
|
list[float] | None
|
Daytime UTCI thresholds for exceedance grids. |
None
|
heat_thresholds_night
|
list[float] | None
|
Nighttime UTCI thresholds for exceedance grids. |
None
|
progress_callback
|
Callable[[int, int], None] | None
|
Called as progress_callback(current, total) per tile-timestep. |
None
|
Returns:
| Type | Description |
|---|---|
TimeseriesSummary
|
TimeseriesSummary with per-pixel grids (mean/max/min Tmrt and UTCI, |
TimeseriesSummary
|
sun/shade hours, heat-stress exceedance). |
Notes
Modelled downwelling longwave (L↓) carries a known +18 to +55 W/m²
positive bias inherited from the UMEP Jonsson et al. (2006) formulation.
The bias is steady across hours and grows with reduced sky-view; see
VALIDATION.md § Ldown overestimation. K↓ at any single pixel is
shadow-edge-sensitive and may spike on a single mis-aligned hour;
spatially-averaged K↓ has much lower error.
Example::
surface = solweig.SurfaceData.prepare(dsm="dsm.tif", working_dir="cache/")
weather = solweig.Weather.from_epw("weather.epw")
summary = solweig.calculate(
surface=surface,
weather=weather,
output_dir="output/",
)
validate_inputs¶
solweig.api.validate_inputs(surface, location=None, weather=None, use_anisotropic_sky=False, precomputed=None)
¶
Validate inputs before calculation (preflight check).
Call this before expensive operations to catch errors early. Raises exceptions for fatal errors, returns warnings for potential issues.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
surface
|
SurfaceData
|
Surface data to validate. |
required |
location
|
Location | None
|
Location to validate (optional). |
None
|
weather
|
Weather | list[Weather] | None
|
Weather data to validate (optional, can be single or list). |
None
|
use_anisotropic_sky
|
bool
|
Whether anisotropic sky will be used. |
False
|
precomputed
|
PrecomputedData | None
|
Precomputed data to validate. |
None
|
Returns:
| Type | Description |
|---|---|
list[str]
|
List of warning messages (empty if all valid). |
Raises:
| Type | Description |
|---|---|
GridShapeMismatch
|
If surface grid shapes don't match DSM. |
MissingPrecomputedData
|
If required precomputed data is missing. |
WeatherDataError
|
If weather data is invalid. |
Example
try: warnings = solweig.validate_inputs(surface, location, weather) for w in warnings: print(f"Warning: {w}") summary = solweig.calculate(surface, weather, location, output_dir="out/") except solweig.GridShapeMismatch as e: print(f"Grid mismatch: {e.field} expected {e.expected}, got {e.got}") except solweig.MissingPrecomputedData as e: print(f"Missing data: {e}")
SurfaceData.prepare¶
The most common entry point for building a SurfaceData
from rasters or in-memory arrays — see the class page for the full method
list. Documented here because every quick-start uses it before calculate().
solweig.SurfaceData.prepare(dsm, working_dir=None, cdsm=None, dem=None, tdsm=None, land_cover=None, wall_height=None, wall_aspect=None, svf_dir=None, bbox=None, pixel_size=None, trunk_ratio=0.25, dsm_relative=False, cdsm_relative=True, tdsm_relative=True, min_object_height=1.0, smooth_quantized_dem=True, dem_smooth_sigma=3.0, force_recompute=False, tile_size=None, feedback=None)
classmethod
¶
Prepare surface data for SOLWEIG calculations.
Loads inputs, computes walls, SVF, and shadow matrices, and returns
a ready-to-use :class:SurfaceData. This is the only setup step
needed before calling :func:calculate.
Accepts either file paths (GeoTIFF) or numpy arrays:
- File mode (dsm is a path): loads and aligns rasters, caches
results in
working_dirfor fast reuse. - Array mode (dsm is an ndarray): works in memory.
pixel_sizeis required;working_diris not needed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dsm
|
str | Path | NDArray[floating]
|
DSM as a GeoTIFF path or numpy array (required). |
required |
working_dir
|
str | Path | None
|
Cache directory (required for file mode). |
None
|
cdsm
|
str | Path | NDArray[floating] | None
|
Canopy height model (tree tops). Optional. |
None
|
dem
|
str | Path | NDArray[floating] | None
|
Ground elevation model. Optional. |
None
|
tdsm
|
str | Path | NDArray[floating] | None
|
Trunk height model. Optional; auto-generated from CDSM
if not provided (using |
None
|
land_cover
|
str | Path | NDArray[integer] | None
|
Land cover classification grid. Optional. |
None
|
wall_height
|
str | Path | NDArray[floating] | None
|
Pre-computed wall heights. Optional; computed from DSM if not provided. |
None
|
wall_aspect
|
str | Path | NDArray[floating] | None
|
Pre-computed wall aspects. Optional; computed from DSM if not provided. |
None
|
svf_dir
|
str | Path | None
|
Directory with existing SVF files (file mode only). |
None
|
bbox
|
list[float] | None
|
Bounding box [minx, miny, maxx, maxy] (file mode only). |
None
|
pixel_size
|
float | None
|
Pixel size in meters. Required for array mode; extracted from GeoTIFF in file mode. |
None
|
trunk_ratio
|
float
|
Trunk-to-canopy height ratio for auto TDSM. Default 0.25. |
0.25
|
dsm_relative
|
bool
|
DSM values are height above ground (not elevation). Default False. |
False
|
cdsm_relative
|
bool
|
CDSM values are height above ground. Default True. |
True
|
tdsm_relative
|
bool
|
TDSM values are height above ground. Default True. |
True
|
min_object_height
|
float
|
Minimum nDSM height (m) for shadow casting. DSM pixels below this height above DEM are flattened to remove kerbs, street furniture, and LiDAR noise. Default 1.0. Set to 0 to disable. Requires DEM. |
1.0
|
smooth_quantized_dem
|
bool
|
Apply Gaussian smoothing to the DEM when it is detected to be integer-quantized (e.g. int16 with 1 m precision). Default True. Integer-stored DEMs produce visible stair-step contour artifacts in SVF over gently sloped open terrain because each 1 m terrain step casts a discrete shadow at low-altitude sky patches; smoothing recovers the sub-metre variation that was lost at storage time. Disable to preserve bit-exact legacy behaviour or when your terrain has genuine 1 m steps (e.g. agricultural terraces). |
True
|
dem_smooth_sigma
|
float
|
Gaussian standard deviation in pixel units at
target resolution. Default 3.0 — FWHM ≈ 7 px gives bulletproof
elimination of the stair-step artifact across all sky patches
including the lowest (3°). Softens real terrain features
smaller than ~15 m horizontal scale; below that scale, a
1 m-quantized DEM has no physically meaningful information
anyway (the sharp transitions are storage truncation, not
real features). Override to 1.5–2.0 for high-resolution
non-quantized DEMs or when 10 m-scale terrain features must
be preserved. Only used when |
3.0
|
force_recompute
|
bool
|
Recompute walls/SVF even if cached (file mode only). |
False
|
tile_size
|
int | None
|
Core tile side length in pixels for SVF tiling. If None (default), auto-calculated from available resources. Minimum 256. |
None
|
feedback
|
Any
|
QGIS QgsProcessingFeedback for progress/cancellation. |
None
|
Returns:
| Type | Description |
|---|---|
SurfaceData
|
SurfaceData ready for :func: |
Example::
# From GeoTIFF files
surface = SurfaceData.prepare(dsm="dsm.tif", working_dir="cache/")
# From numpy arrays
surface = SurfaceData.prepare(dsm=dsm_array, pixel_size=1.0)
GPU helpers¶
Runtime toggles and observability for the wgpu compute path. The GPU is
enabled by default when available; these helpers let scripts inspect,
override, or measure GPU usage. From b87 onwards, enable_gpu /
disable_gpu toggle all three Rust GPU paths (shadows, anisotropic
sky, GVF) in a single call.
is_gpu_available¶
solweig.is_gpu_available()
¶
Check if GPU acceleration is available at runtime.
Returns True if: - GPU support was compiled into the Rust extension - A GPU device was successfully detected and initialized
Use this to check GPU status before running compute-intensive operations.
Returns:
| Type | Description |
|---|---|
bool
|
True if GPU acceleration is available, False otherwise. |
get_compute_backend¶
solweig.get_compute_backend()
¶
Get the current compute backend.
Returns:
| Type | Description |
|---|---|
str
|
"gpu" if GPU acceleration is available and enabled, "cpu" otherwise. |
enable_gpu¶
solweig.enable_gpu()
¶
Enable GPU acceleration on every Rust path (shadows, anisotropic sky, GVF).
The counterpart to :func:disable_gpu. Each Rust pipeline starts
enabled by default at import time, so the common use of this function
is re-enabling after an explicit :func:disable_gpu call (for
instance, between benchmark scenarios).
Has no effect if GPU support wasn't compiled in or no GPU device is
available — both :func:is_gpu_available and the per-path fallbacks
continue to govern actual execution.
disable_gpu¶
solweig.disable_gpu()
¶
Disable GPU acceleration on every Rust path (shadows, anisotropic sky, GVF), falling back to CPU.
Useful for debugging, CPU-only benchmarks, or when GPU results need to be compared against the CPU reference. The change takes effect immediately for subsequent calculations.
Note: Prior to b87 this function only flipped the shadow path; the anisotropic sky and GVF paths kept running on GPU. It now toggles all three so a single call genuinely produces a CPU-only run.
get_gpu_limits¶
solweig.get_gpu_limits()
¶
Query GPU limits from the wgpu adapter.
Returns a dict with keys
max_buffer_size: int — raw adapter-reported maximum buffer size in bytesbackend: str — GPU backend name ("Metal","Vulkan","Dx12","Gl", etc.)gpu_memory_budget: int — resolved GPU memory budget in bytes (only present when real VRAM is detectable via DXGI/sysfs/Metal)
Returns None if GPU is not available or not compiled in.
Lazily initialises the GPU context on first call.
gpu_dispatch_count¶
solweig.gpu_dispatch_count()
¶
Cumulative count of successful GPU dispatches since process start (or
since the last :func:reset_gpu_metrics call).
Reads a thread-safe atomic counter incremented on the success branch
of every GPU kernel call across the three GPU paths (shadows, SVF,
anisotropic sky, GVF). Pair with :func:gpu_fallback_count to
distinguish "GPU is disabled" (both zero after a run) from "GPU tried
and fell back" (dispatch=0, fallback>0).
Use in tests to assert "the GPU path actually ran":
import solweig solweig.reset_gpu_metrics()
... run a calculation ...¶
assert solweig.gpu_dispatch_count() > 0, "GPU path never executed"
gpu_fallback_count¶
solweig.gpu_fallback_count()
¶
Cumulative count of GPU→CPU fall-backs since process start (or since
the last :func:reset_gpu_metrics call).
A non-zero value during a "should be GPU" run indicates either a GPU device problem (driver crash, OOM, unsupported shape) or a per-dispatch failure mode worth investigating. Zero after a CPU-only run just means no fall-back happened because the GPU branch was never entered.
See also: :func:gpu_dispatch_count, :func:reset_gpu_metrics.