petal-qc 0.0.0__tar.gz
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-0.0.0/PKG-INFO +29 -0
- petal_qc-0.0.0/README.md +6 -0
- petal_qc-0.0.0/petal_qc/BTreport/CheckBTtests.py +321 -0
- petal_qc-0.0.0/petal_qc/BTreport/__init__.py +0 -0
- petal_qc-0.0.0/petal_qc/BTreport/bustapeReport.py +144 -0
- petal_qc-0.0.0/petal_qc/__init__.py +14 -0
- petal_qc-0.0.0/petal_qc/metrology/Cluster.py +90 -0
- petal_qc-0.0.0/petal_qc/metrology/DataFile.py +47 -0
- petal_qc-0.0.0/petal_qc/metrology/PetalMetrology.py +327 -0
- petal_qc-0.0.0/petal_qc/metrology/__init__.py +0 -0
- petal_qc-0.0.0/petal_qc/metrology/all2csv.py +57 -0
- petal_qc-0.0.0/petal_qc/metrology/analyze_locking_points.py +597 -0
- petal_qc-0.0.0/petal_qc/metrology/cold_noise.py +106 -0
- petal_qc-0.0.0/petal_qc/metrology/comparisonTable.py +59 -0
- petal_qc-0.0.0/petal_qc/metrology/convert_mitutoyo.py +175 -0
- petal_qc-0.0.0/petal_qc/metrology/convert_smartscope.py +145 -0
- petal_qc-0.0.0/petal_qc/metrology/coreMetrology.py +402 -0
- petal_qc-0.0.0/petal_qc/metrology/data2csv.py +63 -0
- petal_qc-0.0.0/petal_qc/metrology/do_Metrology.py +117 -0
- petal_qc-0.0.0/petal_qc/metrology/flatness4nigel.py +157 -0
- petal_qc-0.0.0/petal_qc/metrology/gtkutils.py +120 -0
- petal_qc-0.0.0/petal_qc/metrology/petal_flatness.py +353 -0
- petal_qc-0.0.0/petal_qc/metrology/show_data_file.py +118 -0
- petal_qc-0.0.0/petal_qc/metrology/testSummary.py +37 -0
- petal_qc-0.0.0/petal_qc/metrology/test_paralelism.py +71 -0
- petal_qc-0.0.0/petal_qc/thermal/CSVImage.py +69 -0
- petal_qc-0.0.0/petal_qc/thermal/DebugPlot.py +76 -0
- petal_qc-0.0.0/petal_qc/thermal/IRBFile.py +768 -0
- petal_qc-0.0.0/petal_qc/thermal/IRCore.py +110 -0
- petal_qc-0.0.0/petal_qc/thermal/IRDataGetter.py +359 -0
- petal_qc-0.0.0/petal_qc/thermal/IRPetal.py +1338 -0
- petal_qc-0.0.0/petal_qc/thermal/IRPetalParam.py +71 -0
- petal_qc-0.0.0/petal_qc/thermal/PetalColorMaps.py +62 -0
- petal_qc-0.0.0/petal_qc/thermal/Petal_IR_Analysis.py +142 -0
- petal_qc-0.0.0/petal_qc/thermal/PipeFit.py +598 -0
- petal_qc-0.0.0/petal_qc/thermal/__init__.py +0 -0
- petal_qc-0.0.0/petal_qc/thermal/analyze_IRCore.py +417 -0
- petal_qc-0.0.0/petal_qc/thermal/contours.py +378 -0
- petal_qc-0.0.0/petal_qc/thermal/create_IRCore.py +185 -0
- petal_qc-0.0.0/petal_qc/thermal/pipe_read.py +182 -0
- petal_qc-0.0.0/petal_qc/thermal/show_IR_petal.py +420 -0
- petal_qc-0.0.0/petal_qc/utils/Geometry.py +756 -0
- petal_qc-0.0.0/petal_qc/utils/Progress.py +182 -0
- petal_qc-0.0.0/petal_qc/utils/__init__.py +0 -0
- petal_qc-0.0.0/petal_qc/utils/all_files.py +35 -0
- petal_qc-0.0.0/petal_qc/utils/docx_utils.py +186 -0
- petal_qc-0.0.0/petal_qc/utils/fit_utils.py +188 -0
- petal_qc-0.0.0/petal_qc/utils/utils.py +180 -0
- petal_qc-0.0.0/petal_qc.egg-info/PKG-INFO +29 -0
- petal_qc-0.0.0/petal_qc.egg-info/SOURCES.txt +54 -0
- petal_qc-0.0.0/petal_qc.egg-info/dependency_links.txt +1 -0
- petal_qc-0.0.0/petal_qc.egg-info/entry_points.txt +3 -0
- petal_qc-0.0.0/petal_qc.egg-info/requires.txt +11 -0
- petal_qc-0.0.0/petal_qc.egg-info/top_level.txt +1 -0
- petal_qc-0.0.0/pyproject.toml +44 -0
- petal_qc-0.0.0/setup.cfg +4 -0
petal_qc-0.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: petal_qc
|
|
3
|
+
Version: 0.0.0
|
|
4
|
+
Summary: A collection of scripts for Petal CORE QC.
|
|
5
|
+
Author-email: Carlos Lacasta <carlos.lacasta@cern.ch>
|
|
6
|
+
Project-URL: Homepage, https://gitlab.cern.ch/atlas-itk/sw/db/itk-pdb-gtk-gui-utils
|
|
7
|
+
Project-URL: Bug Tracker, https://gitlab.cern.ch/atlas-itk/sw/db/itk-pdb-gtk-gui-utils/-/issues
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.7
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
Requires-Dist: itkdb
|
|
13
|
+
Requires-Dist: itkdb_gtk
|
|
14
|
+
Requires-Dist: numpy
|
|
15
|
+
Requires-Dist: matplotlib
|
|
16
|
+
Requires-Dist: lmfit
|
|
17
|
+
Requires-Dist: openpyxl
|
|
18
|
+
Requires-Dist: pandas
|
|
19
|
+
Requires-Dist: python_dateutil
|
|
20
|
+
Requires-Dist: python_docx
|
|
21
|
+
Requires-Dist: scipy
|
|
22
|
+
Requires-Dist: scikit-image
|
|
23
|
+
|
|
24
|
+
# Petal QC
|
|
25
|
+
|
|
26
|
+
The folder contains a collections of scripts to make the analysis of the Petal
|
|
27
|
+
QC metrology and thermal tests.
|
|
28
|
+
|
|
29
|
+
They will also upload the tests to the DB if required.
|
petal_qc-0.0.0/README.md
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Check that bus tapes in petal have been tested.
|
|
3
|
+
|
|
4
|
+
Upload teh Bus Tape Summary TEst to the PDB.
|
|
5
|
+
|
|
6
|
+
To run it
|
|
7
|
+
|
|
8
|
+
python3 CheckBTtests.py petal_SN
|
|
9
|
+
|
|
10
|
+
The main routine is BTreport and can be called from anywhere else.
|
|
11
|
+
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import sys
|
|
15
|
+
import traceback
|
|
16
|
+
import json
|
|
17
|
+
import getpass
|
|
18
|
+
import datetime
|
|
19
|
+
import dateutil.parser
|
|
20
|
+
import itkdb
|
|
21
|
+
from itkdb_gtk import ITkDBlogin
|
|
22
|
+
|
|
23
|
+
def complain(main_msg, secondary_msg=None):
|
|
24
|
+
"""Prints an error message
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
-----
|
|
28
|
+
main (): Main message
|
|
29
|
+
secondary (): Seconday message
|
|
30
|
+
"""
|
|
31
|
+
print("**Error\n{}".format(main_msg))
|
|
32
|
+
if secondary_msg:
|
|
33
|
+
msg = secondary_msg.replace("\n", "\n\t")
|
|
34
|
+
print("\t{}".format(msg))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def find_petal(session, SerialN, silent=False, complain_func=complain):
|
|
38
|
+
"""Find petal with given SerialN.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
-----
|
|
42
|
+
session (itkdb.Client): The DB session
|
|
43
|
+
SerialN (str): The petal SerialNumber
|
|
44
|
+
silent (bool, optional): No compllaint writen. Defaults to False.
|
|
45
|
+
|
|
46
|
+
Returns
|
|
47
|
+
-------
|
|
48
|
+
dict: A petal (JSon)
|
|
49
|
+
|
|
50
|
+
Raises
|
|
51
|
+
------
|
|
52
|
+
LookupError if petal not found
|
|
53
|
+
TypeError if SerialN is not a CORE_AVS
|
|
54
|
+
"""
|
|
55
|
+
try:
|
|
56
|
+
petal_core = session.get('getComponent', json={'component': SerialN})
|
|
57
|
+
|
|
58
|
+
except Exception as ex:
|
|
59
|
+
if not silent:
|
|
60
|
+
complain_func("Could not find Petal Core in DB", str(ex))
|
|
61
|
+
|
|
62
|
+
raise LookupError("Could not find Petal core with SN {}".format(SerialN)) from ex
|
|
63
|
+
|
|
64
|
+
if petal_core["type"]["code"] != "CORE_AVS":
|
|
65
|
+
if not silent:
|
|
66
|
+
complain_func("Wrong component type", "This is not an AVS petal core")
|
|
67
|
+
|
|
68
|
+
raise TypeError("This is not an AVS petal core")
|
|
69
|
+
|
|
70
|
+
return petal_core
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def get_type(child):
|
|
74
|
+
"""Return object type
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
-----
|
|
78
|
+
child: object
|
|
79
|
+
|
|
80
|
+
Returns
|
|
81
|
+
-------
|
|
82
|
+
str: object type
|
|
83
|
+
|
|
84
|
+
"""
|
|
85
|
+
if child["type"] is not None:
|
|
86
|
+
comp_type = child["type"]["code"]
|
|
87
|
+
|
|
88
|
+
else:
|
|
89
|
+
comp_type = child["componentType"]["code"]
|
|
90
|
+
|
|
91
|
+
return comp_type
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def find_bus_tapes(session, petal, complain_func=complain):
|
|
95
|
+
"""Find Bus tapes in petal.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
----
|
|
99
|
+
session (itkdb.Client): The DB session
|
|
100
|
+
petal (Json): The petal object
|
|
101
|
+
|
|
102
|
+
Returns
|
|
103
|
+
-------
|
|
104
|
+
dict: a dict with the bustapes. Key is the BT type.
|
|
105
|
+
"""
|
|
106
|
+
bt_list = {}
|
|
107
|
+
for child in petal["children"]:
|
|
108
|
+
cstage = "Missing"
|
|
109
|
+
if child["component"] is None:
|
|
110
|
+
continue
|
|
111
|
+
|
|
112
|
+
else:
|
|
113
|
+
child_sn = child["component"]["serialNumber"]
|
|
114
|
+
comp_type = get_type(child)
|
|
115
|
+
if "BT_PETAL" not in comp_type:
|
|
116
|
+
continue
|
|
117
|
+
|
|
118
|
+
# We are left with the bus tapes
|
|
119
|
+
cobj = session.get('getComponent', json={'component': child["component"]["id"]})
|
|
120
|
+
cstage = cobj["currentStage"]['code']
|
|
121
|
+
if cstage != "COMPLETED":
|
|
122
|
+
complain_func("Bus tape not in final stages", cstage)
|
|
123
|
+
continue
|
|
124
|
+
|
|
125
|
+
bt_list[comp_type] = cobj, child['id']
|
|
126
|
+
|
|
127
|
+
return bt_list
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def find_but_tape_tests(session, petal_date, bt_sn, complain_func=complain):
|
|
131
|
+
"""Find tests in bus tape.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
session (itkdb.Client): The DB session
|
|
135
|
+
petal_date (DateTime): The petal date
|
|
136
|
+
bt_sn (str): The bus tape SN
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
dict: dict with all tests. key is the test type code.
|
|
140
|
+
|
|
141
|
+
"""
|
|
142
|
+
test_list = session.get("listTestRunsByComponent", json={"component": bt_sn, "stage": "COMPLETED"})
|
|
143
|
+
bt_tests = {}
|
|
144
|
+
for tst in test_list:
|
|
145
|
+
test_type = tst["testType"]["name"]
|
|
146
|
+
test_code = tst["testType"]["code"]
|
|
147
|
+
|
|
148
|
+
# Create the storage for the tests. Used to sort by date in case of multiple tests
|
|
149
|
+
if test_code not in bt_tests:
|
|
150
|
+
bt_tests[test_code] = []
|
|
151
|
+
|
|
152
|
+
test_date = tst["date"]
|
|
153
|
+
bt_tests[test_code].append(tst)
|
|
154
|
+
|
|
155
|
+
for key, val in bt_tests.items():
|
|
156
|
+
val.sort(key=lambda a: dateutil.parser.parse(a["date"]), reverse=True)
|
|
157
|
+
the_test = val[0]
|
|
158
|
+
if petal_date > dateutil.parser.parse(val[0]["date"]):
|
|
159
|
+
complain_func("Test on tape happened before petal", "")
|
|
160
|
+
bt_tests[key] = None
|
|
161
|
+
else:
|
|
162
|
+
bt_tests[key] = val[0]
|
|
163
|
+
|
|
164
|
+
return bt_tests
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def date2string(the_date=None):
|
|
168
|
+
"""REturns date string in TTkDB format."""
|
|
169
|
+
if the_date is None:
|
|
170
|
+
the_date = datetime.datetime.now()
|
|
171
|
+
out = the_date.isoformat(timespec='milliseconds')
|
|
172
|
+
if out[-1] not in ['zZ']:
|
|
173
|
+
out += 'Z'
|
|
174
|
+
|
|
175
|
+
return out
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def BTreport(session, SerialN, complain_func=complain):
|
|
179
|
+
"""Makes the BTreport for a petal core.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
session (itkdb.Client): The DB session
|
|
183
|
+
SerialN (str): The Petal core SB
|
|
184
|
+
"""
|
|
185
|
+
# get petal frm DB.
|
|
186
|
+
try:
|
|
187
|
+
petal = find_petal(session, SerialN, complain_func=complain_func)
|
|
188
|
+
|
|
189
|
+
except Exception as ex:
|
|
190
|
+
print(str(ex))
|
|
191
|
+
return None
|
|
192
|
+
|
|
193
|
+
print("+++ Petal core {} [{}]".format(SerialN, petal["alternativeIdentifier"]))
|
|
194
|
+
petal_date = dateutil.parser.parse(petal["stateTs"])
|
|
195
|
+
comp_type = get_type(petal)
|
|
196
|
+
if comp_type != "CORE_AVS":
|
|
197
|
+
complain_func("This is not a petal cores", comp_type)
|
|
198
|
+
return None
|
|
199
|
+
|
|
200
|
+
# Check that the petal core is in the proper stage.
|
|
201
|
+
stage = petal["currentStage"]['code']
|
|
202
|
+
if stage != "AT_QC_SITE":
|
|
203
|
+
complain_func("Petal core is not at QC_SITE", stage)
|
|
204
|
+
return None
|
|
205
|
+
|
|
206
|
+
# Check children
|
|
207
|
+
if "children" not in petal:
|
|
208
|
+
complain_func("{}[{}]".format(SerialN, id), "Not assembled")
|
|
209
|
+
return None
|
|
210
|
+
|
|
211
|
+
# Loop on children an find bustapes
|
|
212
|
+
bt_list = find_bus_tapes(session, petal, complain_func=complain_func)
|
|
213
|
+
if len(bt_list) == 0:
|
|
214
|
+
complain_func("no valid bustape found", "Either not assembled or in incorrect stage.")
|
|
215
|
+
return None
|
|
216
|
+
|
|
217
|
+
out = {
|
|
218
|
+
"component": SerialN,
|
|
219
|
+
"testType": "BTTESTING",
|
|
220
|
+
"institution": petal["currentLocation"]["code"],
|
|
221
|
+
"runNumber": "1",
|
|
222
|
+
"date": date2string(),
|
|
223
|
+
"passed": True,
|
|
224
|
+
"problems": False,
|
|
225
|
+
"results": {
|
|
226
|
+
"PASS": [],
|
|
227
|
+
"RUNS_ELECTRICALTEST": []
|
|
228
|
+
# "RUNS_STRETCHTEST": []
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
# Check te tests in the bustapes
|
|
233
|
+
ngood = 0
|
|
234
|
+
ntrouble = 0
|
|
235
|
+
for bt, cp_id in bt_list.values():
|
|
236
|
+
bt_sn = bt["serialNumber"]
|
|
237
|
+
print("bus tape {}".format(bt_sn))
|
|
238
|
+
|
|
239
|
+
bt_ngood = 0
|
|
240
|
+
bt_nprob = 0
|
|
241
|
+
# get list of tests and select the latest.
|
|
242
|
+
bt_tests = find_but_tape_tests(session, petal_date, bt_sn, complain_func=complain_func)
|
|
243
|
+
|
|
244
|
+
results = {}
|
|
245
|
+
childId = {}
|
|
246
|
+
for key, the_test in bt_tests.items():
|
|
247
|
+
print("\t->The Test {} [{}] {}".format(the_test["testType"]["name"],
|
|
248
|
+
the_test["date"][0:16],
|
|
249
|
+
"PASSED" if the_test["passed"] else "FAILED"))
|
|
250
|
+
|
|
251
|
+
results[the_test["testType"]["code"]] = the_test["passed"]
|
|
252
|
+
childId[the_test["testType"]["code"]] = the_test['id']
|
|
253
|
+
if the_test["passed"]:
|
|
254
|
+
ngood += 1
|
|
255
|
+
bt_ngood += 1
|
|
256
|
+
|
|
257
|
+
if the_test["problems"]:
|
|
258
|
+
ntrouble += 1
|
|
259
|
+
bt_nprob += 1
|
|
260
|
+
|
|
261
|
+
out["results"]["PASS"].append(
|
|
262
|
+
{"value": (bt_ngood == 2),
|
|
263
|
+
"childParentRelation": cp_id})
|
|
264
|
+
|
|
265
|
+
out["results"]["RUNS_ELECTRICALTEST"].append(
|
|
266
|
+
{"value": childId["BTELECTRICAL"],
|
|
267
|
+
"childParentRelation": cp_id})
|
|
268
|
+
|
|
269
|
+
# out["results"]["RUNS_STRETCHTEST"].append(
|
|
270
|
+
# {"value": childId["BTSTRETCHP"],
|
|
271
|
+
# "childParentRelation": cp_id})
|
|
272
|
+
|
|
273
|
+
out["passed"] = (ngood == 4)
|
|
274
|
+
out["problems"] = (ntrouble > 0)
|
|
275
|
+
print("BusTape Report\n\tN. good {}\n\tN. prob {}".format(ngood, ntrouble))
|
|
276
|
+
|
|
277
|
+
return out
|
|
278
|
+
|
|
279
|
+
def main():
|
|
280
|
+
"""Main entry."""
|
|
281
|
+
try:
|
|
282
|
+
SN = sys.argv[1]
|
|
283
|
+
except IndexError:
|
|
284
|
+
print("I need a petal core SN")
|
|
285
|
+
sys.exit()
|
|
286
|
+
|
|
287
|
+
# ITk PDB authentication
|
|
288
|
+
dlg = None
|
|
289
|
+
try:
|
|
290
|
+
# We use here the Gtk GUI
|
|
291
|
+
dlg = ITkDBlogin.ITkDBlogin()
|
|
292
|
+
client = dlg.get_client()
|
|
293
|
+
|
|
294
|
+
except Exception:
|
|
295
|
+
# Login with "standard" if the above fails.
|
|
296
|
+
client = itkdb.Client()
|
|
297
|
+
client.user._access_code1 = getpass.getpass("Access 1: ")
|
|
298
|
+
client.user._access_code2 = getpass.getpass("Access 2: ")
|
|
299
|
+
client.user.authenticate()
|
|
300
|
+
print("Hello {} !".format(client.user.name))
|
|
301
|
+
|
|
302
|
+
# Check the Bustape tests
|
|
303
|
+
try:
|
|
304
|
+
out = BTreport(client, SN)
|
|
305
|
+
# Upload test
|
|
306
|
+
if out:
|
|
307
|
+
db_response = client.post("uploadTestRunResults", json=out)
|
|
308
|
+
print(json.dumps(db_response, indent=3))
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
except Exception:
|
|
312
|
+
print(traceback.format_exc())
|
|
313
|
+
|
|
314
|
+
try:
|
|
315
|
+
dlg.die()
|
|
316
|
+
|
|
317
|
+
except Exception:
|
|
318
|
+
print("Bye !")
|
|
319
|
+
|
|
320
|
+
if __name__ == "__main__":
|
|
321
|
+
main()
|
|
File without changes
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from contextlib import redirect_stdout
|
|
3
|
+
|
|
4
|
+
from itkdb_gtk import ITkDButils
|
|
5
|
+
from itkdb_gtk import dbGtkUtils
|
|
6
|
+
from itkdb_gtk import ITkDBlogin
|
|
7
|
+
import itkdb
|
|
8
|
+
|
|
9
|
+
from petal_qc.BTreport import CheckBTtests
|
|
10
|
+
|
|
11
|
+
import gi
|
|
12
|
+
gi.require_version("Gtk", "3.0")
|
|
13
|
+
from gi.repository import Gtk, Gio
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BusTapeReport(dbGtkUtils.ITkDBWindow):
|
|
17
|
+
"""Makes a report of bustapes."""
|
|
18
|
+
|
|
19
|
+
def __init__(self, session=None, title="", panel_size=100):
|
|
20
|
+
"""Initialization.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
title: The title of the window.
|
|
24
|
+
pannel_size: size of message panel.
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
super().__init__(session=session, title=title, show_search="SEarch for Petal CORE")
|
|
28
|
+
self.petal_SN = None
|
|
29
|
+
self.alternativeID = None
|
|
30
|
+
self.outDB = None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Active button in header
|
|
34
|
+
button = Gtk.Button()
|
|
35
|
+
icon = Gio.ThemedIcon(name="document-send-symbolic")
|
|
36
|
+
image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON)
|
|
37
|
+
button.add(image)
|
|
38
|
+
button.set_tooltip_text("Click to upload test")
|
|
39
|
+
button.connect("clicked", self.upload_test_gui)
|
|
40
|
+
self.hb.pack_end(button)
|
|
41
|
+
|
|
42
|
+
# JScon edit
|
|
43
|
+
button = Gtk.Button()
|
|
44
|
+
icon = Gio.ThemedIcon(name="accessories-text-editor-symbolic")
|
|
45
|
+
image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON)
|
|
46
|
+
button.add(image)
|
|
47
|
+
button.set_tooltip_text("Click to see the test data")
|
|
48
|
+
button.connect("clicked", self.show_test_gui)
|
|
49
|
+
self.hb.pack_end(button)
|
|
50
|
+
|
|
51
|
+
# The Serial number
|
|
52
|
+
self.SN = dbGtkUtils.TextEntry()
|
|
53
|
+
self.SN.connect("text-changed", self.on_SN_changed)
|
|
54
|
+
|
|
55
|
+
# Put the 3 objects in a Grid
|
|
56
|
+
grid = Gtk.Grid(column_spacing=5, row_spacing=5)
|
|
57
|
+
self.mainBox.pack_start(grid, False, True, 0)
|
|
58
|
+
|
|
59
|
+
grid.attach(Gtk.Label(label="Serial No."), 0, 0, 1, 1)
|
|
60
|
+
grid.attach(self.SN.entry, 1, 0, 1, 1)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
self.mainBox.pack_start(self.message_panel.frame, True, True, 0)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def quit(self, *args):
|
|
67
|
+
"""Quits the application."""
|
|
68
|
+
self.hide()
|
|
69
|
+
self.destroy()
|
|
70
|
+
|
|
71
|
+
def on_SN_changed(self, entry, value):
|
|
72
|
+
"""New SN given. Ask in PDB,"""
|
|
73
|
+
if len(value) <= 0:
|
|
74
|
+
return None
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
obj = ITkDButils.get_DB_component(self.session, value)
|
|
78
|
+
if obj is not None:
|
|
79
|
+
entry.set_text(obj["serialNumber"])
|
|
80
|
+
self.alternativeID = obj["alternativeIdentifier"]
|
|
81
|
+
|
|
82
|
+
else:
|
|
83
|
+
dbGtkUtils.complain("Invalid SN", value)
|
|
84
|
+
|
|
85
|
+
def query_db(self, *args):
|
|
86
|
+
"""Search petal and bustapes."""
|
|
87
|
+
SN = self.SN.get_text()
|
|
88
|
+
if SN is None or len(SN)==0:
|
|
89
|
+
dbGtkUtils.complain("Invalid Serial Number", "Wrong value: {}".format(SN))
|
|
90
|
+
return
|
|
91
|
+
|
|
92
|
+
self.outDB = CheckBTtests.BTreport(self.session, SN, complain_func=dbGtkUtils.complain)
|
|
93
|
+
|
|
94
|
+
if self.outDB is None:
|
|
95
|
+
dbGtkUtils.complain("Could not get he report.")
|
|
96
|
+
|
|
97
|
+
def show_test_gui(self, *args):
|
|
98
|
+
"""Show test data."""
|
|
99
|
+
if self.outDB is None:
|
|
100
|
+
return
|
|
101
|
+
|
|
102
|
+
values, rc = dbGtkUtils.DictDialog.create_json_data_editor(self.outDB)
|
|
103
|
+
if rc == Gtk.ResponseType.OK:
|
|
104
|
+
self.outDB = values
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def upload_test_gui(self, *args):
|
|
108
|
+
"""Uploads test and attachments."""
|
|
109
|
+
pass
|
|
110
|
+
|
|
111
|
+
def main():
|
|
112
|
+
# ITk PDB authentication
|
|
113
|
+
dlg = None
|
|
114
|
+
try:
|
|
115
|
+
# We use here the Gtk GUI
|
|
116
|
+
dlg = ITkDBlogin.ITkDBlogin()
|
|
117
|
+
client = dlg.get_client()
|
|
118
|
+
|
|
119
|
+
except Exception:
|
|
120
|
+
# Login with "standard" if the above fails.
|
|
121
|
+
client = itkdb.Client()
|
|
122
|
+
client.user._access_code1 = getpass.getpass("Access 1: ")
|
|
123
|
+
client.user._access_code2 = getpass.getpass("Access 2: ")
|
|
124
|
+
client.user.authenticate()
|
|
125
|
+
print("Hello {} !".format(client.user.name))
|
|
126
|
+
|
|
127
|
+
BT = BusTapeReport(client, title="Bustape Report")
|
|
128
|
+
BT.write_message("Welcome !!\n")
|
|
129
|
+
BT.connect("destroy", Gtk.main_quit)
|
|
130
|
+
BT.show_all()
|
|
131
|
+
|
|
132
|
+
try:
|
|
133
|
+
Gtk.main()
|
|
134
|
+
except KeyboardInterrupt:
|
|
135
|
+
print("Arrrgggg!!!")
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
dlg.die()
|
|
139
|
+
|
|
140
|
+
except Exception:
|
|
141
|
+
print("Bye !")
|
|
142
|
+
|
|
143
|
+
if __name__ == "__main__":
|
|
144
|
+
main()
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""petal_qc python module."""
|
|
2
|
+
__version__ = "0.0.0"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def coreMetrology():
|
|
6
|
+
"""Launches the Core metrology analysis ahd PDB script."""
|
|
7
|
+
from .metrology.coreMetrology import main
|
|
8
|
+
main()
|
|
9
|
+
|
|
10
|
+
def bustapeReport():
|
|
11
|
+
"""Launches the Core metrology analysis ahd PDB script."""
|
|
12
|
+
from .BTreport.bustapeReport import main
|
|
13
|
+
main()
|
|
14
|
+
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Find point clisters."""
|
|
2
|
+
import math
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Cluster(object):
|
|
8
|
+
"""A cluster."""
|
|
9
|
+
|
|
10
|
+
def __init__(self, x=0, y=0, z=0):
|
|
11
|
+
"""Initialize the cluster."""
|
|
12
|
+
self.x = x
|
|
13
|
+
self.y = y
|
|
14
|
+
self.z = z
|
|
15
|
+
self.N = 0.0
|
|
16
|
+
self.points = []
|
|
17
|
+
self.xtra = []
|
|
18
|
+
|
|
19
|
+
def add(self, P, xtra=None):
|
|
20
|
+
"""Add a new point."""
|
|
21
|
+
N = self.N + 1.0
|
|
22
|
+
self.x = (self.x * self.N + P[0])/N
|
|
23
|
+
self.y = (self.y * self.N + P[1])/N
|
|
24
|
+
try:
|
|
25
|
+
self.z = (self.z * self.N + P[2])/N
|
|
26
|
+
|
|
27
|
+
except IndexError:
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
self.N += 1.0
|
|
31
|
+
self.points.append(P)
|
|
32
|
+
self.xtra.append(xtra)
|
|
33
|
+
|
|
34
|
+
def get_points(self):
|
|
35
|
+
"""Return the array of points."""
|
|
36
|
+
return np.array(self.points)
|
|
37
|
+
|
|
38
|
+
def distance(self, P):
|
|
39
|
+
"""Compute distance to Point."""
|
|
40
|
+
dist = math.sqrt((self.x-P[0])**2 + (self.y-P[1])**2)
|
|
41
|
+
return dist
|
|
42
|
+
|
|
43
|
+
def __lt__(self, other):
|
|
44
|
+
"""Sort two clusters.
|
|
45
|
+
|
|
46
|
+
A cluster is smaller if has smaller Y.
|
|
47
|
+
"""
|
|
48
|
+
return self.y < other.y
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def cluster_points(points, distance):
|
|
52
|
+
"""Cluster Points.
|
|
53
|
+
|
|
54
|
+
Group the points in clusters formed by points whose
|
|
55
|
+
distance is smaller than distance
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
----
|
|
59
|
+
points (list): list of points in the for [x, y, z] or equivalent
|
|
60
|
+
distance (float): distance.
|
|
61
|
+
|
|
62
|
+
Returns
|
|
63
|
+
-------
|
|
64
|
+
list: List of Clusters
|
|
65
|
+
|
|
66
|
+
"""
|
|
67
|
+
# Cluster points which are closer than distance.
|
|
68
|
+
clusters = []
|
|
69
|
+
for ipoint, P in enumerate(points):
|
|
70
|
+
if np.isnan(P[0]) or np.isnan(P[1]):
|
|
71
|
+
continue
|
|
72
|
+
|
|
73
|
+
dist_min = 1e9
|
|
74
|
+
clst_min = -1
|
|
75
|
+
for iclst, C in enumerate(clusters):
|
|
76
|
+
dist = C.distance(P)
|
|
77
|
+
if dist < dist_min:
|
|
78
|
+
clst_min = iclst
|
|
79
|
+
dist_min = dist
|
|
80
|
+
|
|
81
|
+
if clst_min < 0 or dist_min > distance:
|
|
82
|
+
C = Cluster()
|
|
83
|
+
C.add(P, ipoint)
|
|
84
|
+
clusters.append(C)
|
|
85
|
+
|
|
86
|
+
else:
|
|
87
|
+
clusters[clst_min].add(P, ipoint)
|
|
88
|
+
|
|
89
|
+
clusters.sort(key=lambda x: x.N, reverse=True)
|
|
90
|
+
return clusters
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Gets the Metrology data from a file."""
|
|
2
|
+
from tempfile import NamedTemporaryFile
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from .convert_mitutoyo import mitutoyo2cvs
|
|
7
|
+
from .convert_smartscope import read_smartscope
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def read(fname, label='\\w+', type="Punto", keep=False):
|
|
11
|
+
"""Read a file.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
----
|
|
15
|
+
fname: The file name
|
|
16
|
+
label: the label for an mitutyyo file
|
|
17
|
+
type: the entry type in a mitutoyo file
|
|
18
|
+
keep: if true keeps the label
|
|
19
|
+
"""
|
|
20
|
+
try:
|
|
21
|
+
data = np.loadtxt(fname, unpack=False, skiprows=1, delimiter=',')
|
|
22
|
+
|
|
23
|
+
except FileNotFoundError:
|
|
24
|
+
print("Input file not found.")
|
|
25
|
+
return None
|
|
26
|
+
|
|
27
|
+
except Exception:
|
|
28
|
+
# This might be CMM file
|
|
29
|
+
is_mitutoyo = False
|
|
30
|
+
with open(fname, 'r', encoding='cp1252') as fin:
|
|
31
|
+
for line in fin:
|
|
32
|
+
if 'Elemento' in line:
|
|
33
|
+
is_mitutoyo = True
|
|
34
|
+
break
|
|
35
|
+
elif 'Quality Vision' in line:
|
|
36
|
+
is_mitutoyo = False
|
|
37
|
+
break
|
|
38
|
+
|
|
39
|
+
ofile = NamedTemporaryFile()
|
|
40
|
+
if is_mitutoyo:
|
|
41
|
+
mitutoyo2cvs([fname], ofile.name, label=label, data_type=type, keep=keep)
|
|
42
|
+
else:
|
|
43
|
+
read_smartscope(fname, ofile.name, label, keep=keep)
|
|
44
|
+
|
|
45
|
+
data = np.loadtxt(ofile.name, unpack=False, skiprows=1, delimiter=',')
|
|
46
|
+
|
|
47
|
+
return data
|