voxcity.generator ================= .. py:module:: voxcity.generator .. autoapi-nested-parse:: VoxCity generator subpackage. This package organizes the voxel city generation pipeline into focused modules while preserving the original public API under `voxcity.generator`. Orientation contract: - All 2D grids use uv_m/SOUTH_UP orientation (axis 0 = u/north, row 0 = southern origin edge; axis 1 = v/east). - 3D indexing follows (row, col, z) = (north→south, west→east, ground→up). Submodules ---------- .. toctree:: :maxdepth: 1 /autoapi/voxcity/generator/api/index /autoapi/voxcity/generator/grids/index /autoapi/voxcity/generator/io/index /autoapi/voxcity/generator/pipeline/index /autoapi/voxcity/generator/update/index /autoapi/voxcity/generator/voxelizer/index Attributes ---------- .. autoapisummary:: voxcity.generator.GROUND_CODE voxcity.generator.TREE_CODE voxcity.generator.BUILDING_CODE Classes ------- .. toctree:: :hidden: /autoapi/voxcity/generator/Voxelizer /autoapi/voxcity/generator/VoxCityPipeline .. autoapisummary:: voxcity.generator.Voxelizer voxcity.generator.VoxCityPipeline Functions --------- .. autoapisummary:: voxcity.generator.get_voxcity voxcity.generator.get_voxcity_CityGML voxcity.generator.auto_select_data_sources voxcity.generator.get_land_cover_grid voxcity.generator.get_building_height_grid voxcity.generator.get_canopy_height_grid voxcity.generator.get_dem_grid voxcity.generator.save_voxcity voxcity.generator.load_voxcity voxcity.generator.save_h5 voxcity.generator.load_h5 voxcity.generator.save_results_h5 voxcity.generator.load_results_h5 voxcity.generator.update_voxcity voxcity.generator.regenerate_voxels Package Contents ---------------- .. py:function:: get_voxcity(rectangle_vertices, meshsize, building_source=None, land_cover_source=None, canopy_height_source=None, dem_source=None, building_complementary_source=None, building_gdf=None, terrain_gdf=None, **kwargs) Generate a VoxCity model with automatic or custom data source selection. This function supports both auto mode and custom mode: - Auto mode: When sources are not specified (None), they are automatically selected based on location - Custom mode: When sources are explicitly specified, they are used as-is - Hybrid mode: Specify some sources and auto-select others :param rectangle_vertices: List of (lon, lat) tuples defining the area of interest :param meshsize: Grid resolution in meters (required) :param building_source: Building base source (default: auto-selected based on location) :param land_cover_source: Land cover source (default: auto-selected based on location) :param canopy_height_source: Canopy height source (default: auto-selected based on location) :param dem_source: Digital elevation model source (default: auto-selected based on location) :param building_complementary_source: Building complementary source (default: auto-selected based on location) :param building_gdf: Optional pre-loaded building GeoDataFrame :param terrain_gdf: Optional pre-loaded terrain GeoDataFrame :param \*\*kwargs: Additional options for building, land cover, canopy, DEM, visualization, and I/O. Performance options include: - parallel_download: bool, if True downloads run concurrently (default: False) I/O options include: - output_dir: Directory for intermediate/downloaded data (default: "output") - save_path: Full file path to save the VoxCity object (overrides output_dir default) - save_voxcity_data / save_voxctiy_data: bool flag to enable saving (default: True) :returns: VoxCity object containing the generated 3D city model .. py:function:: get_voxcity_CityGML(rectangle_vertices, land_cover_source, canopy_height_source, meshsize, url_citygml=None, citygml_path=None, **kwargs) .. py:function:: auto_select_data_sources(rectangle_vertices) Automatically choose data sources for buildings, land cover, canopy height, and DEM based on the target area's location. Rules (heuristic, partially inferred from latest availability): - Buildings (base): 'OpenStreetMap'. - Buildings (complementary): * USA, Europe, Australia -> 'Microsoft Building Footprints' * England -> 'England 1m DSM - DTM' (height from DSM-DTM) * Netherlands -> 'Netherlands 0.5m DSM - DTM' (height from DSM-DTM) * Africa, South Asia, SE Asia, Latin America & Caribbean -> 'Open Building 2.5D Temporal' * Otherwise -> 'None' - Land cover: USA -> 'Urbanwatch'; Japan -> 'OpenEarthMapJapan'; otherwise 'OpenStreetMap'. (If OSM is insufficient, consider 'ESA WorldCover' manually.) - Canopy height: 'High Resolution 1m Global Canopy Height Maps'. - DEM: High-resolution where available (USA, England, Australia, France, Netherlands), else 'FABDEM'. Returns a dict with keys: building_source, building_complementary_source, land_cover_source, canopy_height_source, dem_source. .. py:function:: get_land_cover_grid(rectangle_vertices, meshsize, source, output_dir, print_class_info=True, **kwargs) .. py:function:: get_building_height_grid(rectangle_vertices, meshsize, source, output_dir, building_gdf=None, **kwargs) .. py:function:: get_canopy_height_grid(rectangle_vertices, meshsize, source, output_dir, **kwargs) .. py:function:: get_dem_grid(rectangle_vertices, meshsize, source, output_dir, **kwargs) .. py:data:: GROUND_CODE :value: -1 .. py:data:: TREE_CODE :value: -2 .. py:data:: BUILDING_CODE :value: -3 .. py:function:: save_voxcity(output_path, city) Save a VoxCity instance to disk. The format is chosen automatically based on the file extension: * ``.h5`` / ``.hdf5`` → safe HDF5 format (recommended). * Anything else (e.g. ``.pkl``) → legacy pickle format. :param output_path: Destination file path. :type output_path: str or Path :param city: The model to save. :type city: VoxCity .. py:function:: load_voxcity(input_path, *, trusted: bool = False) Load a VoxCity instance from a file. The format is detected automatically based on the file extension: * ``.h5`` / ``.hdf5`` → safe HDF5 format (no warning). * Anything else (e.g. ``.pkl``) → legacy pickle format. .. warning:: Pickle files can execute arbitrary code on load. Only load files you created yourself or received from a trusted source. Pass ``trusted=True`` to suppress this warning. :param input_path: Path to the file. :type input_path: str or Path :param trusted: (Pickle only) Set to ``True`` to acknowledge the security implications of loading a pickle file and suppress the warning. :type trusted: bool, default False :rtype: VoxCity .. py:function:: save_h5(output_path, city) Save a VoxCity model to an HDF5 file (no simulation results). This is the recommended alternative to :func:`save_voxcity` (pickle-based) because HDF5 files cannot execute arbitrary code on load. :param output_path: Destination file path (e.g. ``"model.h5"``). :type output_path: str or Path :param city: The VoxCity model instance. :type city: VoxCity .. seealso:: :py:obj:`load_h5` Load a VoxCity model from an HDF5 file. :py:obj:`save_results_h5` Save a VoxCity model together with simulation results. .. py:function:: load_h5(input_path) Load a VoxCity model from an HDF5 file. This is the safe counterpart to :func:`load_voxcity` (pickle-based). Works with files written by either :func:`save_h5` or :func:`save_results_h5` — simulation result groups are simply ignored. :param input_path: Path to the HDF5 file. :type input_path: str or Path :returns: The reconstructed VoxCity model. :rtype: VoxCity .. seealso:: :py:obj:`save_h5` Save a VoxCity model to an HDF5 file. :py:obj:`load_results_h5` Load a VoxCity model together with simulation results. .. py:function:: save_results_h5(output_path, city, ground_results=None, building_results=None, simulation_results=None) Save a VoxCity model and simulation results to an HDF5 file. :param output_path: Destination file path (e.g. ``"results.h5"``). :type output_path: str :param city: The VoxCity model instance. :type city: VoxCity :param ground_results: Ground-level simulation results. Keys whose values are :class:`numpy.ndarray` are stored as HDF5 datasets (with gzip compression); all other JSON-serializable values are stored as group attributes. Typical keys produced by the GPU solar integration module:: { 'sunlight_hours': np.ndarray (ny, nx), 'cumulative_global': np.ndarray (ny, nx), 'svf': np.ndarray (ny, nx), 'potential_sunlight_hours': float, 'mode': str, ... } If the input numpy array carries a ``.metadata`` dict (e.g. ``ArrayWithMetadata``), those metadata entries are also persisted as sub-attributes. :type ground_results: dict, optional :param building_results: Building-surface simulation results. The dict **must** contain a ``'mesh'`` key whose value is a Trimesh object. Per-face data arrays are taken either from the ``'metadata'`` sub-dict or directly from the Trimesh's ``.metadata`` attribute. Typical keys produced by the GPU solar integration module:: { 'mesh': trimesh.Trimesh, 'metadata': { 'irradiance_direct': np.ndarray (n_faces,), 'irradiance_diffuse': np.ndarray (n_faces,), 'sunlight_hours': np.ndarray (n_faces,), 'potential_sunlight_hours': float, ... }, } If ``'metadata'`` is *not* provided explicitly, the function falls back to ``mesh.metadata``. :type building_results: dict, optional :param simulation_results: Multiple named simulation results grouped by simulation type. The recommended structure is:: { 'ground': { 'solar_cumulative': {'cumulative_global': array, ...}, 'sunlight_hours_dsh': {'sunlight_hours': array, ...}, }, 'building_surface': { 'solar_cumulative': trimesh_obj, 'sky_view_factor': {'mesh': trimesh_obj, 'metadata': {...}}, }, } Supported simulation types are ``'ground'`` and ``'building_surface'``. The legacy ``ground_results`` and ``building_results`` arguments remain supported for saving one unnamed/default result of each type. :type simulation_results: dict, optional .. rubric:: Notes * Requires the ``h5py`` package (``pip install h5py``). * The file is self-contained – no pickle dependency at load time. * Datasets use ``compression='gzip'`` by default for compact files. .. py:function:: load_results_h5(input_path) Load a VoxCity model and simulation results from an HDF5 file. :param input_path: Path to the HDF5 file created by :func:`save_results_h5`. :type input_path: str :returns: A dictionary with the following keys: ``'voxcity'`` The reconstructed :class:`~voxcity.models.VoxCity` instance. ``'ground'`` *(if present)* dict mapping dataset names to numpy arrays, plus scalar metadata entries. ``'building'`` *(if present)* dict with ``'mesh_vertices'``, ``'mesh_faces'``, ``'mesh_face_normals'`` (numpy arrays) and per-face data arrays / scalar metadata. ``'simulations'`` *(if present)* nested dict of named simulation results grouped by simulation type, e.g. ``data['simulations']['ground']['solar_cumulative']`` or ``data['simulations']['building_surface']['sky_view_factor']``. Legacy top-level ``'ground'`` and ``'building'`` groups are also exposed as ``'default'`` entries in this nested structure. ``'meta'`` dict with ``'crs'``, ``'meshsize'``, ``'bounds'``. :rtype: dict .. rubric:: Notes The returned ``'voxcity'`` object is a fully reconstructed :class:`VoxCity` dataclass – it can be passed directly to any simulator or visualizer function. .. py:function:: update_voxcity(city: voxcity.models.VoxCity, *, buildings: Optional[voxcity.models.BuildingGrid] = None, building_heights: Optional[numpy.ndarray] = None, building_min_heights: Optional[numpy.ndarray] = None, building_ids: Optional[numpy.ndarray] = None, land_cover: Optional[Union[voxcity.models.LandCoverGrid, numpy.ndarray]] = None, dem: Optional[Union[voxcity.models.DemGrid, numpy.ndarray]] = None, tree_canopy: Optional[Union[voxcity.models.CanopyGrid, numpy.ndarray]] = None, canopy_top: Optional[numpy.ndarray] = None, canopy_bottom: Optional[numpy.ndarray] = None, building_gdf=None, tree_gdf=None, tree_gdf_mode: str = 'replace', land_cover_source: Optional[str] = None, trunk_height_ratio: Optional[float] = None, voxel_dtype=None, max_voxel_ram_mb: Optional[float] = None, inplace: bool = False) -> voxcity.models.VoxCity Update a VoxCity object with new grid data and regenerate the VoxelGrid. This function allows partial updates - only the grids you provide will be updated, while the rest will be taken from the existing VoxCity object. The VoxelGrid is always regenerated from the (updated) component grids. :param city: The existing VoxCity object to update. :type city: VoxCity :param buildings: Complete replacement for the building grid. If provided, takes precedence over individual building_heights/building_min_heights/building_ids. :type buildings: BuildingGrid, optional :param building_heights: 2D array of building heights. If buildings is not provided, this updates only the heights while keeping existing min_heights and ids. :type building_heights: np.ndarray, optional :param building_min_heights: 2D object-dtype array of lists containing [min_height, max_height] pairs for each building segment per cell. :type building_min_heights: np.ndarray, optional :param building_ids: 2D array of building IDs per cell. :type building_ids: np.ndarray, optional :param land_cover: New land cover data. Can be a LandCoverGrid or a raw numpy array. :type land_cover: LandCoverGrid or np.ndarray, optional :param dem: New DEM/elevation data. Can be a DemGrid or a raw numpy array. :type dem: DemGrid or np.ndarray, optional :param tree_canopy: New tree canopy data. Can be a CanopyGrid (with top/bottom) or a raw numpy array (interpreted as canopy top heights). :type tree_canopy: CanopyGrid or np.ndarray, optional :param canopy_top: 2D array of tree canopy top heights. Takes precedence over tree_canopy for top heights if both are provided. :type canopy_top: np.ndarray, optional :param canopy_bottom: 2D array of tree canopy bottom heights (crown base). :type canopy_bottom: np.ndarray, optional :param building_gdf: Updated building GeoDataFrame. If provided without building grids (building_heights, building_min_heights, building_ids), the function will automatically generate the building grids from the GeoDataFrame using create_building_height_grid_from_gdf_polygon. The GeoDataFrame is also stored in city.extras['building_gdf']. :type building_gdf: GeoDataFrame, optional :param tree_gdf: Updated tree GeoDataFrame. If provided without tree canopy data (tree_canopy, canopy_top, canopy_bottom), the function will automatically generate the canopy grids from the GeoDataFrame using create_canopy_grids_from_tree_gdf. The GeoDataFrame must contain 'top_height', 'bottom_height', 'crown_diameter', and 'geometry' columns. The GeoDataFrame is stored in city.extras['tree_gdf']. :type tree_gdf: GeoDataFrame, optional :param tree_gdf_mode: How to combine tree_gdf with existing canopy data. Options: - "replace": Replace the existing canopy grids with new ones from tree_gdf. - "add": Merge the tree_gdf grids with existing (or provided) canopy grids by taking the maximum height at each cell (preserves existing trees). When canopy_top/canopy_bottom are also provided, the tree_gdf grids are merged on top of those arrays instead of the existing city canopy. :type tree_gdf_mode: str, default "replace" :param land_cover_source: The land cover source name for proper voxelization. If not provided, attempts to use the source from city.extras or defaults to 'OpenStreetMap'. :type land_cover_source: str, optional :param trunk_height_ratio: Ratio of trunk height to total tree height for canopy bottom calculation. Default is approximately 0.588 (11.76/19.98). :type trunk_height_ratio: float, optional :param voxel_dtype: NumPy dtype for the voxel grid. Defaults to np.int8. :type voxel_dtype: dtype, optional :param max_voxel_ram_mb: Maximum RAM in MB for voxel grid allocation. Raises MemoryError if exceeded. :type max_voxel_ram_mb: float, optional :param inplace: If True, modifies the input city object directly and returns it. If False, creates and returns a new VoxCity object. :type inplace: bool, default False :returns: The updated VoxCity object with regenerated VoxelGrid. :rtype: VoxCity .. rubric:: Examples Update building heights and regenerate voxels: >>> import numpy as np >>> new_heights = city.buildings.heights.copy() >>> new_heights[10:20, 10:20] = 50.0 # Increase height in a region >>> updated = update_voxcity(city, building_heights=new_heights) Update with a complete new BuildingGrid: >>> from voxcity.models import BuildingGrid >>> new_buildings = BuildingGrid(heights=..., min_heights=..., ids=..., meta=city.buildings.meta) >>> updated = update_voxcity(city, buildings=new_buildings) Update land cover and DEM together: >>> updated = update_voxcity(city, land_cover=new_lc_array, dem=new_dem_array) Update buildings from GeoDataFrame (automatic grid generation): >>> updated = update_voxcity(city, building_gdf=updated_building_gdf) Update trees from GeoDataFrame (replace existing canopy): >>> updated = update_voxcity(city, tree_gdf=updated_tree_gdf) Add trees from GeoDataFrame to existing canopy: >>> updated = update_voxcity(city, tree_gdf=new_tree_gdf, tree_gdf_mode="add") .. py:function:: regenerate_voxels(city: voxcity.models.VoxCity, *, land_cover_source: Optional[str] = None, trunk_height_ratio: Optional[float] = None, voxel_dtype=None, max_voxel_ram_mb: Optional[float] = None, inplace: bool = False) -> voxcity.models.VoxCity Regenerate only the VoxelGrid from existing component grids. This is a convenience function for when you've modified the grids in-place and need to regenerate the voxels without passing all parameters. :param city: The VoxCity object whose voxels should be regenerated. :type city: VoxCity :param land_cover_source: Land cover source for voxelization. Defaults to source from extras. :type land_cover_source: str, optional :param trunk_height_ratio: Trunk height ratio for tree canopy calculation. :type trunk_height_ratio: float, optional :param voxel_dtype: NumPy dtype for voxel grid. :type voxel_dtype: dtype, optional :param max_voxel_ram_mb: Maximum RAM in MB for voxel allocation. :type max_voxel_ram_mb: float, optional :param inplace: If True, modifies city directly; otherwise returns a new object. :type inplace: bool, default False :returns: The VoxCity object with regenerated VoxelGrid. :rtype: VoxCity .. rubric:: Examples >>> # Modify building heights in place >>> city.buildings.heights[50:60, 50:60] = 100.0 >>> # Regenerate voxels to reflect the change >>> city = regenerate_voxels(city, inplace=True)