voxcity.simulator_gpu.solar.integration.utilsยถ
Common utility functions for VoxCity solar integration module.
This module contains shared helper functions used across ground, building, and volumetric solar irradiance calculations to reduce code duplication.
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 ground surface k-level for each (i,j) cell from voxel data. |
|
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. |
|
Get hour-of-year range from time period strings. |
|
Get UTC timezone offset (in hours) from longitude/latitude using timezonefinder. |
|
Generate a pandas DataFrame with hourly timestamps for a full year. |
|
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). |
|
Add metadata dict to a numpy array as an attribute. |
|
Compute mask for vertical faces on domain boundary. |
|
Apply 2D computation mask to mesh face values. |
Module Contentsยถ
- voxcity.simulator_gpu.solar.integration.utils.VOXCITY_GROUND_CODE = -1ยถ
- voxcity.simulator_gpu.solar.integration.utils.VOXCITY_TREE_CODE = -2ยถ
- voxcity.simulator_gpu.solar.integration.utils.VOXCITY_BUILDING_CODE = -3ยถ
- voxcity.simulator_gpu.solar.integration.utils.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.utils.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.utils.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.utils.compute_ground_k_from_voxels(voxel_data: numpy.ndarray) numpy.ndarray[source]ยถ
Compute ground surface k-level for each (i,j) cell from voxel data.
This finds the terrain top - the highest k where the cell below the first air cell is solid ground (not building). This is used for terrain-following height extraction in volumetric calculations.
- Parameters:
voxel_data โ 3D array of voxel class codes
- Returns:
2D array of ground k-levels (ni, nj). -1 means no valid ground found.
- voxcity.simulator_gpu.solar.integration.utils.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.utils.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.utils.filter_df_to_period(df, start_time: str, end_time: str, tz: float)[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
- 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.utils.get_hour_range_from_period(start_time: str, end_time: str) Tuple[int, int][source]ยถ
Get hour-of-year range from time period 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_hour, end_hour) as hour-of-year values
- voxcity.simulator_gpu.solar.integration.utils.get_timezone_offset_from_location(lon: float, lat: float) float[source]ยถ
Get UTC timezone offset (in hours) from longitude/latitude using timezonefinder.
Falls back to a simple longitude-based estimate if timezonefinder is not available.
- Parameters:
lon โ Longitude in degrees
lat โ Latitude in degrees
- Returns:
Timezone offset in hours (e.g. 9.0 for JST, -5.0 for EST)
- voxcity.simulator_gpu.solar.integration.utils.generate_annual_hourly_dataframe(year: int = 2020)[source]ยถ
Generate a pandas DataFrame with hourly timestamps for a full year.
The DataFrame has a datetime index (timezone-naive) and no weather columns, suitable for DSH (Direct Sun Hours) calculations that only need solar position data and do not require weather/EPW data.
- Parameters:
year โ The year to generate timestamps for (default: 2020, a non-leap year is fine since solar geometry varies negligibly between years)
- Returns:
pandas DataFrame with hourly datetime index spanning the full year
- voxcity.simulator_gpu.solar.integration.utils.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.utils.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.utils.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.utils.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.utils.add_metadata_to_array(arr: numpy.ndarray, metadata: dict) numpy.ndarray[source]ยถ
Add metadata dict to a numpy array as an attribute.
- Parameters:
arr โ Input numpy array
metadata โ Dictionary of metadata to attach
- Returns:
Array with metadata attribute
- voxcity.simulator_gpu.solar.integration.utils.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.utils.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