Skip to content

Commit

Permalink
Merge pull request #170 from Deltares/#133_Spatialbuildingfootprint
Browse files Browse the repository at this point in the history
#133 spatialbuildingfootprint
  • Loading branch information
frederique-hub authored Oct 19, 2023
2 parents d808ff7 + d191a0e commit 7447b65
Show file tree
Hide file tree
Showing 9 changed files with 3,307 additions and 1 deletion.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -122,5 +122,6 @@ cache
/examples/FIAT_database
hydromt_fiat/data/damage_functions/flooding/AllDDF_HAZUS_fractions.xlsx
hydromt_fiat/data/damage_functions/flooding/~$AllDDF_HAZUS_fractions.xlsx
examples/data/building_footprints/fiat_model_bfs
examples/data/aggregation_zones_example/aggregation_test_1_output
examples/data/aggregation_zones_example/aggregation_test_2_output
examples/data/aggregation_zones_example/aggregation_test_2_output
Binary file not shown.
Binary file not shown.
3,082 changes: 3,082 additions & 0 deletions examples/data/building_footprints/fiat_model/exposure/exposure.csv

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions examples/data/building_footprints/fiat_model/settings.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[global]
crs = "epsg:4326"

[output]
path = "output"

[output.csv]
name = "output.csv"

[output.geom]
name1 = "spatial.gpkg"

[vulnerability]
file = "./vulnerability/vulnerability_curves.csv"
scale = 0.1

[exposure.geom]
csv = "./exposure/exposure.csv"
crs = "EPSG:4326"
file1 = "./exposure/buildings.gpkg"
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#UNIT=feet
#METHOD,max,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean,mean
water depth [feet],AGR1,COM1,COM10,COM2,COM3,COM4,COM5,COM6,COM7,COM8,COM9,EDU1,EDU2,GOV1,GOV2,IND1,IND2,IND3,IND4,IND5,IND6,REL1,RES1-1SNB,RES1-1SWB,RES1-2SNB,RES1-2SWB,RES1-3SNB,RES1-3SWB,RES2,RES3A,RES3B,RES3C,RES3D,RES3E,RES3F,RES4,RES5,RES6
-9.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
-8.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1e-06,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
-7.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.008,0.0,0.01,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
-6.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.021,0.0,0.023,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
-5.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.037,0.0,0.037,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
-4.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.057,0.0,0.052,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
-3.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.08,0.0,0.068,0.0,0.05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
-2.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.105,0.0,0.084,0.0,0.07,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
-1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.024,0.132,0.01,0.101,0.0,0.08,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
0.0,0.06,0.02,0.0,0.03,0.004,0.0,0.0,0.0,0.0,0.13,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.02,0.15,0.02,0.0,0.0,0.081,0.16,0.05,0.119,0.06,0.14,0.03,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
1.0,0.2,0.26,0.11,0.16,0.164,0.2,0.5,0.146,0.28,0.45,0.04,0.217,0.27,0.3,0.08,0.15,0.193,0.2,0.2,0.2,0.2,0.293,0.133,0.189,0.087,0.138,0.11,0.18,0.27,0.217,0.217,0.217,0.217,0.217,0.217,0.161,0.15,0.38
2.0,0.43,0.42,0.17,0.27,0.289,0.3,0.74,0.27,0.51,0.55,0.06,0.304,0.38,0.59,0.2,0.24,0.31,0.41,0.26,0.41,0.35,0.484,0.179,0.218,0.122,0.157,0.15,0.22,0.49,0.304,0.304,0.304,0.304,0.304,0.304,0.263,0.25,0.6
3.0,0.58,0.56,0.2,0.36,0.409,0.4,0.83,0.37,0.6,0.64,0.08,0.39,0.53,0.74,0.38,0.34,0.423,0.51,0.31,0.51,0.47,0.6,0.22,0.247,0.155,0.177,0.19,0.25,0.64,0.39,0.39,0.39,0.39,0.39,0.39,0.341,0.4,0.73
4.0,0.65,0.68,0.23,0.49,0.577,0.575,1.0,0.534,0.63,0.73,0.09,0.45,0.64,0.83,0.55,0.41,0.523,0.62,0.37,0.62,0.56,0.693,0.257,0.274,0.185,0.198,0.23,0.29,0.7,0.45,0.45,0.45,0.45,0.45,0.45,0.397,0.5,0.81
5.0,0.66,0.78,0.25,0.57,0.633,0.7,1.0,0.7,0.67,0.77,0.1,0.479,0.68,0.9,0.7,0.47,0.607,0.67,0.4,0.67,0.59,0.764,0.288,0.3,0.213,0.22,0.26,0.31,0.76,0.479,0.479,0.479,0.479,0.479,0.479,0.487,0.58,0.88
6.0,0.66,0.83,0.29,0.63,0.707,0.8,1.0,0.791,0.71,0.8,0.12,0.519,0.7,1.0,0.81,0.52,0.72,0.71,0.44,0.71,0.66,0.814,0.315,0.324,0.239,0.243,0.29,0.34,0.78,0.519,0.519,0.519,0.519,0.519,0.519,0.524,0.65,0.94
7.0,0.67,0.85,0.35,0.69,0.793,0.838,1.0,0.856,0.72,0.82,0.17,0.557,0.72,1.0,0.89,0.57,0.821,0.73,0.48,0.73,0.69,0.884,0.338,0.345,0.263,0.267,0.32,0.36,0.79,0.557,0.557,0.557,0.557,0.557,0.557,0.584,0.78,1.0
8.0,0.7,0.87,0.42,0.72,0.843,1.0,1.0,0.925,0.74,0.83,0.22,0.593,0.75,1.0,0.98,0.6,0.907,0.76,0.53,0.76,0.71,0.943,0.357,0.363,0.284,0.291,0.35,0.39,0.81,0.593,0.593,0.593,0.593,0.593,0.593,0.613,0.9,1.0
9.0,0.75,0.88,0.51,0.76,0.871,1.0,1.0,0.956,0.77,0.85,0.3,0.606,0.79,1.0,1.0,0.63,0.943,0.78,0.56,0.78,0.72,0.971,0.372,0.377,0.303,0.317,0.41,0.44,0.83,0.606,0.606,0.606,0.606,0.606,0.606,0.631,0.9,1.0
10.0,0.76,0.89,0.63,0.8,0.871,1.0,1.0,0.963,0.81,0.87,0.41,0.634,0.83,1.0,1.0,0.64,0.95,0.79,0.57,0.79,0.78,0.971,0.384,0.386,0.32,0.344,0.43,0.46,0.83,0.634,0.634,0.634,0.634,0.634,0.634,0.649,0.92,1.0
11.0,0.76,0.9,0.77,0.82,0.871,1.0,1.0,0.963,0.86,0.89,0.57,0.634,0.88,1.0,1.0,0.66,0.95,0.82,0.6,0.82,0.79,0.971,0.392,0.391,0.334,0.372,0.45,0.47,0.83,0.634,0.634,0.634,0.634,0.634,0.634,0.649,0.92,1.0
12.0,0.76,0.91,0.93,0.84,0.871,1.0,1.0,0.963,0.92,0.9,0.66,0.634,0.94,1.0,1.0,0.68,0.95,0.83,0.62,0.83,0.8,0.971,0.397,0.391,0.347,0.4,0.48,0.5,0.83,0.634,0.634,0.634,0.634,0.634,0.634,0.649,0.92,1.0
13.0,0.77,0.92,1.0,0.86,0.871,1.0,1.0,0.963,0.94,0.91,0.73,0.634,1.0,1.0,1.0,0.69,0.95,0.84,0.63,0.84,0.8,0.971,0.4,0.391,0.356,0.43,0.5,0.52,0.83,0.634,0.634,0.634,0.634,0.634,0.634,0.649,0.92,1.0
14.0,0.77,0.92,1.0,0.87,0.871,1.0,1.0,0.963,0.97,0.92,0.79,0.634,1.0,1.0,1.0,0.72,0.95,0.86,0.63,0.86,0.81,0.971,0.4,0.391,0.364,0.461,0.52,0.53,0.83,0.634,0.634,0.634,0.634,0.634,0.634,0.649,0.92,1.0
15.0,0.77,0.92,1.0,0.87,0.871,1.0,1.0,0.963,0.99,0.93,0.84,0.634,1.0,1.0,1.0,0.73,0.95,0.87,0.63,0.87,0.81,0.971,0.4,0.391,0.369,0.493,0.54,0.55,0.83,0.634,0.634,0.634,0.634,0.634,0.634,0.649,0.92,1.0
16.0,0.78,0.93,1.0,0.88,0.871,1.0,1.0,0.963,1.0,0.94,0.9,0.634,1.0,1.0,1.0,0.73,0.95,0.87,0.64,0.87,0.81,0.971,0.4,0.391,0.372,0.526,0.56,0.57,0.83,0.634,0.634,0.634,0.634,0.634,0.634,0.649,0.92,1.0
17.0,0.78,0.93,1.0,0.89,0.871,1.0,1.0,0.963,1.0,0.95,0.97,0.634,1.0,1.0,1.0,0.73,0.95,0.88,0.65,0.88,0.82,0.971,0.4,0.391,0.372,0.526,0.58,0.58,0.83,0.634,0.634,0.634,0.634,0.634,0.634,0.649,0.92,1.0
18.0,0.78,0.94,1.0,0.89,0.871,1.0,1.0,0.963,1.0,0.96,0.98,0.634,1.0,1.0,1.0,0.74,0.95,0.88,0.65,0.88,0.82,0.971,0.4,0.391,0.372,0.526,0.6,0.6,0.83,0.634,0.634,0.634,0.634,0.634,0.634,0.649,0.92,1.0
19.0,0.79,0.94,1.0,0.89,0.871,1.0,1.0,0.963,1.0,0.96,1.0,0.634,1.0,1.0,1.0,0.74,0.95,0.88,0.65,0.88,0.82,0.971,0.4,0.391,0.372,0.526,0.6,0.6,0.83,0.634,0.634,0.634,0.634,0.634,0.634,0.649,0.92,1.0
20.0,0.79,0.94,1.0,0.89,0.871,1.0,1.0,0.963,1.0,0.96,1.0,0.634,1.0,1.0,1.0,0.74,0.95,0.88,0.65,0.88,0.83,0.971,0.4,0.391,0.372,0.526,0.6,0.6,0.83,0.634,0.634,0.634,0.634,0.634,0.634,0.649,0.92,1.0
21.0,0.79,0.94,1.0,0.89,0.871,1.0,1.0,0.963,1.0,0.96,1.0,0.634,1.0,1.0,1.0,0.74,0.95,0.88,0.65,0.88,0.83,0.971,0.4,0.391,0.372,0.526,0.6,0.6,0.83,0.634,0.634,0.634,0.634,0.634,0.634,0.649,0.92,1.0
22.0,0.79,0.94,1.0,0.89,0.871,1.0,1.0,0.963,1.0,0.96,1.0,0.634,1.0,1.0,1.0,0.75,0.95,0.88,0.65,0.88,0.83,0.971,0.4,0.391,0.372,0.526,0.6,0.6,0.83,0.634,0.634,0.634,0.634,0.634,0.634,0.649,0.92,1.0
23.0,0.8,0.94,1.0,0.89,0.871,1.0,1.0,0.963,1.0,0.96,1.0,0.634,1.0,1.0,1.0,0.75,0.95,0.88,0.65,0.88,0.83,0.971,0.4,0.391,0.372,0.526,0.6,0.6,0.83,0.634,0.634,0.634,0.634,0.634,0.634,0.649,0.92,1.0
24.0,0.8,0.94,1.0,0.89,0.871,1.0,1.0,0.963,1.0,0.96,1.0,0.634,1.0,1.0,1.0,0.75,0.95,0.88,0.65,0.88,0.83,0.971,0.4,0.391,0.372,0.526,0.6,0.6,0.83,0.634,0.634,0.634,0.634,0.634,0.634,0.649,0.92,1.0
40 changes: 40 additions & 0 deletions hydromt_fiat/fiat.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from hydromt_fiat.workflows.social_vulnerability_index import SocialVulnerabilityIndex
from hydromt_fiat.workflows.vulnerability import Vulnerability
from hydromt_fiat.workflows.aggregation_areas import join_exposure_aggregation_areas
from hydromt_fiat.workflows.building_footprints import join_exposure_building_footprints

__all__ = ["FiatModel"]

Expand Down Expand Up @@ -566,10 +567,49 @@ def setup_aggregation_areas(
attribute_names: Union[List[str], str],
label_names: Union[List[str], str],
):
"""_summary_
Parameters
----------
exposure_gdf : gpd.GeoDataFrame
Exposure data to join the aggregation areas to as "Aggregation
Label: `label_names`".
aggregation_area_fn : Union[List[str], List[Path], str, Path]
Path(s) to the aggregation area(s).
attribute_names : Union[List[str], str]
Name of the attribute(s) to join.
label_names : Union[List[str], str]
Name of the label(s) to join.
"""

exposure_gdf = self.exposure.get_full_gdf(self.exposure.exposure_db)
self.exposure.exposure_db = join_exposure_aggregation_areas(
exposure_gdf, aggregation_area_fn, attribute_names, label_names
)
def setup_building_footprint(
self,
building_footprint_fn: Union[str, Path],
attribute_name: str,
):
"""_summary_
Parameters
----------
exposure_gdf : gpd.GeoDataFrame
Exposure data to join the building footprints to as "BF_FID".
building_footprint_fn : Union[List[str], List[Path], str, Path]
Path(s) to the building footprint.
attribute_names : Union[List[str], str]
Name of the building footprint ID to join.
column_name: str = "BF_FID"
Name of building footprint in new exposure output
"""

exposure_gdf = self.exposure.get_full_gdf(self.exposure.exposure_db)
self.exposure.exposure_db = join_exposure_building_footprints(
exposure_gdf, building_footprint_fn, attribute_name,
)

# Update functions
def update_all(self):
Expand Down
78 changes: 78 additions & 0 deletions hydromt_fiat/workflows/building_footprints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import geopandas as gpd
from typing import Union
from pathlib import Path
import math
from hydromt import gis_utils


def process_value(value):
if isinstance(value, list) and len(value) == 1:
return value[0]
elif isinstance(value, list) and len(value) > 1:
return ", ".join(value)
else:
return value

def join_exposure_building_footprints(
exposure_gdf: gpd.GeoDataFrame,
building_footprint_fn: Union[str, Path],
attribute_name: str,
column_name: str = "BF_FID",
) -> gpd.GeoDataFrame:
"""Join building footprints to the exposure data.
Parameters
----------
exposure_gdf : gpd.GeoDataFrame
Exposure data to join the building footprints to as "BF_FID".
building_footprint_fn : Union[str, Path]
Path(s) to the building footprint.
attribute_name : str
Name of the building footprint ID to join.
column_name : str = "BF_FID"
Name of building footprint in new exposure output
Returns
-------
gpd.GeoDataFrame
An updated exposure GeoDataFrame including the building footprints.
"""
# Read the building footprints file
bf_gdf = gpd.read_file(building_footprint_fn)

# Check if the attribute is in the building footprint file
assert attribute_name in bf_gdf.columns, f"Attribute {attribute_name} not found in {building_footprint_fn}"

# Check for unique identifier attribute
assert bf_gdf[attribute_name].is_unique, "Building footprint ID returns duplicates. Building footprint ID (attribute_name) should be unique."

# Change the column type to be an integer
bf_gdf[attribute_name] = bf_gdf[attribute_name].astype("int")

# check the projection of both gdf and if not match, reproject
if exposure_gdf.crs != bf_gdf.crs:
bf_gdf = bf_gdf.to_crs(exposure_gdf.crs)

# Spatially join the exposure and building footprint data
joined_gdf = gpd.sjoin(
exposure_gdf,
bf_gdf[["geometry", attribute_name]],
predicate="intersects",
how="right",
)

# Aggregate the data if duplicates exist
aggregated = (
joined_gdf.groupby("Object ID")[attribute_name].agg(list).reset_index()
)
exposure_gdf = exposure_gdf.merge(aggregated, on="Object ID", how = 'left')

# Create a string from the list of values in the duplicated aggregation area
# column
exposure_gdf[attribute_name] = exposure_gdf[attribute_name].apply(process_value)

# Rename the 'aggregation_attribute' column to 'new_column_name'
exposure_gdf.rename(columns={attribute_name: column_name}, inplace=True)

return exposure_gdf
48 changes: 48 additions & 0 deletions tests/test_building_footprints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from typing import Sequence
from _pytest.mark.structures import ParameterSet
from hydromt_fiat.fiat import FiatModel
from hydromt.log import setuplog
from pathlib import Path
import pytest
import shutil

EXAMPLEDIR = Path().resolve() / "examples" / "data" / "building_footprints"

#Create test
_cases = {
"join_building_footprints_to_exposure": {
"root": EXAMPLEDIR / "fiat_model",
"new_root": EXAMPLEDIR / "fiat_model_bfs",
"configuration": {
"setup_building_footprint": {
"building_footprint_fn": EXAMPLEDIR / "building_footprints" / "building_footprints.gpkg", # Datasource: https://github.com/microsoft/USBuildingFootprints
"attribute_name": "BF_FID",
}
},
}
}

# Set up Fiat Model
@pytest.mark.parametrize("case", list(_cases.keys()))
def test_building_footprints(case: ParameterSet | Sequence[object] | object):
# Read model in examples folder.
if _cases[case]["new_root"].exists():
shutil.rmtree(_cases[case]["new_root"])
logger = setuplog("hydromt_fiat", log_level=10)

fm = FiatModel(root=_cases[case]["root"], mode="r", logger=logger)
fm.read()
exposure_orig = fm.exposure.exposure_db.copy()

fm.build(write=False, opt=_cases[case]["configuration"])
fm.set_root(_cases[case]["new_root"])
fm.write()

# Check if the BF_FID column is added
assert "BF_FID" in fm.exposure.exposure_db.columns

# Check for Object ID duplicates
assert fm.exposure.exposure_db["Object ID"].duplicated().sum() == 0

# Check original exposure is same length new exposure
assert len(fm.exposure.exposure_db["Object ID"]) == len(exposure_orig["Object ID"])

0 comments on commit 7447b65

Please sign in to comment.