irie 0.0.4__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/networks/networks.js +2 -2
- 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.4.dist-info → irie-0.0.6.dist-info}/METADATA +5 -3
- {irie-0.0.4.dist-info → irie-0.0.6.dist-info}/RECORD +62 -48
- /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.4.dist-info → irie-0.0.6.dist-info}/WHEEL +0 -0
- {irie-0.0.4.dist-info → irie-0.0.6.dist-info}/entry_points.txt +0 -0
- {irie-0.0.4.dist-info → irie-0.0.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import json
|
|
3
|
+
import io
|
|
4
|
+
import base64
|
|
5
|
+
import numpy as np
|
|
6
|
+
# Ensure Agg backend is set for non-interactive plotting
|
|
7
|
+
import matplotlib
|
|
8
|
+
matplotlib.use('Agg')
|
|
9
|
+
from matplotlib import pyplot as plt, ticker, cm
|
|
10
|
+
import quakeio
|
|
11
|
+
from mdof import transform
|
|
12
|
+
from scipy.signal import find_peaks
|
|
13
|
+
from mdof.utilities import Config, extract_channels
|
|
14
|
+
from matplotlib import colormaps
|
|
15
|
+
# try:
|
|
16
|
+
# import scienceplots
|
|
17
|
+
# plt.style.use(["science"])
|
|
18
|
+
# except ImportError:
|
|
19
|
+
# pass
|
|
20
|
+
|
|
21
|
+
N_PEAKS = 5 # number of "significant" peaks per record
|
|
22
|
+
MISSING_CHANNEL_LIMIT = 3 # number of missing output channels allowed before skipping event
|
|
23
|
+
MAX_ACCEL = 3.0
|
|
24
|
+
|
|
25
|
+
from irie.apps.events.models import EventRecord
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def ssid_stats(events, key):
|
|
30
|
+
"""
|
|
31
|
+
mode_results is a list (station level) of lists (event level) of dictionaries (mode level).
|
|
32
|
+
mode_results = [
|
|
33
|
+
[
|
|
34
|
+
{
|
|
35
|
+
"period": ...,
|
|
36
|
+
"frequency": ...,
|
|
37
|
+
"damping": ...,
|
|
38
|
+
"emac": ...,
|
|
39
|
+
"mpc": ...,
|
|
40
|
+
},
|
|
41
|
+
...
|
|
42
|
+
],
|
|
43
|
+
...
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[
|
|
47
|
+
# "Event"
|
|
48
|
+
{"S1": {"period": [0.1]},
|
|
49
|
+
"R1": {"period": [1.2]}}
|
|
50
|
+
]
|
|
51
|
+
"""
|
|
52
|
+
mode_results = [_find_ssid(event.id) for event in events]
|
|
53
|
+
import numpy as np
|
|
54
|
+
|
|
55
|
+
filtered_results = [
|
|
56
|
+
{
|
|
57
|
+
method: [
|
|
58
|
+
result for result in event_results[method]
|
|
59
|
+
if key in result and result.get("emac", 1.0) > 0.5 and result.get("mpc", 1.0) > 0.5
|
|
60
|
+
] for method in event_results
|
|
61
|
+
} for event_results in mode_results
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
from collections import defaultdict
|
|
65
|
+
values = defaultdict(list)
|
|
66
|
+
for event in filtered_results:
|
|
67
|
+
for method in event:
|
|
68
|
+
for result in event[method]:
|
|
69
|
+
values[method].append(result[key])
|
|
70
|
+
|
|
71
|
+
mean = {method: np.mean(values[method]) for method in values}
|
|
72
|
+
std = {method: np.std(values[method]) for method in values}
|
|
73
|
+
|
|
74
|
+
def _first(method_results):
|
|
75
|
+
if method_results and len(method_results) > 0:
|
|
76
|
+
results = np.array([result[key] for result in method_results])
|
|
77
|
+
try:
|
|
78
|
+
idx = np.argmax([result["amplitude"] for result in method_results])
|
|
79
|
+
return results[idx]
|
|
80
|
+
except KeyError:
|
|
81
|
+
return np.max(results)
|
|
82
|
+
else:
|
|
83
|
+
return {}
|
|
84
|
+
|
|
85
|
+
return [
|
|
86
|
+
{method: {
|
|
87
|
+
# "distance": (closest_item[key]-mean)/std),
|
|
88
|
+
"nearest_mean": event_results[method][np.argmin(np.abs(mean[method] \
|
|
89
|
+
- [result[key] for result in event_results[method]]))] \
|
|
90
|
+
if event_results[method] and len(event_results[method]) > 0 else {} ,
|
|
91
|
+
"maximum": _first(event_results[method])
|
|
92
|
+
}
|
|
93
|
+
for method in event_results
|
|
94
|
+
}
|
|
95
|
+
for event_results in filtered_results
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _find_ssid(event_id=None, evaluation=None):
|
|
100
|
+
"""
|
|
101
|
+
Given an event ID, finds the results of the first configured
|
|
102
|
+
system ID run. This generally looks like a list of dicts,
|
|
103
|
+
each with fields "frequency", "damping", etc.
|
|
104
|
+
"""
|
|
105
|
+
from irie.apps.evaluation.models import Evaluation
|
|
106
|
+
|
|
107
|
+
if evaluation is None:
|
|
108
|
+
evaluation = Evaluation.objects.filter(event_id=int(event_id))
|
|
109
|
+
|
|
110
|
+
elif not isinstance(evaluation, list):
|
|
111
|
+
evaluation = [evaluation]
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
if len(evaluation) != 1:
|
|
115
|
+
return []
|
|
116
|
+
|
|
117
|
+
else:
|
|
118
|
+
evaluation_data = evaluation[0].evaluation_data
|
|
119
|
+
|
|
120
|
+
if "SPECTRAL_SHIFT_IDENTIFICATION" in evaluation_data:
|
|
121
|
+
return {
|
|
122
|
+
key: val.get("data", val.get("error", []))
|
|
123
|
+
for key,val in evaluation_data["SPECTRAL_SHIFT_IDENTIFICATION"]["summary"].items()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
else:
|
|
127
|
+
return []
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def ssid_event_plot(evaluation):
|
|
131
|
+
import numpy as np
|
|
132
|
+
from mdof.macro import FrequencyContent
|
|
133
|
+
|
|
134
|
+
plot = FrequencyContent(scale=True, period=True, xlabel="Period (s)", ylabel="Normalized Amplitude")
|
|
135
|
+
|
|
136
|
+
for name, mdata in evaluation["summary"].items():
|
|
137
|
+
periods = []
|
|
138
|
+
amplitudes = []
|
|
139
|
+
for i in mdata.get("data", []):
|
|
140
|
+
if "period" in i:
|
|
141
|
+
periods.append(i["period"])
|
|
142
|
+
if "amplitude" in i:
|
|
143
|
+
amplitudes.append(i["amplitude"])
|
|
144
|
+
|
|
145
|
+
if len(amplitudes) and (len(amplitudes) == len(periods)):
|
|
146
|
+
plot.add(np.array(periods), np.array(amplitudes), label=name)
|
|
147
|
+
else:
|
|
148
|
+
plot.add(np.array(periods), label=name)
|
|
149
|
+
|
|
150
|
+
fig = plot.get_figure()
|
|
151
|
+
return fig.to_json()
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _load_events(asset, output_channels):
|
|
155
|
+
"""
|
|
156
|
+
Parse event file and restructure the relevant data
|
|
157
|
+
(filename, date, peak acceleration, acceleration response history, and timestep).
|
|
158
|
+
|
|
159
|
+
Return a dictionary:
|
|
160
|
+
{
|
|
161
|
+
filename:
|
|
162
|
+
{
|
|
163
|
+
'date': date,
|
|
164
|
+
'peak_accel': peak_accel,
|
|
165
|
+
'outputs': outputs,
|
|
166
|
+
'dt': dt
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
"""
|
|
170
|
+
events = {}
|
|
171
|
+
for evt in EventRecord.objects.filter(asset=asset):
|
|
172
|
+
|
|
173
|
+
try:
|
|
174
|
+
event = quakeio.read(evt.event_file.path, format="csmip.zip", exclusions=["*filter*"])
|
|
175
|
+
outputs, dt = extract_channels(event, output_channels)
|
|
176
|
+
except Exception as e:
|
|
177
|
+
print(f"Error loading event: {e}")
|
|
178
|
+
continue
|
|
179
|
+
|
|
180
|
+
filename = event['file_name']
|
|
181
|
+
date = event['event_date']
|
|
182
|
+
peak_accel = np.abs(event['peak_accel'])/980.665
|
|
183
|
+
events[filename] = {'date': date, 'peak_accel': peak_accel, 'outputs': outputs, 'dt': dt}
|
|
184
|
+
|
|
185
|
+
events = sorted(events.items(), key=lambda k: np.abs(k[1]["peak_accel"]))
|
|
186
|
+
return {k:v for k,v in events}
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def get_spectra(event, period_band, cmap):
|
|
190
|
+
"""
|
|
191
|
+
Get coordinates (periods, amplitudes) of spectra for an event, and return them along
|
|
192
|
+
with the maximum period of the N_PEAKS tallest peaks, as well as plotting options
|
|
193
|
+
such as color and alpha.
|
|
194
|
+
"""
|
|
195
|
+
n_outputs = event['outputs'].shape[0]
|
|
196
|
+
frequencies,_,S = transform.fdd(outputs=event['outputs'], step=event['dt']) # Full frequency spectrum
|
|
197
|
+
periods = 1/frequencies
|
|
198
|
+
period_mask = (periods>=period_band[0]) & (periods<=period_band[1])
|
|
199
|
+
periods = periods[period_mask]
|
|
200
|
+
n_periods = len(periods) # Number of periods, x axis of spectrum. Varies per record.
|
|
201
|
+
spec_coords = np.empty((n_outputs, 3, n_periods)) # Initialize empty array for coordinates.
|
|
202
|
+
xvalue = event['peak_accel']
|
|
203
|
+
for j in range(n_outputs):
|
|
204
|
+
amplitudes = S[j,:]
|
|
205
|
+
amplitudes = amplitudes/max(amplitudes)
|
|
206
|
+
amplitudes = amplitudes[period_mask]
|
|
207
|
+
spec_coords[j] = [[xvalue]*n_periods, periods, amplitudes] # All spectra from FDD. One spectrum for each n_outputs outputs
|
|
208
|
+
peak_indices, _ = find_peaks(amplitudes, prominence=max(amplitudes)*0.01)
|
|
209
|
+
peaks = sorted(peak_indices, key=lambda peak: amplitudes[peak], reverse=True)
|
|
210
|
+
max_peak_period = np.max(periods[peaks[:N_PEAKS]])
|
|
211
|
+
plot_conf = Config()
|
|
212
|
+
plot_conf.color = cmap(event['peak_accel']/MAX_ACCEL)
|
|
213
|
+
plot_conf.alpha = 1
|
|
214
|
+
|
|
215
|
+
return {
|
|
216
|
+
'spec_coords': spec_coords,
|
|
217
|
+
'max_peak_period': max_peak_period,
|
|
218
|
+
'plot_conf': plot_conf
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _plot_3d_spectrum(ax, date, trace, num_spectra=1, label='date', line=True, plotter='matplotlib', **options):
|
|
223
|
+
color = options.get('color', None)
|
|
224
|
+
alpha = options.get('alpha', 0.5)
|
|
225
|
+
if label=='date':
|
|
226
|
+
label = date
|
|
227
|
+
if plotter == 'matplotlib':
|
|
228
|
+
for i in range(num_spectra):
|
|
229
|
+
if line:
|
|
230
|
+
ax.plot(trace[i,0,:],trace[i,1,:],trace[i,2,:], label=label,
|
|
231
|
+
linestyle='-', color=color, alpha=alpha)
|
|
232
|
+
else:
|
|
233
|
+
ax.scatter(trace[i,0,:],trace[i,1,:],trace[i,2,:], label=label,
|
|
234
|
+
marker=options.get('marker','o'), color=color, s=30, alpha=alpha)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _linear_interpolate(x, y, target_x):
|
|
238
|
+
sorted_indices = sorted(range(len(x)), key = lambda i: x[i])
|
|
239
|
+
x = x[sorted_indices]
|
|
240
|
+
y = y[sorted_indices]
|
|
241
|
+
i1 = max(np.where(x<=target_x)[0])
|
|
242
|
+
i2 = min(np.where(x>=target_x)[0])
|
|
243
|
+
x1 = x[i1]
|
|
244
|
+
x2 = x[i2]
|
|
245
|
+
y1 = y[i1]
|
|
246
|
+
y2 = y[i2]
|
|
247
|
+
target_y = y1 + (target_x - x1)*(y2 - y1)/(x2 - x1)
|
|
248
|
+
return target_y
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def plot_spectral_surface(ax, traces, **options):
|
|
252
|
+
alpha = options.get('alpha',0.5)
|
|
253
|
+
colors = options.get('colors',None)
|
|
254
|
+
cmap = options.get('cmap',None)
|
|
255
|
+
n_points_per_trace = 2000
|
|
256
|
+
period_lower_bound = np.max([trace[0,1,-1] for trace in traces])
|
|
257
|
+
period_upper_bound = np.min([trace[0,1,0] for trace in traces])
|
|
258
|
+
standard_periods = np.linspace(period_lower_bound+0.01, period_upper_bound-0.01, n_points_per_trace)
|
|
259
|
+
X = []
|
|
260
|
+
Y = []
|
|
261
|
+
Z = []
|
|
262
|
+
for trace in traces:
|
|
263
|
+
X.append(np.full(n_points_per_trace,trace[0,0,0]))
|
|
264
|
+
Y.append(standard_periods)
|
|
265
|
+
current_periods = trace[0,1,:]
|
|
266
|
+
current_amplitudes = trace[0,2,:]
|
|
267
|
+
z = []
|
|
268
|
+
for period in standard_periods:
|
|
269
|
+
z.append(_linear_interpolate(current_periods,current_amplitudes,period))
|
|
270
|
+
Z.append(z)
|
|
271
|
+
X = np.array(X)
|
|
272
|
+
Y = np.array(Y)
|
|
273
|
+
Z = np.array(Z)
|
|
274
|
+
if colors is None:
|
|
275
|
+
if cmap is None:
|
|
276
|
+
cmap = cm.plasma
|
|
277
|
+
ax.plot_surface(X,Y,Z, cmap=cmap, alpha=alpha)
|
|
278
|
+
else:
|
|
279
|
+
ax.plot_surface(X,Y,X, facecolors=colors)
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def _plot_mountains(spectra, accellim=None):
|
|
283
|
+
fig = plt.figure(figsize=(13,13))
|
|
284
|
+
ax = fig.add_subplot(projection='3d')
|
|
285
|
+
|
|
286
|
+
max_period = 1.1*np.max([event['max_peak_period'] for event in spectra.values()])
|
|
287
|
+
|
|
288
|
+
for event in spectra:
|
|
289
|
+
periods = spectra[event]['spec_coords'][0,1,:]
|
|
290
|
+
spec_coords = spectra[event]['spec_coords'][:,:,(periods<=max_period)]
|
|
291
|
+
_plot_3d_spectrum(ax=ax, date="", # TODO events[event]['date'],
|
|
292
|
+
trace=spec_coords,
|
|
293
|
+
label=None, **(spectra[event]['plot_conf']))
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
ax.tick_params(axis='x', which='major', pad=15)
|
|
297
|
+
ax.tick_params(axis='y', which='major', pad=15)
|
|
298
|
+
for tick in ax.xaxis.get_majorticklabels():
|
|
299
|
+
tick.set_verticalalignment("bottom")
|
|
300
|
+
ax.xaxis.set_minor_locator(ticker.NullLocator())
|
|
301
|
+
if accellim is not None:
|
|
302
|
+
ax.set_xlim((0,accellim))
|
|
303
|
+
ax.view_init(elev=30, azim=-20, roll=2)
|
|
304
|
+
ax.set_box_aspect((5,5,1), zoom=0.75)
|
|
305
|
+
ax.set_xlabel("Peak Station Acceleration (g)", labelpad=30)
|
|
306
|
+
ax.set_ylabel("Period (s)", labelpad=40)
|
|
307
|
+
ax.set_zlabel("Normalized spectral amplitude", labelpad=10)
|
|
308
|
+
# ax.legend(frameon=True, framealpha=0.9, bbox_to_anchor=(0.5,0,0.5,0.7), loc='upper left')
|
|
309
|
+
return fig
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def make_mountains(asset, output_channels=None):
|
|
313
|
+
|
|
314
|
+
cmap = colormaps['plasma']
|
|
315
|
+
conf = Config()
|
|
316
|
+
conf.period_band = (0.1,3)
|
|
317
|
+
conf.damping = 0.02
|
|
318
|
+
conf.ss_decimation = 8
|
|
319
|
+
conf.order = 40
|
|
320
|
+
|
|
321
|
+
if output_channels is None:
|
|
322
|
+
if not asset.bridge_sensors:
|
|
323
|
+
raise ValueError("Failed to determine output sensors for Asset")
|
|
324
|
+
output_channels = json.loads(asset.bridge_sensors[2:-1])
|
|
325
|
+
|
|
326
|
+
n_expected_outputs = len(output_channels)
|
|
327
|
+
events = _load_events(asset, output_channels)
|
|
328
|
+
|
|
329
|
+
spectra = {} # dictionary to store the spectra at each event
|
|
330
|
+
for filename,event in events.items():
|
|
331
|
+
n_parsed_channels = event['outputs'].shape[0]
|
|
332
|
+
if n_parsed_channels < n_expected_outputs-MISSING_CHANNEL_LIMIT:
|
|
333
|
+
print(f"Missing {n_expected_outputs-n_parsed_channels} output channels; skipping event") # Missing too many channels
|
|
334
|
+
continue
|
|
335
|
+
|
|
336
|
+
spectra[filename] = get_spectra(event, conf.period_band, cmap) # {'spec_coords':spec_coords, 'max_peak_period':max_peak_period, 'plot_conf':plot_conf}
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
# if station == 'CE89494':
|
|
340
|
+
# max_period = 2.5
|
|
341
|
+
# if station == 'CE89973':
|
|
342
|
+
# accellim = 2.5
|
|
343
|
+
if len(spectra) == 0:
|
|
344
|
+
return None
|
|
345
|
+
|
|
346
|
+
fig = _plot_mountains(spectra)
|
|
347
|
+
|
|
348
|
+
# Save the plot to a BytesIO buffer
|
|
349
|
+
buffer = io.BytesIO()
|
|
350
|
+
fig.savefig(buffer, format="png")
|
|
351
|
+
buffer.seek(0)
|
|
352
|
+
# plt.show()
|
|
353
|
+
|
|
354
|
+
# Encode the image as Base64
|
|
355
|
+
return base64.b64encode(buffer.read()).decode("utf-8")
|
|
356
|
+
|
|
357
|
+
def parse_args(args):
|
|
358
|
+
procedure = {
|
|
359
|
+
'STATION_TYPE': None,
|
|
360
|
+
'station': None,
|
|
361
|
+
'indir': None,
|
|
362
|
+
'outdir': "./out",
|
|
363
|
+
'accellim': None
|
|
364
|
+
}
|
|
365
|
+
argi = iter(args[1:])
|
|
366
|
+
for arg in argi:
|
|
367
|
+
if arg in ['--help', '-h']:
|
|
368
|
+
print(HELP)
|
|
369
|
+
sys.exit()
|
|
370
|
+
elif arg == '--station':
|
|
371
|
+
procedure['station'] = next(argi)
|
|
372
|
+
elif arg == '--indir':
|
|
373
|
+
procedure['indir'] = next(argi)
|
|
374
|
+
elif arg == '--outdir':
|
|
375
|
+
procedure['outdir'] = next(argi)
|
|
376
|
+
elif arg == '--accellim':
|
|
377
|
+
procedure['accellim'] = float(next(argi))
|
|
378
|
+
else:
|
|
379
|
+
procedure['STATION_TYPE'] = arg
|
|
380
|
+
if procedure['STATION_TYPE'] is None:
|
|
381
|
+
print("Station type ('bridges' or 'buildings') is a required argument.")
|
|
382
|
+
sys.exit()
|
|
383
|
+
return procedure
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
if __name__ == '__main__':
|
|
387
|
+
|
|
388
|
+
import sys
|
|
389
|
+
procedure = parse_args(sys.argv)
|
|
390
|
+
STATION_TYPE = procedure['STATION_TYPE']
|
|
391
|
+
outdir = Path(procedure['outdir'])
|
|
392
|
+
if not outdir.exists():
|
|
393
|
+
outdir.mkdir()
|
|
394
|
+
|
|
395
|
+
conf = Config()
|
|
396
|
+
conf.period_band = (0.1,3) if STATION_TYPE=="bridges" else (0.1,8)
|
|
397
|
+
if procedure['accellim'] is None:
|
|
398
|
+
accellim = 1.5 if STATION_TYPE=="bridges" else 1.2
|
|
399
|
+
else:
|
|
400
|
+
accellim = procedure['accellim']
|
|
401
|
+
conf.damping = 0.02
|
|
402
|
+
conf.ss_decimation = 8
|
|
403
|
+
conf.order = 40
|
|
404
|
+
# cmap = colormaps['seismic']
|
|
405
|
+
cmap = colormaps['plasma']
|
|
406
|
+
path_to_channels = f"../channels_{STATION_TYPE}/channels_summary.json"
|
|
407
|
+
with open(path_to_channels, 'r') as readfile:
|
|
408
|
+
CHANNELS = json.load(readfile)
|
|
409
|
+
|
|
410
|
+
if procedure['station'] is not None:
|
|
411
|
+
CHANNELS = {k:v for k,v in CHANNELS.items() if k==procedure['station']}
|
|
412
|
+
|
|
413
|
+
for station in CHANNELS:
|
|
414
|
+
make_mountains(station)
|
irie/apps/prediction/urls.py
CHANGED
|
@@ -13,7 +13,7 @@ from .views import new_prediction, asset_predictors, predictor_profile, predicto
|
|
|
13
13
|
urlpatterns = [
|
|
14
14
|
re_path("^inventory/[0-9 A-Z-]*/predictors/new", new_prediction),
|
|
15
15
|
re_path("^inventory/[0-9 A-Z-]*/predictors/[0-9]", predictor_profile),
|
|
16
|
-
re_path("
|
|
16
|
+
re_path("^inventory/(?P<calid>[0-9 A-Z-]*)/predictors/create/", predictor_upload),
|
|
17
17
|
re_path("^inventory/[0-9 A-Z-]*/predictors/", asset_predictors, name="asset_predictors"),
|
|
18
18
|
re_path("^inventory/[0-9 A-Z-]*/predictors/", asset_predictors),
|
|
19
19
|
]
|
irie/apps/prediction/views.py
CHANGED
|
@@ -32,7 +32,7 @@ from .forms import PredictorForm
|
|
|
32
32
|
def new_prediction(request):
|
|
33
33
|
context = {}
|
|
34
34
|
|
|
35
|
-
page_template = "form-submission.html"
|
|
35
|
+
page_template = "form-submission.html"
|
|
36
36
|
context["segment"] = page_template
|
|
37
37
|
html_template = loader.get_template("prediction/" + page_template)
|
|
38
38
|
return HttpResponse(html_template.render(context, request))
|
|
@@ -59,40 +59,64 @@ def predictor_api(request):
|
|
|
59
59
|
|
|
60
60
|
except:
|
|
61
61
|
return HttpResponse(
|
|
62
|
-
loader.get_template("
|
|
62
|
+
loader.get_template("site/page-404-sidebar.html").render(context, request)
|
|
63
63
|
)
|
|
64
64
|
|
|
65
65
|
if request.method == "POST":
|
|
66
|
-
|
|
66
|
+
print(request.POST)
|
|
67
|
+
PREDICTOR_TYPES["IRIE_PREDICTOR_T2"].create(context["asset"],request).save()
|
|
67
68
|
|
|
68
69
|
html_template = loader.get_template("prediction/asset-predictors.html")
|
|
69
70
|
return HttpResponse(html_template.render(context, request))
|
|
70
71
|
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
@login_required(login_url="/login/")
|
|
74
|
-
|
|
73
|
+
@api_view(["GET", "POST", "PUT"])
|
|
74
|
+
# @login_required(login_url="/login/")
|
|
75
|
+
@permission_classes([IsAuthenticated])
|
|
75
76
|
def asset_predictors(request):
|
|
76
77
|
|
|
77
|
-
|
|
78
|
+
calid = request.path.split("/")[-3]
|
|
78
79
|
|
|
79
|
-
context
|
|
80
|
-
|
|
80
|
+
context = {"segment": "inventory"}
|
|
81
|
+
|
|
82
|
+
context["runners"] = list(reversed([
|
|
83
|
+
{
|
|
84
|
+
"schema": json.dumps(cls.schema),
|
|
81
85
|
"name": cls.__name__,
|
|
82
|
-
"title": cls.schema.get("title", "NO TITLE")
|
|
83
|
-
|
|
86
|
+
"title": cls.schema.get("title", "NO TITLE"),
|
|
87
|
+
"protocol": key
|
|
88
|
+
}
|
|
89
|
+
for key,cls in PREDICTOR_TYPES.items() if key
|
|
84
90
|
]))
|
|
85
91
|
|
|
86
|
-
|
|
92
|
+
|
|
87
93
|
try:
|
|
88
94
|
context["asset"] = Asset.objects.get(calid=calid)
|
|
89
|
-
except:
|
|
95
|
+
except Asset.DoesNotExist:
|
|
90
96
|
return HttpResponse(
|
|
91
|
-
loader.get_template("
|
|
97
|
+
loader.get_template("site/page-404-sidebar.html").render(context, request)
|
|
92
98
|
)
|
|
93
99
|
|
|
94
100
|
if request.method == "POST":
|
|
95
|
-
|
|
101
|
+
form = PredictorForm(request.POST, request.FILES)
|
|
102
|
+
if form.is_valid():
|
|
103
|
+
# Process the form data and uploaded file
|
|
104
|
+
# asset = form.cleaned_data['asset']
|
|
105
|
+
asset = Asset.objects.get(calid=calid)
|
|
106
|
+
uploaded_file = request.FILES['config_file']
|
|
107
|
+
|
|
108
|
+
if uploaded_file:
|
|
109
|
+
with open(uploaded_file.name, 'wb+') as destination:
|
|
110
|
+
for chunk in uploaded_file.chunks():
|
|
111
|
+
destination.write(chunk)
|
|
112
|
+
|
|
113
|
+
# Save the predictor
|
|
114
|
+
if request.POST.get("runner", None) == "IRIE_PREDICTOR_T2":
|
|
115
|
+
PREDICTOR_TYPES["IRIE_PREDICTOR_T2"].create(context["asset"],request).save()
|
|
116
|
+
else:
|
|
117
|
+
OpenSeesRunner.create(asset,None,form).save()
|
|
118
|
+
else:
|
|
119
|
+
context["form"] = PredictorForm()
|
|
96
120
|
|
|
97
121
|
html_template = loader.get_template("prediction/asset-predictors.html")
|
|
98
122
|
return HttpResponse(html_template.render(context, request))
|
|
@@ -103,7 +127,7 @@ def predictor_profile(request):
|
|
|
103
127
|
|
|
104
128
|
context = {}
|
|
105
129
|
html_template = loader.get_template("prediction/predictor-profile.html")
|
|
106
|
-
context["segment"] = "
|
|
130
|
+
context["segment"] = "inventory"
|
|
107
131
|
|
|
108
132
|
url_segs = request.path.split("/")
|
|
109
133
|
if len(url_segs) < 5:
|
|
@@ -114,7 +138,7 @@ def predictor_profile(request):
|
|
|
114
138
|
|
|
115
139
|
try:
|
|
116
140
|
asset = Asset.objects.get(calid=calid)
|
|
117
|
-
except
|
|
141
|
+
except Asset.DoesNotExist:
|
|
118
142
|
return raise404(request, context)
|
|
119
143
|
|
|
120
144
|
try:
|
|
@@ -141,19 +165,18 @@ def predictor_profile(request):
|
|
|
141
165
|
|
|
142
166
|
|
|
143
167
|
@login_required(login_url="/login/")
|
|
144
|
-
def predictor_upload(request):
|
|
168
|
+
def predictor_upload(request, calid):
|
|
145
169
|
|
|
146
170
|
context = {}
|
|
147
171
|
html_template = loader.get_template("prediction/predictor-upload.html")
|
|
148
172
|
context["segment"] = "assets"
|
|
149
173
|
|
|
150
|
-
context["title"] = "The Title"
|
|
151
|
-
|
|
152
174
|
if request.method == 'POST':
|
|
153
175
|
form = PredictorForm(request.POST, request.FILES) # include request.FILES
|
|
154
176
|
if form.is_valid():
|
|
155
177
|
# Process the form data and uploaded file
|
|
156
|
-
asset = form.cleaned_data['asset']
|
|
178
|
+
# asset = form.cleaned_data['asset']
|
|
179
|
+
asset = Asset.objects.get(calid=calid)
|
|
157
180
|
uploaded_file = request.FILES['config_file']
|
|
158
181
|
|
|
159
182
|
with open(uploaded_file.name, 'wb+') as destination:
|
|
@@ -172,7 +195,7 @@ def predictor_upload(request):
|
|
|
172
195
|
|
|
173
196
|
|
|
174
197
|
try:
|
|
175
|
-
return render(request, 'prediction/predictor-upload.html', {
|
|
198
|
+
return render(request, 'prediction/predictor-upload.html', {"form": form})
|
|
176
199
|
|
|
177
200
|
|
|
178
201
|
except Exception as e:
|
irie/apps/site/view_sdof.py
CHANGED
|
@@ -9,7 +9,7 @@ from django.urls import reverse
|
|
|
9
9
|
|
|
10
10
|
import quakeio
|
|
11
11
|
|
|
12
|
-
from irie.apps.events.models import
|
|
12
|
+
from irie.apps.events.models import EventRecord
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
@login_required(login_url="/login/")
|
|
@@ -21,7 +21,7 @@ def earthquake_fitter(request):
|
|
|
21
21
|
|
|
22
22
|
context = {}
|
|
23
23
|
|
|
24
|
-
context["event"] =
|
|
24
|
+
context["event"] = EventRecord.objects.filter(pk=pk)[0]
|
|
25
25
|
|
|
26
26
|
try:
|
|
27
27
|
context["event_data"] = quakeio.read(
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{% extends "admin/base.html" %}
|
|
2
|
+
{% load static from static %}
|
|
2
3
|
|
|
3
4
|
{% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}
|
|
5
|
+
{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "css/admin-extra.css" %}" />{% endblock %}
|
|
4
6
|
|
|
5
7
|
{% block branding %}
|
|
6
|
-
<div id="site-name"><a href="{% url 'admin:index' %}">{{ site_header|default:_('Django administration') }}</a></div>
|
|
8
|
+
<div id="site-name"><a style="font-family: Consolas, monospace;" href="{% url 'admin:index' %}">{{ site_header|default:_('Django administration') }}</a></div>
|
|
7
9
|
{% if user.is_anonymous %}
|
|
8
10
|
{% include "admin/color_theme_toggle.html" %}
|
|
9
11
|
{% endif %}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
<nav class="navbar navbar-
|
|
2
|
+
<nav class="navbar navbar-theme-primary navbar-dark px-4 col-12 d-lg-none">
|
|
3
3
|
<a class="navbar-brand me-lg-5" href="/">
|
|
4
4
|
<img class="navbar-brand-light" src="{{ ASSETS_ROOT }}/img/brace2-no_text.png" alt="BRACE2 logo" />
|
|
5
5
|
</a>
|
|
@@ -18,21 +18,21 @@
|
|
|
18
18
|
<nav id="sidebarMenu" class="sidebar d-lg-block collapse bg-gray-200" data-simplebar>
|
|
19
19
|
<div class="sidebar-inner px-4 pt-3">
|
|
20
20
|
<div class="user-card d-flex d-md-none align-items-center justify-content-between justify-content-md-center pb-4">
|
|
21
|
-
{% comment %}
|
|
22
21
|
<div class="d-flex align-items-center">
|
|
22
|
+
{% comment %}
|
|
23
23
|
<div class="avatar-lg me-4">
|
|
24
24
|
<img src="{{ ASSETS_ROOT }}/img/team/profile-picture-3.jpg" class="card-img-top rounded-circle border-white"
|
|
25
|
-
alt="
|
|
25
|
+
alt="Profile picture">
|
|
26
26
|
</div>
|
|
27
|
+
{% endcomment %}
|
|
27
28
|
<div class="d-block">
|
|
28
|
-
<h2 class="h5 mb-3">Hi
|
|
29
|
+
<h2 class="h5 mb-3">Hi</h2>
|
|
29
30
|
<a href="/page-sign-in.html" class="btn btn-secondary btn-sm d-inline-flex align-items-center">
|
|
30
31
|
<svg class="icon icon-xxs me-1" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"></path></svg>
|
|
31
|
-
|
|
32
|
+
Log Out
|
|
32
33
|
</a>
|
|
33
34
|
</div>
|
|
34
35
|
</div>
|
|
35
|
-
{% endcomment %}
|
|
36
36
|
<div class="collapse-close">
|
|
37
37
|
<a href="#sidebarMenu" data-bs-toggle="collapse"
|
|
38
38
|
data-bs-target="#sidebarMenu" aria-controls="sidebarMenu" aria-expanded="true"
|
|
@@ -61,14 +61,7 @@
|
|
|
61
61
|
<span class="sidebar-text">Dashboard</span>
|
|
62
62
|
</a>
|
|
63
63
|
</li>
|
|
64
|
-
|
|
65
|
-
<a href="{% url 'networks' %}" class="nav-link">
|
|
66
|
-
<span class="sidebar-icon">
|
|
67
|
-
<svg class="icon icon-xs me-2" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 10a8 8 0 018-8v8h8a8 8 0 11-16 0z"></path><path d="M12 2.252A8.014 8.014 0 0117.748 8H12V2.252z"></path></svg>
|
|
68
|
-
</span>
|
|
69
|
-
<span class="sidebar-text">Networks</span>
|
|
70
|
-
</a>
|
|
71
|
-
</li>
|
|
64
|
+
|
|
72
65
|
<li class="nav-item {% if 'events' in segment %} active {% endif %}">
|
|
73
66
|
<span
|
|
74
67
|
class="nav-link collapsed d-flex justify-content-between align-items-center"
|
|
@@ -95,6 +88,7 @@
|
|
|
95
88
|
</ul>
|
|
96
89
|
</div>
|
|
97
90
|
</li>
|
|
91
|
+
|
|
98
92
|
<li class="nav-item {% if 'assets' in segment %} active {% endif %}">
|
|
99
93
|
<a href="{% url 'asset_table' %}" class="nav-link">
|
|
100
94
|
<span class="sidebar-icon">
|
|
@@ -105,6 +99,15 @@
|
|
|
105
99
|
</a>
|
|
106
100
|
</li>
|
|
107
101
|
|
|
102
|
+
<li class="nav-item {% if 'networks' in segment %} active {% endif %}">
|
|
103
|
+
<a href="{% url 'networks' %}" class="nav-link">
|
|
104
|
+
<span class="sidebar-icon">
|
|
105
|
+
<svg class="icon icon-xs me-2" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 10a8 8 0 018-8v8h8a8 8 0 11-16 0z"></path><path d="M12 2.252A8.014 8.014 0 0117.748 8H12V2.252z"></path></svg>
|
|
106
|
+
</span>
|
|
107
|
+
<span class="sidebar-text">Networks</span>
|
|
108
|
+
</a>
|
|
109
|
+
</li>
|
|
110
|
+
|
|
108
111
|
<li role="separator" class="dropdown-divider mt-4 mb-3 border-gray-700"></li>
|
|
109
112
|
|
|
110
113
|
|