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

#137-allow-to-use-different-names-for-the-spatial-exposure-data #141

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
4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ def write_nested_dropdown(name, data_cat, note="", categories=[]):
"github_url": "https://github.com", # or your GitHub Enterprise interprise
"github_user": "Deltares",
"github_repo": "hydromt_fiat",
"github_version": "main",
"github_version": "main",
"doc_path": "docs",
"default_mode": "light",
}
Expand Down Expand Up @@ -324,4 +324,4 @@ def write_nested_dropdown(name, data_cat, note="", categories=[]):
"""

# Allow errors in notebooks
# nbsphinx_allow_errors = True
# nbsphinx_allow_errors = True
2 changes: 1 addition & 1 deletion examples/data/hydromt_fiat_catalog_global.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jrc_vulnerability_curves:
paper_doi: https://dx.doi.org/10.2760/16510

jrc_vulnerability_curves_linking:
path: damage_functions/flooding/JRC_damage_functions_linking.csv
path: vulnerability_linking/JRC_damage_functions_linking.csv
data_type: DataFrame
driver: csv
meta:
Expand Down
4 changes: 1 addition & 3 deletions hydromt_fiat/api/exposure_vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ def set_asset_locations_source(
self.exposure_model.occupancy_type = input_source
self.exposure_model.max_potential_damage = input_source
self.exposure_model.ground_floor_height = 1 # TODO: make flexible
self.exposure_model.unit = (
Units.ft.value
) # TODO: make flexible
self.exposure_model.unit = Units.ft.value # TODO: make flexible

# Download NSI from the database
region = self.data_catalog.get_geodataframe("area_of_interest")
Expand Down
30 changes: 30 additions & 0 deletions hydromt_fiat/data/hydromt_fiat_catalog_global.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

jrc_vulnerability_curves:
path: damage_functions/flooding/JRC_damage_functions.csv
data_type: DataFrame
driver: csv
meta:
category: vulnerability
description: JRC depth-damage functions for flooding, processed into a handy format for HydroMT-FIAT.
source_url: https://publications.jrc.ec.europa.eu/repository/handle/JRC105688
paper_ref: Huizinga, J., De Moel, H. and Szewczyk, W., Global flood depth-damage functions - Methodology and the database with guidelines, EUR 28552 EN, Publications Office of the European Union, Luxembourg, 2017, ISBN 978-92-79-67781-6, doi:10.2760/16510, JRC105688.
paper_doi: https://dx.doi.org/10.2760/16510

jrc_vulnerability_curves_linking:
path: vulnerability_linking/JRC_damage_functions_linking.csv
data_type: DataFrame
driver: csv
meta:
category: vulnerability
description: Default linking table for the JRC damage functions (e.g., the residential damage function links to residential buildings).

jrc_damage_values:
path: max_potential_damages/JRC_base_damage_values.csv
data_type: DataFrame
driver: csv
meta:
category: vulnerability
description: Base damage values from the JRC publicated Excel from the tab "MaxDamage-Data", processed into a handy format for HydroMT-FIAT.
source_url: https://publications.jrc.ec.europa.eu/repository/handle/JRC105688
paper_ref: Huizinga, J., De Moel, H. and Szewczyk, W., Global flood depth-damage functions - Methodology and the database with guidelines, EUR 28552 EN, Publications Office of the European Union, Luxembourg, 2017, ISBN 978-92-79-67781-6, doi:10.2760/16510, JRC105688.
paper_doi: https://dx.doi.org/10.2760/16510
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Name,Link,Damage Type,type
FIAT Damage Function Name,Exposure Link,Damage Type,type
residential,residential,total,residential
commercial,commercial,total,commercial
industrial,industrial,total,industrial
4 changes: 1 addition & 3 deletions hydromt_fiat/data_apis/open_street_maps.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ def get_assets_from_osm(polygon: Polygon):

def get_landuse_from_osm(polygon: Polygon):
tags = {"landuse": True} # this is the tag we use to find the correct OSM data
landuse = ox.features.features_from_polygon(
polygon, tags
) # then we query the data
landuse = ox.features.features_from_polygon(polygon, tags) # then we query the data

if landuse.empty:
logging.warning("No land use data found from OSM")
Expand Down
45 changes: 16 additions & 29 deletions hydromt_fiat/fiat.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,13 +271,13 @@ def setup_exposure_vector(
if asset_locations == occupancy_type == max_potential_damage:
# The source for the asset locations, occupancy type and maximum potential
# damage is the same, use one source to create the exposure data.
self.exposure.setup_from_single_source(
self.exposure.setup_buildings_from_single_source(
asset_locations, ground_floor_height, extraction_method
)
else:
# The source for the asset locations, occupancy type and maximum potential
# damage is different, use three sources to create the exposure data.
self.exposure.setup_from_multiple_sources(
self.exposure.setup_buildings_from_multiple_sources(
asset_locations,
occupancy_type,
max_potential_damage,
Expand Down Expand Up @@ -306,7 +306,6 @@ def setup_exposure_vector(
self.set_config("exposure.geom.crs", self.exposure.crs)
self.set_config("exposure.geom.unit", unit)


def setup_exposure_raster(self):
"""Setup raster exposure data for Delft-FIAT.
This function will be implemented at a later stage.
Expand Down Expand Up @@ -574,25 +573,15 @@ def setup_social_vulnerability_index(
# Link the SVI score to the exposure data
exposure_data = self.exposure.get_full_gdf(self.exposure.exposure_db)
exposure_data.sort_values("Object ID")

if svi.svi_data_shp.crs != exposure_data.crs:
svi.svi_data_shp.to_crs(crs=exposure_data.crs, inplace = True)
svi.svi_data_shp.to_crs(crs=exposure_data.crs, inplace=True)

svi_exp_joined = gpd.sjoin(
exposure_data, svi.svi_data_shp, how="left"
)
svi_exp_joined.drop(columns=['geometry'], inplace=True)
svi_exp_joined = gpd.sjoin(exposure_data, svi.svi_data_shp, how="left")
svi_exp_joined.drop(columns=["geometry"], inplace=True)
svi_exp_joined = pd.DataFrame(svi_exp_joined)
self.exposure.exposure_db = svi_exp_joined

# exposure opnieuw opslaan in self._tables

# TODO: geometries toevoegen aan de dataset met API
# we now use the shape download function by the census, the user needs to download their own shape data. They can download this from: https://www.census.gov/cgi-bin/geo/shapefiles/index.php
# #wfs python get request -> geometries

# this link can be used: https://github.com/datamade/census

# Update functions
def update_all(self):
self.logger.info("Updating all data objects...")
Expand All @@ -616,12 +605,16 @@ def update_tables(self):
def update_geoms(self):
# Update the exposure data geoms
if self.exposure and "exposure" in self._tables:
for i, geom in enumerate(self.exposure.exposure_geoms):
file_suffix = i if i > 0 else ""
self.set_geoms(geom=geom, name=f"exposure{file_suffix}")
for i, geom_and_name in enumerate(
zip(self.exposure.exposure_geoms, self.exposure.geom_names)
):
geom = geom_and_name[0]
name = geom_and_name[1]

self.set_geoms(geom=geom, name=name)
self.set_config(
f"exposure.geom.file{str(i+1)}",
f"./exposure/exposure{file_suffix}.gpkg",
f"./exposure/{name}.gpkg",
)

if not self.region.empty:
Expand All @@ -632,7 +625,8 @@ def update_maps(self):

# I/O
def read(self):
"""Method to read the complete model schematization and configuration from file."""
"""Method to read the complete model schematization and configuration from
file."""
self.logger.info(f"Reading model data from {self.root}")

# Read the configuration file
Expand All @@ -654,13 +648,6 @@ def _configread(self, fn):
config = Config()
return config.load_file(fn)

def check_path_exists(self, fn):
"""TODO: decide to use this or another function (check_file_exist in py)"""
path = Path(fn)
self.logger.debug(f"Reading file {str(path.name)}")
if not fn.is_file():
logging.warning(f"File {fn} does not exist!")

def read_tables(self):
"""Read the model tables for vulnerability and exposure data."""
if not self._write:
Expand Down
34 changes: 19 additions & 15 deletions hydromt_fiat/validation.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from pathlib import Path


def check_dir_exist(dir, name=None):
""" """

if not isinstance(dir, Path):
raise TypeError(
f"The directory indicated by the '{name}' parameter does not exist."
)



def check_file_exist(root, param_lst, name=None):
root = Path(root)
param_lst = [Path(p) for p in param_lst]
Expand Down Expand Up @@ -38,12 +40,13 @@ def check_file_exist(root, param_lst, name=None):
else:
assert isinstance(param_lst[param_idx], Path)
except AssertionError:
raise TypeError(
f"The file indicated by the '{name}' parameter does not"
f" exist in the directory '{root}'."
)

#TODO: Improve this tool without calling model.get_congif(input_dir)
raise TypeError(
f"The file indicated by the '{name}' parameter does not"
f" exist in the directory '{root}'."
)


# TODO: Improve this tool without calling model.get_congif(input_dir)
# def check_file_exist(get_config, root, param_lst, name=None, input_dir=None):
# root = Path(root)
# param_lst = [Path(p) for p in param_lst]
Expand Down Expand Up @@ -96,24 +99,23 @@ def check_file_exist(root, param_lst, name=None):
# f"'{get_config(input_dir)}'."
# )

def check_uniqueness(map_name_lst):

def check_uniqueness(map_name_lst):
def check_duplicates(lst):
unique_elements = set()
for element in lst:
if element in unique_elements:
return True # Found a duplicate
unique_elements.add(element)
return False # No duplicates found

check = check_duplicates(map_name_lst)

if check:
raise ValueError(
f"The filenames of the hazard maps should be unique."
)
if check:
raise ValueError(f"The filenames of the hazard maps should be unique.")


#TODO: Improve this tool without calling model. Just checking the maps names
# TODO: Improve this tool without calling model. Just checking the maps names
# def check_uniqueness(model, *args, file_type=None, filename=None):
# """ """

Expand All @@ -136,6 +138,7 @@ def check_duplicates(lst):
# ):
# raise ValueError(f"Each model input layers must be unique.")


def check_param_type(param, name=None, types=None):
""" """

Expand All @@ -155,6 +158,7 @@ def check_param_type(param, name=None, types=None):
f"{type(i)} instead."
)


def get_param(param_lst, map_fn_lst, file_type, filename, i, param_name):
""" """

Expand All @@ -166,4 +170,4 @@ def get_param(param_lst, map_fn_lst, file_type, filename, i, param_name):
raise IndexError(
f"Could not derive the {param_name} parameter for {file_type} "
f"map: {filename}."
)
)
1 change: 1 addition & 0 deletions hydromt_fiat/workflows/exposure_raster.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

logger = logging.getLogger(__name__)


### TO BE UPDATED ###
class ExposureRaster(Exposure):
def setup_buildings_value(
Expand Down
36 changes: 32 additions & 4 deletions hydromt_fiat/workflows/exposure_vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ def __init__(
)
self.exposure_db = pd.DataFrame()
self.exposure_geoms = list() # A list of GeoDataFrames
self.source = gpd.GeoDataFrame()
self.unit = unit
self._geom_names = list() # A list of (original) names of the geometry (files)

def read_table(self, fn: Union[str, Path]):
"""Read the Delft-FIAT exposure data.
Expand All @@ -102,9 +102,10 @@ def read_geoms(self, fn: Union[List[str], List[Path], str, Path]):
fn = [fn]

for f in fn:
self.set_geom_names(Path(f).stem)
self.set_exposure_geoms(gpd.read_file(f, engine="pyogrio"))

def setup_from_single_source(
def setup_buildings_from_single_source(
self,
source: Union[str, Path],
ground_floor_height: Union[int, float, str, Path, None],
Expand Down Expand Up @@ -178,7 +179,10 @@ def setup_from_single_source(
# Set the geoms from the X and Y coordinates
self.set_exposure_geoms_from_xy()

def setup_from_multiple_sources(
# Set the name to the geom_names
self.set_geom_names("buildings")

def setup_buildings_from_multiple_sources(
self,
asset_locations: Union[str, Path],
occupancy_source: Union[str, Path],
Expand Down Expand Up @@ -235,7 +239,28 @@ def setup_asset_locations(self, asset_locations: str) -> None:
assets["Object ID"] = range(1, len(assets.index) + 1)

# Set the asset locations to the geometry variable (self.exposure_geoms)
# and set the geom name
self.set_exposure_geoms(assets)
self.set_geom_names("buildings")

def set_geom_names(self, name: str) -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just for my understanding: the function set_geom_names is defined here but it is already used above.
is self.set_geom_names somewhere else defined beforehand?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question - I did not even think about it because it just worked. It is indeed used in line 244 and only defined in line 246. I think that is possible because they are functions within a class and they are all loaded at initialization of the class. This page explains a bit more: https://stackoverflow.com/questions/29055698/does-the-order-of-variables-and-functions-matter-in-class-python . If you want to read about classes in Python, the documentation is here: https://docs.python.org/3/tutorial/classes.html, although I don't think it's the most clear documentation

"""Append a name to the list of geometry names `geom_names`."""
self.logger.info(f"Setting geometry name to {name}...")
self._geom_names.append(name)

@property
def geom_names(self) -> List[str]:
"""Returns a list with the geom names."""
if len(self._geom_names) > 0 and len(self.exposure_geoms) > 0:
return self._geom_names
elif len(self._geom_names) == 0 and len(self.exposure_geoms) == 1:
return ["exposure"]
else:
self.logger.warning(
"No geometry names found, returning a list with the default names "
"'exposure_X'."
)
return [f"exposure_{i}" for i in range(len(self.exposure_geoms))]

def set_exposure_geoms(self, gdf: gpd.GeoDataFrame) -> None:
"""Append a GeoDataFrame to the exposure geometries `exposure_geoms`."""
Expand Down Expand Up @@ -856,7 +881,10 @@ def link_exposure_vulnerability(
damage_types: Optional[List[str]] = ["Structure", "Content"],
):
linking_dict = dict(
zip(exposure_linking_table["Exposure Link"], exposure_linking_table["FIAT Damage Function Name"])
zip(
exposure_linking_table["Exposure Link"],
exposure_linking_table["FIAT Damage Function Name"],
)
)

# Find the column to link the exposure data to the vulnerability data
Expand Down
2 changes: 2 additions & 0 deletions hydromt_fiat/workflows/hazard.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ def read_floodmaps(

return da_map_fn, da_name, da_type


def load_floodmaps(
data_catalog: DataCatalog,
region: gpd.GeoDataFrame,
Expand Down Expand Up @@ -316,6 +317,7 @@ def load_floodmaps(

return da


# def load_floodmaps(
# data_catalog: DataCatalog,
# region: gpd.GeoDataFrame,
Expand Down
Loading