hkayabilisim commited on
Commit
b304f6f
·
1 Parent(s): 505d2bb

v0.2.2 completed road & power network analysis

Browse files
tomorrowcities/backend/engine.py CHANGED
@@ -119,7 +119,29 @@ def compute_road_infra(buildings, household, individual,
119
  idx = (household_w_node_id['commfacid'] == hospital_bld) & (household_w_node_id['node_id'] == node_with_hospital_access)
120
  household_w_node_id.loc[idx, 'hospital_access'] = True
121
 
122
- 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']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
 
124
  def compute_power_infra(buildings, household, nodes,edges,intensity,fragility,hazard):
125
  print('Computing power infrastructure')
@@ -591,6 +613,8 @@ def calculate_metrics(gdf_buildings, df_household, df_individual, infra, hazard_
591
  metric1_index = df_workers['ds'] > thresholds['metric1']
592
  if 'power' in infra:
593
  metric1_index = (metric1_index) | (df_workers['has_power'] == False)
 
 
594
  df_workers_per_building = df_workers[metric1_index][['individ','hhid','ds']].merge(
595
  df_household[['hhid','bldid']],on='hhid',how='left').groupby(
596
  'bldid',as_index=False).agg({'individ':'count'})
@@ -605,6 +629,8 @@ def calculate_metrics(gdf_buildings, df_household, df_individual, infra, hazard_
605
  metric2_index = df_students['ds'] > thresholds['metric2']
606
  if 'power' in infra:
607
  metric2_index = (metric2_index) | (df_students['has_power'] == False)
 
 
608
  df_students_per_building = df_students[metric2_index][['individ','hhid','ds']].merge(
609
  df_household[['hhid','bldid']],on='hhid',how='left').groupby(
610
  'bldid',as_index=False).agg({'individ':'count'})
@@ -673,6 +699,7 @@ def calculate_metrics(gdf_buildings, df_household, df_individual, infra, hazard_
673
  (df_displaced_indiv['ds_hospital'] > thresholds['metric4'])
674
  if 'road' in infra:
675
  metric7_index = (metric7_index) | (df_displaced_indiv['hospital_access'] == False)
 
676
  if 'power' in infra:
677
  metric7_index = (metric7_index) | (df_displaced_indiv['hospital_has_power'] == False)
678
  metric7_index = (metric7_index) | (df_displaced_indiv['workplace_power'] == False)
 
119
  idx = (household_w_node_id['commfacid'] == hospital_bld) & (household_w_node_id['node_id'] == node_with_hospital_access)
120
  household_w_node_id.loc[idx, 'hospital_access'] = True
121
 
122
+ # Workplace/School (facility) connectivity analysis
123
+ # For each individual, find the closest road node (closest) of the
124
+ # household and the facility
125
+
126
+ individual_w_nodes = individual.merge(household_w_node_id[['hhid','node_id']],on='hhid',how='left')\
127
+ .rename(columns={'node_id':'household_node_id'})\
128
+ .merge(gdf_buildings[['bldid','node_id']],how='left',left_on='indivfacid',right_on='bldid')\
129
+ .rename(columns={'node_id':'facility_node_id'})
130
+
131
+ # Calculate distances between all nodes in the damaged network
132
+ shortest_distance = nx.shortest_path_length(G_dmg)
133
+
134
+ # Create a dictionary to store all open connections
135
+ connection_dict = dict()
136
+ for source, targets in shortest_distance:
137
+ connection_dict[source] = dict()
138
+ for target, hop in targets.items():
139
+ connection_dict[source][target] = True
140
+
141
+ # Based on connectivity, fill-in facillity_access attribute in the individual layer
142
+ 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)
143
+
144
+ 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']
145
 
146
  def compute_power_infra(buildings, household, nodes,edges,intensity,fragility,hazard):
147
  print('Computing power infrastructure')
 
613
  metric1_index = df_workers['ds'] > thresholds['metric1']
614
  if 'power' in infra:
615
  metric1_index = (metric1_index) | (df_workers['has_power'] == False)
616
+ if 'road' in infra:
617
+ metric1_index = (metric1_index) | (df_workers['facility_access'] == False)
618
  df_workers_per_building = df_workers[metric1_index][['individ','hhid','ds']].merge(
619
  df_household[['hhid','bldid']],on='hhid',how='left').groupby(
620
  'bldid',as_index=False).agg({'individ':'count'})
 
629
  metric2_index = df_students['ds'] > thresholds['metric2']
630
  if 'power' in infra:
631
  metric2_index = (metric2_index) | (df_students['has_power'] == False)
632
+ if 'road' in infra:
633
+ metric2_index = (metric2_index) | (df_students['facility_access'] == False)
634
  df_students_per_building = df_students[metric2_index][['individ','hhid','ds']].merge(
635
  df_household[['hhid','bldid']],on='hhid',how='left').groupby(
636
  'bldid',as_index=False).agg({'individ':'count'})
 
699
  (df_displaced_indiv['ds_hospital'] > thresholds['metric4'])
700
  if 'road' in infra:
701
  metric7_index = (metric7_index) | (df_displaced_indiv['hospital_access'] == False)
702
+ metric7_index = (metric7_index) | (df_displaced_indiv['facility_access'] == False)
703
  if 'power' in infra:
704
  metric7_index = (metric7_index) | (df_displaced_indiv['hospital_has_power'] == False)
705
  metric7_index = (metric7_index) | (df_displaced_indiv['workplace_power'] == False)
tomorrowcities/content/articles/metrics.md CHANGED
@@ -19,11 +19,21 @@ Their calculations heavily depend on the damage state of buildings and/or other
19
  infrastructural elements such as electrical power generators, roads or bridges.
20
 
21
  ### Metric 1: Number of workers unemployed
22
- It denotes the number of invidivuals who lost their jobs either due to a damage at the workplace or lost access to a workplace. When the metrics is displayed on a building-level, it is the total number of such individuals living in that building.
 
 
 
 
 
23
 
24
  ### Metric 2: Number of children with no access to education
25
- Similar to the first metrics but individual here refers to a child who is associated with a school.
26
- The metric becomes active if the school is damaged or not accessible.
 
 
 
 
 
27
 
28
  ### Metric 3: Number of households with no access to hospital
29
  The number of households who lost its access to its associated hospital.
@@ -34,7 +44,13 @@ Access is lost when any of the following conditions hold:
34
  * the associated hospital has no electricity
35
 
36
  ### Metric 4: Number of individuals with no access to hospital
37
- It is derived from metric 3 by counting the individuals in the corresponding households.
 
 
 
 
 
 
38
 
39
  ### Metric 5: Number of households displaced
40
  It is direct result of building damage state. If a building is damaged, then the households in it are also
@@ -44,4 +60,9 @@ damaged.
44
  It is derived from metric 5.
45
 
46
  ### Metric 7: Population displacement
47
- An individual is assumed to be displaced if the associated household is damaged, or he/she lost access to workplace, schoold or hospital.
 
 
 
 
 
 
19
  infrastructural elements such as electrical power generators, roads or bridges.
20
 
21
  ### Metric 1: Number of workers unemployed
22
+ It denotes the number of invidivuals who lost their jobs based on any of the following conditions:
23
+
24
+ * the associated workplace is damaged beyond a threshold
25
+ * the associated workplace has lost electricity
26
+ * the associated workplace can not be reached from the building that the individual lives in via
27
+ transportation network.
28
 
29
  ### Metric 2: Number of children with no access to education
30
+ Similar to the first metrics but individual here refers to individuals associated with a school.
31
+ This metric takes place when any of the following conditions holds:
32
+
33
+ * the school is damaged beyond a threshold
34
+ * the school has lost electricity
35
+ * the school can not be reached from the building that the individual lives in via
36
+ transportation network.
37
 
38
  ### Metric 3: Number of households with no access to hospital
39
  The number of households who lost its access to its associated hospital.
 
44
  * the associated hospital has no electricity
45
 
46
  ### Metric 4: Number of individuals with no access to hospital
47
+ This metric is very similar to metric 3 except individual-hospital association
48
+ is used. In this metric, individual-hospital association is built upon household-hospital association.
49
+ An individual is said to lost his/her access to hospital when any of the conditions hold:
50
+
51
+ * the damage state of the associated hospital is beyond a threshold
52
+ * the associated hospital is inaccessible via transportation network
53
+ * the associated hospital has no electricity
54
 
55
  ### Metric 5: Number of households displaced
56
  It is direct result of building damage state. If a building is damaged, then the households in it are also
 
60
  It is derived from metric 5.
61
 
62
  ### Metric 7: Population displacement
63
+ An individual is assumed to be displaced when any of the following condition holds:
64
+
65
+ * the associated household is damaged
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
tomorrowcities/content/articles/power.md CHANGED
@@ -13,4 +13,60 @@ category:
13
 
14
  [TOC]
15
 
16
- ## Power Infrastructure Analysis
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  [TOC]
15
 
16
+ ## Power Infrastructure Analysis
17
+
18
+
19
+ ### Data
20
+ **Power Nodes**
21
+
22
+ node_id|pwr_plant|n_bldgs|eq_vuln|geometry|
23
+ |-------|---------|-------|-------|--------|
24
+ |1 |1 |None |None |POINT (36.80602 -1.31293)|
25
+ |2 |0 |0 |ESS1 |POINT (36.80302 -1.36646)|
26
+ |3 |0 |3 |ESS2 |POINT (36.80302 -1.36646)|
27
+
28
+ **node_id** is a unique identifier for electrical power node.
29
+ **pwr_plant** indicates that the power node is a generator/power source
30
+ when it is set to 1 or True.
31
+ **n_bldgs** is used for the nodes which distributes electricity to the
32
+ neighboring building. If this attribute is a positive value then it will used
33
+ to distribute power to the neighbors. Such nodes are called *server* nodes.
34
+ **eq_vuln** is the taxonomy string used for the structural power node building.
35
+ When not specified, the node is assumed to be immune to hazards. Finally comes
36
+ the geometry column which is simple a point coordinate in WGS84 coordinate
37
+ reference system.
38
+
39
+ **Power Edges**
40
+ The minimum required attributes of the edges is shown below:
41
+
42
+ |edge_id|from_node|to_node|geometry|
43
+ |---------|-------|-------|--------|
44
+ |1 |2 |1 |LINESTRING (82.61515 27.80731, ...|
45
+ |2 |3 |1 |LINESTRING (82.72634 27.68782, ...|
46
+ |3 |1 |2 |LINESTRING (82.06824 27.80731, ...|
47
+
48
+ where **edge_id** is the unique identifier of the transmission line between any two nodes.
49
+ **from/to_node** attributes define the starting and ending nodes of the transmission line.
50
+ Finally comes the geometry as a line string. For transmission lines, no taxonomy information
51
+ is required.
52
+
53
+ **Power Fragility**
54
+ The fragility functions for the power node structures are defined as a tabular tabular data whose
55
+ attributes are shown below.
56
+
57
+ | vuln_string |med_Slight | med_Moderate | med_Extensive | med_Complete | beta_Slight | beta_Moderate | beta_Extensive | beta_Complete | description|
58
+ |--------------|-----------|--------------|---------------|--------------|-------------|---------------|----------------|---------------|--------------------------------------------------|
59
+ | ESS1 | 0.15 | 0.29 | 0.45 | 0.90 | 0.70 | 0.55 | 0.45 | 0.45 | Low Voltage (115 KV) Substation (Anchored/Seis...|
60
+ | ESS2 | 0.13 | 0.26 | 0.34 | 0.74 | 0.65 | 0.50 | 0.40 | 0.40 | Low Voltage (115 KV) Substation (Unanchored/St...|
61
+ | ESS3 | 0.15 | 0.25 | 0.35 | 0.70 | 0.60 | 0.50 | 0.40 | 0.40 | Medium Voltage (230 KV) Substation (Anchored/S...|
62
+
63
+ **vuln_string** of the fragility curves should match **eq_vuln** field of the power nodes. Median and beta values of four fragility curves (slight, moderate, extensive and complete) are defined
64
+ in the same row. It is optional to add a description message.
65
+
66
+ ### Additional Auxillary Attributes
67
+ As soon as the power network analysis is conducted,
68
+ the engine creates internal attributes tagged to building and household layers
69
+ which will be visible in LayerDisplayer. The name of the additional attribute is
70
+ *has_power* which is a boolean variable. When used in the building layer, it indicates
71
+ if a building has power or not. The same attribute is also used in household layer
72
+ which indicates the associated building has power.
tomorrowcities/content/articles/welcome.md CHANGED
@@ -18,7 +18,18 @@ TCDSE is a web application designed to conduct computational tasks to generate i
18
 
19
  ## What is New?
20
 
21
- **v0.2.1**
 
 
 
 
 
 
 
 
 
 
 
22
 
23
  * [27dd195](https://github.com/TomorrowsCities/tomorrowcities/commit/27dd195a240cbb97a97d124fc9b132ee2ea1f5e9) Integrated road network analysis into metric3
24
  * [de6fbca](https://github.com/TomorrowsCities/tomorrowcities/commit/de6fbca8d8b03d350096190ae35646f47a9a0414) Changed engine layout to be more compact
@@ -27,7 +38,7 @@ TCDSE is a web application designed to conduct computational tasks to generate i
27
  * Extended documentation in welcome, data, metrics, and road pages.
28
  * Added [a demonstration video](https://github.com/TomorrowsCities/tomorrowcities/assets/2515171/ec2dc36d-fe76-42fb-b9be-47a1690374de) to GitHub discussion page[discussion](https://github.com/TomorrowsCities/tomorrowcities/discussions/6).
29
 
30
- **v0.2**
31
 
32
  * Transportation network analysis for flood and earthquake damage assessment
33
  * Building and household-level loss of hospital access information
 
18
 
19
  ## What is New?
20
 
21
+ **Changelog: v0.2.2**
22
+
23
+ * Power and Road network analysis is completed.
24
+ * Electrical power loss information is propagated to household and individual layers.
25
+ * All seven impact metrics are updated to reflect electrical power-loss.
26
+ * All seven impact metrics are updated to reflect damage in road network.
27
+ * Documentation in the engine is extended.
28
+ * New version of the engine is redeployed to [HuggingFace](https://huggingface.co/spaces/hkayabilisim/app-engine).
29
+ * Reorganized the folders in the [Sample Dataset](https://drive.google.com/file/d/1BGPZQ2IKJHY9ExOCCHcNNrCTioYZ8D1y/view?usp=sharing).
30
+ * Building layer can now be exported as CSV also.
31
+
32
+ **Changelog: v0.2.1**
33
 
34
  * [27dd195](https://github.com/TomorrowsCities/tomorrowcities/commit/27dd195a240cbb97a97d124fc9b132ee2ea1f5e9) Integrated road network analysis into metric3
35
  * [de6fbca](https://github.com/TomorrowsCities/tomorrowcities/commit/de6fbca8d8b03d350096190ae35646f47a9a0414) Changed engine layout to be more compact
 
38
  * Extended documentation in welcome, data, metrics, and road pages.
39
  * Added [a demonstration video](https://github.com/TomorrowsCities/tomorrowcities/assets/2515171/ec2dc36d-fe76-42fb-b9be-47a1690374de) to GitHub discussion page[discussion](https://github.com/TomorrowsCities/tomorrowcities/discussions/6).
40
 
41
+ **Changelog: v0.2**
42
 
43
  * Transportation network analysis for flood and earthquake damage assessment
44
  * Building and household-level loss of hospital access information
tomorrowcities/pages/engine.py CHANGED
@@ -73,7 +73,7 @@ layers = solara.reactive({
73
  'force_render': solara.reactive(False),
74
  'visible': solara.reactive(False),
75
  'pre_processing': identity_preprocess,
76
- 'extra_cols': {},
77
  'attributes_required': set(['individ', 'hhid', 'gender', 'age', 'eduattstat', 'head', 'indivfacid']),
78
  'attributes': set(['individ', 'hhid', 'gender', 'age', 'eduattstat', 'head', 'indivfacid'])},
79
  'intensity': {
@@ -848,9 +848,12 @@ def LayerDisplayer():
848
  #solara.CrossFilterDataFrame(df=data)
849
  solara.DataFrame(data, items_per_page=5)
850
  if selected == "building":
851
- file_object = data.to_json()
852
- with solara.FileDownload(file_object, "building_export.geojson", mime_type="application/geo+json"):
853
- solara.Button("Download GeoJSON", icon_name="mdi-cloud-download-outline", color="primary")
 
 
 
854
  if selected == 'gem_vulnerability':
855
  VulnerabiliyDisplayer(data)
856
 
@@ -978,7 +981,9 @@ def ExecutePanel():
978
  buildings['hospital_access'] = False
979
  household['node_id'] = None
980
  household['hospital_access'] = False
981
- ds, is_damaged, building_node_id, building_hospital_acess, household_node_id, household_hospital_access = \
 
 
982
  compute_road_infra(buildings, household, individual, nodes, edges, intensity,
983
  fragility, hazard,road_water_height_threshold)
984
 
@@ -988,11 +993,12 @@ def ExecutePanel():
988
  buildings['hospital_access'] = list(building_hospital_acess)
989
  household['node_id'] = list(household_node_id)
990
  household['hospital_access'] = list(household_hospital_access)
 
991
 
992
  print(buildings.head())
993
  print('number of damaged roads/bridges',len(edges[edges['is_damaged']]))
994
 
995
- return edges, buildings, household
996
 
997
  def execute_power():
998
  buildings = layers.value['layers']['building']['data'].value
@@ -1089,10 +1095,11 @@ def ExecutePanel():
1089
  layers.value['layers']['building']['data'].set(buildings)
1090
  layers.value['layers']['household']['data'].set(household)
1091
  if 'road' in layers.value['infra'].value:
1092
- edges, buildings, household = execute_road()
1093
  layers.value['layers']['road edges']['data'].set(edges)
1094
  layers.value['layers']['building']['data'].set(buildings)
1095
  layers.value['layers']['household']['data'].set(household)
 
1096
  if 'building' in layers.value['infra'].value:
1097
  buildings = execute_building()
1098
  layers.value['layers']['building']['data'].set(buildings)
 
73
  'force_render': solara.reactive(False),
74
  'visible': solara.reactive(False),
75
  'pre_processing': identity_preprocess,
76
+ 'extra_cols': {'facility_access':True},
77
  'attributes_required': set(['individ', 'hhid', 'gender', 'age', 'eduattstat', 'head', 'indivfacid']),
78
  'attributes': set(['individ', 'hhid', 'gender', 'age', 'eduattstat', 'head', 'indivfacid'])},
79
  'intensity': {
 
848
  #solara.CrossFilterDataFrame(df=data)
849
  solara.DataFrame(data, items_per_page=5)
850
  if selected == "building":
851
+ with solara.Row():
852
+ file_object = data.to_json()
853
+ with solara.FileDownload(file_object, "building_export.geojson", mime_type="application/geo+json"):
854
+ solara.Button("Download GeoJSON", icon_name="mdi-cloud-download-outline", color="primary")
855
+ with solara.FileDownload(data.to_csv(), "building_export.csv", mime_type="text/csv"):
856
+ solara.Button("Download CSV", icon_name="mdi-cloud-download-outline", color="primary")
857
  if selected == 'gem_vulnerability':
858
  VulnerabiliyDisplayer(data)
859
 
 
981
  buildings['hospital_access'] = False
982
  household['node_id'] = None
983
  household['hospital_access'] = False
984
+ individual['facility_access'] = True
985
+ ds, is_damaged, building_node_id, building_hospital_acess, household_node_id, \
986
+ household_hospital_access, individual_facility_access = \
987
  compute_road_infra(buildings, household, individual, nodes, edges, intensity,
988
  fragility, hazard,road_water_height_threshold)
989
 
 
993
  buildings['hospital_access'] = list(building_hospital_acess)
994
  household['node_id'] = list(household_node_id)
995
  household['hospital_access'] = list(household_hospital_access)
996
+ individual['facility_access'] = list(individual_facility_access)
997
 
998
  print(buildings.head())
999
  print('number of damaged roads/bridges',len(edges[edges['is_damaged']]))
1000
 
1001
+ return edges, buildings, household, individual
1002
 
1003
  def execute_power():
1004
  buildings = layers.value['layers']['building']['data'].value
 
1095
  layers.value['layers']['building']['data'].set(buildings)
1096
  layers.value['layers']['household']['data'].set(household)
1097
  if 'road' in layers.value['infra'].value:
1098
+ edges, buildings, household, individual = execute_road()
1099
  layers.value['layers']['road edges']['data'].set(edges)
1100
  layers.value['layers']['building']['data'].set(buildings)
1101
  layers.value['layers']['household']['data'].set(household)
1102
+ layers.value['layers']['individual']['data'].set(individual)
1103
  if 'building' in layers.value['infra'].value:
1104
  buildings = execute_building()
1105
  layers.value['layers']['building']['data'].set(buildings)