Solar mask model

This notebook demonstrates how to use the solar mask model

[2]:
from buildingmodel import data_path
from buildingmodel.main import Parameters, load_data, run_inference, run_creation
from buildingmodel.io.gis import load_data as load_gis_data
from buildingmodel.io.climate import load_data as load_climate_data
from buildingmodel.models.climate import run_models as run_climate_models
from buildingmodel.creation.boundary import run_creation as run_boundary_creation
from buildingmodel.models.solar_masks import run_models as run_solar_mask_models
from buildingmodel.models.solar_gains import run_models as run_solar_gain_models
from pathlib import Path
import pandas as pd
import geopandas as gpd
import numpy as np
import matplotlib.pyplot as plt

Loading gis data and running the boundary creation model are required before running the solar mask model (the masks are calculated at the center of each exterior wall and roof)

[3]:
parameters = Parameters(
    districts="districts_test_sample.gpkg",
    district_level_census="district_level_census_test_sample.hdf",
    district_level_diagnosis="district_level_diagnosis_data_test_sample.hdf",
    gas_network_route="gas_network_route_sample.gpkg",
    simplification_tolerance=0.1,
)

building_data = Path(data_path["gis"]) / "testing" / "test_sample.gpkg"
climate_data = Path(data_path["climate"]) / "Brest.epw"

buildings, climate, metadata = load_data(building_data, climate_data, parameters)
buildings, boundaries, dwellings = run_creation(buildings, parameters)
dwellings, buildings = run_inference(buildings, dwellings, boundaries, parameters)
run_climate_models(climate, metadata, parameters)
/home/yassine/miniconda3/envs/buildingmodel_dev/lib/python3.8/site-packages/topojson/core/cut.py:112: ShapelyDeprecationWarning: STRtree will be changed in 2.0.0 and will not be compatible with versions < 2.
  tree_splitter = STRtree(mp)

The mask model takes as input the building and boundary GeoDataframes, as well as optional parameters grid_resolution (in meters) and angular_resolution (in degrees)

[6]:
parameters.grid_resolution = 0.2
parameters.angular_resolution = 10.0
parameters.bbox_filter = 100.0

boundaries = run_solar_mask_models(buildings, boundaries, parameters)

The results of the mask model are concatenated to the boundary GeoDataframe passed as input. The number of columns containing mask results depends on the angular resolution.

[7]:
mask_columns = [
    col_name for col_name in boundaries.columns if col_name.startswith("mask_")
]
[8]:
boundaries[mask_columns].head(10)
[8]:
mask_0 mask_1 mask_2 mask_3 mask_4 mask_5 mask_6 mask_7 mask_8 mask_9 ... mask_27 mask_28 mask_29 mask_30 mask_31 mask_32 mask_33 mask_34 mask_35 mask_36
0 0.0 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 ... 90.000000 90.000000 90.000000 19.655833 20.737675 21.306570 85.532880 0.000000 0.000000 0.0
1 90.0 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 ... 7.725851 7.884824 9.086201 10.014632 10.645363 10.931181 10.964663 14.798831 22.270093 0.0
2 90.0 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 ... 28.571591 11.547256 9.941625 9.764441 10.362783 10.653227 10.679292 10.616735 10.262963 0.0
3 90.0 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 ... 45.177657 50.875262 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.0
4 90.0 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 ... 37.754538 34.215829 30.585186 25.044680 18.883746 13.159557 13.197851 13.121730 12.668176 0.0
5 90.0 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 ... 0.000000 0.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.0
6 90.0 90.000000 0.000000 0.000000 0.000000 0.000000 89.330561 14.502335 14.015015 13.060362 ... 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.0
36 0.0 10.607839 12.195332 13.307794 14.199923 14.601427 14.665498 14.578485 13.989155 13.228434 ... 90.000000 90.000000 90.000000 13.717217 14.618307 14.993473 82.732568 0.000000 0.000000 0.0
37 90.0 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 ... 9.772777 8.805085 7.559253 6.932708 7.345726 7.537268 7.552021 7.488912 7.221574 0.0
38 90.0 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 ... 1.943871 7.511871 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.000000 90.0

10 rows × 37 columns

The following function will plot side by side the geometries of the buildings as well as the mask for the i-th boundary

[19]:
def plot_mask(buildings, boundaries, i):
    fig, ax = plt.subplots(1, 2, sharex=False, sharey=False, figsize=(15, 7))

    buildings.plot(ax=ax[0], color="red", alpha=0.5)
    gpd.GeoDataFrame(geometry=[boundaries.iloc[i].geometry]).plot(
        ax=ax[0], color="blue"
    )
    mask_columns = [
        col_name for col_name in boundaries.columns if col_name.startswith("mask_")
    ]
    boundaries[mask_columns].iloc[i].transpose().plot(ax=ax[1])
    plt.show()
[26]:
plot_mask(buildings, boundaries, 52)
../_images/notebooks_SolarMaskModel_11_0.png

The following code will import a 3d plotting utility that relies on additional dependencies mapbox_earcut and k3d. Make sure to install them before executing the next cells.

[8]:
from buildingmodel.io.plot_3D import plot_3D_district
[9]:
boundaries["average_mask"] = boundaries[mask_columns].mean(axis=1)

plot_3D_district(buildings, boundaries, "average_mask", [0.0, 90.0])
/home/yassine/miniconda3/envs/buildingmodel/lib/python3.8/site-packages/traittypes/traittypes.py:97: UserWarning: Given trait value dtype "float64" does not match required type "float32". A coerced copy has been created.
  warnings.warn(
/home/yassine/miniconda3/envs/buildingmodel/lib/python3.8/site-packages/traittypes/traittypes.py:97: UserWarning: Given trait value dtype "float64" does not match required type "uint32". A coerced copy has been created.
  warnings.warn(