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.

Files changed (62) hide show
  1. irie/apps/config.py +0 -1
  2. irie/apps/evaluation/identification.py +1 -1
  3. irie/apps/evaluation/models.py +3 -3
  4. irie/apps/evaluation/views.py +3 -3
  5. irie/apps/events/admin.py +2 -2
  6. irie/apps/events/migrations/0002_rename_event_eventrecord.py +19 -0
  7. irie/apps/events/migrations/0003_hazardevent.py +21 -0
  8. irie/apps/events/models.py +55 -5
  9. irie/apps/events/views.py +48 -3
  10. irie/apps/events/views_events.py +6 -10
  11. irie/apps/inventory/filters.py +37 -0
  12. irie/apps/inventory/models.py +7 -0
  13. irie/apps/inventory/urls.py +1 -0
  14. irie/apps/inventory/views.py +134 -227
  15. irie/apps/prediction/forms.py +4 -8
  16. irie/apps/prediction/metrics.py +0 -2
  17. irie/apps/prediction/migrations/0002_alter_predictormodel_protocol.py +18 -0
  18. irie/apps/prediction/models.py +4 -4
  19. irie/apps/prediction/predictor.py +18 -12
  20. irie/apps/prediction/runners/__init__.py +3 -398
  21. irie/apps/prediction/runners/hazus.py +579 -0
  22. irie/apps/prediction/runners/opensees/__init__.py +395 -0
  23. irie/apps/prediction/runners/{utilities.py → opensees/utilities.py} +7 -7
  24. irie/apps/prediction/runners/ssid.py +414 -0
  25. irie/apps/prediction/urls.py +1 -1
  26. irie/apps/prediction/views.py +45 -22
  27. irie/apps/site/view_sdof.py +2 -2
  28. irie/apps/templates/admin/base_site.html +3 -1
  29. irie/apps/templates/css/admin-extra.css +7 -0
  30. irie/apps/templates/includes/sidebar.html +17 -14
  31. irie/apps/templates/inventory/asset-event-summary.html +3 -2
  32. irie/apps/templates/inventory/asset-profile.html +126 -38
  33. irie/apps/templates/inventory/asset-table.html +191 -135
  34. irie/apps/templates/inventory/dashboard.html +105 -27
  35. irie/apps/templates/inventory/preamble.tex +131 -0
  36. irie/apps/templates/inventory/report.tex +59 -0
  37. irie/apps/templates/networks/corridor_table.html +2 -2
  38. irie/apps/templates/networks/networks.html +164 -0
  39. irie/apps/templates/networks/networks.js +2 -2
  40. irie/apps/templates/prediction/asset-predictors.html +6 -6
  41. irie/apps/templates/prediction/form-submission.html +3 -3
  42. irie/apps/templates/prediction/hazus/event.html +33 -0
  43. irie/apps/templates/prediction/hazus/history.html +1 -0
  44. irie/apps/templates/prediction/hazus/history.js +44 -0
  45. irie/apps/templates/prediction/{new-predictor.html → new-runner.html} +12 -8
  46. irie/apps/templates/site/index.html +29 -47
  47. irie/core/urls.py +7 -2
  48. irie/init/__main__.py +2 -0
  49. irie/init/bridges.py +5 -3
  50. irie/init/management/commands/init_assets.py +24 -45
  51. irie/init/management/commands/init_corridors.py +3 -6
  52. irie/init/management/commands/init_predictors.py +23 -8
  53. irie/post/__main__.py +88 -0
  54. {irie-0.0.4.dist-info → irie-0.0.6.dist-info}/METADATA +5 -3
  55. {irie-0.0.4.dist-info → irie-0.0.6.dist-info}/RECORD +62 -48
  56. /irie/apps/prediction/runners/{metrics.py → opensees/metrics.py} +0 -0
  57. /irie/apps/prediction/runners/{xmlutils.py → opensees/xmlutils.py} +0 -0
  58. /irie/apps/prediction/runners/{zipped.py → opensees/zipped.py} +0 -0
  59. /irie/init/data/{04.tar → nbi/04.tar} +0 -0
  60. {irie-0.0.4.dist-info → irie-0.0.6.dist-info}/WHEEL +0 -0
  61. {irie-0.0.4.dist-info → irie-0.0.6.dist-info}/entry_points.txt +0 -0
  62. {irie-0.0.4.dist-info → irie-0.0.6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,395 @@
1
+ #===----------------------------------------------------------------------===#
2
+ #
3
+ # STAIRLab -- STructural Artificial Intelligence Laboratory
4
+ #
5
+ #===----------------------------------------------------------------------===#
6
+ #
7
+ import os.path
8
+ import shutil
9
+ import sys, json
10
+ import zipfile
11
+ from pathlib import Path
12
+ import contextlib
13
+
14
+ from irie.apps.prediction.runners import (Runner, MetricType, RunID, classproperty)
15
+
16
+ from .utilities import read_model
17
+ from .metrics import (
18
+ accel_response_history_plot,
19
+ column_strain_state_metric,
20
+ peak_acceleration_metric,
21
+ peak_drift_metric
22
+ )
23
+
24
+ OPENSEES = [
25
+ sys.executable, "-m", "opensees",
26
+ ]
27
+
28
+
29
+ @contextlib.contextmanager
30
+ def new_cd(x):
31
+ d = os.getcwd()
32
+
33
+ # This could raise an exception, but it's probably
34
+ # best to let it propagate and let the caller
35
+ # deal with it, since they requested x
36
+ os.chdir(x)
37
+
38
+ try:
39
+ yield
40
+
41
+ finally:
42
+ # This could also raise an exception, but you *really*
43
+ # aren't equipped to figure out what went wrong if the
44
+ # old working directory can't be restored.
45
+ os.chdir(d)
46
+
47
+
48
+ class OpenSeesRunner(Runner):
49
+ @property
50
+ def platform(self):
51
+ return self.conf.get("platform", "")
52
+
53
+
54
+ @classmethod
55
+ def create(cls, asset, request, form):
56
+ predictor = form.save(commit=False)
57
+
58
+ predictor.entry_point = [
59
+ sys.executable, "-m", "opensees"
60
+ ]
61
+ predictor.config = {}
62
+ predictor.protocol = "IRIE_PREDICTOR_T4"
63
+ predictor.active = True
64
+ # predictor.metrics = self.getMetricList()
65
+ return predictor
66
+
67
+
68
+ @classproperty
69
+ def schema(cls):
70
+ from . import schemas
71
+ return {
72
+ "title": "Structural Model",
73
+ "options": {"disable_collaps": True},
74
+ "schema": "http://json-schema.org/draft-04/schema#",
75
+ "type": "object",
76
+ "properties": {
77
+ "platform": {
78
+ "type": "string",
79
+ "title": "Platform",
80
+ "enum": ["OpenSees","CSiBridge"]
81
+ },
82
+ "model": schemas.load("hwd_conf.schema.json"),
83
+ "analysis": schemas.load("hwd_analysis.schema.json"),
84
+ }
85
+ }
86
+
87
+ def getMetricList(self):
88
+ return [
89
+ "COLUMN_STRAIN_STATES",
90
+ "PEAK_ACCEL",
91
+ "PEAK_DRIFT",
92
+ # "ACC_RESPONSE_HISTORY",
93
+ ]
94
+
95
+ def newPrediction(self, event, output_directory = None):
96
+ """
97
+ Create a new prediction run and return the run_id. If output_directory is None,
98
+ the output directory will be created automatically. Otherwise, the output directory
99
+ will be copied to the new output directory.
100
+ """
101
+ event = event.event_file.path
102
+ if output_directory is not None:
103
+ # this case will eventually be deleted, its just for
104
+ # debugging metric renderers.
105
+ run_id = "0"
106
+ self.runs[run_id] = {
107
+ "run_output_directory": Path(output_directory)
108
+ }
109
+
110
+ else:
111
+ # Calculate next output directory and
112
+ # create directory if it doesn't exist
113
+ out_dir = self.out_dir
114
+ if not out_dir.is_dir():
115
+ (out_dir/"0").mkdir(parents=True)
116
+
117
+ latestDir = list(sorted((f for f in out_dir.iterdir() if f.is_dir()), key=lambda m: int(m.name)))[-1]
118
+ run_id = int(latestDir.name)+1
119
+ run_dir = out_dir/str(run_id)
120
+ run_dir = run_dir.resolve()
121
+ run_dir.mkdir(parents=True, exist_ok=False)
122
+
123
+ # Copy files to run directory
124
+ shutil.copyfile(event, run_dir/"event.zip")
125
+ shutil.copyfile(self.model_file.resolve(), run_dir/self.model_file.name)
126
+
127
+ if self.model_file.suffix == ".zip":
128
+ with zipfile.ZipFile(self.model_file, 'r') as zip_ref:
129
+ zip_ref.extractall(run_dir)
130
+ model_file = (run_dir/"nonlinear.tcl").resolve()
131
+
132
+ elif self.model_file.suffix == ".b2k":
133
+ pass
134
+
135
+ elif self.model_file.suffix == ".tcl":
136
+ model_file = (run_dir/self.model_file.name).resolve()
137
+
138
+ self.runs[run_id] = {
139
+ "run_output_directory": run_dir,
140
+ "event_file_name": Path(event),
141
+ "model_file": model_file,
142
+ **self.conf
143
+ }
144
+
145
+ with open(out_dir/str(run_id)/"conf.json", "w") as f:
146
+ json.dump({k: str(v) for k,v in self.runs[run_id].items()}, f)
147
+
148
+ return run_id
149
+
150
+
151
+ def _load_config(self, run_id):
152
+ run_dir = self.out_dir/str(run_id)
153
+ with open(run_dir/"conf.json","r") as f:
154
+ self.runs[run_id] = json.load(f)
155
+
156
+ self.model_file = Path(self.runs[run_id]["model_file"])
157
+
158
+
159
+ def runPrediction(self, run_id, scale: float = None):
160
+ if run_id not in self.runs:
161
+ self._load_config(run_id)
162
+
163
+ event_file_path = os.path.relpath(self.runs[run_id]["event_file_name"],
164
+ self.model_file.parents[0])
165
+ output_directory = os.path.relpath(self.runs[run_id]["run_output_directory"],
166
+ self.model_file.parents[0])
167
+
168
+ event_file_path = self.runs[run_id]["event_file_name"]
169
+
170
+ # Create model
171
+ import opensees.openseespy as ops
172
+
173
+ import sys
174
+ model = ops.Model(echo_file=sys.stdout)
175
+ model.eval("set argv {}")
176
+ with new_cd(self.runs[run_id]["run_output_directory"]):
177
+ model.eval(f"source {self.runs[run_id]['model_file']}")
178
+
179
+ model.eval(f"print -json -file modelDetails.json")
180
+
181
+ model.eval(f"set python {sys.executable}")
182
+
183
+ model.eval(r"""
184
+ proc py {args} {
185
+ global python
186
+ eval "[exec {*}$python {*}$args]"
187
+ }
188
+
189
+ proc pt {args} {
190
+ global python
191
+ puts "[exec {*}$python {*}$args]"
192
+ }
193
+
194
+ proc write_modes {mode_file nmodes} {
195
+ set fid_modes [open $mode_file w+]
196
+ for {set m 1} {$m <= $nmodes} {incr m} {
197
+ puts $fid_modes "$m:"
198
+ foreach n [getNodeTags] {
199
+ puts $fid_modes " $n: \[[join [nodeEigenvector $n $m] {, }]\]";
200
+ }
201
+ }
202
+ close $fid_modes
203
+ }
204
+ proc write_displacements {file_name {resp Disp}} {
205
+ set fid [open "$file_name" "w+"]
206
+ puts $fid "[getTime]:"
207
+ foreach n [getNodeTags] {
208
+ puts $fid " $n: \[[join [node${resp} $n] {, }]\]";
209
+ }
210
+ close $fid;
211
+ }
212
+ """)
213
+
214
+ #
215
+ # Run gravity analysis
216
+ #
217
+ model.eval("""
218
+ wipeAnalysis
219
+ test NormDispIncr 1.0e-8 10 0;
220
+ algorithm Newton;
221
+ integrator LoadControl 0.1;
222
+ numberer Plain;
223
+ constraints Transformation;
224
+ system SparseGeneral;
225
+ analysis Static;
226
+ analyze 10;
227
+ # write_displacements "dispsGrav.yaml"
228
+ """)
229
+
230
+ #
231
+ # DAMPING
232
+ #
233
+ model.eval(r"""
234
+ set nmodes 8; # Number of modes to analyze for modal analysis
235
+
236
+ # set wb [eigen -fullGenLapack $nmodes];
237
+ # puts "\tFundamental-Period After Gravity Analysis:"
238
+ # for {set iPd 1} {$iPd <= $nmodes} {incr iPd 1} {
239
+ # set wwb [lindex $wb $iPd-1];
240
+ # set Tb [expr 2*$pi/sqrt($wwb)];
241
+ # puts "\tPeriod$iPd= $Tb"
242
+ # }
243
+ # write_modes $output_directory/modesPostG.yaml $nmodes
244
+ # remove recorders
245
+
246
+ set nmodes [tcl::mathfunc::max {*}$damping_modes $nmodes]
247
+ set lambdaN [eigen -fullGenLapack $nmodes];
248
+
249
+ # set lambdaN [eigen $nmodes];
250
+ if {$damping_type == "rayleigh"} {
251
+ set nEigenI [lindex $damping_modes 0]; # first rayleigh damping mode
252
+ set nEigenJ [lindex $damping_modes 1]; # second rayleigh damping mode
253
+ set iDamp [lindex $damping_ratios 0]; # first rayleigh damping ratio
254
+ set jDamp [lindex $damping_ratios 1]; # second rayleigh damping ratio
255
+ set lambdaI [lindex $lambdaN [expr $nEigenI-1]];
256
+ set lambdaJ [lindex $lambdaN [expr $nEigenJ-1]];
257
+ set omegaI [expr $lambdaI**0.5];
258
+ set omegaJ [expr $lambdaJ**0.5];
259
+ set TI [expr 2.0*$pi/$omegaI];
260
+ set TJ [expr 2.0*$pi/$omegaJ];
261
+ set alpha0 [expr 2.0*($iDamp/$omegaI-$jDamp/$omegaJ)/(1/$omegaI**2-1/$omegaJ**2)];
262
+ set alpha1 [expr 2.0*$iDamp/$omegaI-$alpha0/$omegaI**2];
263
+ puts "\tRayleigh damping parameters:"
264
+ puts "\tmodes: $nEigenI, $nEigenJ ; ratios: $iDamp, $jDamp"
265
+ puts "\tTI = $TI; TJ = $TJ"
266
+ puts "\tlambdaI = $lambdaI; lambdaJ = $lambdaJ"
267
+ puts "\tomegaI = $omegaI; omegaJ = $omegaJ"
268
+ puts "\talpha0 = $alpha0; alpha1 = $alpha1"
269
+ rayleigh $alpha0 0.0 0.0 $alpha1;
270
+
271
+ } elseif {$damping_type == "modal"} {
272
+ # needs a bit of edit. currently assuming that the ratios are applied in order at the first modes. but should be applied at the specified damping_modes modes.
273
+ set nratios [llength $damping_ratios]
274
+ puts "\tModal damping parameters:"
275
+ puts "\tratios of $damping_ratios at the first $nratios modes"
276
+ for {set i 1} {$i <= [expr $nmodes - $nratios]} {incr i} {
277
+ lappend damping_ratios 0
278
+ }
279
+ modalDamping {*}$damping_ratios
280
+ }
281
+ """)
282
+
283
+
284
+ #
285
+ # DYNAMIC RECORDERS
286
+ #
287
+
288
+ ## COLUMN SECTION DEFORMATIONS AT TOP AND BOTTOM FOR STRAIN-BASED DAMAGE STATES
289
+ column_strains = tuple(k["key"] for k in self.runs[run_id]["columns"] if k["strain"])
290
+ if len(column_strains) > 0:
291
+ model.recorder("Element", "section", 1, "deformation", xml="eleDef1.txt", ele=column_strains) # section 1 deformation]
292
+ model.recorder("Element", "section", 4, "deformation", xml="eleDef4.txt", ele=column_strains) # section 4 deformation]
293
+
294
+
295
+
296
+ #
297
+ # Run dynamic analysis
298
+ #
299
+ model.eval(f"""
300
+ wipeAnalysis
301
+ # Uniform Support Excitation
302
+ # lassign [pt -m CE58658.makePattern {event_file_path} --scale $dynamic_scale_factor --node $input_location] dt steps
303
+ # lassign [py -m CE58658.makePattern {event_file_path} --scale $dynamic_scale_factor --node $input_location] dt steps
304
+ set dt 0.1
305
+ set steps 3
306
+ """)
307
+
308
+ # RESPONSE HISTORY RECORDERS
309
+
310
+ model.recorder("Node", "accel", xml="model/AA_all.txt", timeSeries=(1, 2), dof=(1, 2))
311
+ model.recorder("Node", "accel", xml="model/RD_all.txt", dof=(1, 2))
312
+
313
+ column_nodes = tuple(k["node"] for k in self.runs[run_id]["bents"] if k["record"])
314
+ model.recorder("Node", "accel", file="TopColAccel_X_txt.txt", timeSeries=1 , node=column_nodes, dof=1)
315
+ model.recorder("Node", "accel", file="TopColAccel_Y_txt.txt", timeSeries=2 , node=column_nodes, dof=2)
316
+ model.recorder("Node", "disp", file="TopColDrift_X_txt.txt", node=column_nodes, dof=1)
317
+ model.recorder("Node", "disp", file="TopColDrift_Y_txt.txt", node=column_nodes, dof=2)
318
+
319
+ model.eval("""
320
+ set dtfact 1;
321
+ set Tol 1.0e-8;
322
+ set maxNumIter 100;
323
+ set printFlag 0;
324
+ set TestType EnergyIncr;
325
+ set NewmarkGamma 0.50;
326
+ set NewmarkBeta 0.25;
327
+ constraints Transformation;
328
+ numberer RCM;
329
+ test $TestType $Tol $maxNumIter $printFlag;
330
+ set algorithmType "Newton";
331
+ system BandSPD;
332
+ integrator Newmark $NewmarkGamma $NewmarkBeta;
333
+
334
+ algorithm {*}$algorithmType;
335
+ analysis Transient;
336
+
337
+ set DtAnalysis $dt;
338
+ set TmaxAnalysis [expr $dt*$steps];
339
+ set Nsteps $steps;
340
+ if {$dynamic_truncated != 0} {
341
+ set Nsteps $dynamic_timesteps;
342
+ }
343
+ puts "\tGround Motion: dt= $DtAnalysis, NumPts= $Nsteps, TmaxAnalysis= $TmaxAnalysis";
344
+
345
+ puts "\tRunning dynamic ground motion analysis..."
346
+ set t3 [clock clicks -millisec];
347
+ catch {progress create $Nsteps} _
348
+
349
+ analyze 2 $DtAnalysis;
350
+
351
+ # for {set ik 1} {$ik <= $Nsteps} {incr ik 1} {
352
+ # catch {progress update} _
353
+ # set ok [analyze 1 $DtAnalysis];
354
+ # }
355
+ """)
356
+
357
+ model.wipe()
358
+
359
+
360
+ def getMetricData(self, run_id:int, type:str)->dict:
361
+ import orjson
362
+ def _clean_json(d):
363
+ return orjson.loads(orjson.dumps(d,option=orjson.OPT_SERIALIZE_NUMPY))
364
+
365
+ if run_id not in self.runs:
366
+ self._load_config(run_id)
367
+
368
+ run_data = self.runs.get(run_id, None)
369
+ config = run_data
370
+
371
+ if run_data is not None:
372
+ output_dir = Path(run_data["run_output_directory"])
373
+ else:
374
+ output_dir = self.out_dir/str(run_id)
375
+
376
+ # with open(output_dir/"modelDetails.json", "r") as f:
377
+ # model = json.load(f)
378
+
379
+ model = read_model(output_dir/"modelDetails.json")
380
+
381
+ # if type == "COLUMN_STRAIN_STATES":
382
+ # return _clean_json(column_strain_state_metric(model, output_dir, config))
383
+
384
+ if type == "PEAK_ACCEL":
385
+ return _clean_json(peak_acceleration_metric(output_dir, config))
386
+
387
+ elif type == "PEAK_DRIFT":
388
+ return _clean_json(peak_drift_metric(model, output_dir, config))
389
+
390
+ elif type == "ACC_RESPONSE_HISTORY":
391
+ # config = CONFIG
392
+ # return accel_response_history_plot(output_dir, config)
393
+ return {}
394
+ return {}
395
+
@@ -111,12 +111,11 @@ def iter_section_fibers(model, s, filt=None, match=None):
111
111
  if "material" not in filt:
112
112
  filt["material"] = "*"
113
113
  for fiber in s["fibers"]:
114
- print(fiber)
115
- print(fnmatch.fnmatch(
116
- model["materials"][fiber["material"]]["type"].lower(),
117
- filt["material"]
118
- ))
119
- print([fiber["coord"] in region for region in filt["regions"]])
114
+ # print(fnmatch.fnmatch(
115
+ # model["materials"][fiber["material"]]["type"].lower(),
116
+ # filt["material"]
117
+ # ))
118
+ # print([fiber["coord"] in region for region in filt["regions"]])
120
119
  if (
121
120
  ("material" not in filt) or fnmatch.fnmatch(
122
121
  model["materials"][fiber["material"]]["type"].lower(),
@@ -167,6 +166,7 @@ def getDamageStateStrains(a, dsr, model, elems, strain_data=None):
167
166
 
168
167
  epsEle = []
169
168
  for ele in elems:
169
+ # TODO!!!!!
170
170
  if ele < 12000:
171
171
  regions = REGIONS1
172
172
  elif ele < 13000:
@@ -186,7 +186,7 @@ def getDamageStateStrains(a, dsr, model, elems, strain_data=None):
186
186
  else:
187
187
  strains = strain_data[data_file] = read_sect_xml(a/f"{data_file}")
188
188
 
189
- print(list(iter_elem_fibers(model, [ele], [int(sec)-1], filt=regions["dsr1"])))
189
+ # print(list(iter_elem_fibers(model, [ele], [int(sec)-1], filt=regions["dsr1"])))
190
190
 
191
191
  X,Y,epsRaw = zip(*(
192
192
  (