petal-qc 0.0.10__py3-none-any.whl → 0.0.12__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 petal-qc might be problematic. Click here for more details.
- petal_qc/BTreport/CheckBTtests.py +2 -6
- petal_qc/__init__.py +12 -1
- petal_qc/dashBoard.py +3 -0
- petal_qc/metrology/PetalMetrology.py +0 -5
- petal_qc/metrology/coreMetrology.py +20 -9
- petal_qc/metrology/do_Metrology.py +0 -5
- petal_qc/metrology/petal_flatness.py +0 -4
- petal_qc/metrology/readAVSdata.py +82 -15
- petal_qc/metrology/uploadPetalInformation.py +23 -12
- petal_qc/test/checkAVStests.py +181 -0
- petal_qc/test/compare_golden.py +44 -0
- petal_qc/test/getAVStests.py +133 -24
- petal_qc/test/getPetalCoreTestSummary.py +1 -1
- petal_qc/test/listPetalCoreComponents.py +89 -0
- petal_qc/thermal/DESYdata.py +58 -0
- petal_qc/thermal/IRBFile.py +51 -7
- petal_qc/thermal/IRDataGetter.py +35 -16
- petal_qc/thermal/IRPetal.py +6 -0
- petal_qc/thermal/IRPetalParam.py +1 -1
- petal_qc/thermal/PipeFit.py +8 -0
- petal_qc/thermal/analyze_IRCore.py +12 -6
- petal_qc/thermal/coreThermal.py +121 -32
- petal_qc/thermal/create_IRCore.py +10 -4
- petal_qc/thermal/create_core_report.py +18 -4
- petal_qc/utils/readGraphana.py +2 -1
- {petal_qc-0.0.10.dist-info → petal_qc-0.0.12.dist-info}/METADATA +2 -2
- {petal_qc-0.0.10.dist-info → petal_qc-0.0.12.dist-info}/RECORD +30 -26
- {petal_qc-0.0.10.dist-info → petal_qc-0.0.12.dist-info}/WHEEL +1 -1
- {petal_qc-0.0.10.dist-info → petal_qc-0.0.12.dist-info}/entry_points.txt +2 -0
- {petal_qc-0.0.10.dist-info → petal_qc-0.0.12.dist-info}/top_level.txt +0 -0
petal_qc/test/getAVStests.py
CHANGED
|
@@ -15,8 +15,86 @@ except ImportError:
|
|
|
15
15
|
from itkdb_gtk import ITkDBlogin, ITkDButils
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
def
|
|
19
|
-
|
|
18
|
+
def get_value(results, code):
|
|
19
|
+
"""Return the value of the test parameter."""
|
|
20
|
+
for param in results:
|
|
21
|
+
if param["code"] == code:
|
|
22
|
+
return param["value"]
|
|
23
|
+
|
|
24
|
+
raise KeyError
|
|
25
|
+
|
|
26
|
+
def distance(P1, P2):
|
|
27
|
+
"""Distance between 2 points."""
|
|
28
|
+
P = (P2-P1)
|
|
29
|
+
S = np.sum(np.square(P))
|
|
30
|
+
D = np.sqrt(S)
|
|
31
|
+
return D
|
|
32
|
+
|
|
33
|
+
nominal_values = {
|
|
34
|
+
"LOCATOR1": np.array([0, -3]),
|
|
35
|
+
"LOCATOR2": np.array([127.916, 589.618]),
|
|
36
|
+
"LOCATOR3": np.array([127.916, 589.618]),
|
|
37
|
+
"FIDUCIAL1": np.array([0, 0]),
|
|
38
|
+
"FIDUCIAL2": np.array([131.104, 586.526]),
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
def get_pos(results, obj):
|
|
42
|
+
"""Return position."""
|
|
43
|
+
try:
|
|
44
|
+
X = get_value(results, "{}_X".format(obj))
|
|
45
|
+
Y = get_value(results, "{}_Y".format(obj))
|
|
46
|
+
|
|
47
|
+
if abs(X) > 1000:
|
|
48
|
+
X /= 1000
|
|
49
|
+
if abs(Y)>1000:
|
|
50
|
+
Y /= 1000
|
|
51
|
+
except KeyError:
|
|
52
|
+
X = 0.0
|
|
53
|
+
Y = 0.0
|
|
54
|
+
|
|
55
|
+
P = np.array([X, Y], dtype="float64")
|
|
56
|
+
return P
|
|
57
|
+
|
|
58
|
+
def distance_to_nominal(results, obj):
|
|
59
|
+
"""Return position of given locator or fiducial."""
|
|
60
|
+
P = get_pos(results, obj)
|
|
61
|
+
N = nominal_values[obj]
|
|
62
|
+
D = distance(P, N)
|
|
63
|
+
if abs(D-3)<0.5:
|
|
64
|
+
P[1] -= 3
|
|
65
|
+
D = distance(P, N)
|
|
66
|
+
return D
|
|
67
|
+
|
|
68
|
+
def do_metrology(results, M_values, Mould_values):
|
|
69
|
+
"""Accumulate metrology values."""
|
|
70
|
+
points = ["LOCATOR1", "LOCATOR2", "LOCATOR3", "FIDUCIAL1", "FIDUCIAL2"]
|
|
71
|
+
coord = {}
|
|
72
|
+
for P in points:
|
|
73
|
+
coord[P] = get_pos(results, P)
|
|
74
|
+
|
|
75
|
+
fd1 = np.array(coord["FIDUCIAL1"], dtype="float64")
|
|
76
|
+
if fd1[0]!=0.0 or fd1[1]!=0:
|
|
77
|
+
for V in coord.values():
|
|
78
|
+
V -= fd1
|
|
79
|
+
|
|
80
|
+
for O, P in coord.items():
|
|
81
|
+
D = distance(P, nominal_values[O])
|
|
82
|
+
if D<1.0:
|
|
83
|
+
M_values.setdefault(O, []).append(D)
|
|
84
|
+
Mould_values.setdefault(O, []).append(D)
|
|
85
|
+
|
|
86
|
+
else:
|
|
87
|
+
print("Possibly wrong data in FAT: {} D={:.3f}".format(O, D))
|
|
88
|
+
|
|
89
|
+
def do_manufacturing(T):
|
|
90
|
+
"""Return mould."""
|
|
91
|
+
mould_id = None
|
|
92
|
+
for prop in T["properties"]:
|
|
93
|
+
if prop["code"] == "MOULD_ID":
|
|
94
|
+
mould_id = prop["value"]
|
|
95
|
+
break
|
|
96
|
+
|
|
97
|
+
return mould_id
|
|
20
98
|
|
|
21
99
|
def do_weighing(results, weights):
|
|
22
100
|
"""Accumulates weighing values to produce stack plot.
|
|
@@ -30,10 +108,27 @@ def do_weighing(results, weights):
|
|
|
30
108
|
weights.setdefault(value["code"][ipos+1:], []).append(value["value"])
|
|
31
109
|
|
|
32
110
|
|
|
111
|
+
def plot_metrology(M_values, Mould_values, petal_ids):
|
|
112
|
+
"""Plot metrology values."""
|
|
113
|
+
for key, values in M_values.items():
|
|
114
|
+
fig, ax = plt.subplots(ncols=1, nrows=1, tight_layout=True)
|
|
115
|
+
ax.hist(values, bins=15, range=(0, 0.150))
|
|
116
|
+
ax.set_title(key)
|
|
117
|
+
|
|
118
|
+
for obj in M_values.keys():
|
|
119
|
+
fig, ax = plt.subplots(ncols=1, nrows=4, tight_layout=True)
|
|
120
|
+
fig.suptitle("{} - Mould".format(obj))
|
|
121
|
+
for mould, m_values in Mould_values.items():
|
|
122
|
+
im = int(mould) - 1
|
|
123
|
+
ax[im].hist(m_values[obj], bins=15, range=(0, 0.150), label="Mould {}".format(mould))
|
|
124
|
+
|
|
125
|
+
for i in range(4):
|
|
126
|
+
ax[i].set_title("Mould {}".format(i+1))
|
|
127
|
+
|
|
33
128
|
def plot_weighing(weights, tick_labels, show_total=False):
|
|
34
129
|
"""Make the plot of weights."""
|
|
35
|
-
labels = ["COOLINGLOOPASSEMBLY", "LOCATOR_A", "LOCATOR_B", "LOCATOR_C",
|
|
36
|
-
"HONEYCOMBSET", "FACING_FRONT", "FACING_BACK",
|
|
130
|
+
labels = ["COOLINGLOOPASSEMBLY", "LOCATOR_A", "LOCATOR_B", "LOCATOR_C",
|
|
131
|
+
"HONEYCOMBSET", "FACING_FRONT", "FACING_BACK",
|
|
37
132
|
"EPOXYADHESIVE", "EPOXYPUTTY", "EPOXYCONDUCTIVE"]
|
|
38
133
|
|
|
39
134
|
fig = plt.figure(tight_layout=True)
|
|
@@ -55,7 +150,7 @@ def plot_weighing(weights, tick_labels, show_total=False):
|
|
|
55
150
|
ax.plot(X, [275.0 for x in range(npoints)], linestyle="dashed", color="black", linewidth=1,)
|
|
56
151
|
|
|
57
152
|
|
|
58
|
-
ax.legend(loc="upper left", ncol=
|
|
153
|
+
ax.legend(loc="upper left", ncol=4)
|
|
59
154
|
|
|
60
155
|
|
|
61
156
|
def main(session):
|
|
@@ -74,27 +169,34 @@ def main(session):
|
|
|
74
169
|
}
|
|
75
170
|
|
|
76
171
|
core_list = session.get("listComponents", json=payload)
|
|
77
|
-
core_tests = ["METROLOGY_AVS", "WEIGHING"]
|
|
172
|
+
core_tests = ["METROLOGY_AVS", "WEIGHING", "MANUFACTURING"]
|
|
78
173
|
|
|
79
174
|
weights = {}
|
|
80
175
|
petal_ids = []
|
|
81
|
-
M_values =
|
|
176
|
+
M_values = {}
|
|
177
|
+
Mould_values = {}
|
|
178
|
+
mould_id = None
|
|
82
179
|
for core in core_list:
|
|
83
180
|
SN = core["serialNumber"]
|
|
84
181
|
altid = core['alternativeIdentifier']
|
|
85
182
|
if "PPC" not in altid:
|
|
86
183
|
continue
|
|
87
184
|
|
|
88
|
-
if altid in ["PPC.016", "PPC.017"]:
|
|
89
|
-
pass
|
|
90
|
-
|
|
91
185
|
petal_ids.append(altid)
|
|
92
|
-
|
|
93
186
|
location = core["currentLocation"]['code']
|
|
94
187
|
coreStage = core["currentStage"]['code']
|
|
95
188
|
|
|
96
189
|
print("\nPetal {} [{}] - {}. {}".format(SN, altid, coreStage, location))
|
|
97
|
-
test_list = session.get(
|
|
190
|
+
test_list = session.get(
|
|
191
|
+
"listTestRunsByComponent",
|
|
192
|
+
json={
|
|
193
|
+
"filterMap": {
|
|
194
|
+
"serialNumber": SN,
|
|
195
|
+
"state": "ready",
|
|
196
|
+
"testType": core_tests,
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
)
|
|
98
200
|
|
|
99
201
|
good_tests = {}
|
|
100
202
|
for tst in test_list:
|
|
@@ -114,30 +216,37 @@ def main(session):
|
|
|
114
216
|
else:
|
|
115
217
|
good_tests[ttype] = T
|
|
116
218
|
|
|
219
|
+
mould_desc = do_manufacturing(good_tests["MANUFACTURING"])
|
|
220
|
+
pos = mould_desc.rfind('.')
|
|
221
|
+
mould_id = mould_desc[pos+1:]
|
|
222
|
+
if mould_id not in Mould_values:
|
|
223
|
+
Mould_values[mould_id] = {}
|
|
224
|
+
|
|
117
225
|
for ttype, T in good_tests.items():
|
|
118
226
|
|
|
119
227
|
if ttype == "WEIGHING":
|
|
120
228
|
do_weighing(T["results"], weights)
|
|
121
229
|
|
|
122
230
|
elif ttype == "METROLOGY_AVS":
|
|
123
|
-
do_metrology(T["results"], M_values)
|
|
124
|
-
|
|
231
|
+
do_metrology(T["results"], M_values, Mould_values[mould_id])
|
|
232
|
+
|
|
233
|
+
elif ttype == "MANUFACTURING":
|
|
234
|
+
continue
|
|
235
|
+
|
|
125
236
|
else:
|
|
126
237
|
for value in T["results"]:
|
|
127
238
|
print("\t{} - {}".format(value["code"], value["value"]))
|
|
128
239
|
|
|
240
|
+
if not T["passed"]:
|
|
241
|
+
print("## test {} FAILED".format(T["testType"]["code"]))
|
|
129
242
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if len(T["defects"]):
|
|
135
|
-
for D in T["defects"]:
|
|
136
|
-
print("\t{} - {}".format(D["name"], D["description"]))
|
|
137
|
-
else:
|
|
138
|
-
print("\nNone")
|
|
243
|
+
if len(T["defects"]):
|
|
244
|
+
print("+ Defects:")
|
|
245
|
+
for D in T["defects"]:
|
|
246
|
+
print("\t{} - {}".format(D["name"], D["description"]))
|
|
139
247
|
|
|
140
248
|
plot_weighing(weights, petal_ids)
|
|
249
|
+
plot_metrology(M_values, Mould_values, petal_ids)
|
|
141
250
|
plt.show()
|
|
142
251
|
|
|
143
252
|
if __name__ == "__main__":
|
|
@@ -151,4 +260,4 @@ if __name__ == "__main__":
|
|
|
151
260
|
except Exception as E:
|
|
152
261
|
print(E)
|
|
153
262
|
|
|
154
|
-
dlg.die()
|
|
263
|
+
dlg.die()
|
|
@@ -52,7 +52,7 @@ def main(session):
|
|
|
52
52
|
print("Could not change stage")
|
|
53
53
|
return False
|
|
54
54
|
|
|
55
|
-
print("
|
|
55
|
+
print("\n\nPetal {} [{}] - {}. {}".format(SN, altid, coreStage, location))
|
|
56
56
|
|
|
57
57
|
test_list = session.get("listTestRunsByComponent", json={"filterMap":{"serialNumber": SN, "state": "ready", "testType":core_tests}})
|
|
58
58
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""List petal core components."""
|
|
3
|
+
|
|
4
|
+
from itkdb_gtk import ITkDBlogin
|
|
5
|
+
from itkdb_gtk import ITkDButils
|
|
6
|
+
|
|
7
|
+
def get_type(child):
|
|
8
|
+
"""Return object type.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
child: object
|
|
12
|
+
|
|
13
|
+
Returns
|
|
14
|
+
str: object type
|
|
15
|
+
"""
|
|
16
|
+
if child["type"] is not None:
|
|
17
|
+
comp_type = child["type"]["code"]
|
|
18
|
+
|
|
19
|
+
else:
|
|
20
|
+
comp_type = child["componentType"]["code"]
|
|
21
|
+
|
|
22
|
+
return comp_type
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def listPetalCoreComponents(session):
|
|
26
|
+
"""List petal core components.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
session: The itkdb session
|
|
30
|
+
"""
|
|
31
|
+
final_stage = {
|
|
32
|
+
"BT_PETAL_FRONT": "COMPLETED",
|
|
33
|
+
"BT_PETAL_BACK": "COMPLETED",
|
|
34
|
+
"COOLING_LOOP_PETAL": "CLINCORE",
|
|
35
|
+
"THERMALFOAMSET_PETAL": "IN_CORE"
|
|
36
|
+
}
|
|
37
|
+
# find all cores
|
|
38
|
+
# Now all the objects
|
|
39
|
+
payload = {
|
|
40
|
+
"filterMap": {
|
|
41
|
+
"componentType": ["CORE_PETAL"],
|
|
42
|
+
"type": ["CORE_AVS"],
|
|
43
|
+
"currentLocation": ["IFIC"],
|
|
44
|
+
},
|
|
45
|
+
"sorterList": [
|
|
46
|
+
{"key": "alternativeIdentifier", "descending": False }
|
|
47
|
+
],
|
|
48
|
+
}
|
|
49
|
+
core_list = session.get("listComponents", json=payload)
|
|
50
|
+
|
|
51
|
+
for core in core_list:
|
|
52
|
+
SN = core["serialNumber"]
|
|
53
|
+
altid = core['alternativeIdentifier']
|
|
54
|
+
if "PPC" not in altid:
|
|
55
|
+
continue
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
location = core["currentLocation"]['code']
|
|
59
|
+
coreStage = core["currentStage"]['code']
|
|
60
|
+
print("\n\nPetal {} [{}] - {}. {}".format(SN, altid, coreStage, location))
|
|
61
|
+
|
|
62
|
+
for child in core["children"]:
|
|
63
|
+
obj = ITkDButils.get_DB_component(session, child["component"])
|
|
64
|
+
child_type = get_type(obj)
|
|
65
|
+
child_stage = obj["currentStage"]["code"]
|
|
66
|
+
child_sn = obj["serialNumber"]
|
|
67
|
+
print("+-- {}: {} [{}]".format(child_sn, child_type, child_stage))
|
|
68
|
+
if child_stage != final_stage[child_type]:
|
|
69
|
+
print("Updating child stage.")
|
|
70
|
+
rc = ITkDButils.set_object_stage(session, child_sn, final_stage[child_type])
|
|
71
|
+
if rc is None:
|
|
72
|
+
print("Could not set final stage of {} [{}]".format(child_type, child_sn))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
if __name__ == "__main__":
|
|
76
|
+
# ITk PDB authentication
|
|
77
|
+
dlg = None
|
|
78
|
+
try:
|
|
79
|
+
# We use here the Gtk GUI
|
|
80
|
+
dlg = ITkDBlogin.ITkDBlogin()
|
|
81
|
+
client = dlg.get_client()
|
|
82
|
+
|
|
83
|
+
except Exception:
|
|
84
|
+
# Login with "standard" if the above fails.
|
|
85
|
+
client = ITkDButils.create_client()
|
|
86
|
+
|
|
87
|
+
listPetalCoreComponents(client)
|
|
88
|
+
if dlg:
|
|
89
|
+
dlg.die()
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Dialog to get DESY IRB files."""
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import itkdb_gtk
|
|
4
|
+
import itkdb_gtk.dbGtkUtils
|
|
5
|
+
|
|
6
|
+
import gi
|
|
7
|
+
gi.require_version("Gtk", "3.0")
|
|
8
|
+
from gi.repository import Gtk, Gio
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class DesyData(Gtk.Dialog):
|
|
12
|
+
"""To get DESY data"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, files=None):
|
|
15
|
+
super().__init__(title="DESY IRB files")
|
|
16
|
+
|
|
17
|
+
self.front = None
|
|
18
|
+
self.back = None
|
|
19
|
+
|
|
20
|
+
self.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
|
|
21
|
+
Gtk.STOCK_OK, Gtk.ResponseType.OK)
|
|
22
|
+
|
|
23
|
+
area = self.get_content_area()
|
|
24
|
+
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
|
25
|
+
area.pack_start(box, True, True, 10)
|
|
26
|
+
|
|
27
|
+
lbl = Gtk.Label(label="Choose the IRB files.")
|
|
28
|
+
box.pack_start(lbl, True, True, 10)
|
|
29
|
+
|
|
30
|
+
grid = Gtk.Grid(column_spacing=10, row_spacing=5)
|
|
31
|
+
box.pack_start(grid, True, True, 10)
|
|
32
|
+
grid.attach(Gtk.Label(label="Front"), 0, 0, 1, 1)
|
|
33
|
+
grid.attach(Gtk.Label(label="Back"), 0, 1, 1, 1)
|
|
34
|
+
|
|
35
|
+
fback = Gtk.FileChooserButton()
|
|
36
|
+
fback.connect("file-set", self.on_file_set, 0)
|
|
37
|
+
ffront = Gtk.FileChooserButton()
|
|
38
|
+
ffront.connect("file-set", self.on_file_set, 1)
|
|
39
|
+
grid.attach(ffront, 1, 0, 1, 1)
|
|
40
|
+
grid.attach(fback, 1, 1, 1, 1)
|
|
41
|
+
|
|
42
|
+
if files is not None and len(files)==2:
|
|
43
|
+
ffront.set_file(Gio.File.new_for_path(files[0]))
|
|
44
|
+
fback.set_file(Gio.File.new_for_path(files[1]))
|
|
45
|
+
|
|
46
|
+
def on_file_set(self, *args):
|
|
47
|
+
"""Get back side file."""
|
|
48
|
+
fnam = args[0].get_filename()
|
|
49
|
+
if fnam is None or not Path(fnam).exists():
|
|
50
|
+
itkdb_gtk.dbGtkUtils.complain("Could not find Data File", fnam, parent=self)
|
|
51
|
+
return
|
|
52
|
+
|
|
53
|
+
if args[1] == 0:
|
|
54
|
+
self.back = fnam
|
|
55
|
+
elif args[1] == 1:
|
|
56
|
+
self.front = fnam
|
|
57
|
+
else:
|
|
58
|
+
itkdb_gtk.dbGtkUtils.complain("This should not happen.", fnam, parent=self)
|
petal_qc/thermal/IRBFile.py
CHANGED
|
@@ -166,11 +166,32 @@ class HeaderBlock(object):
|
|
|
166
166
|
self.word8 = ifile.getInt()
|
|
167
167
|
self.end = ifile.tell()
|
|
168
168
|
|
|
169
|
+
if self.end - self.where != 32:
|
|
170
|
+
raise RuntimeError("byte counting error in parsing of HeaderBlock")
|
|
171
|
+
|
|
169
172
|
def get_name(self):
|
|
170
173
|
"""Return the header type as string."""
|
|
171
174
|
return HeaderBlock.header_name[self.type]
|
|
172
175
|
|
|
173
176
|
|
|
177
|
+
class IRBPreview(object):
|
|
178
|
+
"""A preview in the IRB file."""
|
|
179
|
+
|
|
180
|
+
def __init__(self, block):
|
|
181
|
+
"""Initialize.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
block: the block with the information.
|
|
185
|
+
|
|
186
|
+
"""
|
|
187
|
+
self.block = block
|
|
188
|
+
old_position = block.ifile.tell()
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
block.ifile.seek(old_position)
|
|
193
|
+
|
|
194
|
+
|
|
174
195
|
class IRBImage(object):
|
|
175
196
|
"""An image in the IRBis file."""
|
|
176
197
|
|
|
@@ -181,7 +202,6 @@ class IRBImage(object):
|
|
|
181
202
|
"""Initialize.
|
|
182
203
|
|
|
183
204
|
Args:
|
|
184
|
-
----
|
|
185
205
|
ifile: The input file
|
|
186
206
|
block: The block with the information.
|
|
187
207
|
|
|
@@ -233,9 +253,8 @@ class IRBImage(object):
|
|
|
233
253
|
zero = ifile.getShort()
|
|
234
254
|
|
|
235
255
|
if self.width > 10000 or self.height > 10000:
|
|
236
|
-
|
|
256
|
+
raise RuntimeError("Image size out of range ({}x{})".format(
|
|
237
257
|
self.width, self.height))
|
|
238
|
-
return
|
|
239
258
|
|
|
240
259
|
flagsPosition = block.offset + IRBImage.FLAGS_OFFSET
|
|
241
260
|
self.readImageFlags(flagsPosition)
|
|
@@ -314,13 +333,18 @@ class IRBImage(object):
|
|
|
314
333
|
if v2_count < 1:
|
|
315
334
|
v2_count = v2_data[v2_pos]
|
|
316
335
|
v2 = v2_data[v2_pos+1]
|
|
317
|
-
|
|
336
|
+
if v2 < 0:
|
|
337
|
+
v2 += 256
|
|
338
|
+
P1 = self.palette[(v2+1) % 256]
|
|
318
339
|
P2 = self.palette[v2]
|
|
319
340
|
v2_pos += 2
|
|
320
341
|
|
|
321
342
|
v2_count -= 1
|
|
322
343
|
|
|
323
344
|
v1 = v1_data[i]
|
|
345
|
+
if v1 < 0:
|
|
346
|
+
v1 += 256
|
|
347
|
+
|
|
324
348
|
f = v1/256.0
|
|
325
349
|
|
|
326
350
|
# linear interpolation betweeen eighboring palette entries
|
|
@@ -423,6 +447,7 @@ class IRBFile(object):
|
|
|
423
447
|
"""
|
|
424
448
|
self.concatenate = concatenate
|
|
425
449
|
self.imgList = []
|
|
450
|
+
self.previewList = []
|
|
426
451
|
self.blocks = []
|
|
427
452
|
self.ifiles = []
|
|
428
453
|
self.file_images = []
|
|
@@ -493,6 +518,9 @@ class IRBFile(object):
|
|
|
493
518
|
if block.type == HeaderBlock.IMAGE:
|
|
494
519
|
image = IRBImage(block)
|
|
495
520
|
self.imgList.append(image)
|
|
521
|
+
elif block.type == HeaderBlock.PREVIEW:
|
|
522
|
+
image = IRBPreview(block)
|
|
523
|
+
self.previewList.append(image)
|
|
496
524
|
|
|
497
525
|
if self.is_sequence:
|
|
498
526
|
offset = -1
|
|
@@ -549,6 +577,10 @@ class IRBFile(object):
|
|
|
549
577
|
self.current_file = i
|
|
550
578
|
self.imgList = self.file_images[i]
|
|
551
579
|
|
|
580
|
+
def getImage_timestamp(self, i):
|
|
581
|
+
"""Return timestamp of i-th image."""
|
|
582
|
+
return self.imgList[i].timestamp
|
|
583
|
+
|
|
552
584
|
def getImage(self, i):
|
|
553
585
|
"""Get i-th image in current file.
|
|
554
586
|
|
|
@@ -682,7 +714,7 @@ class IRBFile(object):
|
|
|
682
714
|
return out
|
|
683
715
|
|
|
684
716
|
|
|
685
|
-
def open_file(fname):
|
|
717
|
+
def open_file(fname, concat=False):
|
|
686
718
|
"""Opens a file an returns a IRBFile instance.
|
|
687
719
|
|
|
688
720
|
Args:
|
|
@@ -694,7 +726,19 @@ def open_file(fname):
|
|
|
694
726
|
if is_iterable(fname):
|
|
695
727
|
# we assume it is a list of IRB files...
|
|
696
728
|
try:
|
|
697
|
-
|
|
729
|
+
if concat:
|
|
730
|
+
irbf = IRBFile(fname)
|
|
731
|
+
return irbf
|
|
732
|
+
else:
|
|
733
|
+
out = []
|
|
734
|
+
for f in fname:
|
|
735
|
+
irbf = IRBFile(f)
|
|
736
|
+
out.append(irbf)
|
|
737
|
+
|
|
738
|
+
if len(out) == 1:
|
|
739
|
+
out = out[0]
|
|
740
|
+
|
|
741
|
+
return out
|
|
698
742
|
|
|
699
743
|
except FileNotFoundError as eee:
|
|
700
744
|
print(eee)
|
|
@@ -769,4 +813,4 @@ def main():
|
|
|
769
813
|
plt.show()
|
|
770
814
|
|
|
771
815
|
if __name__ == "__main__":
|
|
772
|
-
main()
|
|
816
|
+
main()
|
petal_qc/thermal/IRDataGetter.py
CHANGED
|
@@ -343,14 +343,28 @@ class IRDataDESY(IRDataGetter):
|
|
|
343
343
|
nframes = -1
|
|
344
344
|
|
|
345
345
|
min_T = 1e50
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
346
|
+
i_min = -1
|
|
347
|
+
try:
|
|
348
|
+
avg_img = irbf.append_average(nframes=nframes)
|
|
349
|
+
for img in avg_img:
|
|
350
|
+
val = np.min(img.image)
|
|
351
|
+
if val < min_T:
|
|
352
|
+
min_T = val
|
|
353
|
+
|
|
354
|
+
i_min = irbf.nimages-1
|
|
355
|
+
values = self.get_IR_data(avg_img)
|
|
351
356
|
|
|
352
|
-
|
|
353
|
-
|
|
357
|
+
except AttributeError:
|
|
358
|
+
# We have 2 files, one front y the second back
|
|
359
|
+
values = []
|
|
360
|
+
factors = []
|
|
361
|
+
for ifile in irbf:
|
|
362
|
+
val = self.get_IR_data(ifile.getImage(0))
|
|
363
|
+
Tmin = np.min(val)
|
|
364
|
+
if Tmin < min_T:
|
|
365
|
+
min_T = Tmin
|
|
366
|
+
i_min = 0
|
|
367
|
+
values.append(val)
|
|
354
368
|
|
|
355
369
|
factors = []
|
|
356
370
|
for img in values:
|
|
@@ -359,25 +373,26 @@ class IRDataDESY(IRDataGetter):
|
|
|
359
373
|
|
|
360
374
|
return min_T, i_min, values
|
|
361
375
|
|
|
362
|
-
def extract_pipe_path(self,
|
|
376
|
+
def extract_pipe_path(self, image, params) -> list:
|
|
363
377
|
"""Extract the "pipe path" in a petal IR image.
|
|
364
378
|
|
|
365
379
|
Args:
|
|
366
|
-
|
|
367
|
-
images(list(ndarray)): The array of 2D arrays containing the images
|
|
380
|
+
image(list(ndarray)): The array of 2D arrays containing the images
|
|
368
381
|
params: IRPetalPam object with options.
|
|
369
382
|
|
|
370
383
|
Returns
|
|
371
|
-
-------
|
|
372
384
|
pipe: the list of pipe contours or paths.
|
|
373
385
|
|
|
374
386
|
"""
|
|
375
387
|
pipes = []
|
|
376
|
-
|
|
388
|
+
points_3d = []
|
|
389
|
+
for img in image:
|
|
377
390
|
pipe = IRPetal.extract_pipe_path(img, params)
|
|
391
|
+
points_3d.append(IRPetal.get_all_3d_points())
|
|
378
392
|
pipes.append(pipe)
|
|
379
393
|
|
|
380
|
-
IRPetal.
|
|
394
|
+
IRPetal.set_all_3d_points(points_3d)
|
|
395
|
+
IRPetal.set_images(image)
|
|
381
396
|
return pipes
|
|
382
397
|
|
|
383
398
|
def analyze_IR_image(self, img, pipes, sensors, iside, params):
|
|
@@ -401,7 +416,11 @@ class IRDataDESY(IRDataGetter):
|
|
|
401
416
|
|
|
402
417
|
DESY gets the average of all frames.
|
|
403
418
|
"""
|
|
404
|
-
|
|
405
|
-
irbf.
|
|
419
|
+
try:
|
|
420
|
+
if not irbf.has_average:
|
|
421
|
+
irbf.append_average(nframes=5)
|
|
422
|
+
|
|
423
|
+
return [v[-1] for v in irbf.file_images]
|
|
406
424
|
|
|
407
|
-
|
|
425
|
+
except AttributeError:
|
|
426
|
+
return [irbf[0].getImage(0), irbf[1].getImage(0)]
|
petal_qc/thermal/IRPetal.py
CHANGED
|
@@ -72,6 +72,12 @@ def get_all_3d_points():
|
|
|
72
72
|
"""Return all pipe path 3D points."""
|
|
73
73
|
return the_3d_points
|
|
74
74
|
|
|
75
|
+
def set_all_3d_points(all_3d_points):
|
|
76
|
+
"""Set all pipe path 3D points."""
|
|
77
|
+
global the_3d_points
|
|
78
|
+
the_3d_points = all_3d_points
|
|
79
|
+
|
|
80
|
+
|
|
75
81
|
def get_last_segments():
|
|
76
82
|
"""Return the last segments found."""
|
|
77
83
|
global the_segments
|
petal_qc/thermal/IRPetalParam.py
CHANGED
|
@@ -12,7 +12,7 @@ class IRPetalParam(object):
|
|
|
12
12
|
values: ArgParser or dict with user values-
|
|
13
13
|
|
|
14
14
|
"""
|
|
15
|
-
self.institute =
|
|
15
|
+
self.institute = None # Either IFIC or DESY to treat the different files
|
|
16
16
|
self.thrs = -22.0 # the threshold
|
|
17
17
|
self.tco2 = -35.0 # Inlet temperature
|
|
18
18
|
self.gauss_size = 15 # Radius of gausian filtering
|
petal_qc/thermal/PipeFit.py
CHANGED
|
@@ -413,6 +413,14 @@ class PipeFit(object):
|
|
|
413
413
|
"""
|
|
414
414
|
if M0 is None:
|
|
415
415
|
M = self.initial_guess(data)
|
|
416
|
+
for i, val in enumerate(M):
|
|
417
|
+
if val < self.bounds[0][i]:
|
|
418
|
+
val = 1.01 * self.bounds[0][i]
|
|
419
|
+
M[i] = val
|
|
420
|
+
elif val > self.bounds[1][i]:
|
|
421
|
+
val = 0.99 * self.bounds[0][i]
|
|
422
|
+
M[i] = val
|
|
423
|
+
|
|
416
424
|
if self.debug:
|
|
417
425
|
print("\n** Initial guess")
|
|
418
426
|
self.print_transform(M)
|
|
@@ -528,12 +528,14 @@ def analyze_IRCore(options, show=True):
|
|
|
528
528
|
print("I need a golden file to compare with")
|
|
529
529
|
sys.exit(1)
|
|
530
530
|
|
|
531
|
-
golden_file =
|
|
531
|
+
golden_file = Path(options.golden).expanduser().resolve()
|
|
532
532
|
if not golden_file.exists():
|
|
533
|
-
|
|
534
|
-
|
|
533
|
+
golden_file = find_file(options.folder, options.golden)
|
|
534
|
+
if not golden_file.exists():
|
|
535
|
+
print("Golden file {} does not exist.".format(options.golden))
|
|
536
|
+
sys.exit(1)
|
|
535
537
|
|
|
536
|
-
with open(golden_file, 'r') as fp:
|
|
538
|
+
with open(golden_file, 'r', encoding="utf-8") as fp:
|
|
537
539
|
J = json.load(fp)
|
|
538
540
|
|
|
539
541
|
golden = [Petal_IR_Analysis.AnalysisResult() for i in range(2)]
|
|
@@ -563,7 +565,7 @@ def analyze_IRCore(options, show=True):
|
|
|
563
565
|
F = show_golden_average(golden, cores, "sensor_std")
|
|
564
566
|
add_figures_to_doc(document, F, "Sensor std")
|
|
565
567
|
|
|
566
|
-
if document:
|
|
568
|
+
if document and not hasattr(options, "no_golden_doc"):
|
|
567
569
|
ofile = utils.output_folder(options.folder, "Compare-to-Golden.docx")
|
|
568
570
|
document.save(ofile)
|
|
569
571
|
|
|
@@ -573,7 +575,8 @@ def analyze_IRCore(options, show=True):
|
|
|
573
575
|
return output
|
|
574
576
|
|
|
575
577
|
|
|
576
|
-
|
|
578
|
+
def main():
|
|
579
|
+
"""Main entry."""
|
|
577
580
|
from argparse import ArgumentParser
|
|
578
581
|
# Argument parser
|
|
579
582
|
parser = ArgumentParser()
|
|
@@ -595,3 +598,6 @@ if __name__ == "__main__":
|
|
|
595
598
|
sys.exit()
|
|
596
599
|
|
|
597
600
|
analyze_IRCore(options)
|
|
601
|
+
|
|
602
|
+
if __name__ == "__main__":
|
|
603
|
+
main()
|