Skip to content

Commit

Permalink
Merge pull request #223 from Deltares/gui-updates
Browse files Browse the repository at this point in the history
Update with Model Builder GUI/API updates
  • Loading branch information
Santonia27 authored Dec 11, 2023
2 parents 6def1ce + bf101c8 commit a29d391
Show file tree
Hide file tree
Showing 24 changed files with 3,967 additions and 352 deletions.
13 changes: 7 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,16 @@ cache
hydromt_fiat/data/damage_functions/flooding/AllDDF_HAZUS_fractions.xlsx
hydromt_fiat/data/damage_functions/flooding/Hazus_IWR_curves.csv
hydromt_fiat/data/damage_functions/flooding/Hazus_IWR_curves.xlsx
examples/data/update_ground_floor_height/test_update_ground_floor_height_points
examples/data/update_ground_floor_height/test_update_ground_floor_height_polygons
examples/data/building_footprints/fiat_model_bfs
examples/data/aggregation_zones/output

# notebooks
/examples/aggregation_zones_example_files
/examples/aggregation_zones_example_files/
/examples/data/aggregation_zones/aggregation_zones_test1/
/examples/data/aggregation_zones/aggregation_zones_test2/
examples/aggregation_zones_example.html
examples/aggregation_zones_example_files/
examples/data/road_network/FIAT model
examples/data/road_network/FIAT model/
examples/data/global_OSM_JRC/fiat_model/
examples/data/update_ground_floor_height/test_update_ground_floor_height_points/
examples/data/update_ground_floor_height/test_update_ground_floor_height_polygons/
examples/data/building_footprints/fiat_model_bfs/
examples/data/aggregation_zones/output/
1 change: 1 addition & 0 deletions envs/hydromt-fiat-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ dependencies:
- black
- gdal>=3.1
- geopandas
- geopy
- hydromt=0.8.0
- hydromt_sfincs
- numpy
Expand Down
60 changes: 47 additions & 13 deletions hydromt_fiat/api/data_types.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from enum import Enum
from typing_extensions import Optional, TypedDict, Union, List

from pydantic import BaseModel
from pydantic import BaseModel, Extra


class ExtractionMethod(str, Enum):
Expand All @@ -10,8 +10,8 @@ class ExtractionMethod(str, Enum):


class Units(str, Enum):
m = "meter"
ft = "feet"
m = "m"
ft = "ft"


class Category(str, Enum):
Expand Down Expand Up @@ -46,14 +46,17 @@ class DataCatalogEntry(BaseModel):
meta: Meta


class ModelIni(BaseModel):
site_name: str
scenario_name: str
class GlobalSettings(BaseModel):
crs: Union[str, int]


class OutputSettings(BaseModel):
output_dir: str
crs: str
output_csv_name: str
output_vector_name: str


class VulnerabilityIni(BaseModel):
class VulnerabilitySettings(BaseModel):
vulnerability_fn: str
vulnerability_identifiers_and_linking_fn: str
unit: Units
Expand All @@ -62,7 +65,7 @@ class VulnerabilityIni(BaseModel):
step_size: Union[float, None]


class ExposureBuildingsIni(BaseModel):
class ExposureBuildingsSettings(BaseModel):
asset_locations: str
occupancy_type: str
max_potential_damage: str
Expand All @@ -72,7 +75,38 @@ class ExposureBuildingsIni(BaseModel):
damage_types : Union[List[str], None]


class ConfigIni(BaseModel):
setup_config: ModelIni
setup_vulnerability: VulnerabilityIni
setup_exposure_buildings: ExposureBuildingsIni
class RoadVulnerabilitySettings(BaseModel):
threshold_value: float
min_hazard_value: float
max_hazard_value: float
step_hazard_value: float
vertical_unit: Units


class ExposureRoadsSettings(BaseModel):
roads_fn: str
road_types: Union[List[str], bool]
road_damage: str
unit: Units


class AggregationAreaSettings(BaseModel):
aggregation_area_fn: Union[List[str], str]
attribute_names: Union[List[str], str]
label_names: Union[List[str], str]


class SocialVulnerabilityIndexSettings(BaseModel):
census_key: str
codebook_fn: str
year_data: int


class EquityDataSettings(BaseModel):
census_key: str
year_data: int


class ConfigYaml(BaseModel, extra=Extra.allow):
setup_global_settings: GlobalSettings
setup_output: OutputSettings
97 changes: 75 additions & 22 deletions hydromt_fiat/api/exposure_vm.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict, Optional, Union
from typing import Dict, Optional, Union, List

from hydromt import DataCatalog

Expand All @@ -12,8 +12,10 @@
DataCatalogEntry,
DataType,
Driver,
ExposureBuildingsIni,
ExposureBuildingsSettings,
ExposureRoadsSettings,
ExtractionMethod,
AggregationAreaSettings,
Units,
)

Expand All @@ -22,15 +24,10 @@ class ExposureViewModel:
def __init__(
self, database: IDatabase, data_catalog: DataCatalog, logger: logging.Logger
):
self.exposure_model = ExposureBuildingsIni(
asset_locations="",
occupancy_type="",
max_potential_damage=-999,
ground_floor_height=-999,
unit=Units.m.value,
extraction_method=ExtractionMethod.centroid.value,
damage_types=["structure", "content"]
)
self.exposure_buildings_model = None
self.exposure_roads_model = None
self.aggregation_areas_model = None

self.database: IDatabase = database
self.data_catalog: DataCatalog = data_catalog
self.logger: logging.Logger = logger
Expand All @@ -53,17 +50,21 @@ def create_interest_area(self, **kwargs: str):

def set_asset_locations_source(
self,
input_source: str,
source: str,
fiat_key_maps: Optional[Dict[str, str]] = None,
crs: Union[str, int] = None,
):
if input_source == "NSI":
if source == "NSI":
# NSI is already defined in the data catalog
self.exposure_model.asset_locations = input_source
self.exposure_model.occupancy_type = input_source
self.exposure_model.max_potential_damage = input_source
self.exposure_model.ground_floor_height = input_source
self.exposure_model.unit = Units.ft.value # TODO: make flexible
self.exposure_buildings_model = ExposureBuildingsSettings(
asset_locations=source,
occupancy_type=source,
max_potential_damage=source,
ground_floor_height=source,
unit=Units.ft.value, # TODO: make flexible
extraction_method=ExtractionMethod.centroid.value,
damage_types=["structure", "content"],
)

# Download NSI from the database
region = self.data_catalog.get_geodataframe("area_of_interest")
Expand All @@ -75,8 +76,8 @@ def set_asset_locations_source(
)

self.exposure.setup_buildings_from_single_source(
input_source,
self.exposure_model.ground_floor_height,
source,
self.exposure_buildings_model.ground_floor_height,
"centroid", # TODO: MAKE FLEXIBLE
)
primary_object_types = (
Expand All @@ -93,14 +94,14 @@ def set_asset_locations_source(
secondary_object_types,
)

elif input_source == "file" and fiat_key_maps is not None:
elif source == "file" and fiat_key_maps is not None:
# maybe save fiat_key_maps file in database
# make calls to backend to derive file meta info such as crs, data type and driver
crs: str = "4326"
# save keymaps to database

catalog_entry = DataCatalogEntry(
path=input_source,
path=source,
data_type="GeoDataFrame",
driver="vector",
crs=crs,
Expand All @@ -111,6 +112,58 @@ def set_asset_locations_source(
print(catalog_entry)
# write to data catalog

def set_asset_data_source(self, source):
self.exposure_buildings_model.asset_locations = source

def setup_extraction_method(self, extraction_method):
if self.exposure:
self.exposure.setup_extraction_method(extraction_method)

def get_osm_roads(
self,
road_types: List[str] = [
"motorway",
"motorway_link",
"trunk",
"trunk_link",
"primary",
"primary_link",
"secondary",
"secondary_link",
],
crs=4326,
):
if self.exposure is None:
region = self.data_catalog.get_geodataframe("area_of_interest")
self.exposure = ExposureVector(
data_catalog=self.data_catalog,
logger=self.logger,
region=region,
crs=crs,
)

self.exposure.setup_roads(
source="OSM",
road_damage="default_road_max_potential_damages",
road_types=road_types,
)
roads = self.exposure.exposure_db.loc[
self.exposure.exposure_db["Primary Object Type"] == "roads"
]
gdf = self.exposure.get_full_gdf(roads)

self.exposure_roads_model = ExposureRoadsSettings(
roads_fn="OSM",
road_types=road_types,
road_damage="default_road_max_potential_damages",
unit=Units.ft.value,
)

return gdf

def set_aggregation_areas_config(self, files, attribute_names, label_names):
self.aggregation_areas_model = AggregationAreaSettings(
aggregation_area_fn=files,
attribute_names=attribute_names,
label_names=label_names,
)
55 changes: 38 additions & 17 deletions hydromt_fiat/api/hydromt_fiat_vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
from hydromt import DataCatalog
from pathlib import Path

from hydromt_fiat.api.data_types import ConfigIni
from hydromt_fiat.api.data_types import ConfigYaml
from hydromt_fiat.api.dbs_controller import LocalDatabase
from hydromt_fiat.api.exposure_vm import ExposureViewModel
from hydromt_fiat.api.model_vm import ModelViewModel
from hydromt_fiat.api.vulnerability_vm import VulnerabilityViewModel
from hydromt_fiat.api.svi_vm import SviViewModel
from hydromt_fiat.fiat import FiatModel
from hydromt.log import setuplog

Expand Down Expand Up @@ -43,6 +44,9 @@ def __init__(
self.vulnerability_vm = VulnerabilityViewModel(
HydroMtViewModel.database, HydroMtViewModel.data_catalog, logger
)
self.svi_vm = SviViewModel(
HydroMtViewModel.database, HydroMtViewModel.data_catalog, logger
)

def clear_database(self):
# TODO: delete database after hydromt_fiat has run
Expand All @@ -52,29 +56,46 @@ def save_data_catalog(self):
database_path = self.__class__.database.drive
self.__class__.data_catalog.to_yml(database_path / "data_catalog.yml")

def build_config_ini(self):
config_ini = ConfigIni(
setup_config=self.model_vm.config_model,
setup_vulnerability=self.vulnerability_vm.vulnerability_model,
setup_exposure_buildings=self.exposure_vm.exposure_model,
def build_config_yaml(self):
config_yaml = ConfigYaml(
setup_global_settings=self.model_vm.global_settings_model,
setup_output=self.model_vm.output_model,
)

if self.vulnerability_vm.vulnerability_buildings_model:
config_yaml.setup_vulnerability = self.vulnerability_vm.vulnerability_buildings_model

if self.exposure_vm.exposure_buildings_model:
config_yaml.setup_exposure_buildings = self.exposure_vm.exposure_buildings_model

if self.exposure_vm.aggregation_areas_model:
config_yaml.setup_aggregation_areas = self.exposure_vm.aggregation_areas_model

if self.exposure_vm.exposure_roads_model:
config_yaml.setup_exposure_roads = self.exposure_vm.exposure_roads_model

if self.vulnerability_vm.vulnerability_roads_model:
config_yaml.setup_road_vulnerability = self.vulnerability_vm.vulnerability_roads_model

if self.svi_vm.svi_model:
config_yaml.setup_social_vulnerability_index = self.svi_vm.svi_model

if self.svi_vm.equity_model:
config_yaml.setup_equity_data = self.svi_vm.equity_model

database_path = self.__class__.database.drive

with open(database_path / "config.ini", "wb") as f:
tomli_w.dump(config_ini.dict(exclude_none=True), f)
with open(database_path / "config.yaml", "wb") as f:
tomli_w.dump(config_yaml.dict(exclude_none=True), f)

return config_yaml

def read(self):
self.fiat_model.read()

def run_hydromt_fiat(self):
config_ini = ConfigIni(
setup_config=self.model_vm.config_model,
setup_vulnerability=self.vulnerability_vm.vulnerability_model,
setup_exposure_buildings=self.exposure_vm.exposure_model,
)
region = self.data_catalog.get_geodataframe("area_of_interest")
self.fiat_model.build(region={"geom": region}, opt=config_ini.dict())
self.fiat_model.write()
self.save_data_catalog()
config_yaml = self.build_config_yaml()


region = self.data_catalog.get_geodataframe("area_of_interest")
self.fiat_model.build(region={"geom": region}, opt=config_yaml.dict())
9 changes: 6 additions & 3 deletions hydromt_fiat/api/model_vm.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from hydromt_fiat.api.data_types import ModelIni
from hydromt_fiat.api.data_types import OutputSettings, GlobalSettings


class ModelViewModel:
def __init__(self):
self.config_model = ModelIni(
site_name="", scenario_name="", output_dir="", crs=""
self.global_settings_model = GlobalSettings(crs=4326)
self.output_model = OutputSettings(
output_dir="output",
output_csv_name="output.csv",
output_vector_name="spatial.gpkg",
)
Loading

0 comments on commit a29d391

Please sign in to comment.