Timeseries Calculations¶
For multi-timestep simulations (hours, days, or longer), pass a list of weather objects to calculate(). Thermal state is carried between timesteps, and results are saved to disk as they are computed.
Thermal State Management¶
Ground and wall temperatures depend on accumulated heating from previous hours (thermal inertia). When given multiple weather timesteps, calculate() carries this between timesteps internally (via a ThermalState object you don't need to construct or pass yourself), producing accurate ground-level longwave radiation values.
Basic Timeseries¶
import solweig
# Load surface
surface = solweig.SurfaceData.prepare(
dsm="data/dsm.tif",
working_dir="cache/",
)
# Load weather from EPW file
weather_list = solweig.Weather.from_epw(
"data/weather.epw",
start="2025-07-01",
end="2025-07-03",
)
location = solweig.Location.from_epw("data/weather.epw")
# Calculate all timesteps — results saved to output/
summary = solweig.calculate(
surface=surface,
location=location,
weather=weather_list,
output_dir="output/",
outputs=["tmrt", "shadow"],
)
print(f"Processed {len(summary)} timesteps")
This creates timestamped GeoTIFFs and summary grids:
output/
├── tmrt/
│ ├── tmrt_20250701_0000.tif
│ ├── tmrt_20250701_0100.tif
│ └── ...
├── shadow/
│ ├── shadow_20250701_0000.tif
│ └── ...
├── summary/
│ ├── tmrt_mean.tif
│ ├── tmrt_max.tif
│ ├── utci_mean.tif
│ └── ...
└── run_metadata.json # All parameters for reproducibility
If only summary statistics are required (mean/max/min Tmrt, UTCI, sun hours), omit
outputs — no per-timestep files are written, but the summary grids are still
saved to output/summary/.
summary = solweig.calculate(
surface=surface,
location=location,
weather=weather_list,
output_dir="output/", # Summary grids + metadata saved here
)
Inspecting Results¶
Summary report¶
report() returns a text summary of the run:
summary = solweig.calculate(
surface=surface,
weather=weather_list,
output_dir="output/",
outputs=["tmrt", "shadow"],
)
print(summary.report())
In Jupyter notebooks, placing summary as the last expression in a cell
renders the report via _repr_html_.
Per-timestep timeseries¶
summary.timeseries contains 1-D arrays of spatial means at each timestep,
providing an overview of how conditions evolved over the simulation:
ts = summary.timeseries
print(ts.datetime) # timestamps
print(ts.ta) # air temperature per step
print(ts.tmrt_mean) # spatial mean Tmrt per step
print(ts.utci_mean) # spatial mean UTCI per step
print(ts.sun_fraction) # fraction of sunlit pixels per step
Plotting¶
plot() produces a multi-panel figure showing temperature, radiation,
sun exposure, and meteorological inputs over time:
Requires matplotlib (pip install matplotlib).
Per-Timestep UTCI and PET¶
UTCI and PET summary grids (mean, max, min, day/night averages) are included
in the returned TimeseriesSummary. To save per-timestep UTCI or PET GeoTIFFs,
include them in outputs:
summary = solweig.calculate(
surface=surface,
weather=weather_list,
output_dir="output/",
outputs=["tmrt", "utci"], # per-timestep Tmrt + UTCI saved to disk
)
The indices are computed inline during the main loop (UTCI uses a Rust polynomial implementation; PET uses an iterative solver).
Memory Management for Long Simulations¶
Use a single call for the full period¶
For extended simulations (weeks or months), pass the full weather list to one
calculate() call:
results = solweig.calculate(
surface=surface,
weather=weather_list, # full period
location=location,
output_dir="output/",
)
Thermal state (ground and wall temperature history) carries between timesteps
automatically within a single call. Splitting the period into separate
calculate() calls resets that state at every boundary and produces the
temperature discontinuities described in
Basic Usage.
Memory stays bounded regardless of simulation length: per-timestep grids are
written to output_dir as they are computed, and only the running summary
grids are held in memory. For grids too large to fit in memory, SOLWEIG tiles
the spatial computation internally (see
Working with GeoTIFFs); no chunking of the
weather series is needed.
Surface preparation is memory-bounded as well: above roughly 50 megapixels,
SurfaceData.prepare() processes input layers one at a time through
disk-backed storage instead of holding the whole stack in memory (see
Working with GeoTIFFs).
Performance¶
| Grid size | Surface prep (SVF) | Per timestep | 72 timesteps |
|---|---|---|---|
| 100x100 | ~5 s | ~10 ms | ~1 s |
| 200x200 | ~67 s | ~20 ms | ~2 s |
| 500x500 | ~10 min | ~100 ms | ~8 s |
SVF is computed by SurfaceData.prepare(). For file workflows, a persistent working_dir avoids recomputing SVF on each run.
Run Metadata¶
calculate() saves a run_metadata.json file recording all parameters used. This can be loaded for reproducibility: