petal-qc 0.0.17__py3-none-any.whl → 0.0.24__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.
Files changed (36) hide show
  1. petal_qc/PetalReceptionTests.py +23 -5
  2. petal_qc/__init__.py +6 -1
  3. petal_qc/getPetalCoreTestSummary.py +69 -9
  4. petal_qc/metrology/PetalMetrology.py +23 -11
  5. petal_qc/metrology/analyze_locking_points.py +14 -3
  6. petal_qc/metrology/compare_Cores.py +15 -2
  7. petal_qc/metrology/convert_mitutoyo.py +5 -0
  8. petal_qc/metrology/coreMetrology.py +16 -26
  9. petal_qc/metrology/do_Metrology.py +1 -1
  10. petal_qc/metrology/petal_flatness.py +10 -9
  11. petal_qc/metrology/readAVSdata.py +11 -4
  12. petal_qc/metrology/test_paralelism.py +2 -2
  13. petal_qc/metrology/uploadPetalInformation.py +35 -3
  14. petal_qc/readTemplateTable.py +313 -0
  15. petal_qc/test/analyzeMetrologyTable.py +158 -29
  16. petal_qc/test/checkPipeShipments.py +60 -0
  17. petal_qc/test/getAVStests.py +2 -2
  18. petal_qc/test/reportFromJSon.py +35 -6
  19. petal_qc/test/testMitutoyo.py +10 -0
  20. petal_qc/test/thermalReportFromJSon.py +99 -0
  21. petal_qc/thermal/IRDataGetter.py +2 -0
  22. petal_qc/thermal/IRPetal.py +20 -6
  23. petal_qc/thermal/IRPetalParam.py +12 -3
  24. petal_qc/thermal/Petal_IR_Analysis.py +1 -1
  25. petal_qc/thermal/PipeFit.py +24 -10
  26. petal_qc/thermal/PipeIterFit.py +94 -0
  27. petal_qc/thermal/contours.py +82 -3
  28. petal_qc/thermal/coreThermal.py +2 -2
  29. petal_qc/thermal/create_IRCore.py +11 -6
  30. petal_qc/thermal/create_core_report.py +0 -3
  31. petal_qc/uploadXrays.py +86 -0
  32. {petal_qc-0.0.17.dist-info → petal_qc-0.0.24.dist-info}/METADATA +2 -3
  33. {petal_qc-0.0.17.dist-info → petal_qc-0.0.24.dist-info}/RECORD +36 -30
  34. {petal_qc-0.0.17.dist-info → petal_qc-0.0.24.dist-info}/WHEEL +1 -1
  35. {petal_qc-0.0.17.dist-info → petal_qc-0.0.24.dist-info}/entry_points.txt +1 -0
  36. {petal_qc-0.0.17.dist-info → petal_qc-0.0.24.dist-info}/top_level.txt +0 -0
@@ -317,7 +317,10 @@ class AVSPanel(dbGtkUtils.ITkDBWindow):
317
317
  return
318
318
 
319
319
  self.find_petal(SN, silent=True)
320
- if self.petal_core:
320
+ if self.petal_core and self.petal_core["alternativeIdentifier"] is not None:
321
+ if len(self.petal_core["batches"])==0:
322
+ ITkDButils.set_petal_core_batch(self.session, self.petal_core)
323
+
321
324
  return
322
325
 
323
326
  dialog = Gtk.MessageDialog(
@@ -340,7 +343,7 @@ class AVSPanel(dbGtkUtils.ITkDBWindow):
340
343
  if len(petal_alias) == 0:
341
344
  petal_alias = self.alias
342
345
 
343
- rc = ITkDButils.registerPetalCore(self.session, SN, petal_alias)
346
+ rc = ITkDButils.registerPetalCore(self.session, SN, petal_alias, petal_core=self.petal_core)
344
347
  if rc is None:
345
348
  dbGtkUtils.complain("Could not Register petal {} ({})".format(SN, petal_alias))
346
349
 
@@ -642,6 +645,7 @@ class AVSPanel(dbGtkUtils.ITkDBWindow):
642
645
 
643
646
  values = dctD.values
644
647
  values["component"] = SN
648
+ self.check_retroactive_upload(values)
645
649
  print(json.dumps(values, indent=2))
646
650
  rc = ITkDButils.upload_test(self.session, values)
647
651
  if rc is not None:
@@ -681,7 +685,7 @@ class AVSPanel(dbGtkUtils.ITkDBWindow):
681
685
  self.check_tests(True)
682
686
 
683
687
  def check_tests(self, do_write=False):
684
- """Check whether all tests are find"""
688
+ """Check whether all tests are fine"""
685
689
  nbad = 0
686
690
  bad = []
687
691
  for test in self.test_list:
@@ -712,6 +716,17 @@ class AVSPanel(dbGtkUtils.ITkDBWindow):
712
716
  """Assembly button clicked."""
713
717
  self.check_assembly(self.DESY_comp)
714
718
 
719
+ def check_retroactive_upload(self, values):
720
+ """Check whether retroactive upload is needed."""
721
+ if self.petal_core is None:
722
+ self.query_db()
723
+ if self.petal_core is None:
724
+ return
725
+
726
+ location = self.petal_core["currentLocation"]["code"]
727
+ if location != values["institution"]:
728
+ values["isRetroactive"] = True
729
+
715
730
  def on_upload(self, widget):
716
731
  """Upload tests to DB."""
717
732
  if self.petal_core is None:
@@ -719,8 +734,25 @@ class AVSPanel(dbGtkUtils.ITkDBWindow):
719
734
  if self.petal_core is None:
720
735
  return
721
736
 
737
+ # First Visual Inspection
722
738
  for test in self.test_list:
723
739
  values = test.values
740
+ if values["testType"] != "VISUAL_INSPECTION":
741
+ continue
742
+
743
+ self.check_retroactive_upload(values)
744
+ self.write_message("{}\n".format(values["testType"]))
745
+ res = ITkDButils.upload_test(self.session, values, check_runNumber=True)
746
+ if res is not None:
747
+ dbGtkUtils.complain("Could not upload test {}".format(values["testType"]), res)
748
+
749
+ # Then the rest
750
+ for test in self.test_list:
751
+ values = test.values
752
+ if values["testType"] == "VISUAL_INSPECTION":
753
+ continue
754
+
755
+ self.check_retroactive_upload(values)
724
756
  self.write_message("{}\n".format(values["testType"]))
725
757
  res = ITkDButils.upload_test(self.session, values, check_runNumber=True)
726
758
  if res is not None:
@@ -0,0 +1,313 @@
1
+ #!/usr/bin/env python3
2
+ """Read Python table with reception tests."""
3
+
4
+ import sys
5
+ import math
6
+ import argparse
7
+ import pandas as pd
8
+ import json
9
+ from pathlib import Path
10
+
11
+ from itkdb_gtk import ITkDBlogin, ITkDButils
12
+
13
+ def check_value(value):
14
+ """Check that value is valid."""
15
+ if value is None:
16
+ return False
17
+
18
+ if isinstance(value, float):
19
+ if math.isnan(value):
20
+ return False
21
+
22
+ return True
23
+
24
+
25
+ def string_to_boolean(s):
26
+ """Converts a string to a boolean."""
27
+ val = s.lower()
28
+ if val=="pass" or val=="true" or val=="1":
29
+ return True
30
+ elif val=="fail" or val=="false" or val=="0":
31
+ return False
32
+ else:
33
+ raise ValueError
34
+
35
+ def parse_value(value):
36
+ """Parse value in cell."""
37
+ try:
38
+ spassed, comment = value.split(",")
39
+ except ValueError:
40
+ spassed = value
41
+ comment = ""
42
+
43
+ passed = string_to_boolean(spassed)
44
+ if passed is None:
45
+ return None, None
46
+
47
+ return passed, comment
48
+
49
+ def create_dto(session, SN, test_name):
50
+ """REturns the test DTO."""
51
+ user = ITkDButils.get_db_user(session)
52
+ defaults = {
53
+ "component": SN,
54
+ "institution": user["institutions"][0]["code"],
55
+ "runNumber": "1",
56
+ }
57
+ dto = ITkDButils.get_test_skeleton(session, "CORE_PETAL", test_name, defaults)
58
+ return dto
59
+
60
+ def do_visual_inspection(session, core, value):
61
+ """Uploads visual inspection."""
62
+ if not check_value(value):
63
+ return None
64
+
65
+ SN = core["serialNumber"]
66
+ dto = create_dto(session, SN, "VISUAL_INSPECTION")
67
+
68
+ passed, comment = parse_value(value)
69
+
70
+ if passed is None:
71
+ print("Wrong value fpr PASS/FAIL {} in {} for {}".format(value, "VISUAL_INSPECTION", core["alternativeIdentifier"]) )
72
+ return None
73
+
74
+ if passed:
75
+ dto["passed"] = True
76
+ else:
77
+ dto["passed"] = False
78
+ dto["defects"].append({
79
+ "name": "VISUAL",
80
+ "description": comment,
81
+ "properties": {}
82
+ })
83
+
84
+ return dto
85
+
86
+ def do_grounding(session, core, value):
87
+ """Uploads grounding check"""
88
+ if not check_value(value):
89
+ return None
90
+
91
+ SN = core["serialNumber"]
92
+ dto = create_dto(session, SN, "GROUNDING_CHECK")
93
+
94
+ fb, pipes, pipe_gnd = [float(x) for x in value.split(',')]
95
+ if fb > 2.0:
96
+ dto["passed"] = False
97
+ dto["defects"].append({
98
+ "name": "GROUND_FB",
99
+ "description": "resistance front-back is {} > 2 Ohm".format(fb),
100
+ "properties": {}
101
+ })
102
+
103
+ if pipes>0 and pipes<20.0e6:
104
+ dto["passed"] = False
105
+ dto["defects"].append({
106
+ "name": "GROUND_PIPES",
107
+ "description": "resistance between pipes is {} < 20 MOhm".format(pipes),
108
+ "properties": {}
109
+ })
110
+
111
+ if pipe_gnd>0 and pipe_gnd<20.0e6:
112
+ dto["passed"] = False
113
+ dto["defects"].append({
114
+ "name": "GROUND_PIPE_GND",
115
+ "description": "resistance between pipes and GNDis {} < 20 MOhm".format(pipe_gnd),
116
+ "properties": {}
117
+ })
118
+
119
+ dto["results"]["RESISTANCE_FB"] = fb
120
+ dto["results"]["RESISTANCE_PIPES"] = pipes
121
+ dto["results"]["RESISTANCE_PIPE_GND"] = pipe_gnd
122
+
123
+ return dto
124
+
125
+ def do_bending(session, core, value):
126
+ """Uploads bending."""
127
+ if not check_value(value):
128
+ return None
129
+
130
+ SN = core["serialNumber"]
131
+ dto = create_dto(session, SN, "BENDING120")
132
+ passed, comment = parse_value(value)
133
+ if passed is None:
134
+ print("Wrong value fpr PASS/FAIL {} in {} for {}".format(value, "BENDING120", core["alternativeIdentifier"]) )
135
+ return None
136
+
137
+ if passed:
138
+ dto["passed"] = True
139
+ else:
140
+ dto["passed"] = False
141
+ dto["defects"].append({
142
+ "name": "BENDING120",
143
+ "description": comment,
144
+ "properties": {}
145
+ })
146
+
147
+ return dto
148
+
149
+ def do_weight(session, core, value):
150
+ """Uploads weight."""
151
+ if not check_value(value):
152
+ return None
153
+
154
+ SN = core["serialNumber"]
155
+ dto = create_dto(session, SN, "PETAL_CORE_WEIGHT")
156
+
157
+ weight = float(value)
158
+ dto["results"]["WEIGHT"] = weight
159
+ if abs(weight-250)>25:
160
+ dto["passed"] = False
161
+ dto["defects"].append({
162
+ "name": "WEIGHT",
163
+ "description": "Petal core wights {:.1f} more than 25 gr. beyond 250.".format(weight),
164
+ "properties": {}
165
+ })
166
+ else:
167
+ dto["passed"] = True
168
+
169
+ return dto
170
+
171
+
172
+ def do_thickness(session, core, value):
173
+ """Uploads thickness."""
174
+ if not check_value(value):
175
+ return None
176
+
177
+ SN = core["serialNumber"]
178
+ dto = create_dto(session, SN, "CORE_THICKNESS")
179
+ thickness = float(value)
180
+ dto["results"]["THICKNESS"] = thickness
181
+
182
+ dto["passed"] = True
183
+ if abs(thickness-5.9)>0.25:
184
+ dto["problems"] = True
185
+ dto["comments"].append("Petal core wights {:.1f} more than 25 gr. beyond 250.".format(thickness))
186
+
187
+ return dto
188
+
189
+
190
+ def do_metrology_template(session, core, value):
191
+ """Uploads metrology template."""
192
+ if not check_value(value):
193
+ return None
194
+
195
+ SN = core["serialNumber"]
196
+ dto = create_dto(session, SN, "METROLOGY_TEMPLATE")
197
+ passed, comment = parse_value(value)
198
+ if passed is None:
199
+ print("Wrong value fpr PASS/FAIL {} in {} for {}".format(value, "TEMPLATE", core["alternativeIdentifier"]) )
200
+ return None
201
+
202
+ if passed:
203
+ dto["passed"] = True
204
+ else:
205
+ dto["passed"] = False
206
+ dto["defects"].append({
207
+ "name": "TEMPLATE",
208
+ "description": comment,
209
+ "properties": {}
210
+ })
211
+
212
+ return dto
213
+
214
+
215
+ def do_delamination(session, core, value):
216
+ """Uploads delamination."""
217
+ if not check_value(value):
218
+ return None
219
+
220
+ SN = core["serialNumber"]
221
+ dto = create_dto(session, SN, "DELAMINATION")
222
+
223
+ passed, comment = parse_value(value)
224
+ if passed is None:
225
+ print("Wrong value fpr PASS/FAIL {} in {} for {}".format(value, "DELAMINATION", core["alternativeIdentifier"]) )
226
+ return None
227
+
228
+ if passed:
229
+ dto["passed"] = True
230
+ else:
231
+ dto["passed"] = False
232
+ dto["defects"].append({
233
+ "name": "DELAMINATION",
234
+ "description": comment,
235
+ "properties": {}
236
+ })
237
+
238
+ return dto
239
+
240
+
241
+ def readTemplateTable(session, options):
242
+ """Main entry.
243
+
244
+ Args:
245
+ session (itkdb.Session): The PDB client.
246
+ options: program options
247
+ """
248
+
249
+ core_tests = {
250
+ "VISUAL_INSPECTION": do_visual_inspection,
251
+ "GROUNDING_CHECK": do_grounding,
252
+ "BENDING120": do_bending,
253
+ "PETAL_CORE_WEIGHT": do_weight,
254
+ "CORE_THICKNESS": do_thickness,
255
+ "METROLOGY_TEMPLATE": do_metrology_template,
256
+ "DELAMINATION": do_delamination
257
+ }
258
+ try:
259
+ sheet = int(options.sheet)
260
+ except ValueError:
261
+ sheet = options.sheet
262
+
263
+ df = pd.read_excel(options.files[0], sheet_name=sheet)
264
+ #print(df)
265
+
266
+ for row in df.itertuples():
267
+ petal_id = row.CORE_ID
268
+ if not check_value(petal_id):
269
+ break
270
+
271
+ print("\n\n### {}".format(petal_id))
272
+ core = ITkDButils.get_DB_component(session, petal_id)
273
+ for test, func in core_tests.items():
274
+ data = func(session, core, getattr(row, test))
275
+ if data is None:
276
+ continue
277
+
278
+ data["properties"]["OPERATOR"] = options.operator
279
+
280
+ #print(json.dumps(data, indent=3))
281
+ rc = ITkDButils.upload_test(session, data, check_runNumber=True)
282
+ if rc:
283
+ print("\n*** Could not upload test {} for {}".format(test, petal_id))
284
+ print(rc)
285
+ print()
286
+
287
+ def main():
288
+ """Entry point."""
289
+ parser = argparse.ArgumentParser()
290
+ parser.add_argument("files", nargs='*', help="The template spreadsheet")
291
+ parser.add_argument("--sheet", default="0", help="Sheet to read from excel file.")
292
+ parser.add_argument("--operator", default="Oihan Elesgaray", help="Name of operator.")
293
+
294
+ args = parser.parse_args()
295
+ if len(args.files) == 0:
296
+ print("I need an input file")
297
+ sys.exit()
298
+
299
+ if not Path(args.files[0]).exists():
300
+ print("Input file does not exist.")
301
+ sys.exit()
302
+
303
+
304
+ # ITk_PB authentication
305
+ dlg = ITkDBlogin.ITkDBlogin()
306
+ pdb_session = dlg.get_client()
307
+
308
+ readTemplateTable(pdb_session, args)
309
+
310
+ dlg.die()
311
+
312
+ if __name__ == "__main__":
313
+ main()
@@ -1,5 +1,9 @@
1
1
  #!/usr/bin/env python3
2
- """Analyze the table generated by createMetrologyTable."""
2
+ """Analyze the table generated by createMetrologyTable.
3
+
4
+ It should also work with the table created by analyzeMetrologyTable, which is
5
+ the new default.
6
+ """
3
7
 
4
8
  import sys
5
9
  from pathlib import Path
@@ -13,7 +17,22 @@ from lmfit.models import LinearModel
13
17
 
14
18
  from petal_qc.utils.fit_utils import draw_best_fit
15
19
 
20
+ fig_width = 12.0
21
+ fig_height = 1.2*fig_width/3.0
22
+
23
+
24
+
16
25
  def distance(P1, P2, P3):
26
+ """Distance of P3 to line defined by P1-P2.
27
+
28
+ Args:
29
+ P1: Point 1 of the line
30
+ P2: Point 2 of the line
31
+ P3: Actual point
32
+
33
+ Returns:
34
+ float: distance
35
+ """
17
36
  C = np.cross(P2-P1, P3-P1)
18
37
  D = C/norm(P2-P1)
19
38
  return D
@@ -38,14 +57,41 @@ def remove_outliers_indx(data, cut=2.0, debug=False):
38
57
  indx = np.where(s < cut)[0]
39
58
  return indx
40
59
 
60
+ def draw_delta_scatter(ax, x, y, title, x_lim=None, y_lim=None, radius=None):
41
61
 
42
- def main(options):
43
- """main entry."""
44
- fig_width = 12.0
45
- fig_height = 1.2*fig_width/3.0
62
+ if x_lim is None:
63
+ x_lim=(-150, 150)
46
64
 
47
- T = pd.read_csv(options.files[0])
65
+ if y_lim is None:
66
+ y_lim=(-150, 150)
67
+
68
+ if radius is None:
69
+ radius = (25, 100)
70
+
71
+ ax.set_title(title)
72
+ ax.set_aspect('equal', adjustable='box')
73
+ ax.set_xlim(x_lim)
74
+ ax.set_ylim(y_lim)
75
+ circle = plt.Circle((0,0), radius[1], color="red", alpha=0.25)
76
+ ax.add_patch(circle)
77
+ circle = plt.Circle((0,0), radius[0], color="green", alpha=0.25)
78
+ ax.add_patch(circle)
48
79
 
80
+ ax.set_xlabel("X (µm)")
81
+ ax.set_ylabel("Y (µm)")
82
+ ax.grid()
83
+
84
+ ax.scatter(x, y, marker='.')
85
+
86
+
87
+ def analyze_fiducials(options, T):
88
+ """Analyze relative position of locator fiducials.
89
+
90
+ Args:
91
+ options (_type_): Program options
92
+ T (DataFrame): Pandas data frame.
93
+ """
94
+ side = T["side"].values[0]
49
95
  if options.mould > 0:
50
96
  x = 1000*T.loc[T['mould'] == options.mould, 'fd_dx'].values
51
97
  y = 1000*T.loc[T['mould'] == options.mould, 'fd_dy'].values
@@ -54,22 +100,23 @@ def main(options):
54
100
  x = 1000*T['fd_dx'].values
55
101
  y = 1000*T['fd_dy'].values
56
102
 
57
- fig, ax = plt.subplots(nrows=1, ncols=3, tight_layout=True, figsize=(fig_width, fig_height))
58
- fig.suptitle("Relative Position FD01-FD02")
59
- ax[0].set_title("FD01-FD02")
60
- ax[0].set_aspect('equal', adjustable='box')
61
- ax[0].set_xlim(-150, 150)
62
- ax[0].set_ylim(-150, 150)
63
- circle = plt.Circle((0,0), 75, color="red", alpha=0.25)
64
- ax[0].add_patch(circle)
65
- circle = plt.Circle((0,0), 25, color="green", alpha=0.25)
66
- ax[0].add_patch(circle)
67
-
68
- ax[0].set_xlabel("X (µm)")
69
- ax[0].set_ylabel("Y (µm)")
70
- ax[0].grid()
71
-
72
- ax[0].scatter(x, y, marker='.')
103
+ fig, ax = plt.subplots(nrows=1, ncols=2, tight_layout=True, figsize=(fig_width, fig_height))
104
+ fig.suptitle("Relative Position FD01-FD02 [{}]".format(side))
105
+ draw_delta_scatter(ax[0], x, y, "FD01-FD02")
106
+ # ax[0].set_title("FD01-FD02")
107
+ # ax[0].set_aspect('equal', adjustable='box')
108
+ # ax[0].set_xlim(-150, 150)
109
+ # ax[0].set_ylim(-150, 150)
110
+ # circle = plt.Circle((0,0), 100, color="red", alpha=0.25)
111
+ # ax[0].add_patch(circle)
112
+ # circle = plt.Circle((0,0), 25, color="green", alpha=0.25)
113
+ # ax[0].add_patch(circle)
114
+ #
115
+ # ax[0].set_xlabel("X (µm)")
116
+ # ax[0].set_ylabel("Y (µm)")
117
+ # ax[0].grid()
118
+ #
119
+ # ax[0].scatter(x, y, marker='.')
73
120
 
74
121
  model = LinearModel()
75
122
  params = model.guess(y, x=x)
@@ -94,15 +141,94 @@ def main(options):
94
141
  angle = 180*math.atan( result.best_values['slope'])/math.pi
95
142
  print("angle {:.5f} deg.".format(angle))
96
143
 
97
- ax[1].set_xlim(-150, 150)
98
- ax[1].set_xlabel("X (µm)")
144
+ ax[1].set_xlim(-50, 50)
145
+ ax[1].set_xlabel("distance to line (µm)")
99
146
  ax[1].grid()
100
- ax[1].hist(x)
147
+ ax[1].hist(values)
148
+
149
+ # ax[2].set_xlim(-75, 75)
150
+ # ax[2].set_xlabel("delta_X (µm)")
151
+ # ax[2].grid()
152
+ # ax[2].hist(x)
153
+
154
+ # ax[3].set_xlim(-150, 150)
155
+ # ax[3].set_xlabel("delta_Y (µm)")
156
+ # ax[3].grid()
157
+ # ax[3].hist(y)
158
+
159
+ def analyze_delta_pos(options, T):
160
+ """ Study dependency of delta pos in PL01-FD01 with the other locators.
161
+
162
+ Args:
163
+ options (_type_): Program options
164
+ T (DataFrame): Pandas data frame.
165
+ """
166
+ side = T["side"].values[0]
167
+ x = T["pl01_dx"].values
168
+ y = T["pl01_dy"].values
169
+ delta_pl01 = 1000*np.column_stack((x, y))
170
+ norm = np.array([ np.linalg.norm(P) for P in delta_pl01])
171
+ indx = np.where(norm<75.0)
172
+
173
+ delta_pl02 = 1000*np.column_stack((T["pl02_dx"].values, T["pl02_dy"].values))
174
+ delta_pl03 = 1000*np.column_stack((T["pl03_dx"].values, T["pl03_dy"].values))
175
+
176
+ fig, ax = plt.subplots(nrows=1, ncols=2, tight_layout=True, figsize=(fig_width, fig_height))
177
+ fig.suptitle("Delta from PL01 [{}]".format(side))
178
+ draw_delta_scatter(ax[0], delta_pl02[indx, 0], delta_pl02[indx, 1], "PL02")
179
+ draw_delta_scatter(ax[1], delta_pl03[indx, 0], delta_pl03[indx, 1], "PL02")
180
+
181
+
182
+ def analyze_parallelism(options, T):
183
+ """Analyze parallelism.
184
+
185
+ Args:
186
+ options (_type_): Program options
187
+ T (DataFrame): Pandas data frame.
188
+ """
189
+ if options.institute is None:
190
+ df = T
191
+ else:
192
+ df = T.loc[T["institute"] == options.institute]
193
+
194
+
195
+ side = df["side"].values[0]
196
+ labels = []
197
+ for L in df["petal_id"].values:
198
+ ival = int(L[5:])
199
+ labels.append(ival)
200
+
201
+ x = 1000*df["flatness"].values
202
+ y = 1000*df["parallelism"].values
203
+
204
+ fig, ax = plt.subplots(nrows=1, ncols=1, tight_layout=True)
205
+ fig.suptitle("Parallelism .vs. flatness [{}]".format(side))
206
+
207
+ ax.scatter(x, y, marker='.')
208
+ for xp, yp, lbl in zip(x, y, labels):
209
+ ax.text(xp, yp, "{}".format(lbl))
210
+
211
+ ax.set_xlabel("flatness (µm)")
212
+ ax.set_ylabel("parallelism (µm)")
213
+ ax.grid()
214
+
215
+ fig, ax = plt.subplots(nrows=1, ncols=1, tight_layout=True)
216
+ fig.suptitle("Offset [{}]".format(side))
217
+ ax.hist(1000*T["offset"].values)
218
+
219
+
220
+ def main(options):
221
+ """main entry."""
222
+ T = pd.read_csv(options.files[0])
223
+
224
+ # analyze fiducials
225
+ analyze_fiducials(options, T)
226
+
227
+ # Understand deviation from nominal.
228
+ analyze_delta_pos(options, T)
101
229
 
102
- ax[2].set_xlim(-150, 150)
103
- ax[2].set_xlabel("Y (µm)")
104
- ax[2].grid()
105
- ax[2].hist(y)
230
+ # Correlate planarity y parallelism
231
+ analyze_parallelism(options, T)
106
232
 
107
233
  plt.show()
108
234
 
@@ -110,6 +236,9 @@ if __name__ == "__main__":
110
236
  parser = argparse.ArgumentParser()
111
237
  parser.add_argument('files', nargs='*', help="Input files")
112
238
  parser.add_argument('--mould', default=-1, type=int, help="mould index")
239
+ parser.add_argument("--institute",
240
+ default=None,
241
+ help="Either IFIC or DESY to treat the different files")
113
242
 
114
243
  opts = parser.parse_args()
115
244
  if len(opts.files) == 0:
@@ -0,0 +1,60 @@
1
+ """List pipe shipments."""
2
+ import sys
3
+ from pathlib import Path
4
+ import numpy as np
5
+
6
+ from itkdb_gtk import ITkDBlogin, ITkDButils
7
+
8
+ def main(session):
9
+ """List shipments from DESY to AVS containing PIPES."""
10
+ payload = {
11
+ "filterMap": {
12
+ "sender": "DESYHH",
13
+ "recipient": ["AVS"],
14
+ "status": "delivered"
15
+ }
16
+ }
17
+
18
+ # Loop over shipments
19
+ shpmts = session.get("listShipmentsByInstitution", json=payload)
20
+ for s in shpmts:
21
+ items = session.get("listShipmentItems", json={"shipment": s["id"]})
22
+ pipes = []
23
+ for it in items:
24
+ if it["component"]["componentType"]['code'] == "COOLING_LOOP_PETAL":
25
+ pipes.append(it)
26
+
27
+
28
+ if len(pipes) == 0:
29
+ continue
30
+
31
+ print("Shipment {}".format(s["name"]))
32
+ print(":> {}".format(s["sentTs"]))
33
+ for c in pipes:
34
+ pid = c["component"]["alternativeIdentifier"]
35
+ print("*-- {}".format(pid))
36
+
37
+ the_pipe = ITkDButils.get_DB_component(session, c["component"]["serialNumber"])
38
+ if the_pipe is None:
39
+ print(" !! ERROR: Could not retrieve component {} !!".format(c["component"]["serialNumber"]))
40
+ continue
41
+
42
+ if the_pipe["parents"] is not None:
43
+ for p in the_pipe["parents"]:
44
+ if p["componentType"]["code"] == "CORE_PETAL":
45
+ print( " -> Core Petal: {} [{}]".format(p["component"]["alternativeIdentifier"],the_pipe["currentLocation"]["code"]) )
46
+
47
+ print("\n")
48
+
49
+ if __name__ == "__main__":
50
+ # ITk_PB authentication
51
+ dlg = ITkDBlogin.ITkDBlogin()
52
+ client = dlg.get_client()
53
+
54
+ try:
55
+ main(client)
56
+
57
+ except Exception as E:
58
+ print(E)
59
+
60
+ dlg.die()
@@ -323,10 +323,10 @@ if __name__ == "__main__":
323
323
  parser.add_argument("--cores", dest="cores", action=RangeListAction, default=[],
324
324
  help="Create list of cores to analyze. The list is made with numbers or ranges (ch1:ch2 or ch1:ch2:step) ")
325
325
 
326
-
326
+ opts = parser.parse_args()
327
327
  dlg = ITkDBlogin.ITkDBlogin()
328
328
  session = dlg.get_client()
329
329
 
330
- main(session, options)
330
+ main(session, opts)
331
331
 
332
332
  dlg.die()