irie 0.0.16__py3-none-any.whl → 0.0.17__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/events/views_events.py +4 -6
- irie/apps/inventory/filters.py +37 -5
- irie/apps/inventory/models.py +14 -1
- irie/apps/inventory/sitemaps.py +19 -0
- irie/apps/inventory/views.py +2 -7
- irie/apps/prediction/forms.py +4 -1
- irie/apps/prediction/predictor.py +5 -274
- irie/apps/prediction/runners/__init__.py +17 -15
- irie/apps/prediction/runners/hazus.py +271 -182
- irie/apps/prediction/runners/opensees/__init__.py +88 -11
- irie/apps/prediction/runners/ssid.py +168 -9
- irie/apps/prediction/urls.py +3 -4
- irie/apps/prediction/views.py +8 -85
- irie/apps/sitemaps.py +14 -0
- irie/apps/templates/inventory/asset-profile.html +0 -15
- irie/apps/templates/inventory/asset-table.html +38 -15
- irie/apps/templates/prediction/asset-predictors.html +38 -5
- irie/apps/templates/prediction/new-runner.html +1 -1
- irie/apps/templates/prediction/predictor-profile.html +11 -0
- irie/init/__main__.py +8 -5
- irie/init/data/cgs-stations.json +2967 -0
- irie/init/getCGSData.py +9 -4
- irie/init/management/commands/init_assets.py +1 -1
- irie/init/management/commands/init_cesmd.py +25 -0
- {irie-0.0.16.dist-info → irie-0.0.17.dist-info}/METADATA +1 -1
- {irie-0.0.16.dist-info → irie-0.0.17.dist-info}/RECORD +29 -25
- {irie-0.0.16.dist-info → irie-0.0.17.dist-info}/WHEEL +0 -0
- {irie-0.0.16.dist-info → irie-0.0.17.dist-info}/entry_points.txt +0 -0
- {irie-0.0.16.dist-info → irie-0.0.17.dist-info}/top_level.txt +0 -0
|
@@ -11,7 +11,7 @@ import zipfile
|
|
|
11
11
|
from pathlib import Path
|
|
12
12
|
import contextlib
|
|
13
13
|
|
|
14
|
-
from irie.apps.prediction.runners import (Runner,
|
|
14
|
+
from irie.apps.prediction.runners import (Runner, RunID, classproperty)
|
|
15
15
|
|
|
16
16
|
from .utilities import read_model
|
|
17
17
|
from .metrics import (
|
|
@@ -29,7 +29,6 @@ OPENSEES = [
|
|
|
29
29
|
@contextlib.contextmanager
|
|
30
30
|
def new_cd(x):
|
|
31
31
|
d = os.getcwd()
|
|
32
|
-
|
|
33
32
|
# This could raise an exception, but it's probably
|
|
34
33
|
# best to let it propagate and let the caller
|
|
35
34
|
# deal with it, since they requested x
|
|
@@ -52,19 +51,28 @@ class OpenSeesRunner(Runner):
|
|
|
52
51
|
|
|
53
52
|
|
|
54
53
|
@classmethod
|
|
55
|
-
def create(cls, asset, request
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
54
|
+
def create(cls, asset, request):
|
|
55
|
+
from irie.apps.prediction.models import PredictorModel
|
|
56
|
+
predictor = PredictorModel()
|
|
57
|
+
data = json.loads(request.body)
|
|
58
|
+
# TODO
|
|
59
|
+
data.pop("file")
|
|
60
|
+
uploaded_file = request.FILES.get('config_file', None)
|
|
61
|
+
print(uploaded_file)
|
|
62
|
+
if uploaded_file:
|
|
63
|
+
|
|
64
|
+
with open(uploaded_file.name, 'wb+') as destination:
|
|
65
|
+
for chunk in uploaded_file.chunks():
|
|
66
|
+
destination.write(chunk)
|
|
67
|
+
|
|
68
|
+
# predictor.config_file = uploaded_file # data.pop("file")
|
|
69
|
+
predictor.name = data.pop("name")
|
|
70
|
+
predictor.config = data
|
|
71
|
+
predictor.asset = asset
|
|
62
72
|
predictor.protocol = "IRIE_PREDICTOR_T4"
|
|
63
73
|
predictor.active = True
|
|
64
|
-
# predictor.metrics = self.getMetricList()
|
|
65
74
|
return predictor
|
|
66
75
|
|
|
67
|
-
|
|
68
76
|
@classproperty
|
|
69
77
|
def schema(cls):
|
|
70
78
|
from . import schemas
|
|
@@ -491,3 +499,72 @@ class OpenSeesRunner(Runner):
|
|
|
491
499
|
return {}
|
|
492
500
|
return {}
|
|
493
501
|
|
|
502
|
+
|
|
503
|
+
import subprocess
|
|
504
|
+
class Event: pass
|
|
505
|
+
|
|
506
|
+
class PredictorType1(Runner):
|
|
507
|
+
@property
|
|
508
|
+
def platform(self):
|
|
509
|
+
return self.conf.get("platform", "")
|
|
510
|
+
|
|
511
|
+
@classmethod
|
|
512
|
+
def create(cls, asset, request):
|
|
513
|
+
from irie.apps.prediction.models import PredictorModel
|
|
514
|
+
predictor = PredictorModel()
|
|
515
|
+
data = json.loads(request.data.get("json"))
|
|
516
|
+
predictor.entry_point = [
|
|
517
|
+
sys.executable, "-m", "opensees"
|
|
518
|
+
]
|
|
519
|
+
data["metrics"] = []
|
|
520
|
+
|
|
521
|
+
predictor.name = data.pop("name")
|
|
522
|
+
predictor.config = data
|
|
523
|
+
predictor.asset = asset
|
|
524
|
+
predictor.protocol = "IRIE_PREDICTOR_T1"
|
|
525
|
+
predictor.active = False
|
|
526
|
+
return predictor
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
@classproperty
|
|
530
|
+
def schema(cls):
|
|
531
|
+
from irie.apps.prediction.runners.opensees import schemas
|
|
532
|
+
return {
|
|
533
|
+
"title": "Structural Model",
|
|
534
|
+
"options": {"disable_collaps": True},
|
|
535
|
+
"schema": "http://json-schema.org/draft-04/schema#",
|
|
536
|
+
"type": "object",
|
|
537
|
+
"properties": {
|
|
538
|
+
"platform": {
|
|
539
|
+
"type": "string",
|
|
540
|
+
"title": "Platform",
|
|
541
|
+
"enum": ["OpenSees","CSiBridge"]
|
|
542
|
+
},
|
|
543
|
+
"model": schemas.load("hwd_conf.schema.json"),
|
|
544
|
+
"analysis": schemas.load("hwd_analysis.schema.json"),
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
def newPrediction(self, event: Event) -> RunID:
|
|
549
|
+
self.event = event
|
|
550
|
+
event_file = Path(event.event_file.path).resolve()
|
|
551
|
+
command = [*self.entry_point, "new", event_file]
|
|
552
|
+
run_id = subprocess.check_output(command).decode().strip()
|
|
553
|
+
return RunID(int(run_id))
|
|
554
|
+
|
|
555
|
+
def runPrediction(self, run_id: RunID):
|
|
556
|
+
command = [*self.entry_point, "run", str(run_id)]
|
|
557
|
+
|
|
558
|
+
if "scale" in self.event.upload_data:
|
|
559
|
+
command.extend(["--scale", str(float(self.event.upload_data["scale"]))])
|
|
560
|
+
print(":: Running ", command, file=sys.stderr)
|
|
561
|
+
subprocess.check_output(command)
|
|
562
|
+
|
|
563
|
+
print(f":: Model {self.name} returned", file=sys.stderr)
|
|
564
|
+
return
|
|
565
|
+
|
|
566
|
+
def getMetricData(self, run, metric):
|
|
567
|
+
try:
|
|
568
|
+
return json.loads(subprocess.check_output([*self.entry_point, "get", str(run), metric]).decode())
|
|
569
|
+
except json.decoder.JSONDecodeError:
|
|
570
|
+
return {}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
from irie.apps.events.models import EventRecord
|
|
2
|
+
from irie.apps.prediction.runners import Runner, RunID
|
|
3
|
+
from irie.apps.prediction.models import PredictorModel
|
|
4
|
+
|
|
1
5
|
from pathlib import Path
|
|
2
6
|
import json
|
|
3
7
|
import io
|
|
@@ -12,6 +16,7 @@ from mdof import transform
|
|
|
12
16
|
from scipy.signal import find_peaks
|
|
13
17
|
from mdof.utilities import Config, extract_channels
|
|
14
18
|
from matplotlib import colormaps
|
|
19
|
+
import subprocess
|
|
15
20
|
# try:
|
|
16
21
|
# import scienceplots
|
|
17
22
|
# plt.style.use(["science"])
|
|
@@ -22,7 +27,155 @@ N_PEAKS = 5 # number of "significant" peaks per record
|
|
|
22
27
|
MISSING_CHANNEL_LIMIT = 3 # number of missing output channels allowed before skipping event
|
|
23
28
|
MAX_ACCEL = 3.0
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
|
|
31
|
+
class SystemIdRunner(Runner):
|
|
32
|
+
platform = "mdof"
|
|
33
|
+
|
|
34
|
+
schema = {
|
|
35
|
+
"title": "System ID",
|
|
36
|
+
"name": "P2",
|
|
37
|
+
"type": "object",
|
|
38
|
+
"required": [
|
|
39
|
+
"name",
|
|
40
|
+
"decimation",
|
|
41
|
+
"method",
|
|
42
|
+
"channels"
|
|
43
|
+
],
|
|
44
|
+
"properties": {
|
|
45
|
+
"name": {
|
|
46
|
+
"type": "string",
|
|
47
|
+
"title": "Name",
|
|
48
|
+
"description": "Predictor name",
|
|
49
|
+
"minLength": 2,
|
|
50
|
+
# "default": "S1"
|
|
51
|
+
},
|
|
52
|
+
"method": {
|
|
53
|
+
"type": "string",
|
|
54
|
+
"title": "Method",
|
|
55
|
+
"enum": ["Fourier Spectrum","Response Spectrum","SRIM","OKID"]
|
|
56
|
+
},
|
|
57
|
+
"decimation": {
|
|
58
|
+
"type": "integer",
|
|
59
|
+
"title": "Decimation",
|
|
60
|
+
"default": 1,
|
|
61
|
+
"minimum": 1,
|
|
62
|
+
"maximum": 8
|
|
63
|
+
},
|
|
64
|
+
"order": {
|
|
65
|
+
"type": "integer",
|
|
66
|
+
"title": "Model Order",
|
|
67
|
+
"default": 8,
|
|
68
|
+
"minimum": 2,
|
|
69
|
+
"maximum": 64,
|
|
70
|
+
"options": {"dependencies": {"method": ["SRIM","OKID"]}}
|
|
71
|
+
},
|
|
72
|
+
"horizon": {
|
|
73
|
+
"type": "integer",
|
|
74
|
+
"title": "Prediction Horizon",
|
|
75
|
+
"default": 100,
|
|
76
|
+
"minimum": 50,
|
|
77
|
+
"maximum": 500,
|
|
78
|
+
"options": {"dependencies": {"method": ["SRIM"]}}
|
|
79
|
+
},
|
|
80
|
+
"period_band": {
|
|
81
|
+
"type": "string",
|
|
82
|
+
"title": "Period Band",
|
|
83
|
+
"default": "[0.1,2.3]",
|
|
84
|
+
"options": {"dependencies": {"method": ["Fourier Spectrum"]}},
|
|
85
|
+
"description": "[0.1,2.3] if interested in periods between 0.1 seconds and 2.3 seconds"
|
|
86
|
+
},
|
|
87
|
+
"damping": {
|
|
88
|
+
"type": "float",
|
|
89
|
+
"title": "Damping",
|
|
90
|
+
"default": 0.02,
|
|
91
|
+
"options": {"dependencies": {"method": ["Response Spectrum"]}},
|
|
92
|
+
"description": "assumed damping ratio"
|
|
93
|
+
},
|
|
94
|
+
"channels": {
|
|
95
|
+
"type": "array",
|
|
96
|
+
"format": "table",
|
|
97
|
+
"title": "Channels",
|
|
98
|
+
"uniqueItems": True,
|
|
99
|
+
"items": {
|
|
100
|
+
"title": "Acceleration",
|
|
101
|
+
"type": "object",
|
|
102
|
+
"properties": {
|
|
103
|
+
"type": {
|
|
104
|
+
"type": "string",
|
|
105
|
+
"enum": ["output","input"],
|
|
106
|
+
"default": "output"
|
|
107
|
+
},
|
|
108
|
+
"id": {"type": "integer", "description": "Number identifying signal channel"}
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"default": [{"type": "output", "id": 1}]
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
def render(self):
|
|
117
|
+
try:
|
|
118
|
+
return make_mountains(self.asset, self.conf)
|
|
119
|
+
except:
|
|
120
|
+
return None
|
|
121
|
+
|
|
122
|
+
@classmethod
|
|
123
|
+
def create(cls, asset, request):
|
|
124
|
+
predictor = PredictorModel()
|
|
125
|
+
data = json.loads(request.body)
|
|
126
|
+
method = {
|
|
127
|
+
"Fourier Spectrum": "fourier",
|
|
128
|
+
"Response Spectrum": "response",
|
|
129
|
+
"FDD": "fdd",
|
|
130
|
+
"OKID": "okid-era",
|
|
131
|
+
"SRIM": "srim"
|
|
132
|
+
}[data.pop("method")]
|
|
133
|
+
|
|
134
|
+
predictor.entry_point = [
|
|
135
|
+
sys.executable, "-m", "mdof", method
|
|
136
|
+
]
|
|
137
|
+
data["outputs"] = [i["id"] for i in data["channels"] if i["type"] == "output"]
|
|
138
|
+
data["inputs"] = [i["id"] for i in data["channels"] if i["type"] == "input"]
|
|
139
|
+
data["threads"] = 4
|
|
140
|
+
data["metrics"] = ["SPECTRAL_SHIFT_IDENTIFICATION"]
|
|
141
|
+
del data["channels"]
|
|
142
|
+
|
|
143
|
+
predictor.name = data.pop("name")
|
|
144
|
+
predictor.config = data
|
|
145
|
+
predictor.asset = asset
|
|
146
|
+
predictor.protocol = "IRIE_PREDICTOR_T2"
|
|
147
|
+
predictor.active = True
|
|
148
|
+
return predictor
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def newPrediction(self, event):
|
|
152
|
+
self.event = event
|
|
153
|
+
return RunID(1)
|
|
154
|
+
|
|
155
|
+
def runPrediction(self, run_id: RunID) -> bool:
|
|
156
|
+
event_file = Path(self.event.event_file.path).resolve()
|
|
157
|
+
command = [*self.entry_point,
|
|
158
|
+
"--config",
|
|
159
|
+
json.dumps(self.conf),
|
|
160
|
+
event_file]
|
|
161
|
+
|
|
162
|
+
if False:
|
|
163
|
+
command = [*self.entry_point,
|
|
164
|
+
event_file,
|
|
165
|
+
*map(str, self.conf.get("argv", []))]
|
|
166
|
+
try:
|
|
167
|
+
self.metric_data = json.loads(
|
|
168
|
+
subprocess.check_output(command).decode()
|
|
169
|
+
)
|
|
170
|
+
return True
|
|
171
|
+
except Exception as e:
|
|
172
|
+
self.metric_data = {"error": str(e)}
|
|
173
|
+
return False
|
|
174
|
+
|
|
175
|
+
def getMetricData(self, run, metric):
|
|
176
|
+
if not hasattr(self, "metric_data"):
|
|
177
|
+
raise Exception(f"Error {self.name}({id(self)}), {run}")
|
|
178
|
+
return self.metric_data
|
|
26
179
|
|
|
27
180
|
|
|
28
181
|
|
|
@@ -186,12 +339,14 @@ def _load_events(asset, output_channels):
|
|
|
186
339
|
return {k:v for k,v in events}
|
|
187
340
|
|
|
188
341
|
|
|
189
|
-
def
|
|
342
|
+
def _get_spectra(event, conf, cmap):
|
|
190
343
|
"""
|
|
191
344
|
Get coordinates (periods, amplitudes) of spectra for an event, and return them along
|
|
192
345
|
with the maximum period of the N_PEAKS tallest peaks, as well as plotting options
|
|
193
346
|
such as color and alpha.
|
|
194
347
|
"""
|
|
348
|
+
period_band = conf.period_band
|
|
349
|
+
|
|
195
350
|
n_outputs = event['outputs'].shape[0]
|
|
196
351
|
frequencies,_,S = transform.fdd(outputs=event['outputs'], step=event['dt']) # Full frequency spectrum
|
|
197
352
|
periods = 1/frequencies
|
|
@@ -309,14 +464,18 @@ def _plot_mountains(spectra, accellim=None):
|
|
|
309
464
|
return fig
|
|
310
465
|
|
|
311
466
|
|
|
312
|
-
def make_mountains(asset, output_channels=None):
|
|
467
|
+
def make_mountains(asset, conf=None, output_channels=None):
|
|
313
468
|
|
|
314
469
|
cmap = colormaps['plasma']
|
|
315
|
-
conf
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
470
|
+
if conf is None:
|
|
471
|
+
conf = Config()
|
|
472
|
+
conf.period_band = (0.1,3)
|
|
473
|
+
conf.damping = 0.02
|
|
474
|
+
conf.ss_decimation = 8
|
|
475
|
+
conf.order = 40
|
|
476
|
+
conf.method = "fdd"
|
|
477
|
+
else:
|
|
478
|
+
conf = Config(**conf)
|
|
320
479
|
|
|
321
480
|
if output_channels is None:
|
|
322
481
|
if not asset.bridge_sensors:
|
|
@@ -333,7 +492,7 @@ def make_mountains(asset, output_channels=None):
|
|
|
333
492
|
print(f"Missing {n_expected_outputs-n_parsed_channels} output channels; skipping event") # Missing too many channels
|
|
334
493
|
continue
|
|
335
494
|
|
|
336
|
-
spectra[filename] =
|
|
495
|
+
spectra[filename] = _get_spectra(event, conf, cmap) # {'spec_coords':spec_coords, 'max_peak_period':max_peak_period, 'plot_conf':plot_conf}
|
|
337
496
|
|
|
338
497
|
|
|
339
498
|
# if station == 'CE89494':
|
irie/apps/prediction/urls.py
CHANGED
|
@@ -12,8 +12,7 @@ from .views import new_prediction, asset_predictors, predictor_profile, predicto
|
|
|
12
12
|
|
|
13
13
|
urlpatterns = [
|
|
14
14
|
re_path("^inventory/[0-9 A-Z-]*/predictors/new", new_prediction),
|
|
15
|
-
re_path("^inventory/[0-9 A-Z-]
|
|
16
|
-
re_path("^inventory/(?P<calid>[0-9 A-Z-]*)/predictors/create
|
|
17
|
-
re_path("^inventory/[0-9 A-Z-]*/predictors/", asset_predictors, name="asset_predictors")
|
|
18
|
-
re_path("^inventory/[0-9 A-Z-]*/predictors/", asset_predictors),
|
|
15
|
+
re_path("^inventory/(?P<calid>[0-9 A-Z-]*)/predictors/(?P<preid>[0-9 A-Z-]{1,})", predictor_profile),
|
|
16
|
+
re_path("^inventory/(?P<calid>[0-9 A-Z-]*)/predictors/create", predictor_upload),
|
|
17
|
+
re_path("^inventory/[0-9 A-Z-]*/predictors/", asset_predictors, name="asset_predictors")
|
|
19
18
|
]
|
irie/apps/prediction/views.py
CHANGED
|
@@ -19,9 +19,6 @@ from django.core.exceptions import ObjectDoesNotExist
|
|
|
19
19
|
|
|
20
20
|
from django.shortcuts import render
|
|
21
21
|
|
|
22
|
-
from rest_framework.decorators import api_view, permission_classes
|
|
23
|
-
from rest_framework.permissions import IsAuthenticated
|
|
24
|
-
|
|
25
22
|
from irie.apps.site.view_utils import raise404
|
|
26
23
|
from irie.apps.inventory.models import Asset
|
|
27
24
|
from irie.apps.prediction.predictor import PREDICTOR_TYPES, OpenSeesRunner
|
|
@@ -38,41 +35,7 @@ def new_prediction(request):
|
|
|
38
35
|
return HttpResponse(html_template.render(context, request))
|
|
39
36
|
|
|
40
37
|
|
|
41
|
-
|
|
42
|
-
@api_view(["GET", "POST", "PUT"])
|
|
43
|
-
@permission_classes([IsAuthenticated])
|
|
44
|
-
def predictor_api(request):
|
|
45
|
-
|
|
46
|
-
context = {"segment": "assets"}
|
|
47
|
-
|
|
48
|
-
context["predictor_types"] = list(reversed([
|
|
49
|
-
{"schema": json.dumps(cls.schema),
|
|
50
|
-
"name": cls.__name__,
|
|
51
|
-
"title": cls.schema["title"]}
|
|
52
|
-
for cls in set(PREDICTOR_TYPES.values())
|
|
53
|
-
]))
|
|
54
|
-
|
|
55
|
-
calid = request.path.split("/")[-3]
|
|
56
|
-
|
|
57
|
-
try:
|
|
58
|
-
context["asset"] = Asset.objects.get(calid=calid)
|
|
59
|
-
|
|
60
|
-
except:
|
|
61
|
-
return HttpResponse(
|
|
62
|
-
loader.get_template("site/page-404-sidebar.html").render(context, request)
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
if request.method == "POST":
|
|
66
|
-
print(request.POST)
|
|
67
|
-
PREDICTOR_TYPES["IRIE_PREDICTOR_T2"].create(context["asset"],request).save()
|
|
68
|
-
|
|
69
|
-
html_template = loader.get_template("prediction/asset-predictors.html")
|
|
70
|
-
return HttpResponse(html_template.render(context, request))
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
@api_view(["GET", "POST", "PUT"])
|
|
74
|
-
# @login_required(login_url="/login/")
|
|
75
|
-
@permission_classes([IsAuthenticated])
|
|
38
|
+
@login_required(login_url="/login/")
|
|
76
39
|
def asset_predictors(request):
|
|
77
40
|
|
|
78
41
|
calid = request.path.split("/")[-3]
|
|
@@ -97,45 +60,17 @@ def asset_predictors(request):
|
|
|
97
60
|
loader.get_template("site/page-404-sidebar.html").render(context, request)
|
|
98
61
|
)
|
|
99
62
|
|
|
100
|
-
if request.method == "POST":
|
|
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()
|
|
120
|
-
|
|
121
63
|
html_template = loader.get_template("prediction/asset-predictors.html")
|
|
122
64
|
return HttpResponse(html_template.render(context, request))
|
|
123
65
|
|
|
124
66
|
|
|
125
67
|
@login_required(login_url="/login/")
|
|
126
|
-
def predictor_profile(request):
|
|
68
|
+
def predictor_profile(request, calid, preid):
|
|
127
69
|
|
|
128
70
|
context = {}
|
|
129
71
|
html_template = loader.get_template("prediction/predictor-profile.html")
|
|
130
72
|
context["segment"] = "inventory"
|
|
131
73
|
|
|
132
|
-
url_segs = request.path.split("/")
|
|
133
|
-
if len(url_segs) < 5:
|
|
134
|
-
return raise404(request, context)
|
|
135
|
-
else:
|
|
136
|
-
calid = url_segs[2]
|
|
137
|
-
preid = url_segs[4]
|
|
138
|
-
|
|
139
74
|
try:
|
|
140
75
|
asset = Asset.objects.get(calid=calid)
|
|
141
76
|
except Asset.DoesNotExist:
|
|
@@ -149,7 +84,6 @@ def predictor_profile(request):
|
|
|
149
84
|
context["asset"] = asset
|
|
150
85
|
context["predictor"] = PREDICTOR_TYPES[predictor.protocol](predictor)
|
|
151
86
|
|
|
152
|
-
|
|
153
87
|
try:
|
|
154
88
|
return HttpResponse(html_template.render(context, request))
|
|
155
89
|
|
|
@@ -167,29 +101,19 @@ def predictor_profile(request):
|
|
|
167
101
|
@login_required(login_url="/login/")
|
|
168
102
|
def predictor_upload(request, calid):
|
|
169
103
|
|
|
170
|
-
context = {}
|
|
171
104
|
html_template = loader.get_template("prediction/predictor-upload.html")
|
|
172
|
-
context["segment"] = "assets"
|
|
173
105
|
|
|
174
106
|
if request.method == 'POST':
|
|
175
107
|
form = PredictorForm(request.POST, request.FILES) # include request.FILES
|
|
176
|
-
if form.is_valid():
|
|
177
|
-
|
|
178
|
-
# asset = form.cleaned_data['asset']
|
|
179
|
-
asset = Asset.objects.get(calid=calid)
|
|
180
|
-
uploaded_file = request.FILES['config_file']
|
|
181
|
-
|
|
182
|
-
with open(uploaded_file.name, 'wb+') as destination:
|
|
183
|
-
for chunk in uploaded_file.chunks():
|
|
184
|
-
destination.write(chunk)
|
|
108
|
+
# if form.is_valid():
|
|
109
|
+
asset = Asset.objects.get(calid=calid)
|
|
185
110
|
|
|
186
|
-
|
|
187
|
-
|
|
111
|
+
# Save the predictor
|
|
112
|
+
predictor = PREDICTOR_TYPES[request.POST.get("runner")].create(asset, request)
|
|
113
|
+
predictor.save()
|
|
188
114
|
|
|
189
|
-
|
|
115
|
+
return HttpResponse(json.dumps({"data": {"id": predictor.id}}))
|
|
190
116
|
|
|
191
|
-
return render(request, 'prediction/predictor-upload.html',
|
|
192
|
-
context)
|
|
193
117
|
else:
|
|
194
118
|
form = PredictorForm()
|
|
195
119
|
|
|
@@ -197,7 +121,6 @@ def predictor_upload(request, calid):
|
|
|
197
121
|
try:
|
|
198
122
|
return render(request, 'prediction/predictor-upload.html', {"form": form})
|
|
199
123
|
|
|
200
|
-
|
|
201
124
|
except Exception as e:
|
|
202
125
|
if "DEBUG" in os.environ and os.environ["DEBUG"]:
|
|
203
126
|
raise e
|
irie/apps/sitemaps.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from django.contrib.sitemaps import Sitemap
|
|
2
|
+
from django.urls import reverse
|
|
3
|
+
|
|
4
|
+
class IrieSitemap(Sitemap):
|
|
5
|
+
priority = 0.9
|
|
6
|
+
changefreq = 'weekly'
|
|
7
|
+
|
|
8
|
+
def items(self):
|
|
9
|
+
# Return the names of your static views
|
|
10
|
+
return ['home', 'about', 'dashboard', 'asset_table']
|
|
11
|
+
|
|
12
|
+
def location(self, item):
|
|
13
|
+
return reverse(item)
|
|
14
|
+
|
|
@@ -230,21 +230,6 @@
|
|
|
230
230
|
</div>
|
|
231
231
|
</div>
|
|
232
232
|
</div>
|
|
233
|
-
|
|
234
|
-
{% if mountains %}
|
|
235
|
-
<div class="col-8 card bg-white-100 border-0 shadow mb-4">
|
|
236
|
-
<div class="card-body">
|
|
237
|
-
<h4>Spectrum</h4>
|
|
238
|
-
<div class="crop">
|
|
239
|
-
<img src="data:image/jpeg;base64,{{ mountains }}" alt="Spectral content">
|
|
240
|
-
</div>
|
|
241
|
-
</div>
|
|
242
|
-
<div class="card-footer">
|
|
243
|
-
Powered by <a href="https://chrystalchern.github.io/mdof"><em>mdof</em></a>
|
|
244
|
-
</div>
|
|
245
|
-
</div>
|
|
246
|
-
{% endif %}
|
|
247
|
-
|
|
248
233
|
</details>
|
|
249
234
|
<hr>
|
|
250
235
|
{% endif %}
|
|
@@ -93,6 +93,44 @@ table a[href^="https://"]::after
|
|
|
93
93
|
placeholder="Search assets"
|
|
94
94
|
>
|
|
95
95
|
</div>
|
|
96
|
+
|
|
97
|
+
<!-- Latest Year -->
|
|
98
|
+
<div class="input-group mb-3">
|
|
99
|
+
<span class="input-group-text">
|
|
100
|
+
<svg class="icon icon-xs" x-description="Heroicon name: solid/search" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
101
|
+
<path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd"></path>
|
|
102
|
+
</svg>
|
|
103
|
+
</span>
|
|
104
|
+
<button type="button" class="btn input-group-text btn-outline dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false">
|
|
105
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-caret-down-fill" viewBox="0 0 16 16">
|
|
106
|
+
<path d="M7.247 11.14l-4.796-5.481C2.014 5.334 2.482 4.5 3.25 4.5h9.5c.768 0 1.236.835.799 1.159l-4.796 5.481a1 1 0 0 1-1.506 0z"/>
|
|
107
|
+
</svg>
|
|
108
|
+
<span class="visually-hidden">Toggle Dropdown</span>
|
|
109
|
+
</button>
|
|
110
|
+
<ul class="dropdown-menu">
|
|
111
|
+
<li><a class="dropdown-item" href="#">Include fields:</a></li>
|
|
112
|
+
<li><hr class="dropdown-divider"></li>
|
|
113
|
+
<li><div class="form-check form-switch">
|
|
114
|
+
<input class="form-check-input" type="checkbox" role="switch" id="flexSwitchCheckDefault">
|
|
115
|
+
<label class="form-check-label" for="flexSwitchCheckDefault">Retrofit</label>
|
|
116
|
+
</div></li>
|
|
117
|
+
<li><div class="form-check form-switch">
|
|
118
|
+
<input class="form-check-input" type="checkbox" role="switch" id="flexSwitchCheckChecked" checked>
|
|
119
|
+
<label class="form-check-label" for="flexSwitchCheckChecked">Built</label>
|
|
120
|
+
</div></li>
|
|
121
|
+
</ul>
|
|
122
|
+
<input
|
|
123
|
+
id="max_year"
|
|
124
|
+
name="max_year"
|
|
125
|
+
type="number"
|
|
126
|
+
max="2024"
|
|
127
|
+
step="1"
|
|
128
|
+
class="form-control"
|
|
129
|
+
value="{{ filter.form.max_year.value|default_if_none:'2024' }}"
|
|
130
|
+
placeholder="Latest Year Built"
|
|
131
|
+
>
|
|
132
|
+
</div>
|
|
133
|
+
|
|
96
134
|
|
|
97
135
|
<!-- CESMD Not Null Checkbox -->
|
|
98
136
|
<div class="col-12">
|
|
@@ -108,21 +146,6 @@ table a[href^="https://"]::after
|
|
|
108
146
|
</label>
|
|
109
147
|
</div>
|
|
110
148
|
</div>
|
|
111
|
-
|
|
112
|
-
{# Is Complete Checkbox #}
|
|
113
|
-
<div class="col-12">
|
|
114
|
-
<div class="form-check">
|
|
115
|
-
<input
|
|
116
|
-
type="checkbox"
|
|
117
|
-
name="is_complete"
|
|
118
|
-
id="is_complete"
|
|
119
|
-
class="form-check-input"
|
|
120
|
-
{% if filter.form.is_complete.value %}checked{% endif %}>
|
|
121
|
-
<label for="is_complete" class="form-check-label">
|
|
122
|
-
{{ filter.form.is_complete.label }}
|
|
123
|
-
</label>
|
|
124
|
-
</div>
|
|
125
|
-
</div>
|
|
126
149
|
|
|
127
150
|
{# Buttons #}
|
|
128
151
|
<div class="col-12 d-flex justify-content-between">
|