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¶
Container for sky patch discretization data. |
|
Solar data binned into sky patches for cumulative simulation. |
Functions¶
|
Generate the 145 Tregenza sky patch center directions. |
|
Get the Tregenza patch index for a given sun position. |
|
Generate Reinhart sky patches (subdivided Tregenza). |
|
Generate uniform grid sky patches. |
|
Generate quasi-uniform sky patches using Fibonacci spiral. |
|
Generate sky patches using specified discretization method. |
|
Bin hourly sun positions into sky patches and aggregate radiation. |
|
Get information about a sky discretization method. |
Calculate patch weights for cumulative irradiance simulation. |
|
|
Visualize sky patches on a polar plot. |
Numba-accelerated binning of sun positions to Tregenza patches. |
|
|
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