irie 0.0.0__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 (145) hide show
  1. irie/__main__.py +24 -0
  2. irie/apps/__init__.py +5 -0
  3. irie/apps/authentication/__init__.py +1 -0
  4. irie/apps/authentication/admin.py +1 -0
  5. irie/apps/authentication/config.py +6 -0
  6. irie/apps/authentication/forms.py +41 -0
  7. irie/apps/authentication/migrations/__init__.py +1 -0
  8. irie/apps/authentication/models.py +1 -0
  9. irie/apps/authentication/tests.py +1 -0
  10. irie/apps/authentication/urls.py +9 -0
  11. irie/apps/authentication/views.py +53 -0
  12. irie/apps/config.py +8 -0
  13. irie/apps/context_processors.py +5 -0
  14. irie/apps/documents/__init__.py +0 -0
  15. irie/apps/documents/apps.py +7 -0
  16. irie/apps/documents/documents.py +61 -0
  17. irie/apps/documents/migrations/__init__.py +0 -0
  18. irie/apps/documents/tests.py +3 -0
  19. irie/apps/documents/urls.py +12 -0
  20. irie/apps/documents/views.py +27 -0
  21. irie/apps/evaluation/__init__.py +0 -0
  22. irie/apps/evaluation/admin.py +43 -0
  23. irie/apps/evaluation/apps.py +18 -0
  24. irie/apps/evaluation/daemon.py +107 -0
  25. irie/apps/evaluation/identification.py +196 -0
  26. irie/apps/evaluation/migrations/0001_initial.py +25 -0
  27. irie/apps/evaluation/migrations/0002_remove_evaluation_cesmd.py +17 -0
  28. irie/apps/evaluation/migrations/0003_evaluation_asset.py +20 -0
  29. irie/apps/evaluation/migrations/__init__.py +0 -0
  30. irie/apps/evaluation/models.py +72 -0
  31. irie/apps/evaluation/urls.py +16 -0
  32. irie/apps/evaluation/views.py +68 -0
  33. irie/apps/events/__init__.py +0 -0
  34. irie/apps/events/admin.py +9 -0
  35. irie/apps/events/apps.py +12 -0
  36. irie/apps/events/migrations/0001_initial.py +27 -0
  37. irie/apps/events/migrations/0002_alter_event_id.py +18 -0
  38. irie/apps/events/migrations/0003_event_cesmd.py +19 -0
  39. irie/apps/events/migrations/0004_event_record_identifier.py +19 -0
  40. irie/apps/events/migrations/0005_event_asset.py +21 -0
  41. irie/apps/events/migrations/0006_alter_event_event_file.py +18 -0
  42. irie/apps/events/migrations/__init__.py +0 -0
  43. irie/apps/events/models.py +70 -0
  44. irie/apps/events/tests.py +1 -0
  45. irie/apps/events/tests_events.py +240 -0
  46. irie/apps/events/urls.py +29 -0
  47. irie/apps/events/views.py +55 -0
  48. irie/apps/events/views_events.py +215 -0
  49. irie/apps/inventory/CESMD.py +81 -0
  50. irie/apps/inventory/__init__.py +5 -0
  51. irie/apps/inventory/admin.py +10 -0
  52. irie/apps/inventory/apps.py +12 -0
  53. irie/apps/inventory/archive/arcGIS.py +1175 -0
  54. irie/apps/inventory/calid.py +65 -0
  55. irie/apps/inventory/fields.py +5 -0
  56. irie/apps/inventory/forms.py +12 -0
  57. irie/apps/inventory/migrations/0001_initial.py +31 -0
  58. irie/apps/inventory/migrations/0002_assetevaluationmodel_cesmd.py +19 -0
  59. irie/apps/inventory/migrations/0003_auto_20230520_2030.py +23 -0
  60. irie/apps/inventory/migrations/0004_asset.py +27 -0
  61. irie/apps/inventory/migrations/0005_auto_20230731_1802.py +23 -0
  62. irie/apps/inventory/migrations/0006_auto_20230731_1816.py +28 -0
  63. irie/apps/inventory/migrations/0007_auto_20230731_1827.py +24 -0
  64. irie/apps/inventory/migrations/0008_asset_is_complete.py +19 -0
  65. irie/apps/inventory/migrations/0009_auto_20230731_1842.py +29 -0
  66. irie/apps/inventory/migrations/0010_auto_20230801_0025.py +23 -0
  67. irie/apps/inventory/migrations/0011_alter_asset_cgs_data.py +18 -0
  68. irie/apps/inventory/migrations/0012_corridor.py +22 -0
  69. irie/apps/inventory/migrations/0013_alter_asset_cesmd.py +18 -0
  70. irie/apps/inventory/migrations/0014_alter_asset_cesmd.py +18 -0
  71. irie/apps/inventory/migrations/__init__.py +0 -0
  72. irie/apps/inventory/models.py +70 -0
  73. irie/apps/inventory/tables.py +584 -0
  74. irie/apps/inventory/traffic.py +175052 -0
  75. irie/apps/inventory/urls.py +25 -0
  76. irie/apps/inventory/views.py +515 -0
  77. irie/apps/management/__init__.py +0 -0
  78. irie/apps/management/commands/__init__.py +0 -0
  79. irie/apps/networks/__init__.py +0 -0
  80. irie/apps/networks/apps.py +5 -0
  81. irie/apps/networks/forms.py +64 -0
  82. irie/apps/networks/migrations/0001_initial.py +26 -0
  83. irie/apps/networks/migrations/__init__.py +0 -0
  84. irie/apps/networks/models.py +14 -0
  85. irie/apps/networks/networks.py +782 -0
  86. irie/apps/networks/tests.py +1 -0
  87. irie/apps/networks/urls.py +18 -0
  88. irie/apps/networks/views.py +89 -0
  89. irie/apps/prediction/__init__.py +0 -0
  90. irie/apps/prediction/admin.py +9 -0
  91. irie/apps/prediction/apps.py +12 -0
  92. irie/apps/prediction/forms.py +20 -0
  93. irie/apps/prediction/metrics.py +61 -0
  94. irie/apps/prediction/migrations/0001_initial.py +32 -0
  95. irie/apps/prediction/migrations/0002_auto_20230731_1801.py +27 -0
  96. irie/apps/prediction/migrations/0003_rename_assetevaluationmodel_evaluation.py +18 -0
  97. irie/apps/prediction/migrations/0004_delete_evaluation.py +16 -0
  98. irie/apps/prediction/migrations/0005_predictormodel_protocol.py +18 -0
  99. irie/apps/prediction/migrations/0006_alter_predictormodel_protocol.py +18 -0
  100. irie/apps/prediction/migrations/0007_predictormodel_active.py +19 -0
  101. irie/apps/prediction/migrations/0008_predictormodel_description.py +18 -0
  102. irie/apps/prediction/migrations/0009_predictormodel_entry_point.py +19 -0
  103. irie/apps/prediction/migrations/0010_alter_predictormodel_entry_point.py +18 -0
  104. irie/apps/prediction/migrations/0011_remove_predictormodel_entry_point.py +17 -0
  105. irie/apps/prediction/migrations/0012_predictormodel_entry_point.py +18 -0
  106. irie/apps/prediction/migrations/0013_predictormodel_metrics.py +18 -0
  107. irie/apps/prediction/migrations/0014_auto_20240930_0004.py +28 -0
  108. irie/apps/prediction/migrations/0015_alter_predictormodel_render_file.py +18 -0
  109. irie/apps/prediction/migrations/__init__.py +0 -0
  110. irie/apps/prediction/models.py +37 -0
  111. irie/apps/prediction/predictor.py +286 -0
  112. irie/apps/prediction/runners/__init__.py +450 -0
  113. irie/apps/prediction/runners/metrics.py +168 -0
  114. irie/apps/prediction/runners/opensees/__init__.py +0 -0
  115. irie/apps/prediction/runners/opensees/schemas/__init__.py +39 -0
  116. irie/apps/prediction/runners/utilities.py +277 -0
  117. irie/apps/prediction/runners/xmlutils.py +232 -0
  118. irie/apps/prediction/runners/zipped.py +27 -0
  119. irie/apps/prediction/templatetags/__init__.py +0 -0
  120. irie/apps/prediction/templatetags/predictor.py +20 -0
  121. irie/apps/prediction/urls.py +19 -0
  122. irie/apps/prediction/views.py +184 -0
  123. irie/apps/prediction/views_api.py +216 -0
  124. irie/apps/site/__init__.py +0 -0
  125. irie/apps/site/admin.py +1 -0
  126. irie/apps/site/config.py +6 -0
  127. irie/apps/site/migrations/__init__.py +1 -0
  128. irie/apps/site/models.py +2 -0
  129. irie/apps/site/templatetags/__init__.py +0 -0
  130. irie/apps/site/templatetags/indexing.py +7 -0
  131. irie/apps/site/tests.py +1 -0
  132. irie/apps/site/urls.py +8 -0
  133. irie/apps/site/view_sdof.py +40 -0
  134. irie/apps/site/view_utils.py +13 -0
  135. irie/apps/site/views.py +88 -0
  136. irie/core/__init__.py +5 -0
  137. irie/core/asgi.py +12 -0
  138. irie/core/settings.py +223 -0
  139. irie/core/urls.py +39 -0
  140. irie/core/wsgi.py +12 -0
  141. irie-0.0.0.dist-info/METADATA +48 -0
  142. irie-0.0.0.dist-info/RECORD +145 -0
  143. irie-0.0.0.dist-info/WHEEL +5 -0
  144. irie-0.0.0.dist-info/entry_points.txt +2 -0
  145. irie-0.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,25 @@
1
+ #===----------------------------------------------------------------------===#
2
+ #
3
+ # STAIRLab -- STructural Artificial Intelligence Laboratory
4
+ #
5
+ #===----------------------------------------------------------------------===#
6
+ #
7
+ # Summer 2023, BRACE2 Team
8
+ # Berkeley, CA
9
+ #
10
+ #----------------------------------------------------------------------------#
11
+ from django.urls import path, re_path
12
+ from apps.inventory import views
13
+
14
+ urlpatterns = [
15
+ path("dashboard/", views.dashboard, name="dashboard"),
16
+ path("dashboard.html", views.dashboard),
17
+ path("dashboard/demo", views.dashboard),
18
+
19
+ path("asset-table.html", views.asset_table),
20
+ path("asset-table/", views.asset_table, name="asset_table"),
21
+ re_path(
22
+ r"^evaluations/(?P<event>[0-9 A-Z-]*)/(?P<cesmd>[0-9 A-Z-]*)/.*", views.asset_event_summary, name="asset_event_summary"
23
+ ),
24
+ re_path(r"^inventory/(?P<calid>[0-9 A-Z-]*)/", views.asset_profile, name="asset_profile"),
25
+ ]
@@ -0,0 +1,515 @@
1
+ #===----------------------------------------------------------------------===#
2
+ #
3
+ # STAIRLab -- STructural Artificial Intelligence Laboratory
4
+ #
5
+ #===----------------------------------------------------------------------===#
6
+ #
7
+ # Summer 2023, BRACE2 Team
8
+ # Berkeley, CA
9
+ #
10
+ #----------------------------------------------------------------------------#
11
+ import os
12
+ import re
13
+ from django.core.paginator import Paginator
14
+ from django.template import loader, TemplateDoesNotExist
15
+ from django.http import HttpResponse
16
+ from django.contrib.auth.decorators import login_required
17
+ from django.core.exceptions import ObjectDoesNotExist
18
+
19
+ from apps.events.models import Event
20
+ from apps.site.view_utils import raise404
21
+ from apps.inventory.models import Asset
22
+ from apps.inventory.forms import AssetForm
23
+
24
+
25
+ @login_required(login_url="/login/")
26
+ def fetch_rendering(request):
27
+ asset_id = request.GET.get('asset')
28
+ asset = Asset.objects.get(id=asset_id)
29
+
30
+ if asset.cesmd == "CE58658":
31
+ template = loader.get_template(f"bridges/InteractiveTwin-{asset.cesmd}.html")
32
+ return HttpResponse(template.render({}, request))
33
+
34
+
35
+ from apps.prediction.models import PredictorModel
36
+ for p in PredictorModel.objects.filter(asset=asset):
37
+ if p.protocol == "BRACE2_CLI_PREDICTOR_T4":
38
+ return HttpResponse("html")
39
+
40
+ return HttpResponse("No rendering available for this asset.")
41
+
42
+
43
+
44
+ def _make_freq_plot(evaluation):
45
+ import numpy as np
46
+ from mdof.macro import FrequencyContent
47
+
48
+ plot = FrequencyContent(scale=True, period=True, xlabel="Period (s)", ylabel="Normalized Amplitude")
49
+
50
+ for name, mdata in evaluation["summary"].items():
51
+ periods = []
52
+ amplitudes = []
53
+ for i in mdata.get("data", []):
54
+ if "period" in i:
55
+ periods.append(i["period"])
56
+ if "amplitude" in i:
57
+ amplitudes.append(i["amplitude"])
58
+
59
+ if len(amplitudes) and (len(amplitudes) == len(periods)):
60
+ plot.add(np.array(periods), np.array(amplitudes), label=name)
61
+ else:
62
+ plot.add(np.array(periods), label=name)
63
+
64
+ fig = plot.get_figure()
65
+ return fig.to_json()
66
+
67
+
68
+ @login_required(login_url="/login/")
69
+ def asset_event_summary(request, cesmd, event):
70
+ from apps.evaluation.models import Evaluation
71
+
72
+ context = {}
73
+ context["segment"] = "events"
74
+ html_template = loader.get_template("inventory/asset-event-summary.html")
75
+
76
+ try:
77
+
78
+ segments = request.path.split("/")
79
+ _, _, is_nce = segments[-3:]
80
+
81
+ try:
82
+ evaluation = Evaluation.objects.filter(event_id=int(event))[0]
83
+ evaluation_data = evaluation.evaluation_data
84
+
85
+ except Exception as e:
86
+ # TODO: Handle case where evaluation cant be found
87
+ evaluation_data = {}
88
+ evaluation = None
89
+
90
+ for metric in evaluation_data.values():
91
+ metric["completion"] = (
92
+ 100 * len(metric["summary"])/len(metric["predictors"])
93
+ )
94
+
95
+ if "SPECTRAL_SHIFT_IDENTIFICATION" in evaluation_data:
96
+ context["freq_plot_json"] = \
97
+ _make_freq_plot(evaluation_data["SPECTRAL_SHIFT_IDENTIFICATION"])
98
+
99
+ context["all_evaluations"] = evaluation_data
100
+
101
+ context["evaluation_details"] = {
102
+ metric.replace("_", " ").title(): {
103
+ key: [list(map(lambda i: f"{i:.3}" if isinstance(i,float) else str(i), row)) for row in table]
104
+ for key, table in predictors["details"].items()
105
+ }
106
+ for metric, predictors in sorted(evaluation_data.items(), key=lambda i: i[0])
107
+ }
108
+ context["asset"] = evaluation and evaluation.event.asset or None
109
+ context["nce_version"] = is_nce
110
+ context["event_data"] = Event.objects.get(pk=int(event)).motion_data
111
+
112
+
113
+ resp = html_template.render(context, request)
114
+
115
+ return HttpResponse(resp)
116
+
117
+ except Exception as e:
118
+ if "DEBUG" in os.environ and os.environ["DEBUG"]:
119
+ raise e
120
+ html_template = loader.get_template("site/page-500.html")
121
+ return HttpResponse(html_template.render(context, request))
122
+
123
+ @login_required(login_url="/login/")
124
+ def dashboard(request):
125
+ from apps.inventory.models import Asset
126
+ from apps.evaluation.models import Evaluation
127
+
128
+ context = {}
129
+ context["segment"] = "dashboard"
130
+ try:
131
+ if "demo" in request.path:
132
+ context["demo_version"] = True
133
+
134
+ context["recent_evaluations"] = [
135
+ (evaluation, Event.objects.get(pk=evaluation.event_id))
136
+ for evaluation in reversed(list(Evaluation.objects.all())[-6:])
137
+ ]
138
+ assets = [
139
+ Asset.objects.get(cesmd=event[1].cesmd) for event in context["recent_evaluations"]
140
+ ]
141
+ context["asset_map"] = AssetMap(assets,
142
+ layer_assets=False,
143
+ traffic=False).get_html()
144
+ context["calid"] = {b.cesmd: b.calid for b in assets}
145
+
146
+ html_template = loader.get_template("inventory/dashboard.html")
147
+ return HttpResponse(html_template.render(context, request))
148
+
149
+ except Exception as e:
150
+ if "DEBUG" in os.environ and os.environ["DEBUG"]:
151
+ raise e
152
+ html_template = loader.get_template("site/page-500.html")
153
+ return HttpResponse(html_template.render(context, request))
154
+
155
+
156
+
157
+ def _ssid_stats(events, key):
158
+ """
159
+ mode_results is a list (station level) of lists (event level) of dictionaries (mode level).
160
+ mode_results = [
161
+ [
162
+ {
163
+ "period": ...,
164
+ "frequency": ...,
165
+ "damping": ...,
166
+ "emac": ...,
167
+ "mpc": ...,
168
+ },
169
+ ...
170
+ ],
171
+ ...
172
+ ]
173
+
174
+ [
175
+ # "Event"
176
+ {"S1": {"period": [0.1]},
177
+ "R1": {"period": [1.2]}}
178
+ ]
179
+ """
180
+ mode_results = [_find_ssid(event.id) for event in events]
181
+ import numpy as np
182
+
183
+ filtered_results = [
184
+ {
185
+ method: [
186
+ result for result in event_results[method]
187
+ if key in result and result.get("emac", 1.0) > 0.5 and result.get("mpc", 1.0) > 0.5
188
+ ] for method in event_results
189
+ } for event_results in mode_results
190
+ ]
191
+
192
+ from collections import defaultdict
193
+ values = defaultdict(list)
194
+ for event in filtered_results:
195
+ for method in event:
196
+ for result in event[method]:
197
+ values[method].append(result[key])
198
+
199
+ mean = {method: np.mean(values[method]) for method in values}
200
+ std = {method: np.std(values[method]) for method in values}
201
+
202
+ def _first(method_results):
203
+ if method_results and len(method_results) > 0:
204
+ results = np.array([result[key] for result in method_results])
205
+ try:
206
+ idx = np.argmax([result["amplitude"] for result in method_results])
207
+ return results[idx]
208
+ except KeyError:
209
+ return np.max(results)
210
+ else:
211
+ return {}
212
+
213
+ return [
214
+ {method: {
215
+ # "distance": (closest_item[key]-mean)/std),
216
+ "nearest_mean": event_results[method][np.argmin(np.abs(mean[method] \
217
+ - [result[key] for result in event_results[method]]))] \
218
+ if event_results[method] and len(event_results[method]) > 0 else {} ,
219
+ "maximum": _first(event_results[method])
220
+ }
221
+ for method in event_results
222
+ }
223
+ for event_results in filtered_results
224
+ ]
225
+
226
+
227
+ def _find_ssid(event_id=None, evaluation=None):
228
+ """
229
+ Given an event ID, finds the results of the first configured
230
+ system ID run. This generally looks like a list of dicts,
231
+ each with fields "frequency", "damping", etc.
232
+ """
233
+ from apps.evaluation.models import Evaluation
234
+
235
+ if evaluation is None:
236
+ evaluation = Evaluation.objects.filter(event_id=int(event_id))
237
+
238
+ elif not isinstance(evaluation, list):
239
+ evaluation = [evaluation]
240
+
241
+
242
+ if len(evaluation) != 1:
243
+ return []
244
+
245
+ else:
246
+ evaluation_data = evaluation[0].evaluation_data
247
+
248
+ if "SPECTRAL_SHIFT_IDENTIFICATION" in evaluation_data:
249
+ return {
250
+ key: val.get("data", val.get("error", []))
251
+ for key,val in evaluation_data["SPECTRAL_SHIFT_IDENTIFICATION"]["summary"].items()
252
+ }
253
+
254
+ else:
255
+ return []
256
+
257
+
258
+ @login_required(login_url="/login/")
259
+ def asset_profile(request, calid):
260
+
261
+ context = {}
262
+ html_template = loader.get_template("inventory/asset-profile.html")
263
+ context["segment"] = "assets"
264
+
265
+ context["nce_version"] = True
266
+
267
+ try:
268
+ asset = Asset.objects.get(calid=calid)
269
+
270
+ except ObjectDoesNotExist:
271
+ return raise404(request, context)
272
+
273
+ context["asset"] = asset
274
+
275
+ context["tables"] = _make_tables(asset)
276
+
277
+ if asset.cesmd:
278
+ cesmd = asset.cesmd
279
+
280
+ events = list(reversed(sorted(Event.objects.filter(cesmd=cesmd),
281
+ key=lambda x: x.motion_data["event_date"])))
282
+
283
+ evals = [
284
+ {"event": event,
285
+ "pga": event.pga, #abs(event.motion_data["peak_accel"])/980.,
286
+ "evaluation": ssid,
287
+ }
288
+ for i, (event, ssid) in enumerate(zip(events, _ssid_stats(events, "period")))
289
+ ]
290
+ context["evaluations"] = Paginator(evals, 5).get_page(1)
291
+
292
+ try:
293
+ return HttpResponse(html_template.render(context, request))
294
+
295
+ # except TemplateDoesNotExist:
296
+ # context["rendering"] = None
297
+ # return HttpResponse(html_template.render(context, request))
298
+
299
+ except Exception as e:
300
+ if "DEBUG" in os.environ and os.environ["DEBUG"]:
301
+ raise e
302
+ html_template = loader.get_template("site/page-500.html")
303
+ return HttpResponse(html_template.render(context, request))
304
+
305
+ def _make_tables(asset):
306
+ if asset.cesmd:
307
+ tables = [
308
+ {k: v for k,v in group.items()
309
+ if k not in {
310
+ "Remarks",
311
+ "Instrumentation",
312
+ "Remarks/Notes",
313
+ "Construction Date"
314
+ }
315
+ } for group in asset.cgs_data[1:]
316
+ ]
317
+ else:
318
+ tables = []
319
+
320
+ # Filter out un-interesting information
321
+ nbi_data = [
322
+ {k: v for k,v in group.items()
323
+ if k not in {
324
+ "Owner Agency",
325
+ "Year Reconstructed",
326
+ "Bridge Posting Code",
327
+ "Latitude",
328
+ "Longitude",
329
+ "NBIS Minimum Bridge Length",
330
+ "Record Type",
331
+ "State Name",
332
+ "U.S. Congressional District",
333
+ "Inventory Route NHS Code"
334
+ }
335
+ } for group in asset.nbi_data.values()
336
+ ]
337
+ tables.extend(nbi_data)
338
+ tables = [tables[2], *tables[:2], *tables[3:]]
339
+ condition = {}
340
+ for table in tables:
341
+ keys = set()
342
+ for k in table:
343
+ key = k.lower()
344
+ if "condition" in key \
345
+ or "rating" in key \
346
+ or (re.search("^ *[0-9] - [A-Z]", table[k]) is not None and "code" not in key):
347
+ condition[k] = table[k]
348
+ keys.add(k)
349
+
350
+ for k in keys:
351
+ del table[k]
352
+
353
+ tables.insert(3,condition)
354
+
355
+ # for some tables, all values are empty. Filter these out
356
+ tables = [
357
+ table for table in tables if sum(map(lambda i: len(i),table.values()))
358
+ ]
359
+ return tables
360
+
361
+
362
+
363
+ @login_required(login_url="/login/")
364
+ def asset_table(request):
365
+ """
366
+ Returns a table of all assets in the database, paginated
367
+ """
368
+
369
+ context = {}
370
+ context["segment"] = "assets"
371
+ html_template = loader.get_template("inventory/asset-table.html")
372
+
373
+ page = request.GET.get("page", 1)
374
+ try:
375
+ page = int(page)
376
+ except:
377
+ page = 1
378
+
379
+ assets = Asset.objects.all() #exclude(cesmd__isnull=True),
380
+ context["bridges"] = Paginator(assets, 10).get_page(page)
381
+ context["asset_map"] = AssetMap(assets=assets,
382
+ cesmd=True,
383
+ layer_assets=True).get_html()
384
+
385
+ try:
386
+ return HttpResponse(html_template.render(context, request))
387
+
388
+ except Exception as e:
389
+ if "DEBUG" in os.environ and os.environ["DEBUG"]:
390
+ raise e
391
+ html_template = loader.get_template("site/page-500.html")
392
+ return HttpResponse(html_template.render(context, request))
393
+
394
+
395
+
396
+ import folium
397
+ from folium import branca
398
+
399
+ class AssetMap:
400
+ def __init__(self,
401
+ assets,
402
+ layer_assets=True,
403
+ traffic=False,
404
+ cesmd=True):
405
+ self._layer_assets = layer_assets
406
+
407
+
408
+ self._assets = assets
409
+
410
+ self._figure = figure = folium.Figure()
411
+ self._map = m = folium.Map(
412
+ location=[37.7735, -122.0993], zoom_start=6, tiles=None
413
+ )
414
+
415
+ folium.raster_layers.TileLayer(
416
+ tiles='cartodbpositron',
417
+ name='Instrumented Bridges'
418
+ ).add_to(m)
419
+ m.add_to(figure)
420
+
421
+ if cesmd:
422
+ self.add_CESMD()
423
+
424
+ if traffic:
425
+ self.add_traffic()
426
+
427
+ if self._layer_assets:
428
+
429
+ self._asset_layers = {
430
+ "partial": folium.FeatureGroup(name="Partial Digital Twins"),
431
+ "complete": folium.FeatureGroup(name="Full Digital Twins")
432
+ }
433
+ list(map(lambda i: i.add_to(self._map), self._asset_layers.values()))
434
+ self.add_twins(list(self._asset_layers.values()))
435
+
436
+
437
+ def get_html(self, **kwargs):
438
+ folium.LayerControl(collapsed=False).add_to(self._map)
439
+ self._figure.render()
440
+ return self._map._repr_html_()
441
+
442
+ def add_twins(self, features):
443
+
444
+ for b in self._assets:
445
+ lat, lon = b.coordinates
446
+ popup = folium.Popup(
447
+ folium.Html(
448
+ '<a style="display: inline;" target="_blank" href="/inventory/{calid}/">{label}</a>'.format(
449
+ calid=b.calid,
450
+ label=b.calid
451
+ ),
452
+ script=True
453
+ ),
454
+ min_width= 50,
455
+ max_width=100
456
+ )
457
+ if b.is_complete:
458
+ folium.Marker(
459
+ location=[lat, lon],
460
+ popup=popup,
461
+ icon=folium.Icon(icon="cloud", color="blue" if not b.is_complete else "beige"),
462
+ z_index_offset=1000
463
+ ).add_to(features[int(b.is_complete)])
464
+ else:
465
+ folium.CircleMarker(
466
+ location=[lat, lon],
467
+ popup=popup,
468
+ color="blue",
469
+ fill=True,
470
+ opacity=1,
471
+ fill_opacity=1,
472
+ radius=3,
473
+ z_index_offset=800
474
+ ).add_to(features[int(b.is_complete)])
475
+ return self
476
+
477
+ def add_CESMD(self):
478
+ cesmdbridges = folium.FeatureGroup(name="Registered Bridges")
479
+ cesmdbridges.add_to(self._map)
480
+
481
+ for b in self._assets:
482
+ if not b.cesmd:
483
+ continue
484
+ lat, lon = b.coordinates
485
+
486
+ folium.Marker(
487
+ location=[lat, lon],
488
+ popup=b.cesmd,
489
+ icon=folium.Icon(icon="glyphicon-road", color="lightgray"),
490
+ ).add_to(cesmdbridges)
491
+
492
+
493
+ def add_traffic(self):
494
+ # from apps.inventory.traffic import TRAFFIC_LOW, TRAFFIC_MID, TRAFFIC_HIGH, TRAFFIC_ALL
495
+ from apps.inventory.traffic import TRAFFIC_ALL
496
+ traffic = folium.FeatureGroup(name="Traffic")
497
+ traffic.add_to(self._map)
498
+
499
+ cm = branca.colormap.LinearColormap(colors=['green', 'yellow', 'orange', 'red'], vmin=10000, vmax=100000)
500
+ for loc in TRAFFIC_ALL:
501
+ folium.CircleMarker([loc["coords"][1],loc["coords"][0]],
502
+ radius=5,
503
+ popup=None,
504
+ color=cm.rgb_hex_str(loc["properties"]["AHEAD_AADT"]),
505
+ fill=True,
506
+ opacity=0.5,
507
+ weight=0,
508
+ ).add_to(traffic)
509
+
510
+ cm = branca.colormap.LinearColormap(colors=['green', 'yellow', 'orange', 'red'],
511
+ vmin=10000, vmax=100000,
512
+ caption='Average Annual Daily Traffic Crossings')
513
+ cm.add_to(self._map)
514
+
515
+ return self
File without changes
File without changes
File without changes
@@ -0,0 +1,5 @@
1
+ from django.apps import AppConfig
2
+
3
+ class NetworksConfig(AppConfig):
4
+ default_auto_field = "django.db.models.BigAutoField"
5
+ name = "apps.networks"
@@ -0,0 +1,64 @@
1
+ #===----------------------------------------------------------------------===#
2
+ #
3
+ # STAIRLab -- STructural Artificial Intelligence Laboratory
4
+ #
5
+ #===----------------------------------------------------------------------===#
6
+ from django import forms
7
+ from .models import UserNetworkPreferences
8
+ from crispy_forms.helper import FormHelper
9
+ from crispy_forms.layout import Submit
10
+
11
+ class UserPreferencesForm(forms.ModelForm):
12
+ class Meta:
13
+ model = UserNetworkPreferences
14
+ fields = ['latitude', 'longitude']
15
+
16
+ class WeightInput(forms.NumberInput):
17
+ # template_name = 'styled_inputs.html'
18
+
19
+ def __init__(self, label, attrs=None):
20
+ default_attrs = {
21
+ 'label': label,
22
+ 'class': 'form-row form-inline',
23
+ 'style': 'width: 100px; flex: 1; color: black;'
24
+ }
25
+ if attrs:
26
+ default_attrs.update(attrs)
27
+ super().__init__(attrs=default_attrs)
28
+
29
+
30
+ class CorridorsForm(forms.Form):
31
+ method = forms.TypedChoiceField(
32
+ label='Method',
33
+ choices=[(0, 'A'), (1, 'B'), (2, 'B-alt')],
34
+ coerce=int,
35
+ initial=0
36
+ )
37
+ hos_weight = forms.IntegerField(label="Hospital", initial=1, widget=WeightInput("Hospital"))
38
+ fire_weight = forms.IntegerField(label="Fire station", initial=0, widget=WeightInput("Fire station"))
39
+ police_weight = forms.IntegerField(label="Police station", initial=0, widget=WeightInput("Police station"))
40
+ maintenance_weight = forms.IntegerField(label="Maintenance", initial=0, widget=WeightInput("Maintenance"))
41
+ airport_weight = forms.IntegerField(label="Airport", initial=0, widget=WeightInput("Airport"))
42
+ seaport_weight = forms.IntegerField(label="Seaport", initial=0, widget=WeightInput("Seaport"))
43
+ ferry_weight = forms.IntegerField(label="Ferry terminal", initial=0, widget=WeightInput("Ferry terminal"))
44
+ consider_population = forms.TypedChoiceField(
45
+ label='Consider population',
46
+ choices=[(0, 'No'), (1, 'Yes')],
47
+ coerce=int,
48
+ initial=0
49
+ )
50
+
51
+ corridor_input = forms.IntegerField(widget=forms.HiddenInput(),
52
+ required=False,
53
+ min_value=1,max_value=162)
54
+
55
+ def __init__(self, *args, **kwargs):
56
+ super(CorridorsForm, self).__init__(*args, **kwargs)
57
+ self.helper = FormHelper()
58
+ self.helper.form_class = 'form-inline' # makes the form inline
59
+ self.helper.label_class = 'form-row sr-only' # hides labels if desired
60
+ self.helper.field_class = 'form-row mr-2' # margin for spacing between fields
61
+ self.helper.form_method = 'get'
62
+ # self.helper.form_style = # 'inline'
63
+ self.helper.add_input(Submit('update', 'Rank', css_class='btn btn-primary'))
64
+
@@ -0,0 +1,26 @@
1
+ # Generated by Django 5.1 on 2024-11-03 00:27
2
+
3
+ import django.db.models.deletion
4
+ from django.conf import settings
5
+ from django.db import migrations, models
6
+
7
+
8
+ class Migration(migrations.Migration):
9
+
10
+ initial = True
11
+
12
+ dependencies = [
13
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
14
+ ]
15
+
16
+ operations = [
17
+ migrations.CreateModel(
18
+ name='UserNetworkPreferences',
19
+ fields=[
20
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21
+ ('latitude', models.FloatField(default=37.806)),
22
+ ('longitude', models.FloatField(default=-122.365)),
23
+ ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
24
+ ],
25
+ ),
26
+ ]
File without changes
@@ -0,0 +1,14 @@
1
+ #===----------------------------------------------------------------------===#
2
+ #
3
+ # STAIRLab -- STructural Artificial Intelligence Laboratory
4
+ #
5
+ #===----------------------------------------------------------------------===#
6
+ from django.db import models
7
+ from django.contrib.auth.models import User
8
+
9
+ class UserNetworkPreferences(models.Model):
10
+ user = models.OneToOneField(User, on_delete=models.CASCADE)
11
+ latitude = models.FloatField(default=37.806)
12
+ longitude = models.FloatField(default=-122.365)
13
+
14
+