irie 0.0.58__py3-none-any.whl → 0.0.60__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/evaluation/models.py +7 -0
- irie/apps/events/views_events.py +2 -2
- irie/apps/inventory/migrations/0009_datum_angle_x_datum_angle_y.py +23 -0
- irie/apps/inventory/models.py +1 -1
- irie/apps/inventory/views.py +10 -4
- irie/apps/prediction/forms/csi_upload.py +68 -0
- irie/apps/prediction/migrations/0007_remove_sensorassignment_orient_x_and_more.py +25 -0
- irie/apps/prediction/runners/__init__.py +6 -4
- irie/apps/prediction/runners/opensees/__init__.py +49 -14
- irie/apps/prediction/urls.py +6 -4
- irie/apps/prediction/views.py +248 -17
- irie/apps/static/assets/css/brace.css +1 -1
- irie/apps/static/assets/css/brace.css.map +1 -1
- irie/apps/static/assets/css/brace.min.css +1 -1
- irie/apps/static/assets/js/brace.js +101 -42
- irie/apps/templates/includes/footer.html +1 -1
- irie/apps/templates/inventory/asset-event-summary.html +7 -0
- irie/apps/templates/inventory/asset-on-map.html +22 -22
- irie/apps/templates/inventory/asset-on-map.js +115 -113
- irie/apps/templates/inventory/create-datum.html +44 -0
- irie/apps/templates/inventory/sensor-upload.html +22 -22
- irie/apps/templates/layouts/base.html +3 -3
- irie/apps/templates/prediction/create-model.html +32 -37
- irie/apps/templates/prediction/upload/confirm.html +93 -0
- irie/apps/templates/prediction/upload/step.html +119 -0
- irie/apps/templates/prediction/veux/navigator.html +54 -38
- irie/apps/templates/prediction/veux/navigator.js +222 -154
- irie/apps/templates/prediction/xara-profile.html +7 -3
- irie/core/settings.py +1 -0
- {irie-0.0.58.dist-info → irie-0.0.60.dist-info}/METADATA +7 -6
- {irie-0.0.58.dist-info → irie-0.0.60.dist-info}/RECORD +35 -29
- /irie/apps/prediction/{forms.py → forms/__init__.py} +0 -0
- {irie-0.0.58.dist-info → irie-0.0.60.dist-info}/WHEEL +0 -0
- {irie-0.0.58.dist-info → irie-0.0.60.dist-info}/entry_points.txt +0 -0
- {irie-0.0.58.dist-info → irie-0.0.60.dist-info}/top_level.txt +0 -0
irie/apps/evaluation/models.py
CHANGED
|
@@ -51,6 +51,13 @@ class Evaluation(models.Model):
|
|
|
51
51
|
# Thread(target=evaluate, args=(event, evaluation)).start()
|
|
52
52
|
|
|
53
53
|
return evaluation
|
|
54
|
+
|
|
55
|
+
def evaluate(self):
|
|
56
|
+
"""
|
|
57
|
+
Evaluate the event and update the evaluation status.
|
|
58
|
+
This method can be run in a separate thread.
|
|
59
|
+
"""
|
|
60
|
+
return evaluate(self.event, self)
|
|
54
61
|
|
|
55
62
|
|
|
56
63
|
def evaluate(event, evaluation)->"Evaluation":
|
irie/apps/events/views_events.py
CHANGED
|
@@ -84,8 +84,8 @@ def save_event(request, event, success_status):
|
|
|
84
84
|
# RECORD ID
|
|
85
85
|
rec_id = motion_data.get("record_identifier", "")
|
|
86
86
|
|
|
87
|
-
if EventRecord.objects.filter(record_identifier=rec_id).first():
|
|
88
|
-
print("\n\nSKIPPING
|
|
87
|
+
if (evnt := EventRecord.objects.filter(record_identifier=rec_id).first()):
|
|
88
|
+
print(f"\n\nSKIPPING, {evnt.id}")
|
|
89
89
|
return HttpResponse(json.dumps({"data": ""}), status=success_status)
|
|
90
90
|
|
|
91
91
|
# CREATE EVENT
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Generated by Django 5.1.2 on 2025-07-31 05:48
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('irie_apps_inventory', '0008_alter_sensor_dx_alter_sensor_dy_alter_sensor_dz_and_more'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AddField(
|
|
14
|
+
model_name='datum',
|
|
15
|
+
name='angle_x',
|
|
16
|
+
field=models.DecimalField(blank=True, decimal_places=2, default=0.0, max_digits=10, null=True),
|
|
17
|
+
),
|
|
18
|
+
migrations.AddField(
|
|
19
|
+
model_name='datum',
|
|
20
|
+
name='angle_y',
|
|
21
|
+
field=models.DecimalField(blank=True, decimal_places=2, default=0.0, max_digits=10, null=True),
|
|
22
|
+
),
|
|
23
|
+
]
|
irie/apps/inventory/models.py
CHANGED
irie/apps/inventory/views.py
CHANGED
|
@@ -170,6 +170,9 @@ def asset_event_summary(request, cesmd, event):
|
|
|
170
170
|
evaluation_data = {}
|
|
171
171
|
evaluation = None
|
|
172
172
|
|
|
173
|
+
if request.method == 'POST':
|
|
174
|
+
evaluation.evaluate()
|
|
175
|
+
|
|
173
176
|
try:
|
|
174
177
|
for metric in evaluation_data.values():
|
|
175
178
|
metric["completion"] = (
|
|
@@ -400,13 +403,13 @@ def asset_sensors(request, calid):
|
|
|
400
403
|
|
|
401
404
|
# General Context
|
|
402
405
|
context = {
|
|
403
|
-
"
|
|
404
|
-
"segment": "assets",
|
|
405
|
-
"groups": SensorGroup.objects.filter(asset=asset)
|
|
406
|
+
"segment": "assets"
|
|
406
407
|
}
|
|
407
408
|
|
|
408
409
|
# Database
|
|
409
410
|
asset = get_object_or_404(Asset, calid=calid)
|
|
411
|
+
context["asset"] = asset
|
|
412
|
+
context["groups"] = SensorGroup.objects.filter(asset=asset)
|
|
410
413
|
|
|
411
414
|
return HttpResponse(html_template.render(context, request))
|
|
412
415
|
|
|
@@ -451,7 +454,10 @@ def sensor_upload(request, calid):
|
|
|
451
454
|
"group_form": group_form,
|
|
452
455
|
"formset": formset,
|
|
453
456
|
"renderings": [
|
|
454
|
-
{
|
|
457
|
+
{
|
|
458
|
+
"name": predictor.name,
|
|
459
|
+
"glb": predictor.render_file.url
|
|
460
|
+
}
|
|
455
461
|
for predictor in PredictorModel.objects.filter(asset=asset, protocol="IRIE_PREDICTOR_V1")
|
|
456
462
|
if predictor.render_file and predictor.render_file.url
|
|
457
463
|
],
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# forms.py
|
|
2
|
+
from django import forms
|
|
3
|
+
from irie.apps.inventory.models import Datum
|
|
4
|
+
from irie.apps.prediction.models import PredictorModel, SensorAssignment
|
|
5
|
+
|
|
6
|
+
class DatumSelectForm(forms.Form):
|
|
7
|
+
"""
|
|
8
|
+
Step 0 – choose an existing datum or say 'create new'.
|
|
9
|
+
The empty choice means 'I want to add a new datum'.
|
|
10
|
+
"""
|
|
11
|
+
datum = forms.ModelChoiceField(
|
|
12
|
+
queryset=Datum.objects.none(),
|
|
13
|
+
required=False,
|
|
14
|
+
empty_label="-- create new datum --",
|
|
15
|
+
label="Select Datum",
|
|
16
|
+
help_text="Select an existing datum or create a new one."
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
def __init__(self, *args, asset=None, datum_queryset=None, **kwargs):
|
|
20
|
+
super().__init__(*args, **kwargs)
|
|
21
|
+
self.fields["datum"].queryset = datum_queryset or Datum.objects.none()
|
|
22
|
+
|
|
23
|
+
class DatumCreateForm(forms.ModelForm):
|
|
24
|
+
class Meta:
|
|
25
|
+
model = Datum
|
|
26
|
+
fields = ("angle_x", "angle_y")
|
|
27
|
+
|
|
28
|
+
def __init__(self, *args, asset=None, **kwargs):
|
|
29
|
+
super().__init__(*args, **kwargs)
|
|
30
|
+
self.asset = asset
|
|
31
|
+
|
|
32
|
+
class PredictorForm(forms.ModelForm):
|
|
33
|
+
class Meta:
|
|
34
|
+
model = PredictorModel
|
|
35
|
+
help_text = {
|
|
36
|
+
"config_file": "File exported from CSi Bridge or SAP2000 (.b2k or .s2k).",
|
|
37
|
+
}
|
|
38
|
+
fields = "__all__"
|
|
39
|
+
exclude = [
|
|
40
|
+
"render_file",
|
|
41
|
+
"asset",
|
|
42
|
+
"metrics",
|
|
43
|
+
"active",
|
|
44
|
+
"description",
|
|
45
|
+
"entry_point",
|
|
46
|
+
"config",
|
|
47
|
+
"protocol"
|
|
48
|
+
]
|
|
49
|
+
def __init__(self, *args, asset=None, **kwargs):
|
|
50
|
+
super().__init__(*args, **kwargs)
|
|
51
|
+
self.asset = asset
|
|
52
|
+
self.fields['name'].widget.attrs["class"] = "rounded-0"
|
|
53
|
+
self.fields['config_file'].widget.attrs["class"] = "rounded-0"
|
|
54
|
+
|
|
55
|
+
class SensorForm(forms.ModelForm):
|
|
56
|
+
class Meta:
|
|
57
|
+
model = SensorAssignment
|
|
58
|
+
fields = (
|
|
59
|
+
"role",
|
|
60
|
+
"sensor"
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def __init__(self, *args, **kwargs):
|
|
64
|
+
super().__init__(*args, **kwargs)
|
|
65
|
+
|
|
66
|
+
class ConfirmForm(forms.Form):
|
|
67
|
+
# no fields – just a read-only summary screen
|
|
68
|
+
pass
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Generated by Django 5.1.2 on 2025-07-31 05:48
|
|
2
|
+
|
|
3
|
+
from django.db import migrations
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('apps_prediction', '0006_remove_sensorassignment_show_x_and_more'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.RemoveField(
|
|
14
|
+
model_name='sensorassignment',
|
|
15
|
+
name='orient_x',
|
|
16
|
+
),
|
|
17
|
+
migrations.RemoveField(
|
|
18
|
+
model_name='sensorassignment',
|
|
19
|
+
name='orient_y',
|
|
20
|
+
),
|
|
21
|
+
migrations.RemoveField(
|
|
22
|
+
model_name='sensorassignment',
|
|
23
|
+
name='orient_z',
|
|
24
|
+
),
|
|
25
|
+
]
|
|
@@ -32,13 +32,15 @@ class Runner:
|
|
|
32
32
|
# Create from existing PredictorModel when loaded from database.
|
|
33
33
|
# This is done when running analysis
|
|
34
34
|
self.id = pred.id
|
|
35
|
-
self.asset = pred.asset
|
|
35
|
+
# self.asset = pred.asset
|
|
36
36
|
self.name: str = pred.name
|
|
37
37
|
self.description = "" # conf.description
|
|
38
38
|
self.conf = pred.config
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
if pred.entry_point:
|
|
40
|
+
self.entry_point = pred.entry_point
|
|
41
|
+
if pred.metrics:
|
|
42
|
+
self.metrics = pred.metrics
|
|
43
|
+
self.active = pred.active
|
|
42
44
|
|
|
43
45
|
# NEW:
|
|
44
46
|
self.predictor = pred
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
#
|
|
7
7
|
import os.path
|
|
8
8
|
import shutil
|
|
9
|
+
import tqdm
|
|
9
10
|
import sys, json
|
|
10
11
|
import zipfile
|
|
11
12
|
from pathlib import Path
|
|
@@ -54,7 +55,7 @@ def _create_excitation(model, predictor, inputs, dt):
|
|
|
54
55
|
def _analyze_and_render(model, artist, nt, dt):
|
|
55
56
|
import veux, veux.motion
|
|
56
57
|
motion = veux.motion.Motion(artist)
|
|
57
|
-
for i in range(nt):
|
|
58
|
+
for i in tqdm.tqdm(range(nt)):
|
|
58
59
|
if model.analyze(1, dt) != 0:
|
|
59
60
|
return -1
|
|
60
61
|
motion.advance(i*dt)
|
|
@@ -102,7 +103,7 @@ class OpenSeesRunner(Runner):
|
|
|
102
103
|
with open(uploaded_file.name, 'wb+') as destination:
|
|
103
104
|
for chunk in uploaded_file.chunks():
|
|
104
105
|
destination.write(chunk)
|
|
105
|
-
|
|
106
|
+
|
|
106
107
|
# predictor.config_file = uploaded_file # data.pop("file")
|
|
107
108
|
predictor.name = data.pop("name")
|
|
108
109
|
predictor.config = data
|
|
@@ -227,6 +228,16 @@ class OpenSeesRunner(Runner):
|
|
|
227
228
|
"analysis": schemas.load("hwd_analysis.schema.json"),
|
|
228
229
|
}
|
|
229
230
|
}
|
|
231
|
+
|
|
232
|
+
def render(self):
|
|
233
|
+
import veux
|
|
234
|
+
model = Job(self._csi).assemble().model
|
|
235
|
+
|
|
236
|
+
outlines = collect_outlines(self._csi, model.frame_tags)
|
|
237
|
+
artist = veux.render(model, canvas="gltf", vertical=3,
|
|
238
|
+
reference={"frame.surface", "frame.axes"},
|
|
239
|
+
model_config={"frame_outlines": outlines})
|
|
240
|
+
return artist
|
|
230
241
|
|
|
231
242
|
def getMetricList(self):
|
|
232
243
|
return [
|
|
@@ -236,6 +247,7 @@ class OpenSeesRunner(Runner):
|
|
|
236
247
|
# "ACC_RESPONSE_HISTORY",
|
|
237
248
|
]
|
|
238
249
|
|
|
250
|
+
|
|
239
251
|
def newPrediction(self, event, output_directory = None):
|
|
240
252
|
"""
|
|
241
253
|
Create a new prediction run and return the run_id. If output_directory is None,
|
|
@@ -272,7 +284,7 @@ class OpenSeesRunner(Runner):
|
|
|
272
284
|
if False:
|
|
273
285
|
event = event.event_file.path
|
|
274
286
|
shutil.copyfile(event, run_dir/"event.zip")
|
|
275
|
-
|
|
287
|
+
|
|
276
288
|
model_file = None
|
|
277
289
|
if hasattr(self, "model_file") and self.model_file is not None:
|
|
278
290
|
shutil.copyfile(self.model_file.resolve(),
|
|
@@ -327,7 +339,6 @@ class OpenSeesRunner(Runner):
|
|
|
327
339
|
# Create model
|
|
328
340
|
import opensees.openseespy as ops
|
|
329
341
|
|
|
330
|
-
import sys
|
|
331
342
|
csi = self._csi
|
|
332
343
|
|
|
333
344
|
with new_cd(self.runs[run_id]["run_output_directory"]):
|
|
@@ -445,6 +456,7 @@ class OpenSeesRunner(Runner):
|
|
|
445
456
|
for metric in metrics:
|
|
446
457
|
metric.record(asm)
|
|
447
458
|
|
|
459
|
+
|
|
448
460
|
nt = 500
|
|
449
461
|
dt = 0.02
|
|
450
462
|
_create_excitation(model, self.predictor, self.runs[run_id]["inputs"], dt)
|
|
@@ -496,16 +508,16 @@ class OpenSeesRunner(Runner):
|
|
|
496
508
|
# if type == "COLUMN_STRAIN_STATES":
|
|
497
509
|
# return _clean_json(column_strain_state_metric(model, output_dir, config))
|
|
498
510
|
|
|
499
|
-
|
|
500
|
-
|
|
511
|
+
# if type == "PEAK_ACCEL":
|
|
512
|
+
# return _clean_json(peak_acceleration_metric(output_dir, config))
|
|
501
513
|
|
|
502
|
-
|
|
503
|
-
|
|
514
|
+
# elif type == "PEAK_DRIFT":
|
|
515
|
+
# return _clean_json(peak_drift_metric(model, output_dir, config))
|
|
504
516
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
# return accel_response_history_plot(output_dir, config)
|
|
508
|
-
|
|
517
|
+
# elif type == "ACC_RESPONSE_HISTORY":
|
|
518
|
+
# # config = CONFIG
|
|
519
|
+
# # return accel_response_history_plot(output_dir, config)
|
|
520
|
+
# return {}
|
|
509
521
|
return {}
|
|
510
522
|
|
|
511
523
|
#
|
|
@@ -519,17 +531,40 @@ class OpenSeesRunner(Runner):
|
|
|
519
531
|
try:
|
|
520
532
|
csi_file = self.predictor.config_file
|
|
521
533
|
self._csi_data = load_csi((str(line.decode()).replace("\r\n","\n") for line in csi_file.readlines()))
|
|
534
|
+
|
|
522
535
|
except Exception as e:
|
|
523
536
|
import sys
|
|
524
537
|
print(f"Error loading CSiBridge file: {e}", file=sys.stderr)
|
|
525
|
-
self._csi_data =
|
|
538
|
+
self._csi_data = {}
|
|
526
539
|
|
|
527
540
|
return self._csi_data
|
|
528
541
|
|
|
529
542
|
|
|
530
543
|
def structural_section(self, name):
|
|
531
544
|
if (s:= create_section(self._csi, name)) is not None:
|
|
532
|
-
|
|
545
|
+
model = s._create_model(mesh_size=0.1)
|
|
546
|
+
if model is None:
|
|
547
|
+
return [], None
|
|
548
|
+
cmm = model.cmm()
|
|
549
|
+
cnn = model.cnn()
|
|
550
|
+
cnm = model.cnm()
|
|
551
|
+
properties = [
|
|
552
|
+
{
|
|
553
|
+
"name": "Elastic", "data": [
|
|
554
|
+
{"name": "A", "value": float(cnn[0,0])},
|
|
555
|
+
{"name": "Iyy", "value": float(cmm[1,1])},
|
|
556
|
+
{"name": "Izz", "value": float(cmm[2,2])},
|
|
557
|
+
],
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
"name": "Ultimate", "data": [
|
|
561
|
+
# {"name": "A", "value": float(cnn[0,0])},
|
|
562
|
+
# {"name": "Iyy", "value": float(cmm[1,1])},
|
|
563
|
+
# {"name": "Izz", "value": float(cmm[2,2])},
|
|
564
|
+
]
|
|
565
|
+
}
|
|
566
|
+
]
|
|
567
|
+
return properties, model
|
|
533
568
|
|
|
534
569
|
|
|
535
570
|
def structural_sections(self):
|
irie/apps/prediction/urls.py
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
# Author: Claudio Perez
|
|
8
8
|
#
|
|
9
9
|
#----------------------------------------------------------------------------#
|
|
10
|
-
from django.urls import re_path
|
|
10
|
+
from django.urls import path, re_path
|
|
11
11
|
from .views import (
|
|
12
|
-
asset_predictors, predictor_profile, predictor_render,
|
|
13
|
-
create_mdof, create_model, asset_map
|
|
12
|
+
asset_predictors, predictor_profile, predictor_render, predictor_table,
|
|
13
|
+
create_mdof, create_model, asset_map, CsiUpload, FORMS
|
|
14
14
|
)
|
|
15
15
|
|
|
16
16
|
_ROOT = "^inventory/(?P<calid>[0-9 A-Z-]*)/predictors"
|
|
@@ -18,8 +18,10 @@ _ROOT = "^inventory/(?P<calid>[0-9 A-Z-]*)/predictors"
|
|
|
18
18
|
urlpatterns = [
|
|
19
19
|
re_path(f"{_ROOT}/(?P<preid>[0-9]{{1,}})/$", predictor_profile),
|
|
20
20
|
re_path(f"{_ROOT}/(?P<preid>[0-9]{{1,}})/render/", predictor_render),
|
|
21
|
+
re_path(f"{_ROOT}/(?P<preid>[0-9]{{1,}})/properties/", predictor_table),
|
|
21
22
|
re_path(f"{_ROOT}/create/map/$", asset_map),
|
|
22
|
-
re_path(f"{_ROOT}/create/model/$", create_model),
|
|
23
|
+
# re_path(f"{_ROOT}/create/model/$", create_model),
|
|
24
|
+
re_path(f"{_ROOT}/create/model/$", CsiUpload.as_view(FORMS), name="csi_upload"),
|
|
23
25
|
re_path(f"{_ROOT}/create/v1/$", create_mdof),
|
|
24
26
|
re_path(f"{_ROOT}/$", asset_predictors, name="asset_predictors")
|
|
25
27
|
]
|