petal-qc 0.0.4__py3-none-any.whl → 0.0.5__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.

@@ -19,6 +19,7 @@ import datetime
19
19
  import dateutil.parser
20
20
  import itkdb
21
21
  from itkdb_gtk import ITkDBlogin
22
+ from itkdb_gtk import ITkDButils
22
23
 
23
24
  def complain(main_msg, secondary_msg=None):
24
25
  """Prints an error message
@@ -34,42 +35,6 @@ def complain(main_msg, secondary_msg=None):
34
35
  print("\t{}".format(msg))
35
36
 
36
37
 
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
38
  def get_type(child):
74
39
  """Return object type
75
40
 
@@ -143,7 +108,10 @@ def find_but_tape_tests(session, petal_date, bt_sn, complain_func=complain):
143
108
  dict: dict with all tests. key is the test type code.
144
109
 
145
110
  """
146
- test_list = session.get("listTestRunsByComponent", json={"component": bt_sn, "stage": "COMPLETED"})
111
+ test_list = session.get("listTestRunsByComponent",
112
+ json={"filterMap":{"serialNumber": bt_sn,
113
+ "stage": "COMPLETED"}
114
+ })
147
115
  bt_tests = {}
148
116
  for tst in test_list:
149
117
  test_type = tst["testType"]["name"]
@@ -187,13 +155,13 @@ def BTreport(session, SerialN, complain_func=complain):
187
155
  SerialN (str): The Petal core SB
188
156
  """
189
157
  # get petal frm DB.
190
- try:
191
- petal = find_petal(session, SerialN, complain_func=complain_func)
192
-
193
- except Exception as ex:
194
- print(str(ex))
158
+ petal = ITkDButils.get_DB_component(session, SerialN)
159
+ if petal is None:
160
+ complain_func(SerialN, "Could not find petal core.")
195
161
  return None
196
162
 
163
+ SerialN = petal["serialNumber"]
164
+
197
165
  print("+++ Petal core {} [{}]".format(SerialN, petal["alternativeIdentifier"]))
198
166
  petal_date = dateutil.parser.parse(petal["stateTs"])
199
167
  comp_type = get_type(petal)
@@ -291,7 +259,7 @@ def main():
291
259
  try:
292
260
  SN = sys.argv[1]
293
261
  except IndexError:
294
- print("I need a petal core SN")
262
+ print("I need a petal core SN or AlternativeID")
295
263
  sys.exit()
296
264
 
297
265
  # ITk PDB authentication
@@ -314,8 +282,11 @@ def main():
314
282
  out = BTreport(client, SN)
315
283
  # Upload test
316
284
  if out:
317
- db_response = client.post("uploadTestRunResults", json=out)
318
- print(json.dumps(db_response, indent=3))
285
+ try:
286
+ db_response = client.post("uploadTestRunResults", json=out)
287
+ except Exception as ex:
288
+ print("Could not upload test.")
289
+ print(ex)
319
290
 
320
291
 
321
292
  except Exception:
petal_qc/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
1
  """petal_qc python module."""
2
- __version__ = "0.0.4"
2
+ __version__ = "0.0.5"
3
3
 
4
4
 
5
5
  def coreMetrology():
@@ -7,14 +7,23 @@ def coreMetrology():
7
7
  from .metrology.coreMetrology import main
8
8
  main()
9
9
 
10
+ def doMetrology():
11
+ """Launches the Core metrology analysis in the command line."""
12
+ from .metrology.do_metrology import main
13
+ main()
14
+
10
15
  def coreThermal():
11
16
  """Launches the Core thermal analysis ahd PDB script."""
12
17
  from .thermal.coreThermal import main
13
18
  main()
14
19
 
15
-
16
20
  def bustapeReport():
17
21
  """Launches the Core metrology analysis ahd PDB script."""
18
- from .BTreport.bustapeReport import main
22
+ from .BTreport.CheckBTtests import main
23
+ # from .BTreport.bustapeReport import main
19
24
  main()
20
25
 
26
+ def dashBoard():
27
+ """Launches the Core thermal analysis ahd PDB script."""
28
+ from .dashBoard import main
29
+ main()
petal_qc/dashBoard.py CHANGED
@@ -6,16 +6,123 @@ try:
6
6
 
7
7
  except ImportError:
8
8
  from pathlib import Path
9
- cwd = Path(__file__).parent.parent
9
+ cwd = Path(__file__).parent
10
10
  sys.path.append(cwd.as_posix())
11
-
11
+
12
+ from petal_qc.metrology.coreMetrology import CoreMetrology, CoreMetrologyOptions
13
+ from petal_qc.thermal.coreThermal import CoreThermal
14
+ from petal_qc.thermal.IRPetalParam import IRPetalParam
15
+
12
16
  from itkdb_gtk import dbGtkUtils
13
- from itkdb_gtk import GetShipments
14
- from itkdb_gtk import PetalReceptionTests
15
17
  from itkdb_gtk import ITkDBlogin
16
- from itkdb_gtk import CreateShipments
17
- from itkdb_gtk import UploadTest
18
- from itkdb_gtk import UploadMultipleTests
19
- from itkdb_gtk import GlueWeight
20
- from itkdb_gtk import UploadModuleIV
21
- from itkdb_gtk import WireBondGui
18
+
19
+ import gi
20
+
21
+ gi.require_version("Gtk", "3.0")
22
+ from gi.repository import Gtk
23
+
24
+ HELP_LINK="https://petal-qc.docs.cern.ch"
25
+
26
+ class DashWindow(dbGtkUtils.ITkDBWindow):
27
+ """Dashboard class."""
28
+ PETAL_CORE_METRO = 1
29
+ PETAL_CORE_THERMAL = 2
30
+
31
+
32
+ def __init__(self, session):
33
+ """Initialization."""
34
+ super().__init__(title="Petal-QC Dashboard", session=session, help_link=HELP_LINK)
35
+ self.mask = 0
36
+
37
+ # set border width
38
+ self.set_border_width(10)
39
+
40
+ # Prepare dashboard
41
+ grid = Gtk.Grid(column_spacing=5, row_spacing=5)
42
+ self.mainBox.pack_start(grid, False, True, 5)
43
+
44
+ irow = 0
45
+ lbl = Gtk.Label()
46
+ lbl.set_markup("<b>Tests</b>")
47
+ lbl.set_xalign(0)
48
+ grid.attach(lbl, 0, irow, 1, 1)
49
+
50
+ irow += 1
51
+ btnPetalMetrology = Gtk.Button(label="Petal Core Metrology")
52
+ btnPetalMetrology.connect("clicked", self.petal_metrology)
53
+ grid.attach(btnPetalMetrology, 0, irow, 1, 1)
54
+
55
+ btnPetalThermal = Gtk.Button(label="Petal Core Thermal")
56
+ btnPetalThermal.connect("clicked", self.petal_thermal)
57
+ grid.attach(btnPetalThermal, 1, irow, 1, 1)
58
+
59
+
60
+ irow += 1
61
+ grid.attach(Gtk.Label(), 0, irow, 1, 1)
62
+
63
+ self.mainBox.pack_start(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL), False, True, 5)
64
+
65
+ self.show_all()
66
+
67
+
68
+ def petal_metrology(self, *args):
69
+ """Do petal metrology"""
70
+ bitn = DashWindow.PETAL_CORE_METRO
71
+ bt = 1 << bitn
72
+ if self.mask & bt:
73
+ return
74
+
75
+ self.mask |= bt
76
+ opts = CoreMetrologyOptions()
77
+ W = CoreMetrology(opts, session=self.session, title="Petal Core Metrology")
78
+ W.connect("destroy", self.app_closed, bitn)
79
+ W.show_all()
80
+
81
+ def petal_thermal(self, *args):
82
+ """Do petal thermal."""
83
+ bitn = DashWindow.PETAL_CORE_THERMAL
84
+ bt = 1 << bitn
85
+ if self.mask & bt:
86
+ return
87
+
88
+ self.mask |= bt
89
+ opt = IRPetalParam()
90
+ opt.folder = None
91
+ opt.out = None
92
+ opt.alias = None
93
+ opt.SN = None
94
+ W = CoreThermal(opt, self.session, title="Petal Thermal Test.")
95
+ W.connect("destroy", self.app_closed, bitn)
96
+ W.show_all()
97
+
98
+ def app_closed(self, *args):
99
+ """Application window closed. Clear mask."""
100
+ bt = 1 << args[1]
101
+ self.mask &= ~bt
102
+ # print(bt, self.mask)
103
+
104
+ def main():
105
+ """Main entry"""
106
+ # DB login
107
+ dlg = ITkDBlogin.ITkDBlogin()
108
+ client = dlg.get_client()
109
+ if client is None:
110
+ print("Could not connect to DB with provided credentials.")
111
+ dlg.die()
112
+ sys.exit()
113
+
114
+ client.user_gui = dlg
115
+
116
+ dashW = DashWindow(client)
117
+ dashW.connect("destroy", Gtk.main_quit)
118
+ try:
119
+ Gtk.main()
120
+
121
+ except KeyboardInterrupt:
122
+ print("Arrrgggg!!!")
123
+
124
+ dlg.die()
125
+
126
+
127
+ if __name__ == "__main__":
128
+ main()
@@ -4,6 +4,8 @@ import io
4
4
  import json
5
5
  import sys
6
6
  import traceback
7
+ from tempfile import NamedTemporaryFile
8
+
7
9
  from argparse import Action
8
10
  from argparse import ArgumentParser
9
11
  from datetime import datetime
@@ -19,6 +21,7 @@ from petal_qc.metrology import DataFile
19
21
  from petal_qc.metrology.analyze_locking_points import analyze_locking_point_data
20
22
  from petal_qc.metrology.analyze_locking_points import locking_point_positions
21
23
  from petal_qc.metrology.convert_mitutoyo import mitutoyo2cvs
24
+ from petal_qc.metrology.convert_smartscope import get_smarscope_locator_positions
22
25
  from petal_qc.metrology.petal_flatness import petal_flatness
23
26
 
24
27
 
@@ -46,11 +49,11 @@ def check_spec(val, nom, fraction=0.0):
46
49
  class CommaSeparatedListAction(Action):
47
50
  """Create a list from the comma sepparated numbers at imput."""
48
51
 
49
- def __call__(self, parser, namespace, values, option_string=None):
52
+ def __call__(self, args_parser, namespace, values, option_string=None):
50
53
  """The actual action."""
51
54
  value = np.array(list(map(float, values.split(','))), dtype='float64')
52
55
  if value.shape[0] < 3:
53
- raise Exception("{} needs a 3D vector".format(self.dest))
56
+ raise ValueError("{} needs a 3D vector".format(self.dest))
54
57
 
55
58
  setattr(namespace, self.dest, value)
56
59
 
@@ -59,12 +62,10 @@ def petal_metrology(ifile, options):
59
62
  """Do the analysis of the petal metrology data.
60
63
 
61
64
  Args:
62
- ----
63
65
  ifile: Input file from Mitutoyo.
64
66
  options: Command line options.
65
67
 
66
68
  Return
67
- ------
68
69
  Dictionary with DB values
69
70
 
70
71
  """
@@ -111,7 +112,8 @@ def petal_metrology(ifile, options):
111
112
  "PARALLELISM": 0,
112
113
  "CHECK_BOT_LOC_DIAM": True,
113
114
  "CHECK_SLOT_LOC_DIAM": True,
114
- "CHECK_OVERSIZE_LOC_DIAM": True
115
+ "CHECK_OVERSIZE_LOC_DIAM": True,
116
+ "DIAM": {"FD01": 0., "FD02":0, "PL01":0, "PL02":0, "PL03":0}
115
117
  }
116
118
 
117
119
  # Open the output doc.
@@ -152,7 +154,7 @@ def petal_metrology(ifile, options):
152
154
  # Do locator flatness analysis
153
155
  TM = None # TODO: fix this
154
156
  if options.desy:
155
- locator_data = DataFile.read(ifile, ".*_FineFlatness")
157
+ locator_data = DataFile.read(ifile, "PL[0-9]+_Plane") #".*_FineFlatness")
156
158
  else:
157
159
  locator_data = DataFile.read(ifile, "PuntoLocator", "Punto")
158
160
  locator_data[:, 2] -= Fmean
@@ -179,8 +181,8 @@ def petal_metrology(ifile, options):
179
181
  dbOut["comments"].append("Offset of locator plane w.r.t BT is {:.3f} mm".format(val))
180
182
 
181
183
  # Analyze locking point positions
184
+ ofile = io.StringIO()
182
185
  if not options.desy:
183
- ofile = io.StringIO()
184
186
  mitutoyo2cvs([ifile], ofile,
185
187
  label=r"agujero_inf|Locator\w*|Slot\w+|Fiducial\w+",
186
188
  data_type="Círculo|Punto",
@@ -190,61 +192,85 @@ def petal_metrology(ifile, options):
190
192
  tbl = pd.read_csv(ofile, names=["X", "Y", "Z", "D", "R", "C", "Name"], sep=',', skiprows=1, index_col="Name")
191
193
  print(tbl)
192
194
 
193
- keywords = [n for n in tbl.index]
195
+ # keywords = [n for n in tbl.index]
194
196
  # if "FiducialBot" in keywords:
195
197
  # indx = ["agujero_inf", "LocatorTop", "FiducialBot", "FiducialTop"]
196
198
  # offset = 0
197
199
  # else:
198
200
  # indx = ["LocatorBot", "LocatorTop", "agujero_inf", "FiducialTop"]
199
201
  # offset = 3
200
-
202
+
201
203
  indx = ["LocatorBot", "LocatorTop", "agujero_inf", "FiducialTop"]
202
204
  offset = 3
203
-
204
205
 
206
+ # Compute Slot center (get average of diameter)
205
207
  slot_center = np.mean(tbl.loc[["SlotSup", "SlotInf"]][["X", "Y", "D"]].values, axis=0)
206
208
 
207
209
  print("")
208
210
  print()
209
211
  print(tbl.loc[indx][["X", "Y", "D"]])
210
- input = tbl.loc[indx][["X", "Y", "D"]].values
212
+ tvalues = tbl.loc[indx][["X", "Y", "D"]].values
211
213
 
212
- ninput = np.insert(input, 1, slot_center, axis=0)
214
+ ninput = np.insert(tvalues, 1, slot_center, axis=0)
215
+ ninput[:, 1] += offset
216
+
217
+ else:
218
+ get_smarscope_locator_positions(ifile, ofile, "\\w+(PL|_Fiducial)\\s+", keep=True)
219
+ ofile.seek(0)
220
+ tbl = pd.read_csv(ofile, names=["X", "Y", "D", "Name"], sep=',', skiprows=1, index_col="Name")
221
+ print("")
222
+ print()
223
+ print(tbl)
224
+ ninput = tbl[["X", "Y", "D"]].values
225
+ offset = 3
213
226
  ninput[:, 1] += offset
214
- out = locking_point_positions(ninput, document)
215
- for key, val in out.items():
216
- results[key] = val
217
- if key == "LOCATION_DELTA":
218
- for k, v in val.items():
219
- delta = np.linalg.norm(v)
220
- if not check_spec(delta, 0.050):
221
- dbOut["defects"].append({
222
- "name": key,
223
- "description": "Delta {} is {:.3f} mm > 0.050 mm.".format(k, delta)
224
- })
225
-
226
- elif key == "REL_POS_DELTA":
227
- for k, v in val.items():
228
- delta = np.linalg.norm(v)
229
- if not check_spec(delta, 0.025):
230
- dbOut["defects"].append({
231
- "name": key,
232
- "description": "Delta {} is {:.3f} mm > 0.025 mm.".format(k, delta)
233
- })
234
-
235
- elif "CHECK_" in key:
236
- if "OVERSIZE" in key:
237
- if not check_spec(abs(val), 0.050):
238
- dbOut["defects"].append({
239
- "name": key,
240
- "description": "LOC DIAM delta is {:.3f} mm > 0.025 mm.".format(abs(val))
241
- })
242
- else:
243
- if val < 0 or val > 0.012:
244
- dbOut["defects"].append({
245
- "name": key,
246
- "description": "LOC DIAM is not H7 0 <= {:.3f} <= 0.012 mm.".format(val)
247
- })
227
+
228
+ # Input array is
229
+ # 0 - Bottom locator (PL01)
230
+ # 1 - Top Slot (PL02)
231
+ # 2 - Oversized (PL03)
232
+ # 3 - Bottom Fid (FD01)
233
+ # 4 - Top Fid (FD02)
234
+ results["DIAM"]["FD01"] = ninput[3, 2]
235
+ results["DIAM"]["FD02"] = ninput[4, 2]
236
+ results["DIAM"]["PL01"] = ninput[0, 2]
237
+ results["DIAM"]["PL02"] = ninput[1, 2]
238
+ results["DIAM"]["PL03"] = ninput[2, 2]
239
+
240
+ out = locking_point_positions(ninput, document)
241
+ for key, val in out.items():
242
+ results[key] = val
243
+ if key == "LOCATION_DELTA":
244
+ for k, v in val.items():
245
+ delta = np.linalg.norm(v)
246
+ if not check_spec(delta, 0.050):
247
+ dbOut["defects"].append({
248
+ "name": key,
249
+ "description": "Delta {} is {:.3f} mm > 0.050 mm.".format(k, delta)
250
+ })
251
+
252
+ elif key == "REL_POS_DELTA":
253
+ for k, v in val.items():
254
+ delta = np.linalg.norm(v)
255
+ if not check_spec(delta, 0.025):
256
+ dbOut["defects"].append({
257
+ "name": key,
258
+ "description": "Delta {} is {:.3f} mm > 0.025 mm.".format(k, delta)
259
+ })
260
+
261
+ elif "CHECK_" in key:
262
+ if "OVERSIZE" in key:
263
+ if not check_spec(abs(val), 0.050):
264
+ dbOut["defects"].append({
265
+ "name": key,
266
+ "description": "LOC DIAM delta is {:.3f} mm > 0.025 mm.".format(abs(val))
267
+ })
268
+ else:
269
+ if val < 0 or val > 0.012:
270
+ dbOut["defects"].append({
271
+ "name": key,
272
+ "description": "LOC DIAM is not H7 0 <= {:.3f} <= 0.012 mm.".format(val)
273
+ })
248
274
 
249
275
  ofile.close()
250
276
 
@@ -282,8 +308,8 @@ def petal_metrology(ifile, options):
282
308
 
283
309
  return dbOut
284
310
 
285
-
286
- if __name__ == "__main__":
311
+ def do_petal_metrology():
312
+ """main entry."""
287
313
  parser = ArgumentParser()
288
314
  parser.add_argument('files', nargs='*', help="Input files")
289
315
  parser.add_argument("--SN", default="SNxxxx", help="Petal core serial nunber")
@@ -309,19 +335,34 @@ if __name__ == "__main__":
309
335
  parser.add_argument("--label", default="\\w+", help="The label to select")
310
336
  parser.add_argument("--type", default="Punto", help="The class to select")
311
337
 
312
- options = parser.parse_args()
313
- if len(options.files) == 0:
338
+ args = parser.parse_args()
339
+ if len(args.files) == 0:
314
340
  print(sys.argv[0])
315
341
  print("I need an input file")
316
342
  sys.exit()
317
343
 
344
+ if len(args.files) == 1:
345
+ ifile = args.files[0]
346
+ else:
347
+ ifnam = NamedTemporaryFile(delete_on_close=False)
348
+ ifile = ifnam.name
349
+ for ff in args.files:
350
+ with open(ff, 'rb') as F:
351
+ ifnam.write(F.read())
352
+
353
+ ifnam.close()
354
+
355
+
318
356
  try:
319
- outDB = petal_metrology(options.files[0], options)
320
- ofile = output_folder(options.folder, options.prefix + '.json')
321
- with open(ofile, 'w') as of:
357
+ outDB = petal_metrology(ifile, args)
358
+ ofile = output_folder(args.folder, args.prefix + '.json')
359
+ with open(ofile, 'w', encoding="UTF-8") as of:
322
360
  json.dump(outDB, of)
323
361
 
324
362
  except Exception:
325
363
  print(traceback.format_exc())
326
364
 
327
365
  plt.show()
366
+
367
+ if __name__ == "__main__":
368
+ do_petal_metrology()
@@ -14,7 +14,7 @@ import petal_qc.utils.docx_utils as docx_utils
14
14
  from petal_qc.metrology import DataFile
15
15
  from petal_qc.metrology.Cluster import cluster_points
16
16
  from petal_qc.utils.Geometry import fit_plane
17
- from petal_qc.utils.Geometry import flatness_conhull
17
+ from petal_qc.utils.Geometry import flatness_conhull, flatness_LSPL
18
18
  from petal_qc.utils.Geometry import project_to_plane
19
19
  from petal_qc.utils.Geometry import vector_angle
20
20
  from petal_qc.utils.utils import get_min_max
@@ -400,15 +400,15 @@ def analyze_locking_point_data(orig_data, nbins=50, plane_fit=True, cut=3, docum
400
400
  print("{:7.3f} {:7.3f} {:7.3f}".format(C.x, C.y, C.z))
401
401
 
402
402
  if len(good):
403
- flatness = flatness_conhull(plane[good, :])
404
- print("Locking point flatness: {:.1f}".format(1000*flatness))
403
+ flatness = flatness_LSPL(plane[good, :])
404
+ print("Locking point flatness (LSPL): {:.1f}".format(1000*flatness))
405
405
  else:
406
406
  print("Not enough points to compute flatness.")
407
407
  flatness = -1.e-3
408
408
 
409
409
  outDB["COPLANARITY_LOCATORS"] = flatness
410
410
  if document:
411
- document.add_paragraph("Locking point flatness (convex hull): {:.1f} µm.".format(1000*flatness))
411
+ document.add_paragraph("Locking point flatness (LSPL): {:.1f} µm.".format(1000*flatness))
412
412
 
413
413
  # Show all data
414
414
  fig = show_data(plane[good, :], "All", nbins=nbins, color_bar=True)