Table of contents

UrbIrrad

UrbIrrad is an open-source Python tool for calculating solar irradiance on a sensor mesh. It prepares the scene, calls Radiance through PyRadiance, and packages the results in HDF5. It supports building and urban studies indoors, outdoors and in semi-open spaces.

UrbIrrad logo

The aim is to make solar calculations with Radiance more accessible, without having to assemble its command pipeline yourself. Provide geometry and weather data, define materials, sensors and dates in YAML, then run the calculation from your terminal. Install the library with python -m pip install urbirrad.

The simplest calculation gives direct sunlight received on a plane, accounting for shadows and transmission through glazing. You can then add sky-diffuse irradiance and diffuse reflections of direct sunlight, or calculate exposure in six directions. A separate geometric mode also provides potential sunshine hours.

Results are stored in HDF5, with an XDMF companion for exploration in ParaView. The tool handles shortwave solar radiation only: six-direction outputs can inform comfort studies, but UrbIrrad calculates neither longwave radiation nor complete mean radiant temperature. The full documentation describes settings and limitations for each option.

Required inputs

A case combines an EPW weather file, scene surfaces and a sensor mesh. A YAML file defines solar properties: reflectance for opaque surfaces, transmittance for glazing, receiving-plane orientation, dates and calculation components.

STL, VTP, VTK, OBJ and PLY are supported. Meshes must already be triangulated: there is no automatic repair or CAD import. Coordinates use X East, Y North, Z Up, in metres. Optical properties come from YAML, not file colours or textures.

Each sensor-mesh triangle provides a calculation point at its centre, with a configurable offset to avoid placing it exactly on a surface. In plane mode, a common normal defines all receiving-plane orientations; it is not inferred from triangle normals.

Three distinct components

ComponentMeaningParaView field
DirectSunlight received on the plane, with shadows and glazing transmission, without surface reflectionssolar_direct
DiffuseSky contribution, with obstruction, transmission and permitted diffuse reflectionssolar_diffuse
Reflected directSunlight contributions involving at least one diffuse surface reflectionsolar_direct_reflected

Results are incident irradiances in W/m², not simply the weather file’s DNI or DHI. Grazing radiation contributes less than perpendicular radiation, and radiation arriving from behind the receiving plane does not contribute.

Direct solar irradiance on the sensor plane

Direct: sunlight is evaluated at its hourly positions, including shadows and transmission through glazing.

Sky-diffuse irradiance on the sensor plane

Diffuse: the sky is an extended source. Access depends on obstructions, openings and permitted reflection paths.

Irradiance from diffuse reflections of direct sunlight

Reflected direct: an additional contribution driven by sunlight and scene surfaces. These figures use independent colour scales; compare the legends in W/m², not colours alone.

The diffuse component does not contain sun-driven reflections. These are calculated separately. Reflected direct is a sky-patch-based approximation; it excludes purely specular paths, such as sunlight reflected only by glass or a mirror.

Why use matrices

Radiance follows radiation paths from receivers towards sources. Integrating diffuse irradiance on a plane requires sampling a hemisphere and secondary paths: it is not just a shadow test.

For fixed geometry and materials, the scene’s response to different sky regions can be calculated once. UrbIrrad separates that geometric response from sky intensity, which changes with the weather:

$$ \mathbf{E} = \mathbf{C}\,\mathbf{S} $$

Matrix C connects receiving planes to sky and ground patches; matrix S contains their intensities at each weather interval. Their product provides irradiances for every interval. This is a schematic expression: Radiance matrices carry three channels, subsequently reduced to scalar irradiance.

The main Radiance programs have distinct roles:

  • oconv compiles an octree to accelerate ray/surface intersections.
  • gendaymtx creates weather-dependent skies and solar sources from the EPW.
  • rfluxmtx calculates transfer matrices through the scene.
  • rcontrib separates source contributions, particularly for the direct calculation.
  • dctimestep applies sky matrices to coefficients without retracing geometry.

This avoids launching a complete scene calculation for every diffuse-weather interval. Loops, ray sampling, matrix multiplication and output writing still require work.

Direct uses a different approach: sources at the intervals’ solar positions are processed in a batch. It uses neither the sky-patch approximation nor dctimestep. For reflected direct, two traces use identical hemisphere rays with and without diffuse bounces; subtracting them isolates the reflected contribution and avoids counting direct sunlight twice.

Accuracy and runtime

Our trials show the following pattern:

CalculationObserved first-run cost
DirectVery fast
Sky diffuseQuite reasonable for the scenes tested
Reflected directSubstantially longer; sampling reflected paths often dominates total runtime

This is not a universal benchmark. Sensor count, six orientations instead of one, geometry, ray count, reflection depth and hardware all affect cost. --nproc parallelizes ray tracing, but doubling workers does not guarantee halving runtime. The terminal reports progress and stage timings.

Diffuse and reflected-direct coefficients are cached. Another period or weather file can reuse them when geometry, materials, sensors and numerical settings remain compatible. The cache does not remove direct computation, sky generation, matrix multiplication or output writing.

MF=1 represents the sky with 145 patches plus ground; MF=2 uses 577 sky patches plus ground. Finer resolution improves angular discretization at additional cost; it does not change the direct calculation’s solar positions.

The initial diffuse setting is ambient_bounces: 3. Receiving-plane integration consumes one Radiance ambient level, leaving up to two physical diffuse surface reflections. Reflected direct has separate settings. Example values do not replace scene-specific convergence checks.

Installation and execution

In a Python 3.12 or newer environment:

python -m pip install urbirrad

PyRadiance supplies the required Radiance executables on Windows. Example data are not included in the package; obtain them from the repository:

git clone https://gitlab.com/arep-dev/urbirrad.git
cd urbirrad
python -m urbirrad.cli check examples/template_case/case.yaml
python -m urbirrad.cli run examples/template_case/case.yaml --nproc 4

The default example calculates direct irradiance only. Separate YAML files progressively add diffuse sky, six directions and reflected direct. In a copied and adapted case, this configuration excerpt selects July and all three components:

simulation:
  components:
    direct: true
    diffuse: true
    reflected_direct: true
  period:
    start: "07-01"
    end: "07-31"

output:
  directory: ./results
  format: hdf5
  save_vtk_snapshots: false

Dates are inclusive and data paths are relative to the YAML file. This excerpt supplements an existing case; it does not replace weather, geometry and material definitions.

Six directions and sunshine hours

six_directions mode calculates six hemispherical irradiances oriented East, West, North, South, Up and Down. It is intended for comfort studies and directional approaches to radiation received by a person. These are not six individual rays or a mean radiant temperature.

potential_sunshine mode counts potential sunshine hours on sensor planes. Opaque obstacles remain, glazing is removed, and clouds and weather irradiance are ignored. Sampling is hourly or half-hourly. The result is a static sunshine_hours field without timesteps; the same information can also accompany a direct-irradiance calculation. Radiance is slightly overkill for this task alone, but the geometry is already there!

Glazing and outputs

A separate command helps estimate normal-incidence solar transmittance when manufacturer data provide only glazing U-value Ug and solar factor g:

python -m urbirrad.glazing --ug 1.1 --g 0.71 --tl 0.83

The estimate here is approximately 0.643. It uses the correlation from the EnergyPlus simple glazing model , not an exact standards-based conversion. Visible transmittance TL is recorded but does not enter the solar estimate. Solar factor g also includes secondary thermal gains: it should not be used directly as solar transmittance. Appropriate manufacturer transmittance takes priority; for glazing with film, inputs must describe the complete assembly. See the assumptions and limitations .

Irradiances are stored in HDF5 with separate components, geometry and time information. An XDMF companion enables ParaView visualization. For these files in ParaView 6.1, choose XDMF Reader, not Xdmf3 Reader or Xdmf3 Reader T, then select the field to colour by.

Scope and resources

UrbIrrad is under active development and distributed under the MIT licence. It handles shortwave solar radiation only. It calculates neither longwave thermal radiation nor complete MRT, and is not a standalone thermal-comfort model.