voxcity.simulator_gpu.solar.integration¶
VoxCity GPU-accelerated Solar Irradiance Integration Package
This package provides GPU-accelerated solar irradiance calculations for VoxCity voxel grids using Taichi. It supports:
Ground-level (horizontal) solar irradiance maps
Building surface irradiance with directional faces
Volumetric 3D radiation fields for thermal comfort analysis
Cumulative time-integrated irradiance and sunlight hours
Sky patch discretization (Tregenza, Reinhart, uniform, Fibonacci)
Surface reflections (optional)
- Modules:
utils: Common helper functions
caching: Cache infrastructure for models and calculators
ground: Ground-level solar irradiance functions
building: Building surface irradiance functions
volumetric: Volumetric 3D radiation field functions
- Public API:
The package re-exports all public functions for backward compatibility. Import directly from this package:
- from voxcity.simulator_gpu.solar.integration import (
get_global_solar_irradiance_map, get_cumulative_global_solar_irradiance, get_sunlight_hours, get_building_solar_irradiance, get_volumetric_solar_irradiance_map, # … etc
)
Submodules¶
Attributes¶
Classes¶
NumPy array subclass that can hold metadata. |
Functions¶
|
Extract latitude/longitude from VoxCity object or return defaults. |
|
Convert VoxCity voxel codes to is_solid and LAD arrays using vectorized operations. |
|
Compute valid ground mask and ground k-levels using vectorized operations. |
|
Compute sun direction vector from azimuth and elevation angles. |
|
Parse start and end time strings. |
|
Filter weather DataFrame to specified time period and convert to UTC. |
|
Load EPW weather data, optionally downloading the nearest file. |
|
Compute solar azimuth and elevation for given times and location using Astral. |
|
Extract a terrain-following 2D slice from a 3D flux field (vectorized). |
Accumulate terrain-following values from a 3D flux field into a 2D map (vectorized, in-place). |
|
|
Compute mask for vertical faces on domain boundary. |
|
Apply 2D computation mask to mesh face values. |
Package Contents¶
- voxcity.simulator_gpu.solar.integration.get_location_from_voxcity(voxcity, default_lat: float = 1.35, default_lon: float = 103.82) Tuple[float, float][source]¶
Extract latitude/longitude from VoxCity object or return defaults.
- Parameters:
voxcity – VoxCity object with extras containing rectangle_vertices
default_lat – Default latitude if not found (Singapore)
default_lon – Default longitude if not found (Singapore)
- Returns:
Tuple of (origin_lat, origin_lon)
- voxcity.simulator_gpu.solar.integration.convert_voxel_data_to_arrays(voxel_data: numpy.ndarray, default_lad: float = 1.0) Tuple[numpy.ndarray, numpy.ndarray][source]¶
Convert VoxCity voxel codes to is_solid and LAD arrays using vectorized operations.
This is 10-100x faster than triple-nested Python loops for large grids.
- Parameters:
voxel_data – 3D array of VoxCity voxel class codes
default_lad – Default Leaf Area Density for tree voxels (m²/m³)
- Returns:
Tuple of (is_solid, lad) numpy arrays with same shape as voxel_data
- voxcity.simulator_gpu.solar.integration.compute_valid_ground_vectorized(voxel_data: numpy.ndarray) Tuple[numpy.ndarray, numpy.ndarray][source]¶
Compute valid ground mask and ground k-levels using vectorized operations.
Valid ground cells are those where: - The transition from solid to air/tree occurs - The solid below is not water (7,8,9) or building/underground (negative codes)
- Parameters:
voxel_data – 3D array of VoxCity voxel class codes (ni, nj, nk)
- Returns:
Tuple of (valid_ground 2D bool array, ground_k 2D int array) ground_k[i,j] = -1 means no valid ground found
- voxcity.simulator_gpu.solar.integration.compute_sun_direction(azimuth_degrees_ori: float, elevation_degrees: float, rotation_angle: float = 0) Tuple[float, float, float, float][source]¶
Compute sun direction vector from azimuth and elevation angles.
- Parameters:
azimuth_degrees_ori – Solar azimuth in VoxCity convention (0=North, clockwise)
elevation_degrees – Solar elevation in degrees above horizon
rotation_angle – Grid rotation angle in degrees (clockwise, from voxcity.extras)
- Returns:
Tuple of (sun_dir_x, sun_dir_y, sun_dir_z, cos_zenith)
- voxcity.simulator_gpu.solar.integration.parse_time_period(start_time: str, end_time: str) Tuple[datetime.datetime, datetime.datetime][source]¶
Parse start and end time strings.
- Parameters:
start_time – Start time in format ‘MM-DD HH:MM:SS’
end_time – End time in format ‘MM-DD HH:MM:SS’
- Returns:
Tuple of (start_dt, end_dt) datetime objects
- Raises:
ValueError – If time format is invalid
- voxcity.simulator_gpu.solar.integration.filter_df_to_period(df, start_time: str, end_time: str, tz: float, daily_start_hour: int | None = None, daily_end_hour: int | None = None)[source]¶
Filter weather DataFrame to specified time period and convert to UTC.
- Parameters:
df – pandas DataFrame with datetime index
start_time – Start time in format ‘MM-DD HH:MM:SS’
end_time – End time in format ‘MM-DD HH:MM:SS’
tz – Timezone offset in hours
daily_start_hour – Optional inclusive hour-of-day lower bound (0-23) for a daily window crossed with the date range. None disables the daily filter.
daily_end_hour – Optional inclusive hour-of-day upper bound (0-23). None disables the daily filter. Supports wraparound when start > end (e.g. 22-3 spans overnight).
- Returns:
Tuple of (df_period_utc, df with hour_of_year column)
- Raises:
ValueError – If time format is invalid or no data in period
- voxcity.simulator_gpu.solar.integration.load_epw_data(epw_file_path: str | None = None, download_nearest_epw: bool = False, voxcity=None, **kwargs) Tuple[source]¶
Load EPW weather data, optionally downloading the nearest file.
- Parameters:
epw_file_path – Path to EPW file (required if download_nearest_epw=False)
download_nearest_epw – If True, download nearest EPW based on location
voxcity – VoxCity object (needed for location when downloading)
**kwargs – Additional parameters (output_dir, max_distance, rectangle_vertices)
- Returns:
Tuple of (df, lon, lat, tz) where df is the weather DataFrame
- Raises:
ValueError – If EPW file not provided and download_nearest_epw=False
ImportError – If required modules not available
- voxcity.simulator_gpu.solar.integration.get_solar_positions_astral(times, lon: float, lat: float)[source]¶
Compute solar azimuth and elevation for given times and location using Astral.
- Parameters:
times – Pandas DatetimeIndex of times (should be timezone-aware, preferably UTC)
lon – Longitude in degrees
lat – Latitude in degrees
- Returns:
DataFrame indexed by times with columns [‘azimuth’, ‘elevation’] in degrees
- voxcity.simulator_gpu.solar.integration.extract_terrain_following_slice(flux_3d: numpy.ndarray, ground_k: numpy.ndarray, height_offset_k: int, is_solid: numpy.ndarray) numpy.ndarray[source]¶
Extract a terrain-following 2D slice from a 3D flux field (vectorized).
For each (i,j), extracts the value at ground_k[i,j] + height_offset_k. Cells that are solid at the extraction point, have no valid ground, or are above the domain are marked as NaN.
- Parameters:
flux_3d – 3D array of flux values (ni, nj, nk)
ground_k – 2D array of ground k-levels (ni, nj), -1 means no valid ground
height_offset_k – Number of cells above ground to extract
is_solid – 3D array marking solid cells (ni, nj, nk)
- Returns:
2D array of extracted values (ni, nj) with NaN for invalid cells
- voxcity.simulator_gpu.solar.integration.accumulate_terrain_following_slice(cumulative_map: numpy.ndarray, flux_3d: numpy.ndarray, ground_k: numpy.ndarray, height_offset_k: int, is_solid: numpy.ndarray, weight: float = 1.0) None[source]¶
Accumulate terrain-following values from a 3D flux field into a 2D map (vectorized, in-place).
For each (i,j), adds flux_3d[i,j,k_extract] * weight to cumulative_map[i,j] where k_extract = ground_k[i,j] + height_offset_k.
- Parameters:
cumulative_map – 2D array to accumulate into (ni, nj), modified in-place
flux_3d – 3D array of flux values (ni, nj, nk)
ground_k – 2D array of ground k-levels (ni, nj), -1 means no valid ground
height_offset_k – Number of cells above ground to extract
is_solid – 3D array marking solid cells (ni, nj, nk)
weight – Multiplier for values before accumulating (e.g., time_step_hours)
- voxcity.simulator_gpu.solar.integration.compute_boundary_vertical_mask(mesh_face_centers: numpy.ndarray, mesh_face_normals: numpy.ndarray, grid_bounds: numpy.ndarray, boundary_epsilon: float) numpy.ndarray[source]¶
Compute mask for vertical faces on domain boundary.
- Parameters:
mesh_face_centers – (N, 3) array of face center coordinates
mesh_face_normals – (N, 3) array of face normal vectors
grid_bounds – (2, 3) array of [[min_x, min_y, min_z], [max_x, max_y, max_z]]
boundary_epsilon – Tolerance for boundary detection
- Returns:
Boolean mask (N,) - True for vertical boundary faces
- voxcity.simulator_gpu.solar.integration.apply_computation_mask_to_faces(values: numpy.ndarray, mesh_face_centers: numpy.ndarray, computation_mask: numpy.ndarray, meshsize: float, grid_shape: Tuple[int, int]) numpy.ndarray[source]¶
Apply 2D computation mask to mesh face values.
- Parameters:
values – (N,) array of face values
mesh_face_centers – (N, 3) array of face center coordinates
computation_mask – 2D boolean mask matching grid_shape
meshsize – Grid cell size
grid_shape – (ny_vc, nx_vc) grid dimensions
- Returns:
Modified values array with NaN for masked-out faces
- voxcity.simulator_gpu.solar.integration.VOXCITY_GROUND_CODE = -1¶
- voxcity.simulator_gpu.solar.integration.VOXCITY_TREE_CODE = -2¶
- voxcity.simulator_gpu.solar.integration.VOXCITY_BUILDING_CODE = -3¶