Spaces:
Runtime error
Runtime error
Merge pull request #119 from TomorrowsCities/feature_monte_carlo_earthquake
Browse files
tomorrowcities/backend/engine.py
CHANGED
|
@@ -445,6 +445,7 @@ def compute(gdf_landuse, gdf_buildings, df_household, df_individual,gdf_intensit
|
|
| 445 |
cdf_median_increase_in_percent = 0.20,
|
| 446 |
flood_depth_reduction = 0.20,
|
| 447 |
damage_curve_suppress_factor = 0.9,
|
|
|
|
| 448 |
):
|
| 449 |
print('threshold_flood', threshold_flood)
|
| 450 |
print('cdf_median_increase_in_percent',cdf_median_increase_in_percent)
|
|
@@ -456,7 +457,11 @@ def compute(gdf_landuse, gdf_buildings, df_household, df_individual,gdf_intensit
|
|
| 456 |
|
| 457 |
gem_fragility = True if isinstance(df_hazard, dict) else False
|
| 458 |
print('gem_fragility mode', gem_fragility)
|
| 459 |
-
if hazard_type
|
|
|
|
|
|
|
|
|
|
|
|
|
| 460 |
np.random.seed(seed=0)
|
| 461 |
|
| 462 |
column_names = {'zoneID':'zoneid','bldID':'bldid','nHouse':'nhouse',
|
|
@@ -722,11 +727,16 @@ def compute(gdf_landuse, gdf_buildings, df_household, df_individual,gdf_intensit
|
|
| 722 |
return prob_ds1, prob_ds2, prob_ds3, prob_ds4
|
| 723 |
bld_eq[['prob_ds1','prob_ds2','prob_ds3','prob_ds4']] = bld_eq.apply(computer_damage_state, axis=1,result_type='expand')
|
| 724 |
|
| 725 |
-
|
| 726 |
-
|
| 727 |
-
bld_eq[
|
| 728 |
-
|
| 729 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 730 |
casualty_rates = np.array([0, 0.05, 0.28, 1.152, 74.41]) # percent
|
| 731 |
bld_eq['casualy'] = 0
|
| 732 |
bld_eq = bld_eq.assign(casualty=lambda x: casualty_rates[x['eq_ds']] * x['residents'] / 100)
|
|
|
|
| 445 |
cdf_median_increase_in_percent = 0.20,
|
| 446 |
flood_depth_reduction = 0.20,
|
| 447 |
damage_curve_suppress_factor = 0.9,
|
| 448 |
+
earthquake_simulation_method = 'legacy'
|
| 449 |
):
|
| 450 |
print('threshold_flood', threshold_flood)
|
| 451 |
print('cdf_median_increase_in_percent',cdf_median_increase_in_percent)
|
|
|
|
| 457 |
|
| 458 |
gem_fragility = True if isinstance(df_hazard, dict) else False
|
| 459 |
print('gem_fragility mode', gem_fragility)
|
| 460 |
+
if hazard_type == 'landslide' or \
|
| 461 |
+
(hazard_type == 'earthquake' and earthquake_simulation_method == 'monte carlo'):
|
| 462 |
+
# do not assign a fixed seed, we are in a simulation zone
|
| 463 |
+
pass
|
| 464 |
+
else:
|
| 465 |
np.random.seed(seed=0)
|
| 466 |
|
| 467 |
column_names = {'zoneID':'zoneid','bldID':'bldid','nHouse':'nhouse',
|
|
|
|
| 727 |
return prob_ds1, prob_ds2, prob_ds3, prob_ds4
|
| 728 |
bld_eq[['prob_ds1','prob_ds2','prob_ds3','prob_ds4']] = bld_eq.apply(computer_damage_state, axis=1,result_type='expand')
|
| 729 |
|
| 730 |
+
# legacy (most common approach)
|
| 731 |
+
if earthquake_simulation_method == 'legacy':
|
| 732 |
+
bld_eq[['prob_ds0','prob_ds5']] = [1,0]
|
| 733 |
+
for i in [1,2,3,4,5]:
|
| 734 |
+
bld_eq[f'ds_{i}'] = np.abs(bld_eq[f'prob_ds{i-1}'] - bld_eq[f'prob_ds{i}'])
|
| 735 |
+
df_ds = bld_eq[['ds_1','ds_2','ds_3','ds_4','ds_5']]
|
| 736 |
+
bld_eq['eq_ds'] = df_ds.idxmax(axis='columns').str.extract(r'ds_([0-9]+)').astype('int') - 1
|
| 737 |
+
elif earthquake_simulation_method == 'monte carlo':
|
| 738 |
+
bld_eq['eq_ds'] = pd.concat([(bld_eq['rnd'] < bld_eq[f'prob_ds{i}']).astype(int) for i in [1,2,3,4]], axis=1).sum(axis=1)
|
| 739 |
+
|
| 740 |
casualty_rates = np.array([0, 0.05, 0.28, 1.152, 74.41]) # percent
|
| 741 |
bld_eq['casualy'] = 0
|
| 742 |
bld_eq = bld_eq.assign(casualty=lambda x: casualty_rates[x['eq_ds']] * x['residents'] / 100)
|
tomorrowcities/pages/engine.py
CHANGED
|
@@ -50,6 +50,9 @@ def create_new_app_state():
|
|
| 50 |
'landslide_trigger_level': solara.reactive('moderate'),
|
| 51 |
'landslide_trigger_level_list': ['minor','moderate','severe'],
|
| 52 |
'earthquake_intensity_unit': solara.reactive('m/s2'),
|
|
|
|
|
|
|
|
|
|
| 53 |
'cdf_median_increase_in_percent': solara.reactive(0.2),
|
| 54 |
'threshold_increase_culvert_water_height': solara.reactive(0.2),
|
| 55 |
'threshold_increase_road_water_height': solara.reactive(0.2),
|
|
@@ -272,6 +275,7 @@ def create_new_app_state():
|
|
| 272 |
'map_info_detail': solara.reactive({}),
|
| 273 |
'tally_filter_cols': ['ds','income','material','gender','age','head','eduattstat','luf','occupancy'],
|
| 274 |
'tally_is_available': solara.reactive(False),
|
|
|
|
| 275 |
'metrics': {
|
| 276 |
"metric1": {"desc": "Number of workers unemployed", "value": 0, "max_value": 100},
|
| 277 |
"metric2": {"desc": "Number of children with no access to education", "value": 0, "max_value": 100},
|
|
@@ -1111,7 +1115,68 @@ def MetricPanel():
|
|
| 1111 |
metric['max_value'],
|
| 1112 |
layers.value['render_count'].value)
|
| 1113 |
|
| 1114 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1115 |
@solara.component
|
| 1116 |
def MapViewer():
|
| 1117 |
print('rendering mapviewer')
|
|
@@ -1401,6 +1466,7 @@ def ExecutePanel():
|
|
| 1401 |
flood_depth_reduction = layers.value['flood_depth_reduction'].value
|
| 1402 |
cdf_median_increase_in_percent = layers.value['cdf_median_increase_in_percent'].value
|
| 1403 |
damage_curve_suppress_factor = layers.value['damage_curve_suppress_factor'].value
|
|
|
|
| 1404 |
threshold_flood = [threshold_flood_ds2.value, threshold_flood_ds3.value, threshold_flood_ds4.value]
|
| 1405 |
|
| 1406 |
policies = [p['id'] for _, p in layers.value['policies'].items() if f"{p['description']} ({p['label']})" in layers.value['selected_policies'].value]
|
|
@@ -1430,7 +1496,8 @@ def ExecutePanel():
|
|
| 1430 |
earthquake_intensity_unit=earthquake_intensity_unit,
|
| 1431 |
cdf_median_increase_in_percent=cdf_median_increase_in_percent,
|
| 1432 |
flood_depth_reduction=flood_depth_reduction,
|
| 1433 |
-
damage_curve_suppress_factor=damage_curve_suppress_factor
|
|
|
|
| 1434 |
)
|
| 1435 |
else:
|
| 1436 |
if fragility is None:
|
|
@@ -1449,6 +1516,7 @@ def ExecutePanel():
|
|
| 1449 |
cdf_median_increase_in_percent=cdf_median_increase_in_percent,
|
| 1450 |
flood_depth_reduction=flood_depth_reduction,
|
| 1451 |
damage_curve_suppress_factor=damage_curve_suppress_factor,
|
|
|
|
| 1452 |
)
|
| 1453 |
buildings['ds'] = list(df_bld_hazard['ds'])
|
| 1454 |
buildings['casualty'] = list(df_bld_hazard['casualty'])
|
|
@@ -1471,7 +1539,17 @@ def ExecutePanel():
|
|
| 1471 |
is_ready, message = pre_compute_checks()
|
| 1472 |
if not is_ready:
|
| 1473 |
raise Exception(message)
|
| 1474 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1475 |
for trial in range(1,max_trials+1):
|
| 1476 |
if trial == 1:
|
| 1477 |
set_progress_message('Running...')
|
|
@@ -1508,6 +1586,13 @@ def ExecutePanel():
|
|
| 1508 |
store_info_to_session()
|
| 1509 |
layers.value['tally_is_available'].value = True
|
| 1510 |
tally_counter.value += 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1511 |
set_progress_message('')
|
| 1512 |
# trigger render event
|
| 1513 |
layers.value['render_count'].set(layers.value['render_count'].value + 1)
|
|
@@ -1525,7 +1610,11 @@ def ExecutePanel():
|
|
| 1525 |
with solara.Row(justify="left"):
|
| 1526 |
solara.ToggleButtonsSingle(value=layers.value['hazard'].value, on_value=layers.value['hazard'].set, values=layers.value['hazard_list'])
|
| 1527 |
if layers.value['hazard'].value == 'earthquake':
|
| 1528 |
-
solara.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1529 |
if layers.value['hazard'].value == 'landslide':
|
| 1530 |
solara.Markdown("#### Landslide trigger level")
|
| 1531 |
with solara.Row(justify="left"):
|
|
@@ -2002,6 +2091,11 @@ def WebApp():
|
|
| 2002 |
with solara.Row(justify="center"):
|
| 2003 |
MetricPanel()
|
| 2004 |
#LayerDisplayer()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2005 |
solara.Details(
|
| 2006 |
summary="Layer Details",
|
| 2007 |
children=[LayerDisplayer()],
|
|
|
|
| 50 |
'landslide_trigger_level': solara.reactive('moderate'),
|
| 51 |
'landslide_trigger_level_list': ['minor','moderate','severe'],
|
| 52 |
'earthquake_intensity_unit': solara.reactive('m/s2'),
|
| 53 |
+
'earthquake_simulation_methods': ["legacy","monte carlo"],
|
| 54 |
+
'earthquake_simulation_method_selected': solara.reactive('legacy'),
|
| 55 |
+
'earthquake_simulation_trial_count': solara.reactive(5),
|
| 56 |
'cdf_median_increase_in_percent': solara.reactive(0.2),
|
| 57 |
'threshold_increase_culvert_water_height': solara.reactive(0.2),
|
| 58 |
'threshold_increase_road_water_height': solara.reactive(0.2),
|
|
|
|
| 275 |
'map_info_detail': solara.reactive({}),
|
| 276 |
'tally_filter_cols': ['ds','income','material','gender','age','head','eduattstat','luf','occupancy'],
|
| 277 |
'tally_is_available': solara.reactive(False),
|
| 278 |
+
'metrics_realized': solara.reactive(None),
|
| 279 |
'metrics': {
|
| 280 |
"metric1": {"desc": "Number of workers unemployed", "value": 0, "max_value": 100},
|
| 281 |
"metric2": {"desc": "Number of children with no access to education", "value": 0, "max_value": 100},
|
|
|
|
| 1115 |
metric['max_value'],
|
| 1116 |
layers.value['render_count'].value)
|
| 1117 |
|
| 1118 |
+
@solara.component
|
| 1119 |
+
def MetricStatistics():
|
| 1120 |
+
if layers.value['metrics_realized'].value is None:
|
| 1121 |
+
solara.Text('There is no metrics statistics data yet!')
|
| 1122 |
+
return
|
| 1123 |
+
|
| 1124 |
+
# list of metrics measurements
|
| 1125 |
+
metrics = layers.value['metrics_realized'].value
|
| 1126 |
+
|
| 1127 |
+
# get the metric names from the first measurement
|
| 1128 |
+
metric_names = metrics[0].keys()
|
| 1129 |
+
|
| 1130 |
+
metric_dict = {}
|
| 1131 |
+
for metric_name in metric_names:
|
| 1132 |
+
metric_values = [m[metric_name]['value'] for m in metrics]
|
| 1133 |
+
metric_dict[metric_name] = metric_values
|
| 1134 |
+
df = pd.DataFrame.from_dict(metric_dict)
|
| 1135 |
+
summary = df.describe()
|
| 1136 |
+
|
| 1137 |
+
data = []
|
| 1138 |
+
for metric_name in metric_names:
|
| 1139 |
+
value = [float(summary[metric_name][k]) for k in ['min','25%','50%','75%','max']]
|
| 1140 |
+
data.append({"name":metric_name, "value": value})
|
| 1141 |
+
|
| 1142 |
+
options = {
|
| 1143 |
+
"title": [{"text": 'Impact Metrics of Different Realizations', "left": 'center' },],
|
| 1144 |
+
"tooltip": {
|
| 1145 |
+
"trigger": 'item',
|
| 1146 |
+
"axisPointer": {
|
| 1147 |
+
"type": 'shadow'
|
| 1148 |
+
}
|
| 1149 |
+
},
|
| 1150 |
+
"xAxis": {
|
| 1151 |
+
"type": 'category',
|
| 1152 |
+
"data": ['metric1', 'metric2', 'metric3', 'metric4','metric5', 'metric6', 'metric7', 'metric8'],
|
| 1153 |
+
},
|
| 1154 |
+
"yAxis": {
|
| 1155 |
+
"type": 'value',
|
| 1156 |
+
"splitArea": {
|
| 1157 |
+
"show": True
|
| 1158 |
+
}
|
| 1159 |
+
},
|
| 1160 |
+
"series": [
|
| 1161 |
+
{
|
| 1162 |
+
"name": 'boxplot',
|
| 1163 |
+
"type": 'boxplot',
|
| 1164 |
+
"itemStyle": {
|
| 1165 |
+
"color": '#b8c5f2'
|
| 1166 |
+
},
|
| 1167 |
+
"data": data
|
| 1168 |
+
},
|
| 1169 |
+
]
|
| 1170 |
+
}
|
| 1171 |
+
with solara.lab.Tabs():
|
| 1172 |
+
with solara.lab.Tab("Boxplot"):
|
| 1173 |
+
with solara.GridFixed(columns=1):
|
| 1174 |
+
solara.FigureEcharts(option=options, attributes={"style": "height:400%; width:100%"})
|
| 1175 |
+
with solara.lab.Tab("Data"):
|
| 1176 |
+
solara.DataFrame(df)
|
| 1177 |
+
with solara.lab.Tab("Stats"):
|
| 1178 |
+
solara.DataFrame(summary.reset_index())
|
| 1179 |
+
|
| 1180 |
@solara.component
|
| 1181 |
def MapViewer():
|
| 1182 |
print('rendering mapviewer')
|
|
|
|
| 1466 |
flood_depth_reduction = layers.value['flood_depth_reduction'].value
|
| 1467 |
cdf_median_increase_in_percent = layers.value['cdf_median_increase_in_percent'].value
|
| 1468 |
damage_curve_suppress_factor = layers.value['damage_curve_suppress_factor'].value
|
| 1469 |
+
earthquake_simulation_method = layers.value['earthquake_simulation_method_selected'].value
|
| 1470 |
threshold_flood = [threshold_flood_ds2.value, threshold_flood_ds3.value, threshold_flood_ds4.value]
|
| 1471 |
|
| 1472 |
policies = [p['id'] for _, p in layers.value['policies'].items() if f"{p['description']} ({p['label']})" in layers.value['selected_policies'].value]
|
|
|
|
| 1496 |
earthquake_intensity_unit=earthquake_intensity_unit,
|
| 1497 |
cdf_median_increase_in_percent=cdf_median_increase_in_percent,
|
| 1498 |
flood_depth_reduction=flood_depth_reduction,
|
| 1499 |
+
damage_curve_suppress_factor=damage_curve_suppress_factor,
|
| 1500 |
+
earthquake_simulation_method=earthquake_simulation_method,
|
| 1501 |
)
|
| 1502 |
else:
|
| 1503 |
if fragility is None:
|
|
|
|
| 1516 |
cdf_median_increase_in_percent=cdf_median_increase_in_percent,
|
| 1517 |
flood_depth_reduction=flood_depth_reduction,
|
| 1518 |
damage_curve_suppress_factor=damage_curve_suppress_factor,
|
| 1519 |
+
earthquake_simulation_method=earthquake_simulation_method,
|
| 1520 |
)
|
| 1521 |
buildings['ds'] = list(df_bld_hazard['ds'])
|
| 1522 |
buildings['casualty'] = list(df_bld_hazard['casualty'])
|
|
|
|
| 1539 |
is_ready, message = pre_compute_checks()
|
| 1540 |
if not is_ready:
|
| 1541 |
raise Exception(message)
|
| 1542 |
+
|
| 1543 |
+
if layers.value['hazard'].value == "earthquake" and layers.value['earthquake_simulation_method_selected'].value == 'monte carlo':
|
| 1544 |
+
max_trials = layers.value['earthquake_simulation_trial_count'].value
|
| 1545 |
+
elif layers.value['hazard'].value == "landslide":
|
| 1546 |
+
max_trials = landslide_max_trials.value
|
| 1547 |
+
elif layers.value['hazard'].value == "flood":
|
| 1548 |
+
max_trials = 1
|
| 1549 |
+
else:
|
| 1550 |
+
max_trials = 1
|
| 1551 |
+
|
| 1552 |
+
metrics_results = []
|
| 1553 |
for trial in range(1,max_trials+1):
|
| 1554 |
if trial == 1:
|
| 1555 |
set_progress_message('Running...')
|
|
|
|
| 1586 |
store_info_to_session()
|
| 1587 |
layers.value['tally_is_available'].value = True
|
| 1588 |
tally_counter.value += 1
|
| 1589 |
+
|
| 1590 |
+
metrics_result = generate_metrics(tally_geo, tally_geo,
|
| 1591 |
+
layers.value['hazard'].value,
|
| 1592 |
+
population_displacement_consensus.value)
|
| 1593 |
+
metrics_results.append(metrics_result)
|
| 1594 |
+
|
| 1595 |
+
layers.value['metrics_realized'].set(metrics_results)
|
| 1596 |
set_progress_message('')
|
| 1597 |
# trigger render event
|
| 1598 |
layers.value['render_count'].set(layers.value['render_count'].value + 1)
|
|
|
|
| 1610 |
with solara.Row(justify="left"):
|
| 1611 |
solara.ToggleButtonsSingle(value=layers.value['hazard'].value, on_value=layers.value['hazard'].set, values=layers.value['hazard_list'])
|
| 1612 |
if layers.value['hazard'].value == 'earthquake':
|
| 1613 |
+
with solara.Column(gap='40px'):
|
| 1614 |
+
solara.Select(label='unit of earthquake intensity map', values=['m/s2','g'], value=layers.value['earthquake_intensity_unit'])
|
| 1615 |
+
solara.Select(label='earthquake simulation method', values=layers.value['earthquake_simulation_methods'], value=layers.value['earthquake_simulation_method_selected'])
|
| 1616 |
+
if layers.value['earthquake_simulation_method_selected'].value == 'monte carlo':
|
| 1617 |
+
solara.InputInt(label='Number of trials',value=layers.value['earthquake_simulation_trial_count'])
|
| 1618 |
if layers.value['hazard'].value == 'landslide':
|
| 1619 |
solara.Markdown("#### Landslide trigger level")
|
| 1620 |
with solara.Row(justify="left"):
|
|
|
|
| 2091 |
with solara.Row(justify="center"):
|
| 2092 |
MetricPanel()
|
| 2093 |
#LayerDisplayer()
|
| 2094 |
+
solara.Details(
|
| 2095 |
+
summary="Metric Statistics",
|
| 2096 |
+
children=[MetricStatistics()],
|
| 2097 |
+
expand=False
|
| 2098 |
+
)
|
| 2099 |
solara.Details(
|
| 2100 |
summary="Layer Details",
|
| 2101 |
children=[LayerDisplayer()],
|