Huseyin Kaya commited on
Commit
304afd3
·
unverified ·
2 Parent(s): ab7379e 38308d3

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 != "landslide":
 
 
 
 
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
- bld_eq[['prob_ds0','prob_ds5']] = [1,0]
726
- for i in [1,2,3,4,5]:
727
- bld_eq[f'ds_{i}'] = np.abs(bld_eq[f'prob_ds{i-1}'] - bld_eq[f'prob_ds{i}'])
728
- df_ds = bld_eq[['ds_1','ds_2','ds_3','ds_4','ds_5']]
729
- bld_eq['eq_ds'] = df_ds.idxmax(axis='columns').str.extract(r'ds_([0-9]+)').astype('int') - 1
 
 
 
 
 
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
- max_trials = landslide_max_trials.value if layers.value['hazard'].value == "landslide" else 1
 
 
 
 
 
 
 
 
 
 
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.Select(label='unit of earthquake intensity map', values=['m/s2','g'], value=layers.value['earthquake_intensity_unit'])
 
 
 
 
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()],