voxcity.simulator_gpu.solar.sky

Sky Discretization Methods for Cumulative Solar Irradiance Calculation.

This module provides various methods for dividing the sky hemisphere into patches to improve efficiency of cumulative solar irradiance calculations. Instead of tracing rays for each hourly sun position, sun positions can be binned into sky patches and rays traced once per patch.

Supported methods: - Tregenza: 145 patches (standard in Radiance, EnergyPlus, DAYSIM) - Reinhart: Tregenza × MF² patches (high-resolution, used in DAYSIM/Honeybee) - Uniform Grid: Regular azimuth × elevation grid - Fibonacci: Quasi-uniform distribution using golden angle spiral

This approach significantly reduces computation time for annual simulations: - 8760 hourly timesteps → ~145-2305 ray traces (30-60× speedup) - Each patch accumulates radiation from multiple sun positions - Patch solid angles weight the contributions correctly

References: - Tregenza, P.R. (1987). “Subdivision of the sky hemisphere for luminance

measurements.” Lighting Research & Technology, 19(1), 13-14.

  • Reinhart, C.F. & Walkenhorst, O. (2001). “Validation of dynamic RADIANCE-based daylight simulations for a test office with external blinds.” Energy and Buildings, 33(7), 683-697.

Attributes

Classes

SkyPatches

Container for sky patch discretization data.

BinnedSolarData

Solar data binned into sky patches for cumulative simulation.

Functions

generate_tregenza_patches(→ SkyPatches)

Generate the 145 Tregenza sky patch center directions.

get_tregenza_patch_index(→ int)

Get the Tregenza patch index for a given sun position.

generate_reinhart_patches(→ SkyPatches)

Generate Reinhart sky patches (subdivided Tregenza).

generate_uniform_grid_patches(→ SkyPatches)

Generate uniform grid sky patches.

generate_fibonacci_patches(→ SkyPatches)

Generate quasi-uniform sky patches using Fibonacci spiral.

generate_sky_patches(→ SkyPatches)

Generate sky patches using specified discretization method.

bin_sun_positions_to_patches(→ BinnedSolarData)

Bin hourly sun positions into sky patches and aggregate radiation.

get_patch_info(→ dict)

Get information about a sky discretization method.

calculate_cumulative_irradiance_weights(...)

Calculate patch weights for cumulative irradiance simulation.

visualize_sky_patches([method, ax, show])

Visualize sky patches on a polar plot.

bin_sun_positions_to_tregenza_fast(...)

Numba-accelerated binning of sun positions to Tregenza patches.

visualize_binned_radiation(binned_data[, show])

Visualize binned solar radiation on a polar plot.

Module Contents

voxcity.simulator_gpu.solar.sky.TREGENZA_BANDS = [(6.0, 30), (18.0, 30), (30.0, 24), (42.0, 24), (54.0, 18), (66.0, 12), (78.0, 6), (90.0, 1)]
voxcity.simulator_gpu.solar.sky.TREGENZA_BAND_BOUNDARIES
voxcity.simulator_gpu.solar.sky.TREGENZA_PATCH_COUNTS
voxcity.simulator_gpu.solar.sky.generate_tregenza_patches() SkyPatches[source]

Generate the 145 Tregenza sky patch center directions.

The Tregenza subdivision divides the sky hemisphere into 145 patches arranged in 8 altitude bands. This is the standard sky discretization used in Radiance (genskyvec), EnergyPlus, DAYSIM, and Ladybug Tools.

Returns:

SkyPatches object with patch data

Example

>>> patches = generate_tregenza_patches()
>>> print(f"Number of patches: {patches.n_patches}")  # 145
>>> print(f"Total solid angle: {patches.solid_angles.sum():.4f}")  # ~2π
voxcity.simulator_gpu.solar.sky.get_tregenza_patch_index(azimuth_deg: float, elevation_deg: float) int[source]

Get the Tregenza patch index for a given sun position.

Numba-accelerated for fast binning of many sun positions.

Parameters:
  • azimuth_deg – Solar azimuth in degrees (0-360, 0=North, clockwise)

  • elevation_deg – Solar elevation in degrees (0-90)

Returns:

Patch index (0-144), or -1 if below horizon

voxcity.simulator_gpu.solar.sky.generate_reinhart_patches(mf: int = 4) SkyPatches[source]

Generate Reinhart sky patches (subdivided Tregenza).

The Reinhart subdivision increases resolution by subdividing each Tregenza band by a multiplication factor (MF). This allows higher accuracy for detailed solar studies.

Parameters:

mf – Multiplication factor. Common values: - MF=1: 145 patches (same as Tregenza) - MF=2: 577 patches - MF=4: 2305 patches (common for annual daylight simulation) - MF=6: 5185 patches

Returns:

SkyPatches object with patch data

Example

>>> patches = generate_reinhart_patches(mf=4)
>>> print(f"Number of patches: {patches.n_patches}")  # ~2305

References

Reinhart, C.F. & Walkenhorst, O. (2001). Energy and Buildings.

voxcity.simulator_gpu.solar.sky.generate_uniform_grid_patches(n_azimuth: int = 36, n_elevation: int = 9) SkyPatches[source]

Generate uniform grid sky patches.

Simple subdivision with equal azimuth and elevation spacing. Note: This creates non-equal solid angle patches (smaller near zenith). Useful when uniform angular sampling is preferred over uniform area.

Parameters:
  • n_azimuth – Number of azimuth divisions (default: 36 = 10° spacing)

  • n_elevation – Number of elevation divisions (default: 9 = 10° spacing)

Returns:

SkyPatches object with patch data

Example

>>> patches = generate_uniform_grid_patches(36, 9)
>>> print(f"Number of patches: {patches.n_patches}")  # 324
voxcity.simulator_gpu.solar.sky.generate_fibonacci_patches(n_patches: int = 145) SkyPatches[source]

Generate quasi-uniform sky patches using Fibonacci spiral.

Uses the golden angle spiral to distribute points nearly uniformly on the hemisphere. This provides more uniform patch areas than regular grids with fewer total patches.

Parameters:

n_patches – Number of patches to generate (default: 145 to match Tregenza)

Returns:

SkyPatches object with patch data

Example

>>> patches = generate_fibonacci_patches(200)
>>> # Check uniformity: solid angles should be equal
>>> print(f"Solid angle std: {patches.solid_angles.std():.6f}")  # ~0
voxcity.simulator_gpu.solar.sky.generate_sky_patches(method: str = 'tregenza', **kwargs) SkyPatches[source]

Generate sky patches using specified discretization method.

This is the main entry point for sky discretization. It dispatches to the appropriate method-specific function.

Parameters:
  • method – Discretization method: - “tregenza”: 145 patches (standard, fast) - “reinhart”: Tregenza × MF² (high-resolution) - “uniform”: Regular grid (simple) - “fibonacci”: Quasi-uniform spiral (balanced)

  • **kwargs – Method-specific parameters: - mf: Multiplication factor for Reinhart (default: 4) - n_azimuth, n_elevation: Grid size for uniform - n_patches: Number of patches for Fibonacci

Returns:

SkyPatches object with patch data

Example

>>> # Standard Tregenza
>>> patches = generate_sky_patches("tregenza")
>>> # High-resolution Reinhart
>>> patches = generate_sky_patches("reinhart", mf=4)
>>> # Custom uniform grid
>>> patches = generate_sky_patches("uniform", n_azimuth=72, n_elevation=18)
voxcity.simulator_gpu.solar.sky.bin_sun_positions_to_patches(azimuth_arr: numpy.ndarray, elevation_arr: numpy.ndarray, dni_arr: numpy.ndarray, dhi_arr: numpy.ndarray | None = None, method: str = 'tregenza', **kwargs) BinnedSolarData[source]

Bin hourly sun positions into sky patches and aggregate radiation.

This is the key optimization for cumulative solar irradiance: instead of tracing rays for every hourly sun position, aggregate radiation values for each sky patch and trace rays once per patch.

The DNI values are summed for each patch where the sun appears. The DHI values are distributed isotropically across all patches.

Parameters:
  • azimuth_arr – Array of solar azimuth values in degrees (0=North)

  • elevation_arr – Array of solar elevation values in degrees

  • dni_arr – Array of Direct Normal Irradiance values (W/m² or Wh/m²)

  • dhi_arr – Array of Diffuse Horizontal Irradiance values (optional)

  • method – Sky discretization method

  • **kwargs – Additional parameters for patch generation

Returns:

BinnedSolarData with accumulated radiation per patch

Example

>>> from palm_solar.epw import prepare_cumulative_simulation_input
>>> az, el, dni, dhi, loc = prepare_cumulative_simulation_input("weather.epw")
>>> binned = bin_sun_positions_to_patches(az, el, dni, dhi)
>>> print(f"Active patches: {(binned.hours_per_patch > 0).sum()}")
voxcity.simulator_gpu.solar.sky.get_patch_info(method: str = 'tregenza', **kwargs) dict[source]

Get information about a sky discretization method.

Parameters:
  • method – Sky discretization method

  • **kwargs – Method-specific parameters

Returns:

Dictionary with method details

Example

>>> info = get_patch_info("reinhart", mf=4)
>>> print(f"{info['method']}: {info['n_patches']} patches")
voxcity.simulator_gpu.solar.sky.calculate_cumulative_irradiance_weights(binned_data: BinnedSolarData, include_diffuse: bool = True) Tuple[numpy.ndarray, numpy.ndarray][source]

Calculate patch weights for cumulative irradiance simulation.

Returns weights that can be used with ray tracing results to compute cumulative irradiance. The direct component uses binned DNI values, and the diffuse component is distributed isotropically.

Parameters:
  • binned_data – BinnedSolarData from bin_sun_positions_to_patches

  • include_diffuse – Whether to include diffuse component

Returns:

  • direct_weights: DNI weight per patch (Wh/m²)

  • diffuse_weights: DHI weight per patch (Wh/m²)

Return type:

Tuple of

Example

>>> binned = bin_sun_positions_to_patches(az, el, dni, dhi)
>>> direct_w, diffuse_w = calculate_cumulative_irradiance_weights(binned)
>>> # Use with ray tracing:
>>> # cumulative_irradiance = sum(visibility * direct_w + svf * diffuse_w)
voxcity.simulator_gpu.solar.sky.visualize_sky_patches(method: str = 'tregenza', ax=None, show: bool = True, **kwargs)[source]

Visualize sky patches on a polar plot.

Parameters:
  • method – Sky discretization method

  • show – Whether to call plt.show()

  • **kwargs – Method-specific parameters

Returns:

matplotlib axis object

voxcity.simulator_gpu.solar.sky.get_tregenza_patch_index_fast
voxcity.simulator_gpu.solar.sky.bin_sun_positions_to_tregenza_fast(azimuth_arr: numpy.ndarray, elevation_arr: numpy.ndarray, dni_arr: numpy.ndarray) Tuple[numpy.ndarray, numpy.ndarray][source]

Numba-accelerated binning of sun positions to Tregenza patches.

This function matches the signature of voxcity.simulator.solar.sky.bin_sun_positions_to_tregenza_fast.

Parameters:
  • azimuth_arr – Array of solar azimuth values in degrees

  • elevation_arr – Array of solar elevation values in degrees

  • dni_arr – Array of Direct Normal Irradiance values (W/m²)

Returns:

  • cumulative_dni: shape (145,) - Cumulative DNI (W·h/m²) for each Tregenza patch

  • hours_count: shape (145,) - Number of hours with sun in each patch

Return type:

Tuple of (cumulative_dni, hours_count) arrays

voxcity.simulator_gpu.solar.sky.visualize_binned_radiation(binned_data: BinnedSolarData, show: bool = True)[source]

Visualize binned solar radiation on a polar plot.

Parameters:
  • binned_data – BinnedSolarData from bin_sun_positions_to_patches

  • show – Whether to call plt.show()

Returns:

matplotlib axis object