Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#133 spatialbuildingfootprint #170

Merged
merged 15 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"])