irie 0.0.5__py3-none-any.whl → 0.0.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of irie might be problematic. Click here for more details.
- irie/apps/config.py +0 -1
- irie/apps/evaluation/identification.py +1 -1
- irie/apps/evaluation/models.py +3 -3
- irie/apps/evaluation/views.py +3 -3
- irie/apps/events/admin.py +2 -2
- irie/apps/events/migrations/0002_rename_event_eventrecord.py +19 -0
- irie/apps/events/migrations/0003_hazardevent.py +21 -0
- irie/apps/events/models.py +55 -5
- irie/apps/events/views.py +48 -3
- irie/apps/events/views_events.py +6 -10
- irie/apps/inventory/filters.py +37 -0
- irie/apps/inventory/models.py +7 -0
- irie/apps/inventory/urls.py +1 -0
- irie/apps/inventory/views.py +134 -227
- irie/apps/prediction/forms.py +4 -8
- irie/apps/prediction/metrics.py +0 -2
- irie/apps/prediction/migrations/0002_alter_predictormodel_protocol.py +18 -0
- irie/apps/prediction/models.py +4 -4
- irie/apps/prediction/predictor.py +18 -12
- irie/apps/prediction/runners/__init__.py +3 -398
- irie/apps/prediction/runners/hazus.py +579 -0
- irie/apps/prediction/runners/opensees/__init__.py +395 -0
- irie/apps/prediction/runners/{utilities.py → opensees/utilities.py} +7 -7
- irie/apps/prediction/runners/ssid.py +414 -0
- irie/apps/prediction/urls.py +1 -1
- irie/apps/prediction/views.py +45 -22
- irie/apps/site/view_sdof.py +2 -2
- irie/apps/templates/admin/base_site.html +3 -1
- irie/apps/templates/css/admin-extra.css +7 -0
- irie/apps/templates/includes/sidebar.html +17 -14
- irie/apps/templates/inventory/asset-event-summary.html +3 -2
- irie/apps/templates/inventory/asset-profile.html +126 -38
- irie/apps/templates/inventory/asset-table.html +191 -135
- irie/apps/templates/inventory/dashboard.html +105 -27
- irie/apps/templates/inventory/preamble.tex +131 -0
- irie/apps/templates/inventory/report.tex +59 -0
- irie/apps/templates/networks/corridor_table.html +2 -2
- irie/apps/templates/networks/networks.html +164 -0
- irie/apps/templates/prediction/asset-predictors.html +6 -6
- irie/apps/templates/prediction/form-submission.html +3 -3
- irie/apps/templates/prediction/hazus/event.html +33 -0
- irie/apps/templates/prediction/hazus/history.html +1 -0
- irie/apps/templates/prediction/hazus/history.js +44 -0
- irie/apps/templates/prediction/{new-predictor.html → new-runner.html} +12 -8
- irie/apps/templates/site/index.html +29 -47
- irie/core/urls.py +7 -2
- irie/init/__main__.py +2 -0
- irie/init/bridges.py +5 -3
- irie/init/management/commands/init_assets.py +24 -45
- irie/init/management/commands/init_corridors.py +3 -6
- irie/init/management/commands/init_predictors.py +23 -8
- irie/post/__main__.py +88 -0
- {irie-0.0.5.dist-info → irie-0.0.6.dist-info}/METADATA +5 -3
- {irie-0.0.5.dist-info → irie-0.0.6.dist-info}/RECORD +61 -47
- /irie/apps/prediction/runners/{metrics.py → opensees/metrics.py} +0 -0
- /irie/apps/prediction/runners/{xmlutils.py → opensees/xmlutils.py} +0 -0
- /irie/apps/prediction/runners/{zipped.py → opensees/zipped.py} +0 -0
- /irie/init/data/{04.tar → nbi/04.tar} +0 -0
- {irie-0.0.5.dist-info → irie-0.0.6.dist-info}/WHEEL +0 -0
- {irie-0.0.5.dist-info → irie-0.0.6.dist-info}/entry_points.txt +0 -0
- {irie-0.0.5.dist-info → irie-0.0.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,579 @@
|
|
|
1
|
+
"""
|
|
2
|
+
From [1] Section 7.1.3 and [2] Section 9.1:
|
|
3
|
+
Bridges are classified based on the following structural characteristics:
|
|
4
|
+
- Seismic Design
|
|
5
|
+
- Number of spans: single vs. multiple span bridges
|
|
6
|
+
- Structure type: concrete, steel, and others
|
|
7
|
+
- Pier type: multiple column bents, single column bents, and pier walls
|
|
8
|
+
- Abutment type and bearing type: monolithic vs. non-monolithic, high rocker bearings, low
|
|
9
|
+
steel bearings, and neoprene rubber bearings
|
|
10
|
+
- Span continuity: continuous, discontinuous (in-span hinges), and simply supported
|
|
11
|
+
|
|
12
|
+
The seismic design of a bridge is taken into account in terms of the
|
|
13
|
+
(i) spectrum modification factor,
|
|
14
|
+
(ii) strength reduction factor due to cyclic motion,
|
|
15
|
+
(iii) drift limits, and
|
|
16
|
+
(iv) the longitudinal reinforcement ratio.
|
|
17
|
+
|
|
18
|
+
[1] Hazus earthquake technical manual
|
|
19
|
+
https://www.fema.gov/sites/default/files/2020-10/fema_hazus_earthquake_technical_manual_4-2.pdf
|
|
20
|
+
|
|
21
|
+
[2] Hazus inventory technical manual
|
|
22
|
+
https://www.fema.gov/sites/default/files/documents/fema_hazus-6-inventory-technical-manual.pdf
|
|
23
|
+
|
|
24
|
+
[3] Mander and Basoz
|
|
25
|
+
https://www.researchgate.net/profile/Jb-Mander/publication/292691534_Seismic_fragility_curve_theory_for_highway_bridges/links/5a7346d7aca2720bc0dbb653/Seismic-fragility-curve-theory-for-highway-bridges.pdf
|
|
26
|
+
|
|
27
|
+
-------------------------------------------
|
|
28
|
+
|
|
29
|
+
Table 9-6 in [2] (also 7-1 in [1])
|
|
30
|
+
|
|
31
|
+
HWB1 All Non-CA < 1990 N/A > 150 N/A EQ1 0 Conventional Major Bridge - Length > 150 meters
|
|
32
|
+
All CA < 1975 N/A > 150 N/A EQ1 0 Conventional Major Bridge - Length > 150 meters
|
|
33
|
+
HWB2 All Non-CA >= 1990 N/A > 150 N/A EQ1 0 Seismic Major Bridge - Length > 150 meters
|
|
34
|
+
All CA >= 1975 N/A > 150 N/A EQ1 0 Seismic Major Bridge - Length > 150 meters
|
|
35
|
+
HWB3 All Non-CA < 1990 1 N/A N/A EQ1 1 Conventional Single Span
|
|
36
|
+
All CA < 1975 1 N/A N/A EQ1 1 Conventional Single Span
|
|
37
|
+
HWB4 All Non-CA >= 1990 1 N/A N/A EQ1 1 Seismic Single Span
|
|
38
|
+
All CA >= 1975 1 N/A N/A EQ1 1 Seismic Single Span
|
|
39
|
+
HWB5 101 106 Non-CA < 1990 N/A N/A N/A EQ1 0 Conventional Multi-Col. Bent, Simple Support - Concrete
|
|
40
|
+
HWB6 101 106 CA < 1975 N/A N/A N/A EQ1 0 Conventional Multi-Col. Bent, Simple Support - Concrete
|
|
41
|
+
HWB7 101 106 Non-CA >= 1990 N/A N/A N/A EQ1 0 Seismic Multi-Col. Bent, Simple Support - Concrete
|
|
42
|
+
101 106 CA >= 1975 N/A N/A N/A EQ1 0 Seismic Multi-Col. Bent, Simple Support - Concrete
|
|
43
|
+
HWB8 205 206 CA < 1975 N/A N/A N/A EQ2 0 Conventional Single Col., Box Girder - Continuous Concrete
|
|
44
|
+
HWB9 205 206 CA >= 1975 N/A N/A N/A EQ3 0 Seismic Single Col., Box Girder - Continuous Concrete
|
|
45
|
+
HWB10 201 206 Non-CA < 1990 N/A N/A N/A EQ2 1 Conventional Continuous Concrete
|
|
46
|
+
201 206 CA < 1975 N/A N/A N/A EQ2 1 Conventional Continuous Concrete
|
|
47
|
+
HWB11 201 206 Non-CA >= 1990 N/A N/A N/A EQ3 1 Seismic Continuous Concrete
|
|
48
|
+
201 206 CA >= 1975 N/A N/A N/A EQ3 1 Seismic Continuous Concrete
|
|
49
|
+
HWB12 301 306 Non-CA < 1990 N/A N/A No EQ4 0 Conventional Multi-Col. Bent, Simple Support - Steel
|
|
50
|
+
HWB13 301 306 CA < 1975 N/A N/A No EQ4 0 Conventional Multi-Col. Bent, Simple Support - Steel
|
|
51
|
+
HWB14 301 306 Non-CA >= 1990 N/A N/A N/A EQ1 0 Seismic Multi-Col. Bent, Simple Support - Steel
|
|
52
|
+
301 306 CA >= 1975 N/A N/A N/A EQ1 0 Seismic Multi-Col. Bent, Simple Support - Steel
|
|
53
|
+
HWB15 402 410 Non-CA < 1990 N/A N/A No EQ5 1 Conventional Continuous Steel
|
|
54
|
+
402 410 CA < 1975 N/A N/A No EQ5 1 Conventional Continuous Steel
|
|
55
|
+
HWB16 402 410 Non-CA >= 1990 N/A N/A N/A EQ3 1 Seismic Continuous Steel
|
|
56
|
+
402 410 CA >= 1975 N/A N/A N/A EQ3 1 Seismic Continuous Steel
|
|
57
|
+
HWB17 501 506 Non-CA < 1990 N/A N/A N/A EQ1 0 Conventional Multi-Col. Bent, Simple Support - Prestressed Concrete
|
|
58
|
+
HWB18 501 506 CA < 1975 N/A N/A N/A EQ1 0 Conventional Multi-Col. Bent, Simple Support - Prestressed Concrete
|
|
59
|
+
HWB19 501 506 Non-CA >= 1990 N/A N/A N/A EQ1 0 Seismic Multi-Col. Bent, Simple Support - Prestressed Concrete
|
|
60
|
+
501 506 CA >= 1975 N/A N/A N/A EQ1 0 Seismic Multi-Col. Bent, Simple Support - Prestressed Concrete
|
|
61
|
+
HWB20 605 606 CA < 1975 N/A N/A N/A EQ2 0 Conventional Single Col., Box Girder - Prestressed Continuous Concrete
|
|
62
|
+
HWB21 605 606 CA >= 1975 N/A N/A N/A EQ3 0 Seismic Single Col., Box Girder - Prestressed Continuous Concrete
|
|
63
|
+
HWB22 601 607 Non-CA < 1990 N/A N/A N/A EQ2 1 Conventional Continuous Concrete
|
|
64
|
+
601 607 CA < 1975 N/A N/A N/A EQ2 1 Conventional Continuous Concrete
|
|
65
|
+
HWB23 601 607 Non-CA >= 1990 N/A N/A N/A EQ3 1 Seismic Continuous Concrete
|
|
66
|
+
601 607 CA >= 1975 N/A N/A N/A EQ3 1 Seismic Continuous Concrete
|
|
67
|
+
HWB24 301 306 Non-CA < 1990 N/A N/A Yes EQ6 0 Conventional Multi-Col. Bent, Simple Support - Steel
|
|
68
|
+
HWB25 301 306 CA < 1975 N/A N/A Yes EQ6 0 Conventional Multi-Col. Bent, Simple Support - Steel
|
|
69
|
+
HWB26 402 410 Non-CA < 1990 N/A N/A Yes EQ7 1 Conventional Continuous Steel
|
|
70
|
+
HWB27 402 410 CA < 1975 N/A N/A Yes EQ7 1 Conventional Continuous Steel
|
|
71
|
+
HWB28 N/A N/A All other bridges that are not classified
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
--------------------------
|
|
75
|
+
|
|
76
|
+
Table 9-7: Hazus Highway System Classification
|
|
77
|
+
|
|
78
|
+
HWB1 Major Bridge - Length > 150 meters (Conventional Design)
|
|
79
|
+
HWB2 Major Bridge - Length > 150 meters (Seismic Design)
|
|
80
|
+
HWB3 Single Span - (Not HWB1 or HWB2) (Conventional Design)
|
|
81
|
+
HWB4 Single Span - (Not HWB1 or HWB2) (Seismic Design)
|
|
82
|
+
HWB5 Concrete, Multi-Column Bent, Simple Support (Conventional Design), Non-California (Non CA)
|
|
83
|
+
HWB6 Concrete, Multi-Column Bent, Simple Support (Conventional Design), California (CA)
|
|
84
|
+
HWB7 Concrete, Multi-Column Bent, Simple Support (Seismic Design)
|
|
85
|
+
HWB8 Continuous Concrete, Single Column, Box Girder (Conventional Design)
|
|
86
|
+
HWB9 Continuous Concrete, Single Column, Box Girder (Seismic Design)
|
|
87
|
+
HWB10 Continuous Concrete, (Not HWB8 or HWB9) (Conventional Design)
|
|
88
|
+
HWB11 Continuous Concrete, (Not HWB8 or HWB9) (Seismic Design)
|
|
89
|
+
HWB12 Steel, Multi-Column Bent, Simple Support (Conventional Design), Non-California (Non-CA)
|
|
90
|
+
HWB13 Steel, Multi-Column Bent, Simple Support (Conventional Design), California (CA)
|
|
91
|
+
HWB14 Steel, Multi-Column Bent, Simple Support (Seismic Design)
|
|
92
|
+
HWB15 Continuous Steel (Conventional Design)
|
|
93
|
+
HWB16 Continuous Steel (Seismic Design)
|
|
94
|
+
HWB17 PS Concrete Multi-Column Bent, Simple Support (Conventional Design), Non-California
|
|
95
|
+
HWB18 PS Concrete, Multi-Column Bent, Simple Support (Conventional Design), California (CA)
|
|
96
|
+
HWB19 PS Concrete, Multi-Column Bent, Simple Support (Seismic Design)
|
|
97
|
+
HWB20 PS Concrete, Single Column, Box Girder (Conventional Design)
|
|
98
|
+
HWB21 PS Concrete, Single Column, Box Girder (Seismic Design)
|
|
99
|
+
HWB22 Continuous Concrete, (Not HWB20/HWB21) (Conventional Design)
|
|
100
|
+
HWB23 Continuous Concrete, (Not HWB20/HWB21) (Seismic Design)
|
|
101
|
+
HWB24 Same definition as HWB12 except the bridge length is less than 20 meters
|
|
102
|
+
HWB25 Same definition as HWB13 except the bridge length is less than 20 meters
|
|
103
|
+
HWB26 Same definition as HWB15 except the bridge length is less than 20 meters and Non-CA
|
|
104
|
+
HWB27 Same definition as HWB15 except the bridge length is less than 20 meters and in CA
|
|
105
|
+
HWB28 All other bridges that are not classified (including wooden bridges)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
-----------------------------
|
|
109
|
+
|
|
110
|
+
Table 7-6 Fragility Function Median Values for Highway Bridges
|
|
111
|
+
|
|
112
|
+
HWB1 0.40 0.50 0.70 0.90 3.9 3.9 3.9 13.8
|
|
113
|
+
HWB2 0.60 0.90 1.10 1.70 3.9 3.9 3.9 13.8
|
|
114
|
+
HWB3 0.80 1.00 1.20 1.70 3.9 3.9 3.9 13.8
|
|
115
|
+
HWB4 0.80 1.00 1.20 1.70 3.9 3.9 3.9 13.8
|
|
116
|
+
HWB5 0.25 0.35 0.45 0.70 3.9 3.9 3.9 13.8
|
|
117
|
+
HWB6 0.30 0.50 0.60 0.90 3.9 3.9 3.9 13.8
|
|
118
|
+
HWB7 0.50 0.80 1.10 1.70 3.9 3.9 3.9 13.8
|
|
119
|
+
HWB8 0.35 0.45 0.55 0.80 3.9 3.9 3.9 13.8
|
|
120
|
+
HWB9 0.60 0.90 1.30 1.60 3.9 3.9 3.9 13.8
|
|
121
|
+
HWB10 0.60 0.90 1.10 1.50 3.9 3.9 3.9 13.8
|
|
122
|
+
HWB11 0.90 0.90 1.10 1.50 3.9 3.9 3.9 13.8
|
|
123
|
+
HWB12 0.25 0.35 0.45 0.70 3.9 3.9 3.9 13.8
|
|
124
|
+
HWB13 0.30 0.50 0.60 0.90 3.9 3.9 3.9 13.8
|
|
125
|
+
HWB14 0.50 0.80 1.10 1.70 3.9 3.9 3.9 13.8
|
|
126
|
+
HWB15 0.75 0.75 0.75 1.10 3.9 3.9 3.9 13.8
|
|
127
|
+
HWB16 0.90 0.90 1.10 1.50 3.9 3.9 3.9 13.8
|
|
128
|
+
HWB17 0.25 0.35 0.45 0.70 3.9 3.9 3.9 13.8
|
|
129
|
+
HWB18 0.30 0.50 0.60 0.90 3.9 3.9 3.9 13.8
|
|
130
|
+
HWB19 0.50 0.80 1.10 1.70 3.9 3.9 3.9 13.8
|
|
131
|
+
HWB20 0.35 0.45 0.55 0.80 3.9 3.9 3.9 13.8
|
|
132
|
+
HWB21 0.60 0.90 1.30 1.60 3.9 3.9 3.9 13.8
|
|
133
|
+
HWB22 0.60 0.90 1.10 1.50 3.9 3.9 3.9 13.8
|
|
134
|
+
HWB23 0.90 0.90 1.10 1.50 3.9 3.9 3.9 13.8
|
|
135
|
+
HWB24 0.25 0.35 0.45 0.70 3.9 3.9 3.9 13.8
|
|
136
|
+
HWB25 0.30 0.50 0.60 0.90 3.9 3.9 3.9 13.8
|
|
137
|
+
HWB26 0.75 0.75 0.75 1.10 3.9 3.9 3.9 13.8
|
|
138
|
+
HWB27 0.75 0.75 0.75 1.10 3.9 3.9 3.9 13.8
|
|
139
|
+
HWB28 0.80 1.00 1.20 1.70 3.9 3.9 3.9 13.8
|
|
140
|
+
"""
|
|
141
|
+
import math
|
|
142
|
+
from scipy.stats import norm
|
|
143
|
+
|
|
144
|
+
Slight, Moderate, Extensive, Complete = range(4)
|
|
145
|
+
|
|
146
|
+
# State codes; We'll add more later, right now we assume
|
|
147
|
+
# everything is in California
|
|
148
|
+
class StateCodes:
|
|
149
|
+
California = 22
|
|
150
|
+
|
|
151
|
+
def hazus_fragility(
|
|
152
|
+
nbi_data: dict,
|
|
153
|
+
pga: float = 0.5, # Peak Ground Acceleration (g)
|
|
154
|
+
sa_03s: float = 1.1, # Spectral Acceleration at 0.3 seconds (g)
|
|
155
|
+
sa_10s: float = 1.4, # Spectral Acceleration at 1.0 seconds (g)
|
|
156
|
+
soil_type: str = "B", # Soil classification ("A", "B", "C", "D", "E")
|
|
157
|
+
level: int = None, # Optional: Specify a damage state (0 = Slight, 1 = Moderate, etc.)
|
|
158
|
+
generate_plot: bool = False, # Generate fragility curve plot
|
|
159
|
+
return_data: bool = False
|
|
160
|
+
) -> dict:
|
|
161
|
+
"""
|
|
162
|
+
Compute fragility probabilities for a given bridge using the Hazus methodology.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
- nbi_data (dict): NBI data containing bridge-specific properties.
|
|
166
|
+
- pga (float): Peak Ground Acceleration (g).
|
|
167
|
+
- sa_03s (float): Spectral Acceleration at 0.3 seconds (g).
|
|
168
|
+
- sa_10s (float): Spectral Acceleration at 1.0 seconds (g).
|
|
169
|
+
- soil_type (str): Soil classification ("A", "B", "C", "D", "E").
|
|
170
|
+
- level (int): Specify a damage state (0 = Slight, 1 = Moderate, etc.) (optional).
|
|
171
|
+
- generate_plot (bool): Whether to generate and return fragility curve plots.
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
- dict: Fragility probabilities for all damage states, optionally with fragility curve plot.
|
|
175
|
+
- float: Probability for the specified damage state (if `level` is provided).
|
|
176
|
+
"""
|
|
177
|
+
# Step 0: Extract relevant bridge properties
|
|
178
|
+
properties = _bridge_info(nbi_data)
|
|
179
|
+
|
|
180
|
+
# Step 1: Determine Hazus bridge type
|
|
181
|
+
hazus_type: int = _hazus_type(properties)
|
|
182
|
+
if hazus_type == -1:
|
|
183
|
+
raise ValueError("Bridge type not found in Hazus classification")
|
|
184
|
+
|
|
185
|
+
# Step 2: Call _hazus_curve to compute fragility probabilities
|
|
186
|
+
fragility_probs = _hazus_curve(hazus_type, properties, pga, sa_03s, sa_10s, soil_type)
|
|
187
|
+
|
|
188
|
+
# Step 3: Generate fragility curve plot if requested
|
|
189
|
+
if generate_plot or return_data:
|
|
190
|
+
# Adjust sa_range to start from 0
|
|
191
|
+
sa_range = [0.0] + [0.1 * i for i in range(1, 21)] # Include 0 explicitly
|
|
192
|
+
|
|
193
|
+
curves = {state: [] for state in fragility_probs.keys()}
|
|
194
|
+
|
|
195
|
+
# Generate fragility values, handling the case for Sa = 0
|
|
196
|
+
for sa in sa_range:
|
|
197
|
+
for state in fragility_probs.keys():
|
|
198
|
+
median = get_old_medians(hazus_type)[state]
|
|
199
|
+
dispersion = 0.6 # β (dispersion factor)
|
|
200
|
+
curves[state].append(
|
|
201
|
+
norm.cdf((math.log(sa / median)) / dispersion) if sa > 0 else 0
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
if return_data:
|
|
205
|
+
fragility_probs["curves"] = curves
|
|
206
|
+
fragility_probs["sa_range"] = sa_range
|
|
207
|
+
|
|
208
|
+
# Step 4: Handle `level` as an integer
|
|
209
|
+
damage_states = ["Slight", "Moderate", "Extensive", "Complete"]
|
|
210
|
+
if level is not None:
|
|
211
|
+
if level not in range(4):
|
|
212
|
+
raise ValueError(f"Invalid level: {level}. Must be an integer in range(4).")
|
|
213
|
+
damage_state = damage_states[level]
|
|
214
|
+
return fragility_probs[damage_state]
|
|
215
|
+
|
|
216
|
+
# Step 5: Return all probabilities and optionally the plot
|
|
217
|
+
return fragility_probs
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _bridge_info(nbi: dict) -> dict:
|
|
221
|
+
"""
|
|
222
|
+
Safely extract bridge properties, handling undefined skew angles and other placeholders.
|
|
223
|
+
"""
|
|
224
|
+
try:
|
|
225
|
+
nbi_bridge = nbi.get("NBI_BRIDGE", {})
|
|
226
|
+
nbi_superstructure = nbi.get("NBI_SUPERSTRUCTURE_DECK", {})
|
|
227
|
+
|
|
228
|
+
# Parse "Skew Angle"
|
|
229
|
+
skew_angle_str = nbi_bridge.get("Skew Angle", "0")
|
|
230
|
+
if "99" in skew_angle_str: # Handle undefined skew
|
|
231
|
+
skew_angle = 0
|
|
232
|
+
else:
|
|
233
|
+
skew_angle = float(skew_angle_str.split(" - ")[0])
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
"state_code": StateCodes.California,
|
|
237
|
+
"year_built": int(nbi_bridge.get("Year Built", 0)),
|
|
238
|
+
"skew_angle": skew_angle,
|
|
239
|
+
"service_type": int(
|
|
240
|
+
nbi_bridge.get("Type of Service on Bridge Code", "0 - Unknown").split(" - ")[0]
|
|
241
|
+
+ nbi_bridge.get("Type Of Service Under Bridge Code", "0 - Unknown").split(" - ")[0]
|
|
242
|
+
),
|
|
243
|
+
"material_flag": int(nbi_superstructure.get("Main Span Material", "0 - Unknown").split(" - ")[0]),
|
|
244
|
+
"geometry_flag": int(nbi_superstructure.get("Main Span Design", "0 - Unknown").split(" - ")[0]),
|
|
245
|
+
"span_count": int(nbi_superstructure.get("Number of Spans in Main Unit", 0)),
|
|
246
|
+
"approach_spans": int(nbi_superstructure.get("Number of Approach Spans", 0)),
|
|
247
|
+
"max_span_length": float(nbi_bridge.get("Length of Maximum Span", 0.0)),
|
|
248
|
+
"total_length": float(nbi_bridge.get("Structure Length", 0.0)),
|
|
249
|
+
"deck_width": float(nbi_bridge.get("Deck Width - Out to Out", 0.0)),
|
|
250
|
+
}
|
|
251
|
+
except ValueError as e:
|
|
252
|
+
raise ValueError(f"Error processing NBI data: {e}")
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def _hazus_curve(type: int, properties: dict, pga: float, sa_03s: float, sa_10s: float, soil_type: str) -> dict:
|
|
258
|
+
"""
|
|
259
|
+
Compute fragility probabilities for the four damage states and optionally generate fragility curves.
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
- type (int): Bridge classification (integer from 1 to 28).
|
|
263
|
+
- properties (dict): Dictionary containing bridge-specific properties.
|
|
264
|
+
- pga (float): Peak Ground Acceleration (g).
|
|
265
|
+
- sa_03s (float): Spectral Acceleration at 0.3 seconds (g).
|
|
266
|
+
- sa_10s (float): Spectral Acceleration at 1.0 seconds (g).
|
|
267
|
+
- soil_type (str): Soil classification ("A", "B", "C", "D", "E").
|
|
268
|
+
- generate_curve (bool): If True, generate and display fragility curves.
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
- dict: Fragility probabilities for Slight, Moderate, Extensive, and Complete damage states.
|
|
272
|
+
"""
|
|
273
|
+
# Validate inputs
|
|
274
|
+
required_keys = {"span_count", "skew_angle"}
|
|
275
|
+
missing_keys = required_keys - properties.keys()
|
|
276
|
+
if missing_keys:
|
|
277
|
+
raise ValueError(f"Missing required properties: {missing_keys}")
|
|
278
|
+
|
|
279
|
+
valid_soil_types = {"A", "B", "C", "D", "E"}
|
|
280
|
+
if soil_type not in valid_soil_types:
|
|
281
|
+
raise ValueError(f"Invalid soil type: {soil_type}. Must be one of {valid_soil_types}.")
|
|
282
|
+
|
|
283
|
+
span_count = properties["span_count"]
|
|
284
|
+
skew_angle = properties["skew_angle"]
|
|
285
|
+
|
|
286
|
+
# Call modify_ground_motion to get the modified values
|
|
287
|
+
modified_values = modify_ground_motion(pga, sa_03s, sa_10s, soil_type)
|
|
288
|
+
modified_pga = modified_values['modified_pga']
|
|
289
|
+
modified_sa_03s = modified_values['modified_sa_03s']
|
|
290
|
+
modified_sa_10s = modified_values['modified_sa_10s']
|
|
291
|
+
|
|
292
|
+
# Compute K_skew, K_shape, K3D
|
|
293
|
+
K_skew = math.sqrt(math.sin(math.radians(90 - skew_angle)))
|
|
294
|
+
if modified_sa_03s == 0:
|
|
295
|
+
raise ValueError("Modified Sa(0.3 sec) cannot be zero.")
|
|
296
|
+
K_shape = (2.5 * modified_sa_10s) / modified_sa_03s
|
|
297
|
+
A, B = get_a_b(type)
|
|
298
|
+
if span_count - B == 0:
|
|
299
|
+
raise ValueError("Invalid span count resulting in division by zero.")
|
|
300
|
+
K3D = 1 + A / (span_count - B)
|
|
301
|
+
|
|
302
|
+
# Retrieve old medians and compute new medians
|
|
303
|
+
old_medians = get_old_medians(type)
|
|
304
|
+
I_shape = get_i_shape(type)
|
|
305
|
+
factor_slight = 1 if I_shape == 0 else min(1, K_shape)
|
|
306
|
+
|
|
307
|
+
new_medians = {"Slight": old_medians["Slight"] * factor_slight}
|
|
308
|
+
damage_states = ["Moderate", "Extensive", "Complete"]
|
|
309
|
+
new_medians.update(
|
|
310
|
+
{state: old_medians[state] * K_skew * K3D for state in damage_states}
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
# Compute fragility probabilities
|
|
314
|
+
def compute_probability(sa: float, median: float, beta: float = 0.6) -> float:
|
|
315
|
+
return norm.cdf((math.log(sa / median)) / beta)
|
|
316
|
+
|
|
317
|
+
if modified_sa_10s <= 0:
|
|
318
|
+
raise ValueError("Modified Sa(1.0 sec) must be positive.")
|
|
319
|
+
fragility_probs = {
|
|
320
|
+
state: compute_probability(modified_sa_10s, median)
|
|
321
|
+
for state, median in new_medians.items()
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return fragility_probs
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def modify_ground_motion(pga: float, sa_03s: float, sa_10s: float, soil_type: str) -> dict:
|
|
328
|
+
"""
|
|
329
|
+
Modify PGA, Sa(0.3 sec), and Sa(1.0 sec) based on soil amplification factors (Table 4.7).
|
|
330
|
+
|
|
331
|
+
Inputs:
|
|
332
|
+
- pga (float): Peak Ground Acceleration (g).
|
|
333
|
+
- sa_03s (float): Spectral Acceleration at 0.3 seconds (g).
|
|
334
|
+
- sa_10s (float): Spectral Acceleration at 1.0 seconds (g).
|
|
335
|
+
- soil_type (str): Soil classification ("A", "B", "C", "D", "E").
|
|
336
|
+
|
|
337
|
+
Returns:
|
|
338
|
+
- dict: Modified PGA, Sa(0.3 sec), and Sa(1.0 sec).
|
|
339
|
+
"""
|
|
340
|
+
|
|
341
|
+
# Amplification factors for each parameter
|
|
342
|
+
amplification_factors = {
|
|
343
|
+
"FPGA": [
|
|
344
|
+
(0.1, {"A": 0.8, "B": 0.9, "C": 1.3, "D": 1.6, "E": 2.4}),
|
|
345
|
+
(0.2, {"A": 0.8, "B": 0.9, "C": 1.2, "D": 1.4, "E": 1.9}),
|
|
346
|
+
(0.3, {"A": 0.8, "B": 0.9, "C": 1.2, "D": 1.3, "E": 1.6}),
|
|
347
|
+
(0.4, {"A": 0.8, "B": 0.9, "C": 1.2, "D": 1.2, "E": 1.4}),
|
|
348
|
+
(0.5, {"A": 0.8, "B": 0.9, "C": 1.2, "D": 1.1, "E": 1.2}),
|
|
349
|
+
(0.6, {"A": 0.8, "B": 0.9, "C": 1.2, "D": 1.1, "E": 1.1}),
|
|
350
|
+
],
|
|
351
|
+
"FA": [
|
|
352
|
+
(0.25, {"A": 0.8, "B": 0.9, "C": 1.3, "D": 1.6, "E": 2.4}),
|
|
353
|
+
(0.5, {"A": 0.8, "B": 0.9, "C": 1.3, "D": 1.4, "E": 1.7}),
|
|
354
|
+
(0.75, {"A": 0.8, "B": 0.9, "C": 1.2, "D": 1.2, "E": 1.3}),
|
|
355
|
+
(1.0, {"A": 0.8, "B": 0.9, "C": 1.2, "D": 1.1, "E": 1.1}),
|
|
356
|
+
(1.25, {"A": 0.8, "B": 0.9, "C": 1.2, "D": 1.0, "E": 0.9}),
|
|
357
|
+
(1.5, {"A": 0.8, "B": 0.9, "C": 1.2, "D": 1.0, "E": 0.8}),
|
|
358
|
+
],
|
|
359
|
+
"FV": [
|
|
360
|
+
(0.1, {"A": 0.8, "B": 0.8, "C": 1.5, "D": 2.4, "E": 4.2}),
|
|
361
|
+
(0.2, {"A": 0.8, "B": 0.8, "C": 1.5, "D": 2.2, "E": 3.3}),
|
|
362
|
+
(0.3, {"A": 0.8, "B": 0.8, "C": 1.5, "D": 2.0, "E": 2.8}),
|
|
363
|
+
(0.4, {"A": 0.8, "B": 0.8, "C": 1.5, "D": 1.9, "E": 2.4}),
|
|
364
|
+
(0.5, {"A": 0.8, "B": 0.8, "C": 1.5, "D": 1.8, "E": 2.2}),
|
|
365
|
+
(0.6, {"A": 0.8, "B": 0.8, "C": 1.4, "D": 1.7, "E": 2.0}),
|
|
366
|
+
],
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
def get_factor(value, factor_type):
|
|
370
|
+
rows = amplification_factors[factor_type]
|
|
371
|
+
# Below minimum threshold
|
|
372
|
+
if value <= rows[0][0]:
|
|
373
|
+
return rows[0][1][soil_type]
|
|
374
|
+
# Above maximum threshold
|
|
375
|
+
if value > rows[-1][0]:
|
|
376
|
+
return rows[-1][1][soil_type]
|
|
377
|
+
# Linear interpolation for intermediate values
|
|
378
|
+
for i in range(len(rows) - 1):
|
|
379
|
+
lower_bound, lower_factors = rows[i]
|
|
380
|
+
upper_bound, upper_factors = rows[i + 1]
|
|
381
|
+
if lower_bound < value <= upper_bound:
|
|
382
|
+
lower_factor = lower_factors[soil_type]
|
|
383
|
+
upper_factor = upper_factors[soil_type]
|
|
384
|
+
# Interpolate
|
|
385
|
+
return lower_factor + (upper_factor - lower_factor) * (value - lower_bound) / (upper_bound - lower_bound)
|
|
386
|
+
raise ValueError("Interpolation failed unexpectedly.")
|
|
387
|
+
|
|
388
|
+
# Calculate modified values
|
|
389
|
+
modified_pga = pga * get_factor(pga, "FPGA")
|
|
390
|
+
modified_sa_03s = sa_03s * get_factor(sa_03s, "FA")
|
|
391
|
+
modified_sa_10s = sa_10s * get_factor(sa_10s, "FV")
|
|
392
|
+
|
|
393
|
+
return {"modified_pga": modified_pga,
|
|
394
|
+
"modified_sa_03s": modified_sa_03s,
|
|
395
|
+
"modified_sa_10s": modified_sa_10s,
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
def get_a_b(bridge_type: int) -> tuple:
|
|
399
|
+
"""
|
|
400
|
+
Retrieve coefficients A and B for K3D calculation based on bridge type.
|
|
401
|
+
|
|
402
|
+
Args:
|
|
403
|
+
- bridge_type (int): The bridge type (integer between 1 and 28).
|
|
404
|
+
|
|
405
|
+
Returns:
|
|
406
|
+
- tuple: Coefficients (A, B) corresponding to the bridge type's equation.
|
|
407
|
+
"""
|
|
408
|
+
# Mapping of equations to A and B values from Table 7-2
|
|
409
|
+
equation_to_ab = {
|
|
410
|
+
"EQ1": (0.25, 1),
|
|
411
|
+
"EQ2": (0.33, 0),
|
|
412
|
+
"EQ3": (0.33, 1),
|
|
413
|
+
"EQ4": (0.09, 1),
|
|
414
|
+
"EQ5": (0.05, 0),
|
|
415
|
+
"EQ6": (0.20, 1),
|
|
416
|
+
"EQ7": (0.10, 0),
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
# Map bridge type to equations from Table 7-1
|
|
420
|
+
bridge_to_equation = {
|
|
421
|
+
1: "EQ1", 2: "EQ1", 3: "EQ1", 4: "EQ1", 5: "EQ1", 6: "EQ1", 7: "EQ1", 8: "EQ2", 9: "EQ3", 10: "EQ2",
|
|
422
|
+
11: "EQ3", 12: "EQ4", 13: "EQ4", 14: "EQ1", 15: "EQ5", 16: "EQ3", 17: "EQ1", 18: "EQ1", 19: "EQ1",
|
|
423
|
+
20: "EQ2", 21: "EQ3", 22: "EQ2", 23: "EQ3", 24: "EQ6", 25: "EQ6", 26: "EQ7", 27: "EQ7",
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
# Get the equation for the bridge type
|
|
427
|
+
equation = bridge_to_equation.get(bridge_type)
|
|
428
|
+
if not equation:
|
|
429
|
+
raise ValueError(f"Unknown bridge type: {bridge_type}")
|
|
430
|
+
|
|
431
|
+
# Retrieve and return A and B values
|
|
432
|
+
return equation_to_ab[equation]
|
|
433
|
+
|
|
434
|
+
def get_i_shape(bridge_type: int) -> int:
|
|
435
|
+
"""
|
|
436
|
+
Retrieve I_shape (indicator for skew effects) for the given bridge type
|
|
437
|
+
from Table 7-1.
|
|
438
|
+
|
|
439
|
+
Args:
|
|
440
|
+
- bridge_type (int): The bridge type (integer from 1 to 28).
|
|
441
|
+
|
|
442
|
+
Returns:
|
|
443
|
+
- int: I_shape value (0 or 1) based on Table 7-1.
|
|
444
|
+
"""
|
|
445
|
+
# Mapping of bridge types to I_shape values from Table 7-1
|
|
446
|
+
i_shape_mapping = {
|
|
447
|
+
1: 0, 2: 0, 3: 1, 4: 1, 5: 0, 6: 0,
|
|
448
|
+
7: 0, 8: 0, 9: 0, 10: 1, 11: 1, 12: 0,
|
|
449
|
+
13: 0, 14: 0, 15: 1, 16: 1, 17: 0, 18: 0,
|
|
450
|
+
19: 0, 20: 0, 21: 0, 22: 1, 23: 1, 24: 0,
|
|
451
|
+
25: 0, 26: 1, 27: 1,
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if bridge_type not in i_shape_mapping:
|
|
455
|
+
raise ValueError(f"Unknown bridge type: {bridge_type}")
|
|
456
|
+
|
|
457
|
+
return i_shape_mapping[bridge_type]
|
|
458
|
+
|
|
459
|
+
def get_old_medians(bridge_type: int) -> dict:
|
|
460
|
+
"""
|
|
461
|
+
Retrieve the old medians for Slight, Moderate, Extensive, and Complete damage states
|
|
462
|
+
from Table 7-6 based on the bridge type.
|
|
463
|
+
|
|
464
|
+
Args:
|
|
465
|
+
- bridge_type (int): The bridge type (integer from 1 to 28).
|
|
466
|
+
|
|
467
|
+
Returns:
|
|
468
|
+
- dict: Old median values for each damage state.
|
|
469
|
+
"""
|
|
470
|
+
old_medians = {
|
|
471
|
+
1: {"Slight": 0.40, "Moderate": 0.50, "Extensive": 0.70, "Complete": 0.90},
|
|
472
|
+
2: {"Slight": 0.60, "Moderate": 0.90, "Extensive": 1.10, "Complete": 1.70},
|
|
473
|
+
3: {"Slight": 0.80, "Moderate": 1.00, "Extensive": 1.20, "Complete": 1.70},
|
|
474
|
+
4: {"Slight": 0.80, "Moderate": 1.00, "Extensive": 1.20, "Complete": 1.70},
|
|
475
|
+
5: {"Slight": 0.25, "Moderate": 0.35, "Extensive": 0.45, "Complete": 0.70},
|
|
476
|
+
6: {"Slight": 0.30, "Moderate": 0.50, "Extensive": 0.60, "Complete": 0.90},
|
|
477
|
+
7: {"Slight": 0.50, "Moderate": 0.80, "Extensive": 1.10, "Complete": 1.70},
|
|
478
|
+
8: {"Slight": 0.35, "Moderate": 0.45, "Extensive": 0.55, "Complete": 0.80},
|
|
479
|
+
9: {"Slight": 0.60, "Moderate": 0.90, "Extensive": 1.30, "Complete": 1.60},
|
|
480
|
+
10: {"Slight": 0.60, "Moderate": 0.90, "Extensive": 1.10, "Complete": 1.50},
|
|
481
|
+
11: {"Slight": 0.90, "Moderate": 0.90, "Extensive": 1.10, "Complete": 1.50},
|
|
482
|
+
12: {"Slight": 0.25, "Moderate": 0.35, "Extensive": 0.45, "Complete": 0.70},
|
|
483
|
+
13: {"Slight": 0.30, "Moderate": 0.50, "Extensive": 0.60, "Complete": 0.90},
|
|
484
|
+
14: {"Slight": 0.50, "Moderate": 0.80, "Extensive": 1.10, "Complete": 1.70},
|
|
485
|
+
15: {"Slight": 0.75, "Moderate": 0.75, "Extensive": 0.75, "Complete": 1.10},
|
|
486
|
+
16: {"Slight": 0.90, "Moderate": 0.90, "Extensive": 1.10, "Complete": 1.50},
|
|
487
|
+
17: {"Slight": 0.25, "Moderate": 0.35, "Extensive": 0.45, "Complete": 0.70},
|
|
488
|
+
18: {"Slight": 0.30, "Moderate": 0.50, "Extensive": 0.60, "Complete": 0.90},
|
|
489
|
+
19: {"Slight": 0.50, "Moderate": 0.80, "Extensive": 1.10, "Complete": 1.70},
|
|
490
|
+
20: {"Slight": 0.35, "Moderate": 0.45, "Extensive": 0.55, "Complete": 0.80},
|
|
491
|
+
21: {"Slight": 0.60, "Moderate": 0.90, "Extensive": 1.30, "Complete": 1.60},
|
|
492
|
+
22: {"Slight": 0.60, "Moderate": 0.90, "Extensive": 1.10, "Complete": 1.50},
|
|
493
|
+
23: {"Slight": 0.90, "Moderate": 0.90, "Extensive": 1.10, "Complete": 1.50},
|
|
494
|
+
24: {"Slight": 0.25, "Moderate": 0.35, "Extensive": 0.45, "Complete": 0.70},
|
|
495
|
+
25: {"Slight": 0.30, "Moderate": 0.50, "Extensive": 0.60, "Complete": 0.90},
|
|
496
|
+
26: {"Slight": 0.75, "Moderate": 0.75, "Extensive": 0.75, "Complete": 1.10},
|
|
497
|
+
27: {"Slight": 0.75, "Moderate": 0.75, "Extensive": 0.75, "Complete": 1.10},
|
|
498
|
+
28: {"Slight": 0.80, "Moderate": 1.00, "Extensive": 1.20, "Complete": 1.70},
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
if bridge_type not in old_medians:
|
|
502
|
+
raise ValueError(f"Unknown bridge type: {bridge_type}")
|
|
503
|
+
|
|
504
|
+
return old_medians[bridge_type]
|
|
505
|
+
|
|
506
|
+
def _hazus_type(properties: dict) -> int:
|
|
507
|
+
"""
|
|
508
|
+
Classify the bridge into one of the Hazus types (1-28) using the properties extracted.
|
|
509
|
+
The mapping logic is based on Table 9.6.
|
|
510
|
+
|
|
511
|
+
Args:
|
|
512
|
+
properties (dict): A dictionary containing the bridge properties extracted from `_bridge_info()`
|
|
513
|
+
|
|
514
|
+
Returns:
|
|
515
|
+
int: Hazus type classification (1-28) or -1 if no match is found
|
|
516
|
+
"""
|
|
517
|
+
year_built = properties["year_built"]
|
|
518
|
+
span_count = properties["span_count"]
|
|
519
|
+
max_length = properties["max_span_length"]
|
|
520
|
+
total_length = properties["total_length"]
|
|
521
|
+
material_flag = properties["material_flag"]
|
|
522
|
+
geometry_flag = properties["geometry_flag"]
|
|
523
|
+
|
|
524
|
+
bridge_class = -1
|
|
525
|
+
|
|
526
|
+
# Determine if the bridge is seismic based on year built and state code
|
|
527
|
+
seismic_year = 1975 if properties["state_code"] == StateCodes.California else 1990
|
|
528
|
+
|
|
529
|
+
# Implement classification rules from Table 9-6
|
|
530
|
+
# Some classes are not relevant and they're not included.
|
|
531
|
+
if year_built < seismic_year:
|
|
532
|
+
if max_length > 150:
|
|
533
|
+
bridge_class = 1 # Older, long-span bridges
|
|
534
|
+
else:
|
|
535
|
+
if span_count == 1:
|
|
536
|
+
bridge_class = 3 # Older, short, single-span bridges
|
|
537
|
+
else:
|
|
538
|
+
if material_flag == 1 :
|
|
539
|
+
bridge_class = 6 # Concrete, simple support
|
|
540
|
+
elif material_flag == 2 and geometry_flag == 6:
|
|
541
|
+
bridge_class = 8 # Single box, continuous concrete
|
|
542
|
+
elif material_flag == 2:
|
|
543
|
+
bridge_class = 10 # Continuous concrete
|
|
544
|
+
elif material_flag == 3 and total_length >= 20:
|
|
545
|
+
bridge_class = 13 # Steel, simple support, total length >= 20
|
|
546
|
+
elif material_flag == 3 and total_length < 20:
|
|
547
|
+
bridge_class = 25 # Steel, simple support, total length < 20
|
|
548
|
+
elif material_flag == 4 and total_length >= 20:
|
|
549
|
+
bridge_class = 15 # Continuous steel, total length >= 20
|
|
550
|
+
elif material_flag == 4 and total_length < 20:
|
|
551
|
+
bridge_class = 17 # Continuous steel, total length < 20
|
|
552
|
+
elif material_flag == 5:
|
|
553
|
+
bridge_class = 18 # Prestressed concrete, simple support
|
|
554
|
+
elif material_flag == 6 and geometry_flag == 6:
|
|
555
|
+
bridge_class = 20 # Prestressed continuous concrete, single box
|
|
556
|
+
else:
|
|
557
|
+
if max_length > 150:
|
|
558
|
+
bridge_class = 2 # Newer, long-span bridges
|
|
559
|
+
else:
|
|
560
|
+
if span_count == 1:
|
|
561
|
+
bridge_class = 4 # Newer, short, single-span bridges
|
|
562
|
+
else:
|
|
563
|
+
if material_flag == 1:
|
|
564
|
+
bridge_class = 7 # Concrete, simple support
|
|
565
|
+
elif material_flag == 2 and geometry_flag == 6:
|
|
566
|
+
bridge_class = 9 # Single box, continuous concrete
|
|
567
|
+
elif material_flag == 2:
|
|
568
|
+
bridge_class = 11 # Continuous concrete
|
|
569
|
+
elif material_flag == 3:
|
|
570
|
+
bridge_class = 14 # Steel, simple support
|
|
571
|
+
elif material_flag == 4:
|
|
572
|
+
bridge_class = 16 # Continuous steel
|
|
573
|
+
elif material_flag == 5:
|
|
574
|
+
bridge_class = 19 # Prestressed concrete, simple support
|
|
575
|
+
elif material_flag == 6:
|
|
576
|
+
bridge_class = 21 # Prestressed continuous concrete, single box
|
|
577
|
+
|
|
578
|
+
return bridge_class
|
|
579
|
+
|