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

ArrayWithMetadata

NumPy array subclass that can hold metadata.

Functions

get_location_from_voxcity(→ Tuple[float, float])

Extract latitude/longitude from VoxCity object or return defaults.

convert_voxel_data_to_arrays(→ Tuple[numpy.ndarray, ...)

Convert VoxCity voxel codes to is_solid and LAD arrays using vectorized operations.

compute_valid_ground_vectorized(→ Tuple[numpy.ndarray, ...)

Compute valid ground mask and ground k-levels using vectorized operations.

compute_sun_direction(→ Tuple[float, float, float, float])

Compute sun direction vector from azimuth and elevation angles.

parse_time_period(→ Tuple[datetime.datetime, ...)

Parse start and end time strings.

filter_df_to_period(df, start_time, end_time, tz[, ...])

Filter weather DataFrame to specified time period and convert to UTC.

load_epw_data(→ Tuple)

Load EPW weather data, optionally downloading the nearest file.

get_solar_positions_astral(times, lon, lat)

Compute solar azimuth and elevation for given times and location using Astral.

extract_terrain_following_slice(→ numpy.ndarray)

Extract a terrain-following 2D slice from a 3D flux field (vectorized).

accumulate_terrain_following_slice(→ None)

Accumulate terrain-following values from a 3D flux field into a 2D map (vectorized, in-place).

compute_boundary_vertical_mask(→ numpy.ndarray)

Compute mask for vertical faces on domain boundary.

apply_computation_mask_to_faces(→ numpy.ndarray)

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