voxcity.simulator ================= .. py:module:: voxcity.simulator Submodules ---------- .. toctree:: :maxdepth: 1 /autoapi/voxcity/simulator/common/index /autoapi/voxcity/simulator/solar/index /autoapi/voxcity/simulator/utils/index /autoapi/voxcity/simulator/view/index /autoapi/voxcity/simulator/visibility/index Attributes ---------- .. autoapisummary:: voxcity.simulator.TREGENZA_BANDS voxcity.simulator.TREGENZA_BAND_BOUNDARIES Functions --------- .. autoapisummary:: voxcity.simulator.get_view_index voxcity.simulator.get_sky_view_factor_map voxcity.simulator.get_surface_view_factor voxcity.simulator.mark_building_by_id voxcity.simulator.compute_landmark_visibility voxcity.simulator.get_landmark_visibility_map voxcity.simulator.get_surface_landmark_visibility voxcity.simulator.rotate_vector_axis_angle voxcity.simulator.compute_direct_solar_irradiance_map_binary voxcity.simulator.get_solar_positions_astral voxcity.simulator.generate_tregenza_patches voxcity.simulator.get_tregenza_patch_index voxcity.simulator.get_tregenza_patch_index_fast voxcity.simulator.generate_reinhart_patches voxcity.simulator.generate_uniform_grid_patches voxcity.simulator.generate_fibonacci_patches voxcity.simulator.bin_sun_positions_to_patches voxcity.simulator.bin_sun_positions_to_tregenza_fast voxcity.simulator.get_patch_info voxcity.simulator.visualize_sky_patches voxcity.simulator.get_direct_solar_irradiance_map voxcity.simulator.get_diffuse_solar_irradiance_map voxcity.simulator.get_global_solar_irradiance_map voxcity.simulator.compute_solar_irradiance_for_all_faces voxcity.simulator.get_building_solar_irradiance voxcity.simulator.get_cumulative_global_solar_irradiance voxcity.simulator.get_cumulative_building_solar_irradiance voxcity.simulator.get_global_solar_irradiance_using_epw voxcity.simulator.get_building_global_solar_irradiance_using_epw voxcity.simulator.save_irradiance_mesh voxcity.simulator.load_irradiance_mesh Package Contents ---------------- .. py:function:: get_view_index(voxcity, mode=None, hit_values=None, inclusion_mode=True, fast_path=True, **kwargs) .. py:function:: get_sky_view_factor_map(voxcity, show_plot=False, **kwargs) .. py:function:: get_surface_view_factor(voxcity, **kwargs) .. py:function:: mark_building_by_id(voxcity_grid_ori, building_id_grid_ori, ids, mark) .. py:function:: compute_landmark_visibility(voxel_data, target_value=-30, view_height_voxel=0, colormap='viridis') .. py:function:: get_landmark_visibility_map(voxcity, building_gdf=None, **kwargs) .. py:function:: get_surface_landmark_visibility(voxcity, building_gdf=None, **kwargs) .. py:function:: rotate_vector_axis_angle(vec, axis, angle) .. py:function:: compute_direct_solar_irradiance_map_binary(voxel_data, sun_direction, view_point_height, hit_values, meshsize, tree_k, tree_lad, inclusion_mode) Return 2D transmittance map (0..1, NaN invalid) for direct beam along sun_direction. .. py:function:: get_solar_positions_astral(times, lon, lat) Compute solar azimuth and elevation for given times and location using Astral. Returns a DataFrame indexed by times with columns ['azimuth', 'elevation'] (degrees). .. py:function:: generate_tregenza_patches() 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: * **patches** (*np.ndarray, shape (145, 2)*) -- Array of (azimuth_degrees, elevation_degrees) for each patch center. * **directions** (*np.ndarray, shape (145, 3)*) -- Unit direction vectors (dx, dy, dz) pointing to each patch center. * **solid_angles** (*np.ndarray, shape (145,)*) -- Solid angle (steradians) of each patch. .. rubric:: References Tregenza, P.R. (1987). "Subdivision of the sky hemisphere for luminance measurements." Lighting Research & Technology, 19(1), 13-14. .. py:function:: get_tregenza_patch_index(azimuth_deg, elevation_deg) Get the Tregenza patch index for a given sun position. :param azimuth_deg: Solar azimuth in degrees (0-360, measured clockwise from north). :type azimuth_deg: float :param elevation_deg: Solar elevation in degrees (0-90). :type elevation_deg: float :returns: Patch index (0-144), or -1 if below horizon. :rtype: int .. py:function:: get_tregenza_patch_index_fast(azimuth_deg, elevation_deg) Numba-accelerated version of get_tregenza_patch_index. :param azimuth_deg: Solar azimuth in degrees (0-360). :type azimuth_deg: float :param elevation_deg: Solar elevation in degrees (0-90). :type elevation_deg: float :returns: Patch index (0-144), or -1 if below horizon. :rtype: int .. py:data:: TREGENZA_BANDS :value: [(6.0, 30), (18.0, 30), (30.0, 24), (42.0, 24), (54.0, 18), (66.0, 12), (78.0, 6), (90.0, 1)] .. py:data:: TREGENZA_BAND_BOUNDARIES :value: [0.0, 12.0, 24.0, 36.0, 48.0, 60.0, 72.0, 84.0, 90.0] .. py:function:: generate_reinhart_patches(mf=4) Generate Reinhart sky patches (subdivided Tregenza). The Reinhart subdivision increases resolution by subdividing each Tregenza patch by a multiplication factor (MF). With MF=4, this yields 2305 patches. :param 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 :type mf: int :returns: * **patches** (*np.ndarray, shape (N, 2)*) -- Array of (azimuth_degrees, elevation_degrees) for each patch center. * **directions** (*np.ndarray, shape (N, 3)*) -- Unit direction vectors (dx, dy, dz) for each patch center. * **solid_angles** (*np.ndarray, shape (N,)*) -- Solid angle (steradians) of each patch. .. rubric:: References 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. .. py:function:: generate_uniform_grid_patches(n_azimuth=36, n_elevation=9) Generate uniform grid sky patches. Simple subdivision with equal azimuth and elevation spacing. Note: This creates non-equal solid angle patches (smaller near zenith). :param n_azimuth: Number of azimuth divisions (default: 36 = 10° spacing). :type n_azimuth: int :param n_elevation: Number of elevation divisions (default: 9 = 10° spacing). :type n_elevation: int :returns: * **patches** (*np.ndarray, shape (N, 2)*) -- Array of (azimuth_degrees, elevation_degrees) for each patch center. * **directions** (*np.ndarray, shape (N, 3)*) -- Unit direction vectors for each patch center. * **solid_angles** (*np.ndarray, shape (N,)*) -- Solid angle (steradians) of each patch. .. py:function:: generate_fibonacci_patches(n_patches=145) 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. :param n_patches: Number of patches to generate (default: 145 to match Tregenza). :type n_patches: int :returns: * **patches** (*np.ndarray, shape (N, 2)*) -- Array of (azimuth_degrees, elevation_degrees) for each patch center. * **directions** (*np.ndarray, shape (N, 3)*) -- Unit direction vectors for each patch center. * **solid_angles** (*np.ndarray, shape (N,)*) -- Approximate solid angle per patch (uniform for Fibonacci). .. py:function:: bin_sun_positions_to_patches(azimuth_arr, elevation_arr, dni_arr, method='tregenza', **kwargs) Bin hourly sun positions into sky patches and aggregate DNI. This is the key optimization for cumulative solar irradiance: instead of tracing rays for every hourly sun position, aggregate DNI values for each sky patch and trace rays once per patch. :param azimuth_arr: Array of solar azimuth values in degrees. :type azimuth_arr: np.ndarray :param elevation_arr: Array of solar elevation values in degrees. :type elevation_arr: np.ndarray :param dni_arr: Array of Direct Normal Irradiance values (W/m²). :type dni_arr: np.ndarray :param method: Sky discretization method: "tregenza", "reinhart", "uniform", "fibonacci". :type method: str :param \*\*kwargs: Additional parameters for patch generation (e.g., mf for Reinhart). :type \*\*kwargs: dict :returns: * **patch_directions** (*np.ndarray, shape (N, 3)*) -- Unit direction vectors for each patch. * **patch_cumulative_dni** (*np.ndarray, shape (N,)*) -- Cumulative DNI (W·h/m²) for each patch. * **patch_solid_angles** (*np.ndarray, shape (N,)*) -- Solid angle of each patch. * **patch_hours** (*np.ndarray, shape (N,)*) -- Number of hours with sun in each patch. .. py:function:: bin_sun_positions_to_tregenza_fast(azimuth_arr, elevation_arr, dni_arr) Numba-accelerated binning of sun positions to Tregenza patches. :param azimuth_arr: Array of solar azimuth values in degrees. :type azimuth_arr: np.ndarray :param elevation_arr: Array of solar elevation values in degrees. :type elevation_arr: np.ndarray :param dni_arr: Array of Direct Normal Irradiance values (W/m²). :type dni_arr: np.ndarray :returns: * **cumulative_dni** (*np.ndarray, shape (145,)*) -- Cumulative DNI (W·h/m²) for each Tregenza patch. * **hours_count** (*np.ndarray, shape (145,)*) -- Number of hours with sun in each patch. .. py:function:: get_patch_info(method='tregenza', **kwargs) Get information about a sky discretization method. :param method: Sky discretization method. :type method: str :param \*\*kwargs: Additional parameters for the method. :type \*\*kwargs: dict :returns: Dictionary with patch count, method name, and parameters. :rtype: dict .. py:function:: visualize_sky_patches(method='tregenza', ax=None, show=True, **kwargs) Visualize sky patches on a polar plot. :param method: Sky discretization method. :type method: str :param ax: Existing polar axis to plot on. :type ax: matplotlib axis, optional :param show: Whether to call plt.show(). :type show: bool :param \*\*kwargs: Additional parameters for patch generation. :type \*\*kwargs: dict :returns: **ax** -- The plot axis. :rtype: matplotlib axis .. py:function:: get_direct_solar_irradiance_map(voxcity: voxcity.models.VoxCity, azimuth_degrees_ori, elevation_degrees, direct_normal_irradiance, show_plot=False, **kwargs) Compute horizontal direct irradiance map (W/m²) with tree transmittance. .. py:function:: get_diffuse_solar_irradiance_map(voxcity: voxcity.models.VoxCity, diffuse_irradiance=1.0, show_plot=False, **kwargs) Compute diffuse horizontal irradiance map (W/m²) using SVF. .. py:function:: get_global_solar_irradiance_map(voxcity: voxcity.models.VoxCity, azimuth_degrees_ori, elevation_degrees, direct_normal_irradiance, diffuse_irradiance, show_plot=False, **kwargs) Combine direct and diffuse horizontal irradiance (W/m²). .. py:function:: compute_solar_irradiance_for_all_faces(face_centers, face_normals, face_svf, sun_direction, direct_normal_irradiance, diffuse_irradiance, voxel_data, meshsize, tree_k, tree_lad, hit_values, inclusion_mode, grid_bounds_real, boundary_epsilon) Numba kernel: compute per-face direct/diffuse/global (W/m²) using generic ray tracer. .. py:function:: get_building_solar_irradiance(voxcity: voxcity.models.VoxCity, building_svf_mesh, azimuth_degrees, elevation_degrees, direct_normal_irradiance, diffuse_irradiance, **kwargs) Compute per-face direct/diffuse/global (W/m²) on a building mesh with SVF. .. py:function:: get_cumulative_global_solar_irradiance(voxcity: voxcity.models.VoxCity, df, lon, lat, tz, direct_normal_irradiance_scaling=1.0, diffuse_irradiance_scaling=1.0, **kwargs) Integrate global horizontal irradiance over a period using EPW data. Returns W/m²·hour accumulation on the ground plane. :param voxcity: The VoxCity model. :type voxcity: VoxCity :param df: Weather data with 'DNI' and 'DHI' columns. :type df: pd.DataFrame :param lon: Longitude and latitude for solar position calculation. :type lon: float :param lat: Longitude and latitude for solar position calculation. :type lat: float :param tz: Timezone offset in hours. :type tz: float :param direct_normal_irradiance_scaling: Scaling factor for DNI. :type direct_normal_irradiance_scaling: float :param diffuse_irradiance_scaling: Scaling factor for DHI. :type diffuse_irradiance_scaling: float :param \*\*kwargs: Additional options: - use_sky_patches : bool (default False) If True, use sky patch aggregation for efficiency. DNI is aggregated into sky patches and ray tracing is done once per patch instead of per timestep. - sky_discretization : str (default "tregenza") Sky discretization method: "tregenza", "reinhart", "uniform", "fibonacci" - reinhart_mf : int (default 4) Multiplication factor for Reinhart subdivision. - sky_n_patches : int (default 145) Number of patches for Fibonacci method. - progress_report : bool Print progress information. :type \*\*kwargs: dict :returns: Cumulative global solar irradiance map (Wh/m²). :rtype: np.ndarray .. py:function:: get_cumulative_building_solar_irradiance(voxcity: voxcity.models.VoxCity, building_svf_mesh, weather_df, lon, lat, tz, **kwargs) Cumulative Wh/m² on building faces over a period from weather dataframe. :param voxcity: The VoxCity model. :type voxcity: VoxCity :param building_svf_mesh: Building mesh with SVF in metadata. :type building_svf_mesh: trimesh.Trimesh :param weather_df: Weather data with 'DNI' and 'DHI' columns. :type weather_df: pd.DataFrame :param lon: Longitude and latitude. :type lon: float :param lat: Longitude and latitude. :type lat: float :param tz: Timezone offset in hours. :type tz: float :param \*\*kwargs: Additional options: - use_sky_patches : bool (default False) If True, use sky patch aggregation for efficiency. Reduces computation from N timesteps to M patches (M << N). - sky_discretization : str (default "tregenza") Method: "tregenza", "reinhart", "uniform", "fibonacci" - reinhart_mf : int (default 4) Multiplication factor for Reinhart subdivision. - fast_path : bool (default True) Use optimized Numba kernels. - progress_report : bool Print progress information. :type \*\*kwargs: dict :returns: Mesh with cumulative irradiance in metadata (direct, diffuse, global in Wh/m²). :rtype: trimesh.Trimesh .. py:function:: get_global_solar_irradiance_using_epw(voxcity: voxcity.models.VoxCity, calc_type: str = 'instantaneous', direct_normal_irradiance_scaling: float = 1.0, diffuse_irradiance_scaling: float = 1.0, **kwargs) Compute global irradiance from EPW, either instantaneous or cumulative. .. py:function:: get_building_global_solar_irradiance_using_epw(*args, **kwargs) Compute building-surface irradiance using EPW (instantaneous or cumulative). .. py:function:: save_irradiance_mesh(irradiance_mesh, output_file_path) Persist irradiance mesh to pickle file. .. py:function:: load_irradiance_mesh(input_file_path) Load irradiance mesh from pickle file.