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

Vulnerability method csv input #48

Merged
merged 13 commits into from
Mar 16, 2023
Merged
Show file tree
Hide file tree
Changes from 9 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 @@ -115,4 +115,5 @@ venv.bak/
.mypy_cache/

# dask
dask-worker-space/
dask-worker-space/
/local_test_database
48 changes: 21 additions & 27 deletions examples/fiat_flood.ini
frederique-hub marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[global]
artifact_data = True # use latest artifact data
artifact_data = False # use latest artifact data

[setup_config]
case = baseline # name of case
case = test_exposure # name of case
strategy = base # name of strategy (optional)
scenario = base # name of scenario (optional)
year = 2021 # case year (optional)
Expand All @@ -16,36 +16,30 @@ risk_output = True # indicator that specifies whether a risk calculation
map_output = True # indicator that specifies whether the result maps should be included in the output (default is True)

[setup_hazard1]
map_fn = data/flood_hand/hand_050cm_rp02.tif # absolute or relative (with respect to the configuration.ini) path to the hazard file
map_fn = max_depth # absolute or relative (with respect to the configuration.ini) path to the hazard file
map_type = water_depth # description of the hazard file type
rp = 2 # hazard return period in years, required for a risk calculation (optional)
crs = 3452 # coordinate reference system of the hazard file (optional)
rp = None # hazard return period in years, required for a risk calculation (optional)
crs = 4326 # coordinate reference system of the hazard file (optional)
nodata = -9999 # value that is assigned as nodata (optional)
var = None # hazard variable name in NetCDF input files (optional)
chunks = 100 # chunk sizes along each dimension used to load the hazard file into a dask array (default is 'auto') (optional)

[setup_hazard2]
map_fn = data/flood_hand/hand_150cm_rp50.tif # absolute or relative (with respect to the configuration.ini) path to the hazard file
map_type = water_depth # description of the hazard file type
rp = 50 # hazard return period in years, required for a risk calculation (optional)
crs = 3452 # coordinate reference system of the hazard file (optional)
nodata = -9999 # value that is assigned as nodata (optional)
var = None # hazard variable name in NetCDF input files (optional)
chunks = 100 # chunk sizes along each dimension used to load the hazard file into a dask array (default is 'auto') (optional)
; [setup_exposure]
; asset_locations = NSI

[setup_vulnerability]

[setup_buildings_value]
bld_fn = guf_bld_2012 # name tag of or absolute or relative (with respect to the configuration file) path to the building footprint file (default is 'wsf_bld_2015')
pop_fn = ghs_pop_2015_54009 # name tag of or absolute or relative (with respect to the configuration file) path to the population count file (default is 'ghs_pop_2015')
chunks = 100 # chunk sizes along each dimension used to load the building footprint and population count files into a dask arrays (default is 'auto') (optional)
function_fn = None # absolute or relative (with respect to the configuration file or susceptibility_dp) path to the susceptibility file (default is the JCR continental susceptibilty function (https://publications.jrc.ec.europa.eu/repository/handle/JRC105688) related to the country parameter) (optional)
scale_factor = 1 # scaling factor of the exposure values (default is 1) (optional)
weight_factor = 1 # weight factor of the exposure values in the total damage and risk results (default is 1) (optional)
vulnerability_source = AllDFF.xlsx [linking_exposure_vulnerability]

# Alternatives to conduct a risk calculation (triggered by a multiple hazard input):
# [setup_hazard]
# map_fn = [hazard/RP_2.tif, hazard/RP_100.tif] # TODO: Not properly working yet, input is '[.., ..]' instead of ['..', '..']
# rp = [2, 100] # TODO: Not properly working yet, input is not parseble.
name1 = RES1-1SNB-SAzone
BldgDmgFnID1 = 157
Occupancy1 = RES1
Source1 = FIA
Description1 = one floor, no basement, Structure, A-Zone
exposure1 = RES1

# Alternative to derive rp from filename:
# [setup_hazard1]
# map_fn = hazard/RP_*.tif
name2 = COM1blabla
occupancy2 = COM1
source2 = FIA
description2 = choose
exposure2 = COM1
Binary file added hydromt_fiat/data/AllDDF.xlsx
Binary file not shown.
12 changes: 12 additions & 0 deletions hydromt_fiat/data/vulnerability_test_file_input.csv
frederique-hub marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Name,Link,ID,Occupancy,Source,Description
My vulnerability function 1,APT,105,RES1,FIA,"one floor, no basement, Structure, A-Zone"
My vulnerability function 2,APT2,105,RES1,FIA,"one floor, no basement, Structure, A-Zone"
My vulnerability function 3,APT3,105,RES1,FIA,"one floor, no basement, Structure, A-Zone"
My vulnerability function 4,HOUS,693,RES3A,BCAR - Jan 2011,"1to2 Stories, Elevated (Obstr)+6ft - no basement, Coastal A or V Zone"
My vulnerability function 5,SHOP,228,COM1,USACE - Galveston,"Drug Store, structure"
My vulnerability function 6,SHOP2,358,COM2,USACE - Galveston,"T.V. Repair, structure"
My vulnerability function 7,MALL,459,COM4,USACE - New Orleans,"Utility Company, structure, salt water, short duration"
My vulnerability function 8,MALL2,459,COM4,USACE - New Orleans,"Utility Company, structure, salt water, short duration"
My vulnerability function 9,OFFI,550,IND1,USACE - Galveston,"Fabrication Shop, structure"
My vulnerability function 10,HOUS2,699,RES3A,BCAR - Jan 2011,"1to2 Stories, Elevated (Obstr)+10ft - no basement, Coastal A or V Zone"
My vulnerability function 11,HOUS3,699,RES3A,BCAR - Jan 2011,"1to2 Stories, Elevated (Obstr)+10ft - no basement, Coastal A or V Zone"
8 changes: 5 additions & 3 deletions hydromt_fiat/fiat.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""Implement fiat model class"""

import logging
from hydromt.models.model_api import Model
from hydromt_fiat.reader import Reader
from hydromt_fiat.writer import Writer
import logging
from hydromt_fiat.workflows.vulnerability import Vulnerability


from . import DATADIR
Expand Down Expand Up @@ -54,8 +55,9 @@ def setup_exposure_vector(self, region, **kwargs):
def setup_exposure_raster(self):
NotImplemented

def setup_vulnerability(self):
NotImplemented
def setup_vulnerability(self, vulnerability_source, vulnerability_identifiers_and_linking):
vul = Vulnerability(self.data_catalog)
vul.get_vulnerability_function(vulnerability_source, vulnerability_identifiers_and_linking)

def setup_hazard(self):
NotImplemented
Expand Down
10 changes: 10 additions & 0 deletions hydromt_fiat/vulnerability_test_file_output.csv
frederique-hub marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#UNIT=meter
water depth,RES1,RES2,COM1
-1,0,0,0
0,0.2,0,0.2
1,0.3,0.2,0.3
2,0.4,0.5,0.4
3,0.6,0.7,0.6
4,1,0.9,1
5,1,1,1
6,1,1,1
85 changes: 65 additions & 20 deletions hydromt_fiat/workflows/vulnerability.py
Copy link
Collaborator

Choose a reason for hiding this comment

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

We can split the get_vulnerability_function into multiple functions.

Original file line number Diff line number Diff line change
@@ -1,27 +1,72 @@
import pandas as pd
import numpy as np
from pathlib import Path
from hydromt.data_catalog import DataCatalog
import re

### TO BE UPDATED ###
class Vulnerability:
def get_susceptibility_function(self):
def __init__(self, data_catalog: DataCatalog):
self.data_catalog = data_catalog

def get_vulnerability_function(self, vulnerability_source, vulnerability_identifiers_and_linking):
# TODO: @Luis: this function needs to be changed. Now it looks up a damage function
# according to country that is chosen but we want the user to choose their
# damage functions per category (res, com, etc.). So our function will be
# quite different.
"""Return the susceptibility function id and the maximum damage number."""

# Read the global exposure configuration.
df_config = pd.read_excel(
Path(self._DATADIR).joinpath("global_configuration.xlsx"),
sheet_name="Buildings",
)

# Get the function id.
sf_id = df_config.loc[
df_config["Alpha-3"] == self.config["country"],
f"Damage_Function_ID_{self.config['hazard_type'].capitalize()}",
].values[0]

# Get the maximum damage value.
max_damage = df_config.loc[
df_config["Alpha-3"] == self.config["country"],
f"Max_Damage_{self.config['hazard_type']. capitalize()}",
].values[0]

return sf_id, max_damage
# Save the source vulnerabilities and input vulnerability identifiers and linking as data frames.
df_source = self.data_catalog.get_dataframe(vulnerability_source)

# USER INPUT, read csv generated via gui or manually inputted
df_identifiers_linking = pd.read_csv(vulnerability_identifiers_and_linking)

# Identify the unique combinations of values from the identifiers and linking data frame that will be used to select subsets of values from the source data frame.
# unique_combinations = df_identifiers_linking.groupby(['ID', 'Occupancy', 'Source', 'Description']).nunique().reset_index()

# Initialize an empty list to hold the subsets
subsets = []

# Loop over the unique combinations of values
for i in range(len(df_identifiers_linking)):
# Use the unique combination of values to select the corresponding subset of values
# from the first data frame using boolean indexing
subset = df_source.loc[(df_source['BldgDmgFnID'] == df_identifiers_linking.loc[i, 'ID']) &
(df_source['Occupancy'] == df_identifiers_linking.loc[i, 'Occupancy']) &
(df_source['Source'] == df_identifiers_linking.loc[i, 'Source']) &
(df_source['Description'] == df_identifiers_linking.loc[i, 'Description'])]

# # Check if the subset is empty
# if subset.empty:
# print(f"No values found for unique combination {df_identifiers_linking.loc[i]}")
# else:
# print(f"Values found for unique combination {df_identifiers_linking.loc[i]}")

# Append the subset of values to the list of subsets
subsets.append(subset)

# Concatenate all of the necessary vulnerability curves info into a single data frame using pd.concat()
combined_df = pd.concat(subsets, ignore_index=True)

# Get vulnerability factors and apply FIAT format.
vf_values_only = combined_df.values.T[4:-1] /100

vf_water_depths_numbers = np.arange(-4,25)
vf_water_depths = np.array(vf_water_depths_numbers.reshape(-1,1))
vf_raw = np.hstack([vf_water_depths,vf_values_only])

top_header_array = np.full((1, vf_names_header.shape[0]), fill_value="", dtype='<U100')
top_header_array[0, 0] = "#UNIT=feet"

vf_names = df_identifiers_linking['Name'].values
vf_names_header = np.append('water depth', vf_names).reshape(top_header_array.shape)

vf_fiat_format = np.concatenate([top_header_array, vf_names_header, vf_raw])

# Create a dataframe out of the previous array.
v_dataframe = pd.DataFrame(vf_fiat_format)

# Export the dataframe to a csv.
v_dataframe.to_csv('vulnerability_test_file_output.csv', index=False, header=False)

29 changes: 25 additions & 4 deletions tests/test_vulnerability.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,30 @@
from hydromt_fiat.workflows.vulnerability import Vulnerability
from hydromt_fiat.fiat import FiatModel
from hydromt.config import configread
from pathlib import Path
import pytest

EXAMPLEDIR = Path().absolute() / "examples"
EXAMPLEDIR = Path().absolute() / "local_test_database"

_cases = {
"vulnerability": {
"data_catalogue": EXAMPLEDIR / "fiat_catalog.yml",
"dir": "test_vulnerability",
"ini": EXAMPLEDIR / "test_vulnerability.ini",
},
}

def test_vulnerability_class_initialization():
@pytest.mark.parametrize("case", list(_cases.keys()))
def test_vulnerability_class_initialization(case):
# Read model in examples folder.
Vulnerability()
root = EXAMPLEDIR.joinpath(_cases[case]["dir"])
data_catalog_yml = str(_cases[case]["data_catalogue"])

fm = FiatModel(
root=root,
mode="w",
data_libs=[data_catalog_yml],
)

opt = configread(_cases[case]["ini"])
fm.build(opt=opt)

31 changes: 31 additions & 0 deletions vulnerability_test_file_output.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#UNIT=feet,,,,,,,,,,,
water depth,My vulnerability function 1,My vulnerability function 2,My vulnerability function 3,My vulnerability function 4,My vulnerability function 5,My vulnerability function 6,My vulnerability function 7,My vulnerability function 8,My vulnerability function 9,My vulnerability function 10,My vulnerability function 11
-4,0,0,0,0.08,0,0,0,0,0,0.38,0.38
-3,0,0,0,0.17,0,0,0,0,0,0.78,0.78
-2,0,0,0,0.53,0,0,0,0,0,1,1
-1,0,0,0,0.93,0,0,0,0,0,1,1
0,0.18,0.18,0.18,1,0,0,0,0,0,1,1
1,0.22,0.22,0.22,1,0.01,0.02,0.72,0.72,0.02,1,1
2,0.25,0.25,0.25,1,0.05,0.06,0.72,0.72,0.05,1,1
3,0.28,0.28,0.28,1,0.05,0.12,1,1,0.1,1,1
4,0.3,0.3,0.3,1,0.05,0.15,1,1,0.15,1,1
5,0.31,0.31,0.31,1,0.07,0.2,1,1,0.2,1,1
6,0.4,0.4,0.4,1,0.08,0.25,1,1,0.25,1,1
7,0.43,0.43,0.43,1,0.11,0.32,1,1,0.3,1,1
8,0.43,0.43,0.43,1,0.14,0.41,1,1,0.35,1,1
9,0.45,0.45,0.45,1,0.18,0.5,1,1,0.4,1,1
10,0.46,0.46,0.46,1,0.22,0.57,1,1,0.5,1,1
11,0.47,0.47,0.47,1,0.27,0.61,1,1,0.75,1,1
12,0.47,0.47,0.47,1,0.33,0.66,1,1,0.75,1,1
13,0.49,0.49,0.49,1,0.38,0.69,1,1,0.75,1,1
14,0.5,0.5,0.5,1,0.45,0.72,1,1,0.75,1,1
15,0.5,0.5,0.5,1,0.51,0.75,1,1,0.75,1,1
16,0.5,0.5,0.5,1,0.57,0.77,1,1,0.75,1,1
17,0.51,0.51,0.51,1,0.63,0.8,1,1,0.75,1,1
18,0.51,0.51,0.51,1,0.68,0.82,1,1,0.75,1,1
19,0.52,0.52,0.52,1,0.73,0.84,1,1,0.75,1,1
20,0.52,0.52,0.52,1,0.78,0.86,1,1,0.75,1,1
21,0.53,0.53,0.53,1,0.83,0.88,1,1,0.75,1,1
22,0.53,0.53,0.53,1,0.88,0.9,1,1,0.75,1,1
23,0.54,0.54,0.54,1,0.93,0.92,1,1,0.75,1,1
24,0.54,0.54,0.54,1,0.98,0.94,1,1,0.75,1,1