Spaces:
Runtime error
Runtime error
Commit
·
00ba576
1
Parent(s):
fe20df4
Completed (eq,fl,ls) x (bld,pwr,road) combinations
Browse files
tomorrowcities/backend/engine.py
CHANGED
|
@@ -45,17 +45,40 @@ def compute_road_infra(buildings, household, individual,
|
|
| 45 |
gdf_buildings = gpd.sjoin_nearest(gdf_buildings,gdf_nodes,
|
| 46 |
how='left', rsuffix='road_node',distance_col='road_node_distance')
|
| 47 |
|
| 48 |
-
if hazard in ['flood', 'debris']:
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
elif hazard == 'earthquake':
|
| 60 |
fragility = fragility.rename(columns={"med_slight": "med_ds1",
|
| 61 |
"med_moderate": "med_ds2",
|
|
@@ -124,11 +147,18 @@ def compute_road_infra(buildings, household, individual,
|
|
| 124 |
# For each individual, find the closest road node (closest) of the
|
| 125 |
# household and the facility
|
| 126 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
individual_w_nodes = individual.merge(household_w_node_id[['hhid','node_id']],on='hhid',how='left')\
|
| 128 |
.rename(columns={'node_id':'household_node_id'})\
|
| 129 |
.merge(gdf_buildings[['bldid','node_id']],how='left',left_on='indivfacid',right_on='bldid')\
|
| 130 |
.rename(columns={'node_id':'facility_node_id'})
|
| 131 |
-
|
|
|
|
| 132 |
# Calculate distances between all nodes in the damaged network
|
| 133 |
shortest_distance = nx.shortest_path_length(G_dmg)
|
| 134 |
|
|
@@ -140,11 +170,13 @@ def compute_road_infra(buildings, household, individual,
|
|
| 140 |
connection_dict[source][target] = True
|
| 141 |
|
| 142 |
# Based on connectivity, fill-in facillity_access attribute in the individual layer
|
|
|
|
| 143 |
individual_w_nodes['facility_access'] = individual_w_nodes.apply(lambda x: x['facility_node_id'] in connection_dict[x['household_node_id']].keys(),axis=1)
|
| 144 |
|
| 145 |
return gdf_edges['ds'], gdf_edges['is_damaged'], gdf_buildings['node_id'], gdf_buildings['hospital_access'], household_w_node_id['node_id'], household_w_node_id['hospital_access'], individual_w_nodes['facility_access']
|
| 146 |
|
| 147 |
-
def compute_power_infra(buildings, household, nodes,edges,intensity,fragility,hazard
|
|
|
|
| 148 |
print('Computing power infrastructure')
|
| 149 |
print(nodes.head())
|
| 150 |
print(edges.head())
|
|
@@ -192,7 +224,8 @@ def compute_power_infra(buildings, household, nodes,edges,intensity,fragility,ha
|
|
| 192 |
"beta_moderate": "beta_ds2",
|
| 193 |
"beta_extensive": "beta_ds3",
|
| 194 |
"beta_complete": "beta_ds4"})
|
| 195 |
-
gdf_nodes = gdf_nodes.merge(fragility, how='left',left_on='eq_vuln',right_on='vuln_string')
|
|
|
|
| 196 |
nulls = gdf_nodes['med_ds1'].isna()
|
| 197 |
gdf_nodes.loc[nulls, ['med_ds1','med_ds2','med_ds3','med_ds4']] = [99999,99999,99999,99999]
|
| 198 |
gdf_nodes.loc[nulls, ['beta_ds1','beta_ds2','beta_ds3','beta_ds4']] = [1,1,1,1]
|
|
@@ -209,6 +242,39 @@ def compute_power_infra(buildings, household, nodes,edges,intensity,fragility,ha
|
|
| 209 |
gdf_nodes[f'ds_{i}'] = np.abs(gdf_nodes[f'prob_ds{i-1}'] - gdf_nodes[f'prob_ds{i}'])
|
| 210 |
df_ds = gdf_nodes[['ds_1','ds_2','ds_3','ds_4','ds_5']]
|
| 211 |
gdf_nodes['ds'] = df_ds.idxmax(axis='columns').str.extract(r'ds_([0-9]+)').astype('int') - 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
|
| 213 |
# All Nodes
|
| 214 |
all_nodes = set(gdf_nodes['node_id'])
|
|
@@ -346,8 +412,28 @@ def compute(gdf_landuse, gdf_buildings, df_household, df_individual,gdf_intensit
|
|
| 346 |
gdf_building_intensity['rnd'] = np.random.random((len(gdf_building_intensity),1))
|
| 347 |
|
| 348 |
if hazard_type == "landslide":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 349 |
gdf_building_collapse_prob = gdf_building_intensity.merge(df_hazard,
|
| 350 |
-
on=
|
|
|
|
|
|
|
|
|
|
| 351 |
gdf_building_collapse_prob['ds'] = DS_NO
|
| 352 |
collapsed_idx = (gdf_building_collapse_prob['rnd'] < gdf_building_collapse_prob['collapse_probability'])
|
| 353 |
gdf_building_collapse_prob.loc[collapsed_idx, 'ds'] = DS_COLLAPSED
|
|
|
|
| 45 |
gdf_buildings = gpd.sjoin_nearest(gdf_buildings,gdf_nodes,
|
| 46 |
how='left', rsuffix='road_node',distance_col='road_node_distance')
|
| 47 |
|
| 48 |
+
if hazard in ['flood', 'debris','landslide']:
|
| 49 |
+
gdf_edges = gpd.sjoin_nearest(gdf_edges, gdf_intensity, how='left',
|
| 50 |
+
rsuffix='intensity',distance_col='distance')
|
| 51 |
+
# TODO: sjoin_nearest or the approach below: compare
|
| 52 |
+
#roads_with_width = gdf_edges['geometry'].buffer(threshold_flood_distance)
|
| 53 |
+
#for i, road in enumerate(roads_with_width):
|
| 54 |
+
# print(i)
|
| 55 |
+
# within_ims = gdf_intensity.clip(road)
|
| 56 |
+
# if len(within_ims) > 0:
|
| 57 |
+
# max_im = within_ims['im'].max()
|
| 58 |
+
# else:
|
| 59 |
+
# max_im = 0
|
| 60 |
+
# gdf_edges.loc[i,'im'] = max_im
|
| 61 |
+
if hazard == 'landslide':
|
| 62 |
+
print('before')
|
| 63 |
+
print(gdf_edges.loc[0])
|
| 64 |
+
gdf_edges['susceptibility'] = 'low'
|
| 65 |
+
gdf_edges.loc[gdf_edges['im'] == 2.0, 'susceptibility'] = 'medium'
|
| 66 |
+
gdf_edges.loc[gdf_edges['im'] == 3.0, 'susceptibility'] = 'high'
|
| 67 |
+
|
| 68 |
+
fragility['landslide_expstr'] = fragility['expstr'].astype(str) + "+"+ fragility["susceptibility"].astype(str)
|
| 69 |
+
gdf_edges['landslide_expstr'] = 'roads'
|
| 70 |
+
gdf_edges['landslide_expstr'] = gdf_edges['landslide_expstr'] + "+" + gdf_edges['susceptibility'].astype(str)
|
| 71 |
+
gdf_edges = gdf_edges.merge(fragility, on='landslide_expstr', how='left')
|
| 72 |
+
gdf_edges['ds'] = DS_NO
|
| 73 |
+
gdf_edges['rnd'] = np.random.random((len(gdf_edges),1))
|
| 74 |
+
collapsed_idx = (gdf_edges['rnd'] < gdf_edges['collapse_probability'])
|
| 75 |
+
gdf_edges.loc[collapsed_idx, 'ds'] = DS_COMPLETE
|
| 76 |
+
gdf_edges.loc[collapsed_idx, 'is_damaged'] = True
|
| 77 |
+
print('after')
|
| 78 |
+
print(gdf_edges.loc[0])
|
| 79 |
+
else:
|
| 80 |
+
gdf_edges.loc[gdf_edges['im'] > road_water_height_threshold, 'ds'] = 1
|
| 81 |
+
gdf_edges.loc[gdf_edges['im'] > road_water_height_threshold, 'is_damaged'] = True
|
| 82 |
elif hazard == 'earthquake':
|
| 83 |
fragility = fragility.rename(columns={"med_slight": "med_ds1",
|
| 84 |
"med_moderate": "med_ds2",
|
|
|
|
| 147 |
# For each individual, find the closest road node (closest) of the
|
| 148 |
# household and the facility
|
| 149 |
|
| 150 |
+
print('individua')
|
| 151 |
+
print(individual)
|
| 152 |
+
print('household_w_node_id')
|
| 153 |
+
print(household_w_node_id)
|
| 154 |
+
print('gdf_buildings')
|
| 155 |
+
print(gdf_buildings)
|
| 156 |
individual_w_nodes = individual.merge(household_w_node_id[['hhid','node_id']],on='hhid',how='left')\
|
| 157 |
.rename(columns={'node_id':'household_node_id'})\
|
| 158 |
.merge(gdf_buildings[['bldid','node_id']],how='left',left_on='indivfacid',right_on='bldid')\
|
| 159 |
.rename(columns={'node_id':'facility_node_id'})
|
| 160 |
+
print('individual_w_nodes')
|
| 161 |
+
print(individual_w_nodes)
|
| 162 |
# Calculate distances between all nodes in the damaged network
|
| 163 |
shortest_distance = nx.shortest_path_length(G_dmg)
|
| 164 |
|
|
|
|
| 170 |
connection_dict[source][target] = True
|
| 171 |
|
| 172 |
# Based on connectivity, fill-in facillity_access attribute in the individual layer
|
| 173 |
+
print(individual_w_nodes)
|
| 174 |
individual_w_nodes['facility_access'] = individual_w_nodes.apply(lambda x: x['facility_node_id'] in connection_dict[x['household_node_id']].keys(),axis=1)
|
| 175 |
|
| 176 |
return gdf_edges['ds'], gdf_edges['is_damaged'], gdf_buildings['node_id'], gdf_buildings['hospital_access'], household_w_node_id['node_id'], household_w_node_id['hospital_access'], individual_w_nodes['facility_access']
|
| 177 |
|
| 178 |
+
def compute_power_infra(buildings, household, nodes,edges,intensity,fragility,hazard,
|
| 179 |
+
threshold_flood, threshold_flood_distance):
|
| 180 |
print('Computing power infrastructure')
|
| 181 |
print(nodes.head())
|
| 182 |
print(edges.head())
|
|
|
|
| 224 |
"beta_moderate": "beta_ds2",
|
| 225 |
"beta_extensive": "beta_ds3",
|
| 226 |
"beta_complete": "beta_ds4"})
|
| 227 |
+
#gdf_nodes = gdf_nodes.merge(fragility, how='left',left_on='eq_vuln',right_on='vuln_string')
|
| 228 |
+
gdf_nodes = gdf_nodes.merge(fragility, how='left',left_on='eq_frgl',right_on='vuln_string')
|
| 229 |
nulls = gdf_nodes['med_ds1'].isna()
|
| 230 |
gdf_nodes.loc[nulls, ['med_ds1','med_ds2','med_ds3','med_ds4']] = [99999,99999,99999,99999]
|
| 231 |
gdf_nodes.loc[nulls, ['beta_ds1','beta_ds2','beta_ds3','beta_ds4']] = [1,1,1,1]
|
|
|
|
| 242 |
gdf_nodes[f'ds_{i}'] = np.abs(gdf_nodes[f'prob_ds{i-1}'] - gdf_nodes[f'prob_ds{i}'])
|
| 243 |
df_ds = gdf_nodes[['ds_1','ds_2','ds_3','ds_4','ds_5']]
|
| 244 |
gdf_nodes['ds'] = df_ds.idxmax(axis='columns').str.extract(r'ds_([0-9]+)').astype('int') - 1
|
| 245 |
+
elif hazard == 'landslide':
|
| 246 |
+
print(gdf_nodes.loc[0])
|
| 247 |
+
gdf_nodes['rnd'] = np.random.random((len(gdf_nodes),1))
|
| 248 |
+
if 'ls_susceptibility' in gdf_nodes.columns:
|
| 249 |
+
gdf_nodes['susceptibility'] = gdf_nodes['ls_susceptibility']
|
| 250 |
+
else:
|
| 251 |
+
gdf_nodes['susceptibility'] = 'low'
|
| 252 |
+
gdf_nodes.loc[gdf_nodes['im'] == 2.0, 'susceptibility'] = 'medium'
|
| 253 |
+
gdf_nodes.loc[gdf_nodes['im'] == 3.0, 'susceptibility'] = 'high'
|
| 254 |
+
fragility['landslide_expstr'] = fragility['expstr'].astype(str) + "+"+ fragility["susceptibility"].astype(str)
|
| 255 |
+
gdf_nodes['landslide_expstr'] = gdf_nodes['ls_frgl'].astype(str) + "+" \
|
| 256 |
+
+ gdf_nodes['susceptibility'].astype(str)
|
| 257 |
+
gdf_nodes = gdf_nodes.merge(fragility, on='landslide_expstr', how='left')
|
| 258 |
+
gdf_nodes['ds'] = DS_NO
|
| 259 |
+
collapsed_idx = (gdf_nodes['rnd'] < gdf_nodes['collapse_probability'])
|
| 260 |
+
gdf_nodes.loc[collapsed_idx, 'ds'] = DS_COMPLETE
|
| 261 |
+
print(gdf_nodes.loc[0])
|
| 262 |
+
elif hazard == 'flood':
|
| 263 |
+
away_from_flood = gdf_nodes['distance'] > threshold_flood_distance
|
| 264 |
+
print('threshold_flood_distance',threshold_flood_distance)
|
| 265 |
+
print('number of distant buildings', len(gdf_nodes.loc[away_from_flood, 'im']))
|
| 266 |
+
gdf_nodes.loc[away_from_flood, 'im'] = 0
|
| 267 |
+
|
| 268 |
+
|
| 269 |
+
gdf_nodes = gdf_nodes.merge(fragility, left_on='fl_vuln', right_on='expstr', how='left')
|
| 270 |
+
x = np.array([0,0.5,1,1.5,2,3,4,5,6])
|
| 271 |
+
y = gdf_nodes[['hw0','hw0_5','hw1','hw1_5','hw2','hw3','hw4','hw5','hw6']].to_numpy()
|
| 272 |
+
xnew = gdf_nodes['im'].to_numpy()
|
| 273 |
+
flood_mapping = interp1d(x,y,axis=1,kind='linear',bounds_error=False, fill_value=(0,1))
|
| 274 |
+
# TODO: find another way for vectorized interpolate
|
| 275 |
+
gdf_nodes['fl_prob'] = np.diag(flood_mapping(xnew))
|
| 276 |
+
gdf_nodes['ds'] = 0
|
| 277 |
+
gdf_nodes.loc[gdf_nodes['fl_prob'] > threshold_flood,'ds'] = 1
|
| 278 |
|
| 279 |
# All Nodes
|
| 280 |
all_nodes = set(gdf_nodes['node_id'])
|
|
|
|
| 412 |
gdf_building_intensity['rnd'] = np.random.random((len(gdf_building_intensity),1))
|
| 413 |
|
| 414 |
if hazard_type == "landslide":
|
| 415 |
+
print('----------up side down prev', gdf_building_intensity.shape)
|
| 416 |
+
print(pd.unique(gdf_building_intensity['im']))
|
| 417 |
+
gdf_building_intensity['susceptibility'] = 'low'
|
| 418 |
+
gdf_building_intensity.loc[gdf_building_intensity['im'] == 2.0, 'susceptibility'] = 'medium'
|
| 419 |
+
gdf_building_intensity.loc[gdf_building_intensity['im'] == 3.0, 'susceptibility'] = 'high'
|
| 420 |
+
print(gdf_building_intensity.loc[0])
|
| 421 |
+
print(gdf_building_intensity.columns)
|
| 422 |
+
print(df_hazard.loc[0])
|
| 423 |
+
df_hazard['landslide_expstr'] = df_hazard['expstr'].astype(str) +"+"+ df_hazard["susceptibility"].astype(str)
|
| 424 |
+
|
| 425 |
+
gdf_building_intensity['landslide_expstr'] = gdf_building_intensity['material'].astype(str) + "+" \
|
| 426 |
+
+ gdf_building_intensity['code_level'].astype(str) + "+" \
|
| 427 |
+
+ gdf_building_intensity["susceptibility"].astype(str)
|
| 428 |
+
print('x1', gdf_building_intensity.columns)
|
| 429 |
+
print('x2', df_hazard.columns)
|
| 430 |
+
|
| 431 |
+
print(len(gdf_building_intensity))
|
| 432 |
gdf_building_collapse_prob = gdf_building_intensity.merge(df_hazard,
|
| 433 |
+
on='landslide_expstr', how='left')
|
| 434 |
+
print('----------up side down ', gdf_building_collapse_prob.shape)
|
| 435 |
+
print(gdf_building_collapse_prob.loc[0])
|
| 436 |
+
print(len(gdf_building_collapse_prob))
|
| 437 |
gdf_building_collapse_prob['ds'] = DS_NO
|
| 438 |
collapsed_idx = (gdf_building_collapse_prob['rnd'] < gdf_building_collapse_prob['collapse_probability'])
|
| 439 |
gdf_building_collapse_prob.loc[collapsed_idx, 'ds'] = DS_COLLAPSED
|
tomorrowcities/components/article.py
CHANGED
|
@@ -6,9 +6,9 @@ from ..data import articles
|
|
| 6 |
@solara.component
|
| 7 |
def ArticleCard(name):
|
| 8 |
article = articles[name]
|
| 9 |
-
with rv.Card(max_width="
|
| 10 |
with solara.Link(f"/docs/{name}"):
|
| 11 |
-
rv.Img(height="
|
| 12 |
rv.CardTitle(children=[article.title])
|
| 13 |
with rv.CardText():
|
| 14 |
solara.Markdown(article.description)
|
|
@@ -21,7 +21,7 @@ def ArticleCard(name):
|
|
| 21 |
def Overview():
|
| 22 |
with solara.ColumnsResponsive(12) as main:
|
| 23 |
with solara.Card():
|
| 24 |
-
with solara.ColumnsResponsive(12, small=6, large=
|
| 25 |
for name in articles:
|
| 26 |
ArticleCard(name)
|
| 27 |
return main
|
|
|
|
| 6 |
@solara.component
|
| 7 |
def ArticleCard(name):
|
| 8 |
article = articles[name]
|
| 9 |
+
with rv.Card(max_width="300px") as main:
|
| 10 |
with solara.Link(f"/docs/{name}"):
|
| 11 |
+
rv.Img(height="150", src=article.image_url)
|
| 12 |
rv.CardTitle(children=[article.title])
|
| 13 |
with rv.CardText():
|
| 14 |
solara.Markdown(article.description)
|
|
|
|
| 21 |
def Overview():
|
| 22 |
with solara.ColumnsResponsive(12) as main:
|
| 23 |
with solara.Card():
|
| 24 |
+
with solara.ColumnsResponsive(12, small=6, large=2):
|
| 25 |
for name in articles:
|
| 26 |
ArticleCard(name)
|
| 27 |
return main
|
tomorrowcities/content/articles/data.md
CHANGED
|
@@ -43,7 +43,8 @@ in the GeoTIFF are labelled such as "PGA", "SA 0.3", "SA 1", etc.
|
|
| 43 |
|
| 44 |
|
| 45 |
## Layers
|
| 46 |
-
The layers supported by tomorrowcities are listed below. In this section, we will cover all of them and provide information so that the users are able to generate data compatible to web application.
|
|
|
|
| 47 |
|
| 48 |
* land use
|
| 49 |
* building
|
|
@@ -55,6 +56,17 @@ The layers supported by tomorrowcities are listed below. In this section, we wi
|
|
| 55 |
* power nodes
|
| 56 |
* power edges
|
| 57 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
### Buildings
|
| 59 |
Buildings are the core component of visioning scenarios. The features of the building with some example data are shown below:
|
| 60 |
|
|
@@ -86,6 +98,26 @@ where
|
|
| 86 |
* **nind (integer)** is the number of individuals living in the household
|
| 87 |
* **commfacid (integer)** is the building identifier of the community facility. In Tomorrow's Cities, it is used to define the hospital associated with the household.
|
| 88 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
### Intensity Measures
|
| 90 |
Whether it is flood, debris or earthquake, every hazard map should contain at least two properties: a point geometry and intensity measure denotes by 'im'. The data can be provided via GeoTIFF or GeoJSON format. TIFF files should contain CRS
|
| 91 |
information so that the engine could map the coordinates to a common CRS to conduct calculations.
|
|
|
|
| 43 |
|
| 44 |
|
| 45 |
## Layers
|
| 46 |
+
The layers supported by tomorrowcities are listed below. In this section, we will cover all of them and provide information so that the users are able to generate data compatible to web application. Unless otherwise
|
| 47 |
+
mentioned, all geo-spatial layers have WGS 84 coordinate reference system with EPSG:4326.
|
| 48 |
|
| 49 |
* land use
|
| 50 |
* building
|
|
|
|
| 56 |
* power nodes
|
| 57 |
* power edges
|
| 58 |
|
| 59 |
+
### Landuse
|
| 60 |
+
Landuse plan is presented as a GeoJSON format whose attributes are given below:
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
|population|status|zone|densitycap|luf|landuse_lu|area|zoneid|floorarear|setback|avgincome|
|
| 64 |
+
|----------|------|----|----------|---|----------|----|------|----------|-------|---------|
|
| 65 |
+
0|None |Agricultural Zone |0.0 |Agricultural Zone |Agricultural Zone |4099.24144134 |4 |0.0 |0.0 |None|
|
| 66 |
+
0| None |Forest Zone |0.0 |Forest Zone |Forest Zone |30843.9849839 |5 |0.0 |0.0 |None|
|
| 67 |
+
7081 |None |Residential Very Low Density |5.0 |Residential-Very Low Density | Agriculture Cum Resedential |1416.16357154 |226 |0.0 |0.0 |lowIncome|
|
| 68 |
+
|
| 69 |
+
|
| 70 |
### Buildings
|
| 71 |
Buildings are the core component of visioning scenarios. The features of the building with some example data are shown below:
|
| 72 |
|
|
|
|
| 98 |
* **nind (integer)** is the number of individuals living in the household
|
| 99 |
* **commfacid (integer)** is the building identifier of the community facility. In Tomorrow's Cities, it is used to define the hospital associated with the household.
|
| 100 |
|
| 101 |
+
### Individuals
|
| 102 |
+
Individual layer is a tabular data which can be stored in Excel or JSON format.
|
| 103 |
+
The attributes are:
|
| 104 |
+
|
| 105 |
+
|hhid|individ|gender|age|head|eduattstat|indivfacid|
|
| 106 |
+
|----|-------|------|---|----|----------|----------|
|
| 107 |
+
|24448| 1| 2| 8| 1| 3| -1|
|
| 108 |
+
|1 |5552 |2 |2 |8 |1 |4 |-1 |
|
| 109 |
+
|2 |31586 |3 |2 |9 |1 |5 |-1 |
|
| 110 |
+
|
| 111 |
+
where
|
| 112 |
+
|
| 113 |
+
* **hhid** refers to household identifier where the individual lives in.
|
| 114 |
+
* **individ** is the unique individual identifier
|
| 115 |
+
* **gender** is a categorical variable for gender: 1: male, 2:female
|
| 116 |
+
* **age** is the age category
|
| 117 |
+
* **head** is a binary feature indicating that the individual is the head of the household
|
| 118 |
+
* **eduattstat** is the education level
|
| 119 |
+
* **indivfacid** is the facility (school or workspace) that the individual is associated with
|
| 120 |
+
|
| 121 |
### Intensity Measures
|
| 122 |
Whether it is flood, debris or earthquake, every hazard map should contain at least two properties: a point geometry and intensity measure denotes by 'im'. The data can be provided via GeoTIFF or GeoJSON format. TIFF files should contain CRS
|
| 123 |
information so that the engine could map the coordinates to a common CRS to conduct calculations.
|
tomorrowcities/pages/engine.py
CHANGED
|
@@ -48,18 +48,7 @@ layers = solara.reactive({
|
|
| 48 |
'pre_processing': identity_preprocess,
|
| 49 |
'extra_cols': {},
|
| 50 |
'attributes_required': [set(['expstr','susceptibility','minor','moderate','severe'])],
|
| 51 |
-
'attributes': [set(['expstr','susceptibility','minor','moderate','severe'])]},
|
| 52 |
-
'landslide susceptibility': {
|
| 53 |
-
'render_order': 21,
|
| 54 |
-
'map_info_tooltip': 'Number of zones in the landslide susceptibility map',
|
| 55 |
-
'data': solara.reactive(None),
|
| 56 |
-
'map_layer': solara.reactive(None),
|
| 57 |
-
'force_render': solara.reactive(False),
|
| 58 |
-
'visible': solara.reactive(False),
|
| 59 |
-
'pre_processing': identity_preprocess,
|
| 60 |
-
'extra_cols': {},
|
| 61 |
-
'attributes_required': [set(['id','susceptibility','geometry'])],
|
| 62 |
-
'attributes': [set(['id','susceptibility','geometry'])]},
|
| 63 |
'building': {
|
| 64 |
'render_order': 50,
|
| 65 |
'map_info_tooltip': 'Number of buildings',
|
|
@@ -159,7 +148,7 @@ layers = solara.reactive({
|
|
| 159 |
'visible': solara.reactive(False),
|
| 160 |
'pre_processing': identity_preprocess,
|
| 161 |
'extra_cols': {'ds': 0, 'is_damaged': False, 'is_operational': True},
|
| 162 |
-
'attributes_required': [set(['geometry', 'node_id', 'pwr_plant', 'n_bldgs'
|
| 163 |
'attributes': [set(['geometry', 'fltytype', 'strctype', 'utilfcltyc', 'indpnode', 'guid',
|
| 164 |
'node_id', 'x_coord', 'y_coord', 'pwr_plant', 'serv_area', 'n_bldgs',
|
| 165 |
'income', 'eq_vuln'])]},
|
|
@@ -346,11 +335,6 @@ def load_app_state():
|
|
| 346 |
def generic_layer_colors(feature):
|
| 347 |
return None
|
| 348 |
|
| 349 |
-
def susceptibility_colors(feature):
|
| 350 |
-
susceptibility = feature['properties']['susceptibility']
|
| 351 |
-
s_to_color = {'low': 'green', 'medium':'orange','high': 'red'}
|
| 352 |
-
return {'fillColor': s_to_color[susceptibility], 'color': s_to_color[susceptibility]}
|
| 353 |
-
|
| 354 |
def generic_layer_click_handler(event=None, feature=None, id=None, properties=None):
|
| 355 |
layers.value['map_info_detail'].set(properties)
|
| 356 |
layers.value['map_info_button'].set("detail")
|
|
@@ -486,9 +470,12 @@ def create_map_layer(df, name):
|
|
| 486 |
if name == "intensity":
|
| 487 |
# Take the largest 500_000 values to display
|
| 488 |
im_col = 'pga' if 'pga' in df.columns else 'im'
|
| 489 |
-
|
|
|
|
|
|
|
|
|
|
| 490 |
locs = np.array([df_limited.geometry.y.to_list(), df_limited.geometry.x.to_list(), df_limited[im_col].to_list()]).transpose().tolist()
|
| 491 |
-
map_layer = ipyleaflet.Heatmap(locations=locs, radius = 5)
|
| 492 |
elif name == "landuse":
|
| 493 |
map_layer = ipyleaflet.GeoJSON(data = json.loads(df.to_json()),
|
| 494 |
style={'opacity': 1, 'dashArray': '9', 'fillOpacity': 0.5, 'weight': 1},
|
|
@@ -537,13 +524,7 @@ def create_map_layer(df, name):
|
|
| 537 |
markers.append(marker)
|
| 538 |
map_layer= ipyleaflet.MarkerCluster(markers=markers,
|
| 539 |
disable_clustering_at_zoom=5)
|
| 540 |
-
|
| 541 |
-
elif name == 'landslide susceptibility':
|
| 542 |
-
map_layer = ipyleaflet.GeoJSON(data = json.loads(df.to_json()),
|
| 543 |
-
style={'opacity': 1, 'dashArray': '9', 'fillOpacity': 0.5, 'weight': 1},
|
| 544 |
-
hover_style={'color': 'white', 'dashArray': '0', 'fillOpacity': 0.5},
|
| 545 |
-
style_callback=susceptibility_colors)
|
| 546 |
-
map_layer.on_click(generic_layer_click_handler)
|
| 547 |
else:
|
| 548 |
map_layer = ipyleaflet.GeoJSON(data = json.loads(df.to_json()),
|
| 549 |
style={'opacity': 1, 'dashArray': '9', 'fillOpacity': 0.5, 'weight': 1},
|
|
@@ -1017,23 +998,35 @@ def ExecutePanel():
|
|
| 1017 |
missing += list(set(["landuse","building","household","individual","intensity","fragility"]) - existing_layers)
|
| 1018 |
elif hazard == "flood":
|
| 1019 |
if "power" in infra:
|
| 1020 |
-
missing += list(set(["power edges","power nodes","intensity","
|
| 1021 |
if "road" in infra:
|
| 1022 |
-
missing += list(set(["road edges","road nodes","intensity"]) - existing_layers)
|
| 1023 |
if "building" in infra:
|
| 1024 |
missing += list(set(["landuse","building","household","individual","intensity","vulnerability"]) - existing_layers)
|
| 1025 |
elif hazard == "landslide":
|
| 1026 |
if "power" in infra:
|
| 1027 |
-
missing += list(set(["power edges","power nodes","landslide fragility"
|
| 1028 |
if "road" in infra:
|
| 1029 |
-
missing += list(set(["road edges","road nodes","landslide fragility"
|
| 1030 |
if "building" in infra:
|
| 1031 |
-
missing += list(set(["landuse","building","household","individual","landslide fragility"
|
| 1032 |
|
| 1033 |
if infra == []:
|
| 1034 |
missing += ['You should select at least one of power, road or building']
|
| 1035 |
return missing == [], missing
|
| 1036 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1037 |
|
| 1038 |
|
| 1039 |
def execute_engine():
|
|
@@ -1047,6 +1040,10 @@ def ExecutePanel():
|
|
| 1047 |
edges = layers.value['layers']['road edges']['data'].value
|
| 1048 |
intensity = layers.value['layers']['intensity']['data'].value
|
| 1049 |
fragility = layers.value['layers']['road fragility']['data'].value
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1050 |
hazard = layers.value['hazard'].value
|
| 1051 |
|
| 1052 |
edges['ds'] = 0
|
|
@@ -1080,9 +1077,16 @@ def ExecutePanel():
|
|
| 1080 |
nodes = layers.value['layers']['power nodes']['data'].value
|
| 1081 |
edges = layers.value['layers']['power edges']['data'].value
|
| 1082 |
intensity = layers.value['layers']['intensity']['data'].value
|
| 1083 |
-
|
| 1084 |
hazard = layers.value['hazard'].value
|
| 1085 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1086 |
|
| 1087 |
ds, is_damaged, is_operational, has_power, household_has_power, hospital_has_power = \
|
| 1088 |
compute_power_infra(buildings,
|
|
@@ -1090,8 +1094,8 @@ def ExecutePanel():
|
|
| 1090 |
nodes,
|
| 1091 |
edges,
|
| 1092 |
intensity,
|
| 1093 |
-
|
| 1094 |
-
hazard)
|
| 1095 |
|
| 1096 |
#power_node_df = dfs['Power Nodes'].copy()
|
| 1097 |
nodes['ds'] = list(ds)
|
|
@@ -1124,7 +1128,6 @@ def ExecutePanel():
|
|
| 1124 |
#print('policies',policies)
|
| 1125 |
if layers.value['hazard'].value == 'landslide':
|
| 1126 |
fragility = layers.value['layers']['landslide fragility']['data'].value
|
| 1127 |
-
intensity = layers.value['layers']['landslide susceptibility']['data'].value
|
| 1128 |
trigger_level= layers.value['landslide_trigger_level'].value
|
| 1129 |
df_bld_hazard = compute(
|
| 1130 |
landuse,
|
|
@@ -1180,9 +1183,15 @@ def ExecutePanel():
|
|
| 1180 |
is_ready, missing = is_ready_to_run(layers.value['infra'].value, layers.value['hazard'].value)
|
| 1181 |
if not is_ready:
|
| 1182 |
raise Exception(f'Missing {missing}')
|
|
|
|
|
|
|
|
|
|
| 1183 |
max_trials = landslide_max_trials.value if layers.value['hazard'].value == "landslide" else 1
|
| 1184 |
for trial in range(1,max_trials+1):
|
| 1185 |
-
|
|
|
|
|
|
|
|
|
|
| 1186 |
if 'power' in layers.value['infra'].value:
|
| 1187 |
nodes, buildings, household = execute_power()
|
| 1188 |
layers.value['layers']['power nodes']['data'].set(nodes)
|
|
|
|
| 48 |
'pre_processing': identity_preprocess,
|
| 49 |
'extra_cols': {},
|
| 50 |
'attributes_required': [set(['expstr','susceptibility','minor','moderate','severe'])],
|
| 51 |
+
'attributes': [set(['expstr','susceptibility','minor','moderate','severe','description'])]},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
'building': {
|
| 53 |
'render_order': 50,
|
| 54 |
'map_info_tooltip': 'Number of buildings',
|
|
|
|
| 148 |
'visible': solara.reactive(False),
|
| 149 |
'pre_processing': identity_preprocess,
|
| 150 |
'extra_cols': {'ds': 0, 'is_damaged': False, 'is_operational': True},
|
| 151 |
+
'attributes_required': [set(['geometry', 'node_id', 'pwr_plant', 'n_bldgs'])],
|
| 152 |
'attributes': [set(['geometry', 'fltytype', 'strctype', 'utilfcltyc', 'indpnode', 'guid',
|
| 153 |
'node_id', 'x_coord', 'y_coord', 'pwr_plant', 'serv_area', 'n_bldgs',
|
| 154 |
'income', 'eq_vuln'])]},
|
|
|
|
| 335 |
def generic_layer_colors(feature):
|
| 336 |
return None
|
| 337 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 338 |
def generic_layer_click_handler(event=None, feature=None, id=None, properties=None):
|
| 339 |
layers.value['map_info_detail'].set(properties)
|
| 340 |
layers.value['map_info_button'].set("detail")
|
|
|
|
| 470 |
if name == "intensity":
|
| 471 |
# Take the largest 500_000 values to display
|
| 472 |
im_col = 'pga' if 'pga' in df.columns else 'im'
|
| 473 |
+
df_non_zero = df[df[im_col] > 0]
|
| 474 |
+
df_limited = df_non_zero.sample(min(len(df_non_zero),500_000))
|
| 475 |
+
df_limited[im_col] = df_limited[im_col] / df_limited[im_col].max()
|
| 476 |
+
#df_limited = df.sort_values(by=im_col,ascending=False).head(500_000)
|
| 477 |
locs = np.array([df_limited.geometry.y.to_list(), df_limited.geometry.x.to_list(), df_limited[im_col].to_list()]).transpose().tolist()
|
| 478 |
+
map_layer = ipyleaflet.Heatmap(locations=locs, radius = 5, blur = 1)
|
| 479 |
elif name == "landuse":
|
| 480 |
map_layer = ipyleaflet.GeoJSON(data = json.loads(df.to_json()),
|
| 481 |
style={'opacity': 1, 'dashArray': '9', 'fillOpacity': 0.5, 'weight': 1},
|
|
|
|
| 524 |
markers.append(marker)
|
| 525 |
map_layer= ipyleaflet.MarkerCluster(markers=markers,
|
| 526 |
disable_clustering_at_zoom=5)
|
| 527 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 528 |
else:
|
| 529 |
map_layer = ipyleaflet.GeoJSON(data = json.loads(df.to_json()),
|
| 530 |
style={'opacity': 1, 'dashArray': '9', 'fillOpacity': 0.5, 'weight': 1},
|
|
|
|
| 998 |
missing += list(set(["landuse","building","household","individual","intensity","fragility"]) - existing_layers)
|
| 999 |
elif hazard == "flood":
|
| 1000 |
if "power" in infra:
|
| 1001 |
+
missing += list(set(["landuse","building","household","individual","power edges","power nodes","intensity","vulnerability"]) - existing_layers)
|
| 1002 |
if "road" in infra:
|
| 1003 |
+
missing += list(set(["landuse","building","household","individual","road edges","road nodes","intensity"]) - existing_layers)
|
| 1004 |
if "building" in infra:
|
| 1005 |
missing += list(set(["landuse","building","household","individual","intensity","vulnerability"]) - existing_layers)
|
| 1006 |
elif hazard == "landslide":
|
| 1007 |
if "power" in infra:
|
| 1008 |
+
missing += list(set(["landuse","building","household","individual","power edges","power nodes","landslide fragility"]) - existing_layers)
|
| 1009 |
if "road" in infra:
|
| 1010 |
+
missing += list(set(["landuse","building","household","individual","road edges","road nodes","landslide fragility"]) - existing_layers)
|
| 1011 |
if "building" in infra:
|
| 1012 |
+
missing += list(set(["landuse","building","household","individual","landslide fragility"]) - existing_layers)
|
| 1013 |
|
| 1014 |
if infra == []:
|
| 1015 |
missing += ['You should select at least one of power, road or building']
|
| 1016 |
return missing == [], missing
|
| 1017 |
|
| 1018 |
+
def pre_compute_checks():
|
| 1019 |
+
hazard = layers.value['hazard'].value
|
| 1020 |
+
infra = layers.value['infra'].value
|
| 1021 |
+
building = layers.value['layers']['building']['data'].value
|
| 1022 |
+
household = layers.value['layers']['household']['data'].value
|
| 1023 |
+
|
| 1024 |
+
missing_buildings = set(household['bldid']) - set(building['bldid'])
|
| 1025 |
+
print('missing buildings', missing_buildings)
|
| 1026 |
+
if len(missing_buildings) > 0:
|
| 1027 |
+
return False, f"There are {len(missing_buildings)} household without buildings. Please add buildings for these households."
|
| 1028 |
+
|
| 1029 |
+
return True, ''
|
| 1030 |
|
| 1031 |
|
| 1032 |
def execute_engine():
|
|
|
|
| 1040 |
edges = layers.value['layers']['road edges']['data'].value
|
| 1041 |
intensity = layers.value['layers']['intensity']['data'].value
|
| 1042 |
fragility = layers.value['layers']['road fragility']['data'].value
|
| 1043 |
+
if layers.value['hazard'].value == 'landslide':
|
| 1044 |
+
fragility = layers.value['layers']['landslide fragility']['data'].value
|
| 1045 |
+
trigger_level= layers.value['landslide_trigger_level'].value
|
| 1046 |
+
fragility = fragility[['expstr','susceptibility',trigger_level]].rename(columns={trigger_level:'collapse_probability'})
|
| 1047 |
hazard = layers.value['hazard'].value
|
| 1048 |
|
| 1049 |
edges['ds'] = 0
|
|
|
|
| 1077 |
nodes = layers.value['layers']['power nodes']['data'].value
|
| 1078 |
edges = layers.value['layers']['power edges']['data'].value
|
| 1079 |
intensity = layers.value['layers']['intensity']['data'].value
|
| 1080 |
+
fragility = layers.value['layers']['power fragility']['data'].value
|
| 1081 |
hazard = layers.value['hazard'].value
|
| 1082 |
|
| 1083 |
+
if layers.value['hazard'].value == 'landslide':
|
| 1084 |
+
fragility = layers.value['layers']['landslide fragility']['data'].value
|
| 1085 |
+
trigger_level= layers.value['landslide_trigger_level'].value
|
| 1086 |
+
fragility = fragility[['expstr','susceptibility',trigger_level]].rename(columns={trigger_level:'collapse_probability'})
|
| 1087 |
+
|
| 1088 |
+
if layers.value['hazard'].value == 'flood':
|
| 1089 |
+
fragility = layers.value['layers']['vulnerability']['data'].value
|
| 1090 |
|
| 1091 |
ds, is_damaged, is_operational, has_power, household_has_power, hospital_has_power = \
|
| 1092 |
compute_power_infra(buildings,
|
|
|
|
| 1094 |
nodes,
|
| 1095 |
edges,
|
| 1096 |
intensity,
|
| 1097 |
+
fragility,
|
| 1098 |
+
hazard, threshold_flood.value, threshold_flood_distance.value)
|
| 1099 |
|
| 1100 |
#power_node_df = dfs['Power Nodes'].copy()
|
| 1101 |
nodes['ds'] = list(ds)
|
|
|
|
| 1128 |
#print('policies',policies)
|
| 1129 |
if layers.value['hazard'].value == 'landslide':
|
| 1130 |
fragility = layers.value['layers']['landslide fragility']['data'].value
|
|
|
|
| 1131 |
trigger_level= layers.value['landslide_trigger_level'].value
|
| 1132 |
df_bld_hazard = compute(
|
| 1133 |
landuse,
|
|
|
|
| 1183 |
is_ready, missing = is_ready_to_run(layers.value['infra'].value, layers.value['hazard'].value)
|
| 1184 |
if not is_ready:
|
| 1185 |
raise Exception(f'Missing {missing}')
|
| 1186 |
+
#is_ready, message = pre_compute_checks()
|
| 1187 |
+
#if not is_ready:
|
| 1188 |
+
# raise Exception(message)
|
| 1189 |
max_trials = landslide_max_trials.value if layers.value['hazard'].value == "landslide" else 1
|
| 1190 |
for trial in range(1,max_trials+1):
|
| 1191 |
+
if trial == 1:
|
| 1192 |
+
set_progress_message('Running...')
|
| 1193 |
+
else:
|
| 1194 |
+
set_progress_message(f'Monte-Carlo trial {trial}/{max_trials}...')
|
| 1195 |
if 'power' in layers.value['infra'].value:
|
| 1196 |
nodes, buildings, household = execute_power()
|
| 1197 |
layers.value['layers']['power nodes']['data'].set(nodes)
|