Spaces:
Runtime error
Runtime error
Commit
·
c818aff
1
Parent(s):
1ad6ce2
Completed landslide + building + metric average
Browse files
tomorrowcities/backend/engine.py
CHANGED
|
@@ -290,7 +290,8 @@ def compute_power_infra(buildings, household, nodes,edges,intensity,fragility,ha
|
|
| 290 |
|
| 291 |
def compute(gdf_landuse, gdf_buildings, df_household, df_individual,gdf_intensity, df_hazard, hazard_type, policies=[]):
|
| 292 |
|
| 293 |
-
|
|
|
|
| 294 |
|
| 295 |
column_names = {'zoneID':'zoneid','bldID':'bldid','nHouse':'nhouse',
|
| 296 |
'specialFac':'specialfac','expStr':'expstr','repValue':'repvalue',
|
|
@@ -344,6 +345,15 @@ def compute(gdf_landuse, gdf_buildings, df_household, df_individual,gdf_intensit
|
|
| 344 |
|
| 345 |
gdf_building_intensity['rnd'] = np.random.random((len(gdf_building_intensity),1))
|
| 346 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 347 |
# TODO: Check if the logic makes sense
|
| 348 |
if hazard_type == HAZARD_FLOOD:
|
| 349 |
away_from_flood = gdf_building_intensity['distance'] > threshold_flood_distance
|
|
|
|
| 290 |
|
| 291 |
def compute(gdf_landuse, gdf_buildings, df_household, df_individual,gdf_intensity, df_hazard, hazard_type, policies=[]):
|
| 292 |
|
| 293 |
+
if hazard_type != "landslide":
|
| 294 |
+
np.random.seed(seed=0)
|
| 295 |
|
| 296 |
column_names = {'zoneID':'zoneid','bldID':'bldid','nHouse':'nhouse',
|
| 297 |
'specialFac':'specialfac','expStr':'expstr','repValue':'repvalue',
|
|
|
|
| 345 |
|
| 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=['expstr','susceptibility'], how='left')
|
| 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
|
| 354 |
+
bld_hazard = gdf_building_collapse_prob[['bldid','ds']]
|
| 355 |
+
return bld_hazard
|
| 356 |
+
|
| 357 |
# TODO: Check if the logic makes sense
|
| 358 |
if hazard_type == HAZARD_FLOOD:
|
| 359 |
away_from_flood = gdf_building_intensity['distance'] > threshold_flood_distance
|
tomorrowcities/content/articles/contribution.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
author: huseyin.kaya
|
| 3 |
+
title: Contributing
|
| 4 |
+
description: A step-by-step guideline for contributors
|
| 5 |
+
image: https://github.com/TomorrowsCities/tomorrowcities/blob/main/tomorrowcities/content/images/data.png?raw=true
|
| 6 |
+
thumbnail: https://github.com/TomorrowsCities/tomorrowcities/blob/main/tomorrowcities/content/images/data.png?raw=true
|
| 7 |
+
alt: "Data Formats"
|
| 8 |
+
createdAt: 2023-10-10
|
| 9 |
+
duration: 6 min read
|
| 10 |
+
category:
|
| 11 |
+
- general
|
| 12 |
+
---
|
| 13 |
+
|
| 14 |
+
[TOC]
|
| 15 |
+
|
| 16 |
+
## Adding a new layer
|
| 17 |
+
|
| 18 |
+
On top of the **engine.py**, there is a reactive variable caller **layers**
|
| 19 |
+
to contain all information about the layers. You can add a new layer to that
|
| 20 |
+
variable. Here we provide an example.
|
| 21 |
+
|
| 22 |
+
```python
|
| 23 |
+
layers = solara.reactive({
|
| 24 |
+
# ...
|
| 25 |
+
'layers' : {
|
| 26 |
+
'landslide susceptibility': {
|
| 27 |
+
'render_order': 50,
|
| 28 |
+
'map_info_tooltip': 'Number of zones in the susceptibility map',
|
| 29 |
+
'data': solara.reactive(None),
|
| 30 |
+
'map_layer': solara.reactive(None),
|
| 31 |
+
'force_render': solara.reactive(False),
|
| 32 |
+
'visible': solara.reactive(False),
|
| 33 |
+
'pre_processing': identity_preprocess,
|
| 34 |
+
'extra_cols': {},
|
| 35 |
+
'attributes_required': [set(['id','susceptibility','geometry'])],
|
| 36 |
+
'attributes': [set(['id','susceptibility','geometry'])]},
|
| 37 |
+
#...
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
The above step is the minimum requirement of importing data and visualizing
|
| 41 |
+
on the map. If you need extra stuff for visualization, then edit **create_map_layer** function.
|
| 42 |
+
|
| 43 |
+
## Adding a new Hazard
|
| 44 |
+
Add your hazard to application state:
|
| 45 |
+
|
| 46 |
+
```python
|
| 47 |
+
app_state = solara.reactive({
|
| 48 |
+
#...
|
| 49 |
+
'hazard_list': ["earthquake","flood","landslide"],
|
| 50 |
+
#...
|
| 51 |
+
```
|
| 52 |
+
|
| 53 |
+
Update **is_ready_to_run** to add the required layers for your hazard.
|
| 54 |
+
|
| 55 |
+
Update **execute_engine** to include the relation with your hazard and infrastructure type.
|
| 56 |
+
For each instrastructure type, you'll see dedicated functions such as **execute_road**,
|
| 57 |
+
or **execute_power**, etc. Inside each one, make sure you load the necessary data
|
| 58 |
+
before calling the backend.
|
tomorrowcities/content/articles/landslide.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
author: huseyin.kaya
|
| 3 |
+
title: Land Slide
|
| 4 |
+
description: Land Slide damage assessment via Monte-Carlo Approach
|
| 5 |
+
image: https://raw.githubusercontent.com/TomorrowsCities/tomorrowcities/main/tomorrowcities/content/images/landslide.jpg?raw=true
|
| 6 |
+
thumbnail: https://raw.githubusercontent.com/TomorrowsCities/tomorrowcities/main/tomorrowcities/content/images/landslide.jpg?raw=true
|
| 7 |
+
alt: "Landslide analysis"
|
| 8 |
+
createdAt: 2023-10-10
|
| 9 |
+
duration: 6 min read
|
| 10 |
+
category:
|
| 11 |
+
- general
|
| 12 |
+
---
|
| 13 |
+
|
| 14 |
+
[TOC]
|
| 15 |
+
|
| 16 |
+
## Data Formats
|
| 17 |
+
|
| 18 |
+
### Susceptibility Map
|
| 19 |
+
Since it contains geo-spatial information, the format of this file should be GeoJSON.
|
| 20 |
+
|
| 21 |
+
|id|susceptibility|geometry|
|
| 22 |
+
|--|--------------|--------|
|
| 23 |
+
|0 |low |MULTIPOLYGON (((82.66785 27.80147, 82.66906 27... |
|
| 24 |
+
|1 |medium |MULTIPOLYGON (((82.60206 27.85078, 82.60202 27... |
|
| 25 |
+
|2 |low |MULTIPOLYGON (((82.68074 27.79833, 82.68025 27... |
|
| 26 |
+
|3 |high |MULTIPOLYGON (((82.62131 27.86873, 82.62120 27... |
|
| 27 |
+
|
| 28 |
+
### Fragility
|
| 29 |
+
Collapse probability depends on three factors:
|
| 30 |
+
|
| 31 |
+
* **expstr**: taxonomy of the structure
|
| 32 |
+
* **susceptibility**: which susceptibility zone the structure is in
|
| 33 |
+
* **trigger level**: amount of rainfall which is categorized into minor, moderate and severe.
|
| 34 |
+
|
| 35 |
+
Since it is a tabular data with no geo-spatial context, the data can be provided in
|
| 36 |
+
Microsoft Excel or JSON format.
|
| 37 |
+
|
| 38 |
+
|expstr|susceptibility|minor|moderate|severe|
|
| 39 |
+
|------|--------------|-----|--------|------|
|
| 40 |
+
|Adb+HC+10s+Edu| low |0.01 |0.02 |0.03|
|
| 41 |
+
|Adb+HC+1s+Res | low |0.03 |0.04 |0.05|
|
| 42 |
+
|Adb+HC+1s+ResCom| low |0.06 |0.08 |0.09|
|
| 43 |
+
|
| 44 |
+
### Trigger Level
|
| 45 |
+
Trigger level selection becomes active when the user selects "landuse" hazard type.
|
| 46 |
+
There are three pre-defined levels: minor, moderate, and severe. The fragility data
|
| 47 |
+
should contain a column for each category.
|
| 48 |
+
|
| 49 |
+
## Algorithm
|
| 50 |
+
The algorithm starts with geo-spatial merge of susceptibility map and the building layer.
|
| 51 |
+
For this purpose, **sjoin_nearest** function of GeoPandas is used. As a result of
|
| 52 |
+
merging process, the buildings have susceptibility attribute.
|
| 53 |
+
|
| 54 |
+
The merged tabular data is left joined with fragility data. In this merge, instead of using all minor, moderate
|
| 55 |
+
and severe columns, only the column matching to the trigger level is used. For instance, if the trigger level
|
| 56 |
+
is moderate, expstr, susceptibility, and moderate columns are used. As a result of this merge, the buildings
|
| 57 |
+
now have collapse probabilities.
|
| 58 |
+
|
| 59 |
+
The next step is Monte-Carlo simulation. For each building, a random number between zero and one is picked.
|
| 60 |
+
If it is less than the building's collapse probability, then the damage state of the building is set to DS_COLLAPSED (4)
|
| 61 |
+
otherwise to DS_NO (0).
|
| 62 |
+
|
| 63 |
+
Then by using household, landuse and individual layers, the seven impact metrics are calculated.
|
| 64 |
+
|
| 65 |
+
Above process is repeated N times and the impact metrics are averaged. In the metric widgets
|
| 66 |
+
these averaged impact metrics are displayed.
|
| 67 |
+
|
| 68 |
+
In the map, and the layer displayer, however, the damage states of the buildings and other infrastructures are displayed
|
| 69 |
+
according to the last Monte-Carlo random realization. However, the attributes metric1,...,metric7 denote the average
|
| 70 |
+
over N random trials.
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
|
tomorrowcities/content/articles/metrics.md
CHANGED
|
@@ -66,3 +66,7 @@ An individual is assumed to be displaced when any of the following condition hol
|
|
| 66 |
* the individual's workplace, school, or associated hospital is damaged
|
| 67 |
* the individual can not reach to workplace, school, or associated hospital via transportation network
|
| 68 |
* the individual's workplace, school, or associated hospital has no electricity
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
* the individual's workplace, school, or associated hospital is damaged
|
| 67 |
* the individual can not reach to workplace, school, or associated hospital via transportation network
|
| 68 |
* the individual's workplace, school, or associated hospital has no electricity
|
| 69 |
+
|
| 70 |
+
## Average Impact Metrics in Monte-Carlo Simulations
|
| 71 |
+
When the hazard scenario is run with different random realizations such as landslide calculations,
|
| 72 |
+
then the impact metrics are calculated by taking average of all simulations.
|
tomorrowcities/pages/engine.py
CHANGED
|
@@ -21,7 +21,7 @@ import logging, sys
|
|
| 21 |
#logging.basicConfig(stream=sys.stderr, level=logging.INFO)
|
| 22 |
import pickle
|
| 23 |
import datetime
|
| 24 |
-
from .settings import storage
|
| 25 |
from ..backend.engine import compute, compute_power_infra, compute_road_infra, calculate_metrics
|
| 26 |
from ..backend.utils import building_preprocess, identity_preprocess
|
| 27 |
from .utilities import S3FileBrowser, extension_list, extension_list_w_dots
|
|
@@ -30,11 +30,36 @@ from .docs import data_import_help
|
|
| 30 |
layers = solara.reactive({
|
| 31 |
'infra': solara.reactive(["building"]),
|
| 32 |
'hazard': solara.reactive("flood"),
|
|
|
|
| 33 |
'datetime_analysis': datetime.datetime.utcnow(),
|
| 34 |
'road_water_height_threshold': solara.reactive(0.3),
|
|
|
|
|
|
|
| 35 |
'dialog_message_to_be_shown': solara.reactive(None),
|
| 36 |
'version': '0.2.3',
|
| 37 |
'layers' : {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
'building': {
|
| 39 |
'render_order': 50,
|
| 40 |
'map_info_tooltip': 'Number of buildings',
|
|
@@ -318,6 +343,17 @@ def load_app_state():
|
|
| 318 |
loaded_state = pickle.load(fileObj)
|
| 319 |
load_from_state(loaded_state)
|
| 320 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 321 |
|
| 322 |
def building_colors(feature):
|
| 323 |
ds_to_color = {0: 'lavender', 1:'violet',2:'fuchsia',3:'indigo',4:'darkslateblue',5:'black'}
|
|
@@ -328,7 +364,7 @@ def building_colors(feature):
|
|
| 328 |
occupancy = feature['properties']['occupancy']
|
| 329 |
normal_color = 'green' if occupancy == 'Hea' else 'blue'
|
| 330 |
#return {'fillColor': 'black', 'color': 'red' if hospital_access == False else normal_color}
|
| 331 |
-
return {'fillColor': 'black', 'color': 'green' if
|
| 332 |
|
| 333 |
def building_click_handler(event=None, feature=None, id=None, properties=None):
|
| 334 |
layers.value['map_info_detail'].set(properties)
|
|
@@ -502,9 +538,18 @@ def create_map_layer(df, name):
|
|
| 502 |
map_layer= ipyleaflet.MarkerCluster(markers=markers,
|
| 503 |
disable_clustering_at_zoom=5)
|
| 504 |
|
| 505 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 506 |
else:
|
| 507 |
-
map_layer = ipyleaflet.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 508 |
layers.value['layers'][name]['map_layer'].set(map_layer)
|
| 509 |
layers.value['layers'][name]['force_render'].set(False)
|
| 510 |
return map_layer
|
|
@@ -950,7 +995,7 @@ def MapViewer():
|
|
| 950 |
@solara.component
|
| 951 |
def ExecutePanel():
|
| 952 |
|
| 953 |
-
|
| 954 |
execute_counter, set_execute_counter = solara.use_state(0)
|
| 955 |
execute_btn_disabled, set_execute_btn_disabled = solara.use_state(False)
|
| 956 |
execute_error = solara.reactive("")
|
|
@@ -977,6 +1022,13 @@ def ExecutePanel():
|
|
| 977 |
missing += list(set(["road edges","road nodes","intensity"]) - existing_layers)
|
| 978 |
if "building" in infra:
|
| 979 |
missing += list(set(["landuse","building","household","individual","intensity","vulnerability"]) - existing_layers)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 980 |
|
| 981 |
if infra == []:
|
| 982 |
missing += ['You should select at least one of power, road or building']
|
|
@@ -1071,14 +1123,28 @@ def ExecutePanel():
|
|
| 1071 |
buildings_freqincome = buildings[['bldid']].merge(freqincome,on='bldid',how='left')
|
| 1072 |
buildings['freqincome'] = buildings_freqincome['freqincome']
|
| 1073 |
print('policies',policies)
|
| 1074 |
-
|
| 1075 |
-
|
| 1076 |
-
|
| 1077 |
-
|
| 1078 |
-
|
| 1079 |
-
|
| 1080 |
-
|
| 1081 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1082 |
buildings['ds'] = list(df_bld_hazard['ds'])
|
| 1083 |
|
| 1084 |
return buildings
|
|
@@ -1111,25 +1177,40 @@ def ExecutePanel():
|
|
| 1111 |
is_ready, missing = is_ready_to_run(layers.value['infra'].value, layers.value['hazard'].value)
|
| 1112 |
if not is_ready:
|
| 1113 |
raise Exception(f'Missing {missing}')
|
| 1114 |
-
|
| 1115 |
-
|
| 1116 |
-
|
| 1117 |
-
layers.value['
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1118 |
layers.value['layers']['building']['data'].set(buildings)
|
| 1119 |
-
layers.value['layers']['household']['data'].set(household)
|
| 1120 |
-
if 'road' in layers.value['infra'].value:
|
| 1121 |
-
edges, buildings, household, individual = execute_road()
|
| 1122 |
-
layers.value['layers']['road edges']['data'].set(edges)
|
| 1123 |
-
layers.value['layers']['building']['data'].set(buildings)
|
| 1124 |
-
layers.value['layers']['household']['data'].set(household)
|
| 1125 |
-
layers.value['layers']['individual']['data'].set(individual)
|
| 1126 |
-
if 'building' in layers.value['infra'].value:
|
| 1127 |
-
buildings = execute_building()
|
| 1128 |
-
layers.value['layers']['building']['data'].set(buildings)
|
| 1129 |
-
|
| 1130 |
-
buildings = execute_metric()
|
| 1131 |
-
layers.value['layers']['building']['data'].set(buildings)
|
| 1132 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1133 |
# trigger render event
|
| 1134 |
layers.value['render_count'].set(layers.value['render_count'].value + 1)
|
| 1135 |
if 'power' in layers.value['infra'].value:
|
|
@@ -1154,7 +1235,13 @@ def ExecutePanel():
|
|
| 1154 |
solara.ToggleButtonsMultiple(value=layers.value['infra'].value, on_value=layers.value['infra'].set, values=["building","power","road"])
|
| 1155 |
solara.Markdown("#### Hazard")
|
| 1156 |
with solara.Row(justify="left"):
|
| 1157 |
-
solara.ToggleButtonsSingle(value=layers.value['hazard'].value, on_value=layers.value['hazard'].set, values=[
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1158 |
with solara.Tooltip("Building-level metrics will be increased by 25% and 50% for medium and low"):
|
| 1159 |
solara.Markdown("#### Implementation Capacity Score")
|
| 1160 |
with solara.Row(justify="left"):
|
|
@@ -1180,8 +1267,10 @@ def ExecutePanel():
|
|
| 1180 |
|
| 1181 |
if result.state in [solara.ResultState.RUNNING, solara.ResultState.WAITING]:
|
| 1182 |
set_execute_btn_disabled(True)
|
|
|
|
| 1183 |
solara.ProgressLinear(value=True)
|
| 1184 |
else:
|
|
|
|
| 1185 |
set_execute_btn_disabled(False)
|
| 1186 |
solara.ProgressLinear(value=False)
|
| 1187 |
|
|
|
|
| 21 |
#logging.basicConfig(stream=sys.stderr, level=logging.INFO)
|
| 22 |
import pickle
|
| 23 |
import datetime
|
| 24 |
+
from .settings import storage, landslide_max_trials
|
| 25 |
from ..backend.engine import compute, compute_power_infra, compute_road_infra, calculate_metrics
|
| 26 |
from ..backend.utils import building_preprocess, identity_preprocess
|
| 27 |
from .utilities import S3FileBrowser, extension_list, extension_list_w_dots
|
|
|
|
| 30 |
layers = solara.reactive({
|
| 31 |
'infra': solara.reactive(["building"]),
|
| 32 |
'hazard': solara.reactive("flood"),
|
| 33 |
+
'hazard_list': ["earthquake","flood","landslide"],
|
| 34 |
'datetime_analysis': datetime.datetime.utcnow(),
|
| 35 |
'road_water_height_threshold': solara.reactive(0.3),
|
| 36 |
+
'landslide_trigger_level': solara.reactive('moderate'),
|
| 37 |
+
'landslide_trigger_level_list': ['minor','moderate','severe'],
|
| 38 |
'dialog_message_to_be_shown': solara.reactive(None),
|
| 39 |
'version': '0.2.3',
|
| 40 |
'layers' : {
|
| 41 |
+
'landslide fragility': {
|
| 42 |
+
'render_order': 0,
|
| 43 |
+
'map_info_tooltip': 'Number of landslide fragility records',
|
| 44 |
+
'data': solara.reactive(None),
|
| 45 |
+
'map_layer': solara.reactive(None),
|
| 46 |
+
'force_render': solara.reactive(False),
|
| 47 |
+
'visible': solara.reactive(False),
|
| 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',
|
|
|
|
| 343 |
loaded_state = pickle.load(fileObj)
|
| 344 |
load_from_state(loaded_state)
|
| 345 |
|
| 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")
|
| 357 |
|
| 358 |
def building_colors(feature):
|
| 359 |
ds_to_color = {0: 'lavender', 1:'violet',2:'fuchsia',3:'indigo',4:'darkslateblue',5:'black'}
|
|
|
|
| 364 |
occupancy = feature['properties']['occupancy']
|
| 365 |
normal_color = 'green' if occupancy == 'Hea' else 'blue'
|
| 366 |
#return {'fillColor': 'black', 'color': 'red' if hospital_access == False else normal_color}
|
| 367 |
+
return {'fillColor': 'black', 'color': 'green' if ds == 0 else 'red'}
|
| 368 |
|
| 369 |
def building_click_handler(event=None, feature=None, id=None, properties=None):
|
| 370 |
layers.value['map_info_detail'].set(properties)
|
|
|
|
| 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},
|
| 550 |
+
hover_style={'color': 'white', 'dashArray': '0', 'fillOpacity': 0.5},
|
| 551 |
+
style_callback=generic_layer_colors)
|
| 552 |
+
map_layer.on_click(generic_layer_click_handler)
|
| 553 |
layers.value['layers'][name]['map_layer'].set(map_layer)
|
| 554 |
layers.value['layers'][name]['force_render'].set(False)
|
| 555 |
return map_layer
|
|
|
|
| 995 |
@solara.component
|
| 996 |
def ExecutePanel():
|
| 997 |
|
| 998 |
+
progress_message, set_progress_message = solara.use_state("")
|
| 999 |
execute_counter, set_execute_counter = solara.use_state(0)
|
| 1000 |
execute_btn_disabled, set_execute_btn_disabled = solara.use_state(False)
|
| 1001 |
execute_error = solara.reactive("")
|
|
|
|
| 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","landslide susceptibility"]) - existing_layers)
|
| 1028 |
+
if "road" in infra:
|
| 1029 |
+
missing += list(set(["road edges","road nodes","landslide fragility","landslide susceptibility"]) - existing_layers)
|
| 1030 |
+
if "building" in infra:
|
| 1031 |
+
missing += list(set(["landuse","building","household","individual","landslide fragility","landslide susceptibility"]) - existing_layers)
|
| 1032 |
|
| 1033 |
if infra == []:
|
| 1034 |
missing += ['You should select at least one of power, road or building']
|
|
|
|
| 1123 |
buildings_freqincome = buildings[['bldid']].merge(freqincome,on='bldid',how='left')
|
| 1124 |
buildings['freqincome'] = buildings_freqincome['freqincome']
|
| 1125 |
print('policies',policies)
|
| 1126 |
+
if layers.value['hazard'].value == 'landslide':
|
| 1127 |
+
fragility = layers.value['layers']['landslide fragility']['data'].value
|
| 1128 |
+
intensity = layers.value['layers']['landslide susceptibility']['data'].value
|
| 1129 |
+
trigger_level= layers.value['landslide_trigger_level'].value
|
| 1130 |
+
df_bld_hazard = compute(
|
| 1131 |
+
landuse,
|
| 1132 |
+
buildings,
|
| 1133 |
+
household,
|
| 1134 |
+
individual,
|
| 1135 |
+
intensity,
|
| 1136 |
+
fragility[['expstr','susceptibility',trigger_level]].rename(columns={trigger_level:'collapse_probability'}),
|
| 1137 |
+
layers.value['hazard'].value,
|
| 1138 |
+
policies=policies)
|
| 1139 |
+
else:
|
| 1140 |
+
df_bld_hazard = compute(
|
| 1141 |
+
landuse,
|
| 1142 |
+
buildings,
|
| 1143 |
+
household,
|
| 1144 |
+
individual,
|
| 1145 |
+
intensity,
|
| 1146 |
+
fragility if layers.value['hazard'].value == "earthquake" else vulnerability,
|
| 1147 |
+
layers.value['hazard'].value, policies=policies)
|
| 1148 |
buildings['ds'] = list(df_bld_hazard['ds'])
|
| 1149 |
|
| 1150 |
return buildings
|
|
|
|
| 1177 |
is_ready, missing = is_ready_to_run(layers.value['infra'].value, layers.value['hazard'].value)
|
| 1178 |
if not is_ready:
|
| 1179 |
raise Exception(f'Missing {missing}')
|
| 1180 |
+
max_trials = landslide_max_trials.value if layers.value['hazard'].value == "landslide" else 1
|
| 1181 |
+
for trial in range(1,max_trials+1):
|
| 1182 |
+
set_progress_message(f'Monte-Carlo trial {trial}/{max_trials}...')
|
| 1183 |
+
if 'power' in layers.value['infra'].value:
|
| 1184 |
+
nodes, buildings, household = execute_power()
|
| 1185 |
+
layers.value['layers']['power nodes']['data'].set(nodes)
|
| 1186 |
+
layers.value['layers']['building']['data'].set(buildings)
|
| 1187 |
+
layers.value['layers']['household']['data'].set(household)
|
| 1188 |
+
if 'road' in layers.value['infra'].value:
|
| 1189 |
+
edges, buildings, household, individual = execute_road()
|
| 1190 |
+
layers.value['layers']['road edges']['data'].set(edges)
|
| 1191 |
+
layers.value['layers']['building']['data'].set(buildings)
|
| 1192 |
+
layers.value['layers']['household']['data'].set(household)
|
| 1193 |
+
layers.value['layers']['individual']['data'].set(individual)
|
| 1194 |
+
if 'building' in layers.value['infra'].value:
|
| 1195 |
+
buildings = execute_building()
|
| 1196 |
+
layers.value['layers']['building']['data'].set(buildings)
|
| 1197 |
+
|
| 1198 |
+
buildings = execute_metric()
|
| 1199 |
layers.value['layers']['building']['data'].set(buildings)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1200 |
|
| 1201 |
+
# Taking average without storing intermediate values
|
| 1202 |
+
# averaga_n = [(n-1)*average_(n-1) + value_n]/2
|
| 1203 |
+
if trial == 1:
|
| 1204 |
+
avg_metrics = buildings[layers.value['metrics'].keys()]
|
| 1205 |
+
else:
|
| 1206 |
+
avg_metrics = ((trial-1) * avg_metrics + buildings[layers.value['metrics'].keys()])/trial
|
| 1207 |
+
for metric in layers.value['metrics'].keys():
|
| 1208 |
+
print('average', metric, avg_metrics[metric].sum())
|
| 1209 |
+
|
| 1210 |
+
for metric in layers.value['metrics'].keys():
|
| 1211 |
+
buildings[metric] = list(avg_metrics[metric])
|
| 1212 |
+
layers.value['metrics'][metric]['value'] = avg_metrics[metric].sum()
|
| 1213 |
+
set_progress_message('')
|
| 1214 |
# trigger render event
|
| 1215 |
layers.value['render_count'].set(layers.value['render_count'].value + 1)
|
| 1216 |
if 'power' in layers.value['infra'].value:
|
|
|
|
| 1235 |
solara.ToggleButtonsMultiple(value=layers.value['infra'].value, on_value=layers.value['infra'].set, values=["building","power","road"])
|
| 1236 |
solara.Markdown("#### Hazard")
|
| 1237 |
with solara.Row(justify="left"):
|
| 1238 |
+
solara.ToggleButtonsSingle(value=layers.value['hazard'].value, on_value=layers.value['hazard'].set, values=layers.value['hazard_list'])
|
| 1239 |
+
if layers.value['hazard'].value == 'landslide':
|
| 1240 |
+
solara.Markdown("#### Landslide trigger level")
|
| 1241 |
+
with solara.Row(justify="left"):
|
| 1242 |
+
solara.ToggleButtonsSingle(value=layers.value['landslide_trigger_level'].value,
|
| 1243 |
+
on_value=layers.value['landslide_trigger_level'].set,
|
| 1244 |
+
values=layers.value['landslide_trigger_level_list'])
|
| 1245 |
with solara.Tooltip("Building-level metrics will be increased by 25% and 50% for medium and low"):
|
| 1246 |
solara.Markdown("#### Implementation Capacity Score")
|
| 1247 |
with solara.Row(justify="left"):
|
|
|
|
| 1267 |
|
| 1268 |
if result.state in [solara.ResultState.RUNNING, solara.ResultState.WAITING]:
|
| 1269 |
set_execute_btn_disabled(True)
|
| 1270 |
+
solara.Text(progress_message)
|
| 1271 |
solara.ProgressLinear(value=True)
|
| 1272 |
else:
|
| 1273 |
+
solara.Text("Spacer", style={"visibility": "hidden"})
|
| 1274 |
set_execute_btn_disabled(False)
|
| 1275 |
solara.ProgressLinear(value=False)
|
| 1276 |
|
tomorrowcities/pages/settings.py
CHANGED
|
@@ -3,7 +3,6 @@ from typing import Optional, cast
|
|
| 3 |
import pickle
|
| 4 |
import boto3
|
| 5 |
import os
|
| 6 |
-
|
| 7 |
from . import user
|
| 8 |
|
| 9 |
class S3Storage:
|
|
@@ -86,6 +85,7 @@ def revive_storage():
|
|
| 86 |
os.environ['bucket_name'])
|
| 87 |
|
| 88 |
storage = solara.reactive(revive_storage())
|
|
|
|
| 89 |
|
| 90 |
def storage_control(aws_access_key_id: str, aws_secret_access_key: str, region_name: str, bucket_name: str):
|
| 91 |
storage.value = S3Storage(aws_access_key_id, aws_secret_access_key, region_name, bucket_name)
|
|
@@ -164,4 +164,7 @@ def Page(name: Optional[str] = None, page: int = 0, page_size=100):
|
|
| 164 |
# StorageViewer()
|
| 165 |
|
| 166 |
if err_message != '':
|
| 167 |
-
solara.Error(err_message)
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
import pickle
|
| 4 |
import boto3
|
| 5 |
import os
|
|
|
|
| 6 |
from . import user
|
| 7 |
|
| 8 |
class S3Storage:
|
|
|
|
| 85 |
os.environ['bucket_name'])
|
| 86 |
|
| 87 |
storage = solara.reactive(revive_storage())
|
| 88 |
+
landslide_max_trials = solara.reactive(5)
|
| 89 |
|
| 90 |
def storage_control(aws_access_key_id: str, aws_secret_access_key: str, region_name: str, bucket_name: str):
|
| 91 |
storage.value = S3Storage(aws_access_key_id, aws_secret_access_key, region_name, bucket_name)
|
|
|
|
| 164 |
# StorageViewer()
|
| 165 |
|
| 166 |
if err_message != '':
|
| 167 |
+
solara.Error(err_message)
|
| 168 |
+
|
| 169 |
+
with solara.Card(title='Landslide Parameters',subtitle='Choose the parameters for the landslide simulation'):
|
| 170 |
+
solara.SliderInt(label='Number of Monte-Carlo Trials', value=landslide_max_trials, min=1,max=100)
|