petal-qc 0.0.0__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.

Files changed (51) hide show
  1. petal_qc/BTreport/CheckBTtests.py +321 -0
  2. petal_qc/BTreport/__init__.py +0 -0
  3. petal_qc/BTreport/bustapeReport.py +144 -0
  4. petal_qc/__init__.py +14 -0
  5. petal_qc/metrology/Cluster.py +90 -0
  6. petal_qc/metrology/DataFile.py +47 -0
  7. petal_qc/metrology/PetalMetrology.py +327 -0
  8. petal_qc/metrology/__init__.py +0 -0
  9. petal_qc/metrology/all2csv.py +57 -0
  10. petal_qc/metrology/analyze_locking_points.py +597 -0
  11. petal_qc/metrology/cold_noise.py +106 -0
  12. petal_qc/metrology/comparisonTable.py +59 -0
  13. petal_qc/metrology/convert_mitutoyo.py +175 -0
  14. petal_qc/metrology/convert_smartscope.py +145 -0
  15. petal_qc/metrology/coreMetrology.py +402 -0
  16. petal_qc/metrology/data2csv.py +63 -0
  17. petal_qc/metrology/do_Metrology.py +117 -0
  18. petal_qc/metrology/flatness4nigel.py +157 -0
  19. petal_qc/metrology/gtkutils.py +120 -0
  20. petal_qc/metrology/petal_flatness.py +353 -0
  21. petal_qc/metrology/show_data_file.py +118 -0
  22. petal_qc/metrology/testSummary.py +37 -0
  23. petal_qc/metrology/test_paralelism.py +71 -0
  24. petal_qc/thermal/CSVImage.py +69 -0
  25. petal_qc/thermal/DebugPlot.py +76 -0
  26. petal_qc/thermal/IRBFile.py +768 -0
  27. petal_qc/thermal/IRCore.py +110 -0
  28. petal_qc/thermal/IRDataGetter.py +359 -0
  29. petal_qc/thermal/IRPetal.py +1338 -0
  30. petal_qc/thermal/IRPetalParam.py +71 -0
  31. petal_qc/thermal/PetalColorMaps.py +62 -0
  32. petal_qc/thermal/Petal_IR_Analysis.py +142 -0
  33. petal_qc/thermal/PipeFit.py +598 -0
  34. petal_qc/thermal/__init__.py +0 -0
  35. petal_qc/thermal/analyze_IRCore.py +417 -0
  36. petal_qc/thermal/contours.py +378 -0
  37. petal_qc/thermal/create_IRCore.py +185 -0
  38. petal_qc/thermal/pipe_read.py +182 -0
  39. petal_qc/thermal/show_IR_petal.py +420 -0
  40. petal_qc/utils/Geometry.py +756 -0
  41. petal_qc/utils/Progress.py +182 -0
  42. petal_qc/utils/__init__.py +0 -0
  43. petal_qc/utils/all_files.py +35 -0
  44. petal_qc/utils/docx_utils.py +186 -0
  45. petal_qc/utils/fit_utils.py +188 -0
  46. petal_qc/utils/utils.py +180 -0
  47. petal_qc-0.0.0.dist-info/METADATA +29 -0
  48. petal_qc-0.0.0.dist-info/RECORD +51 -0
  49. petal_qc-0.0.0.dist-info/WHEEL +5 -0
  50. petal_qc-0.0.0.dist-info/entry_points.txt +3 -0
  51. petal_qc-0.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,417 @@
1
+ #!/usr/bin/env python3
2
+ """Analyze the JS files generated by create_IRCore."""
3
+ import json
4
+ import os
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ import matplotlib.dates as pldates
9
+ import matplotlib.pyplot as plt
10
+ import matplotlib.ticker as ticker
11
+ import numpy as np
12
+ from scipy.interpolate import CubicSpline
13
+ from petal_qc.utils.utils import find_file
14
+ from petal_qc.utils.utils import output_folder
15
+
16
+ from petal_qc.thermal import IRCore
17
+ from petal_qc.thermal import Petal_IR_Analysis
18
+
19
+ CO2_Temp_setting = -35
20
+
21
+
22
+ def get_acceptance_band():
23
+ """returns the width of the acceptance band."""
24
+ band = 0.1*CO2_Temp_setting # 10% of setting point
25
+ return abs(band)
26
+
27
+
28
+ def get_names(files):
29
+ """GEt names from filenames."""
30
+ names = []
31
+ for ifile in files:
32
+ ifile = Path(ifile)
33
+ names.append(ifile.stem)
34
+ return names
35
+
36
+
37
+ class GoldenAxis(object):
38
+ """Get best X path."""
39
+ def __init__(self) -> None:
40
+ self.xaxis = [] # Set of coordinates
41
+ self.nitems = [] # number of curves with this axis
42
+ self.index = []
43
+ self.size = []
44
+ self.current = 0
45
+
46
+ @staticmethod
47
+ def round_npts(V):
48
+ """Return the closest multiple of 10."""
49
+ npts = len(V)
50
+ return int(int(npts/10.0 + 0.5)*10)
51
+
52
+ def check_axis(self, X, indx):
53
+ """Check in X array is there or not.
54
+
55
+ Args:
56
+ X (np.ndarray): The axis to check.
57
+ i (int): the index in the array of results.
58
+
59
+ """
60
+ npts = self.round_npts(X)
61
+ for i, v in enumerate(self.xaxis):
62
+ nv = self.size[i]
63
+ if npts == nv:
64
+ self.nitems[i] += 1
65
+ self.index[i].append(indx)
66
+ return
67
+
68
+ self.xaxis.append(X)
69
+ self.size.append(npts)
70
+ self.nitems.append(1)
71
+ self.index.append([indx])
72
+
73
+ def get_axis(self):
74
+ """Get the actual axis."""
75
+ imax = -1
76
+ indx = -1
77
+ for i, n in enumerate(self.nitems):
78
+ if n > imax:
79
+ imax = n
80
+ indx = i
81
+
82
+ return np.linspace(0., 1.0, num=self.size[indx])
83
+
84
+
85
+ def compute_average(values):
86
+ """Compute the mean of arrays in input."""
87
+ data = np.zeros([len(values), len(values[0])])
88
+ for i, V in enumerate(values):
89
+ data[i, :] = V
90
+
91
+ avg = np.mean(data, axis=0)
92
+ return avg
93
+
94
+
95
+ def create_golden_average(files, options):
96
+ """Create golden average.
97
+
98
+ Args:
99
+ ----
100
+ files (list): List of input files
101
+ options: other options.
102
+
103
+ """
104
+ names = get_names(files)
105
+ result_list = []
106
+ # Create the axes
107
+ axes = [GoldenAxis() for i in range(2)]
108
+
109
+ # Get the Xaxis.
110
+ # Will be the linspace between 0 and 1 with the most repeated
111
+ # number of points.
112
+ for i, ifile in enumerate(files):
113
+ ifile = find_file(options.folder, ifile)
114
+ if not ifile.exists():
115
+ print("+++ File {} does not exist.".format(ifile))
116
+ continue
117
+
118
+ alias = names[i]
119
+ result = IRCore.IRCore.read_json(ifile)
120
+ if result.aliasID is None or result.aliasID == "":
121
+ result.aliasID = names[i]
122
+
123
+ result_list.append(result)
124
+
125
+ # Loop to get best axis
126
+ R = result.results
127
+ for iside in range(2):
128
+ the_axis = R[iside].path_length
129
+ axes[iside].check_axis(the_axis, i)
130
+
131
+ # Prepare the results for the golden average.
132
+ xvalues = [axes[i].get_axis() for i in range(2)]
133
+ for i, R in enumerate(result_list):
134
+ R.golden = []
135
+ for iside in range(2):
136
+ G = Petal_IR_Analysis.AnalysisResult()
137
+ splnT = CubicSpline(R.results[iside].path_length, R.results[iside].path_temp)
138
+ splnS = CubicSpline(R.results[iside].path_length, R.results[iside].path_spread)
139
+ G.path_length = xvalues[iside]
140
+ G.path_temp = np.array([splnT(x) for x in G.path_length])
141
+ G.path_spread = np.array([splnS(x) for x in G.path_length])
142
+ G.sensor_avg = np.array(R.results[iside].sensor_avg)
143
+ G.sensor_std = np.array(R.results[iside].sensor_std)
144
+ R.golden.append(G)
145
+
146
+ if options.debug:
147
+ fig, ax = plt.subplots(2, 1, tight_layout=True)
148
+ fig.suptitle(R.aliasID)
149
+ for i in range(2):
150
+ ax[i].plot(R.results[i].path_length, R.results[i].path_temp, label="original")
151
+ ax[i].plot(R.golden[i].path_length, R.golden[i].path_temp, label="golden")
152
+ ax[i].legend()
153
+
154
+ # Create the golden object
155
+ golden = [Petal_IR_Analysis.AnalysisResult() for i in range(2)]
156
+ for i, G in enumerate(golden):
157
+ G.path_length = xvalues[i]
158
+ G.path_temp = compute_average([R.golden[i].path_temp for R in result_list])
159
+ G.path_spread = compute_average([R.golden[i].path_spread for R in result_list])
160
+ G.sensor_avg = compute_average([R.golden[i].sensor_avg for R in result_list])
161
+ G.sensor_std = compute_average([R.golden[i].sensor_std for R in result_list])
162
+
163
+ return golden, result_list
164
+
165
+
166
+ def show_golden_average(golden, results, value):
167
+ """Create golden average.
168
+
169
+ Args:
170
+ ----
171
+ golden: golden values (from create_golgen_average)
172
+ resuls: results from create_golden_average
173
+ value: value to show, ej path_temp, path_spread, sensor_avg, sensor_std
174
+
175
+ """
176
+ tick_labels = ["R0", "R1", "R2", "R3", "R3", "R4", "R4", "R5", "R5", "EoS"]
177
+
178
+ factor = 1.0
179
+ if value.find("sensor") >= 0:
180
+ factor = 2.0
181
+
182
+ # Get acceptance band
183
+ band = get_acceptance_band()
184
+
185
+ for iside in range(2):
186
+ fig, ax = plt.subplots(2, 1, tight_layout=True, gridspec_kw={'height_ratios': (0.66, 0.34)}, figsize=(7, 6))
187
+ fig.suptitle("Golden average for {} - side {}.".format(value, iside))
188
+ for a in ax:
189
+ a.grid()
190
+
191
+ if value.find("path") < 0:
192
+ for i in range(2):
193
+ ax[i].set_xticks(range(10), labels=tick_labels)
194
+
195
+ for R in results:
196
+ RS = R.results[iside]
197
+ Y = getattr(RS, value)
198
+ gY = getattr(golden[iside], value)
199
+ O = getattr(R.golden[iside], value) - gY
200
+ if value.find("path") >= 0:
201
+ X = RS.path_length
202
+ gX = golden[iside].path_length
203
+
204
+ else:
205
+ X = np.array([float(x) for x in range(10)])
206
+ gX = X
207
+
208
+ ax[0].plot(X, Y, '-', label=R.aliasID, linewidth=1)
209
+ ax[1].plot(gX, O, '-', label=R.aliasID, linewidth=1)
210
+
211
+ Tmean = np.mean(Y)
212
+ Tband = factor*abs(Tmean)/3
213
+ ax[0].plot(gX, gY, '-', label="Golden", linewidth=4, alpha=0.4, color="black")
214
+
215
+ ax[0].legend(ncol=3, fontsize="x-small")
216
+ ax[0].set_title("T$_{prof}$ values")
217
+ if value.find("temp") >= 0 or value.find("_avg") >= 0:
218
+ ax[0].set_ylim(Tmean-Tband, Tmean+Tband)
219
+ ax[0].fill_between(gX,
220
+ getattr(golden[iside], value) + band,
221
+ getattr(golden[iside], value) - band,
222
+ facecolor="yellow", alpha=0.25,
223
+ label="Acceptance band")
224
+
225
+ ax[1].fill_between(gX, band, -band,
226
+ facecolor="yellow", alpha=0.25,
227
+ label="Acceptance band")
228
+
229
+ ax[1].legend(ncol=4, fontsize="x-small")
230
+ ax[1].set_title("T$_{prof}$ - Golden avg.")
231
+ if value.find("temp") >= 0 or value.find("_avg") >= 0:
232
+ ax[1].set_ylim(-Tband, Tband)
233
+
234
+
235
+ def compare_golden(core, golden, value):
236
+ """Comapres petal core with golden average.
237
+
238
+ Args:
239
+ ----
240
+ core (AnalusysResolt): The petal core
241
+ golden (AnalysisResult): The golden avrage
242
+ value (str): The name of the variable to compare
243
+
244
+ """
245
+ Y = getattr(core, value)
246
+ gY = getattr(golden, value)
247
+ if value.find("path") >= 0:
248
+ X = core.path_length
249
+ gX = golden.path_length
250
+
251
+ else:
252
+ X = np.array([float(x) for x in range(10)])
253
+ gX = X
254
+
255
+ # convert to golden X
256
+ spln = CubicSpline(X, Y)
257
+ gC = np.array([spln(x) for x in gX])
258
+
259
+ # compute difference
260
+ band = get_acceptance_band()
261
+ diff = np.abs(gC-gY)
262
+ outsiders = np.where(diff > band)
263
+ mxval = np.amax(diff)
264
+
265
+ rc = mxval < band
266
+ return rc, mxval, len(outsiders)
267
+
268
+
269
+ def analyze_petal_cores(files, golden, options):
270
+ """Create golden average.
271
+
272
+ Args:
273
+ ----
274
+ files (list): List of input files
275
+ golden: the golden object
276
+ options: other options.
277
+
278
+ """
279
+ names = get_names(files)
280
+ for i, ifile in enumerate(files):
281
+ ifile = find_file(options.folder, ifile)
282
+ if not ifile.exists():
283
+ print("+++ File {} does not exist.".format(ifile))
284
+ continue
285
+
286
+ alias = names[i]
287
+ core = IRCore.IRCore.read_json(ifile)
288
+ if core.aliasID is None or core.aliasID == "":
289
+ core.aliasID = names[i]
290
+
291
+ if core.coreID is None or core.coreID == "":
292
+ print("+++ File {} does not have component serial number.")
293
+ continue
294
+
295
+ out = [{}, {}]
296
+ for iside in range(2):
297
+ for val in ("path_temp", "sensor_avg", "sensor_std"):
298
+ out[iside][val] = compare_golden(core.results[iside], golden[iside], val)
299
+
300
+ dbOut = {
301
+ "component": core.coreID,
302
+ "testType": "THERMAL_EVALUATION",
303
+ "institution": core.institute,
304
+ "runNumber": "1",
305
+ "date": core.date,
306
+ "passed": True,
307
+ "problems": True,
308
+ "comments": [],
309
+ "defects": [],
310
+ "results": {}
311
+ }
312
+
313
+ if options.add_attachments:
314
+ golden_file = Path(options.golden).expanduser().resolve()
315
+ dbOut["attachments"] = [
316
+ {
317
+ "path": ifile.as_posix(),
318
+ "title": "Raw data (IRCore)",
319
+ "description": "Raw Data of the test"
320
+ },
321
+ {
322
+ "path": golden_file.as_posix(),
323
+ "title": "Golden",
324
+ "description": "The golden object used for this test."
325
+ }
326
+ ]
327
+
328
+ for iside, side in enumerate(out):
329
+ for key, val in side.items():
330
+ if val[0]:
331
+ continue
332
+
333
+ if val[2] < 2:
334
+ dbOut["comments"].append(
335
+ "{} in side {}: 1 point out of acceptance band.".format(
336
+ key, iside)
337
+ )
338
+ else:
339
+ dbOut["defects"].append(
340
+ {"name": key,
341
+ "description": "{} in side {}: {} points out of acceptance band".format(key, iside, val[2]),
342
+ "properties": "{} > {}".format(val[1], get_acceptance_band())
343
+ }
344
+ )
345
+ dbOut["passed"] = (len(dbOut["defects"]) == 0)
346
+ dbOut["problems"] = (len(dbOut["comments"]) > 0)
347
+
348
+ if options.out is None:
349
+ ofile = "{}-Thermal.json".format(core.coreID)
350
+ else:
351
+ ofile = options.out
352
+
353
+ # Check if we are given an output folder
354
+ ofile = output_folder(options.folder, ofile)
355
+ with open(ofile, 'w') as fp:
356
+ print("writing {}".format(ofile))
357
+ json.dump(dbOut, fp, indent=3, cls=IRCore.NumpyArrayEncoder)
358
+
359
+
360
+ def analyze_IRCore(options):
361
+ """Main entry."""
362
+ if options.create_golden:
363
+ golden, results = create_golden_average(options.files, options)
364
+ if options.out is None:
365
+ options.out = "out-golden.json"
366
+
367
+ ofile = output_folder(options.folder, options.out)
368
+ with open(ofile, 'w') as fp:
369
+ json.dump(golden, fp, indent=3, cls=IRCore.NumpyArrayEncoder)
370
+
371
+ show_golden_average(golden, results, "path_temp")
372
+ show_golden_average(golden, results, "path_spread")
373
+ show_golden_average(golden, results, "sensor_avg")
374
+ show_golden_average(golden, results, "sensor_std")
375
+
376
+ else:
377
+ if options.golden is None:
378
+ print("I need a golden file to compare with")
379
+ sys.exit(1)
380
+
381
+ golden_file = find_file(options.folder, options.golden)
382
+ if not golden_file.exists():
383
+ print("Golden file does not exist.")
384
+ sys.exit(1)
385
+
386
+ with open(golden_file, 'r') as fp:
387
+ J = json.load(fp)
388
+
389
+ golden = [Petal_IR_Analysis.AnalysisResult() for i in range(2)]
390
+ for i, Jside in enumerate(J):
391
+ golden[i].from_json(Jside)
392
+
393
+ analyze_petal_cores(options.files, golden, options)
394
+
395
+ plt.show()
396
+
397
+
398
+ if __name__ == "__main__":
399
+ from argparse import ArgumentParser
400
+ # Argument parser
401
+ parser = ArgumentParser()
402
+ parser.add_argument('files', nargs='*', help="Input files")
403
+ parser.add_argument("--create-golden", action="store_true", default=False, help="Draw golden average")
404
+ parser.add_argument("--add_attachments", action="store_true", default=False,
405
+ help="If true add the attachments section os DB file.")
406
+ parser.add_argument("--golden", default=None, help="The golden to compare width")
407
+ parser.add_argument("--prefix", default="golden", help="Prefix for figures")
408
+ parser.add_argument("--debug", action="store_true", default=False, help="Set to debug")
409
+ parser.add_argument("--out", default=None, help="File to store Golden.")
410
+ parser.add_argument("--folder", default=None, help="Folder to store output files. Superseeds folder in --out")
411
+
412
+ options = parser.parse_args()
413
+ if len(options.files) == 0:
414
+ print("I need an input file")
415
+ sys.exit()
416
+
417
+ analyze_IRCore(options)