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

@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env python3
2
+ """Locates all raw data files."""
3
+
4
+ import os
5
+ import sys
6
+ import fnmatch
7
+ import re
8
+ import shutil
9
+ from pathlib import Path
10
+ import argparse
11
+
12
+ def all_files(root, patterns='*', single_level=False, yield_folders=False):
13
+ """A generator that reruns all files in the given folder.
14
+
15
+ Args:
16
+ ----
17
+ root (file path): The folder
18
+ patterns (str, optional): The pattern of the files. Defaults to '*'.
19
+ single_level (bool, optional): If true, do not go into sub folders. Defaults to False.
20
+ yield_folders (bool, optional): If True, return folders as well. Defaults to False.
21
+
22
+ Yields
23
+ ------
24
+ str: file path name
25
+
26
+ """
27
+ patterns = patterns.split(';')
28
+ for path, subdirs, files in os.walk(root):
29
+ if yield_folders:
30
+ files.extend(subdirs)
31
+
32
+ files.sort()
33
+ for name in files:
34
+ for pattern in patterns:
35
+ if fnmatch.fnmatch(name, pattern):
36
+ yield os.path.join(path, name)
37
+ break
38
+
39
+ if single_level:
40
+ break
41
+
42
+ def main(options):
43
+ """Locate raw data files in input folder and copies them in out folder
44
+
45
+ Args:
46
+ folder_in (Path): Input folder
47
+ folder_oyt (Path): Output folder
48
+ """
49
+ reg = re.compile(r"(PPC\.[0-9]+)-(\w+)")
50
+ outF = Path(options.output).expanduser().resolve()
51
+ with open(outF, "w", encoding="utf-8") as fout:
52
+ for folder_in in options.files:
53
+ inF = Path(folder_in).expanduser().resolve()
54
+ if not inF.exists():
55
+ print("Input folder does not exist. {}".format(inF))
56
+ continue
57
+
58
+ for fnam in all_files(inF, "PPC*.txt", yield_folders=False):
59
+ R = reg.search(fnam)
60
+ if R is None:
61
+ continue
62
+
63
+ petal_id = R.group(1)
64
+ side = R.group(2)
65
+ fout.write("{ifile} {pid}-{side} {pid}\n".format(ifile=fnam, side=side, pid=petal_id))
66
+
67
+
68
+ if __name__ == "__main__":
69
+ parser = argparse.ArgumentParser()
70
+ parser.add_argument('files', nargs='*', help="Input files")
71
+ parser.add_argument("--output", dest="output", help="Output file", default="out.txt")
72
+ opts = parser.parse_args()
73
+ if len(opts.files)==0:
74
+ print("I need at least one input folder")
75
+ sys.exit(-1)
76
+
77
+ main(opts)
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env python3
2
+ """Get module bow from desy metrology files"""
3
+ import sys
4
+ import re
5
+ from pathlib import Path
6
+ import matplotlib.pyplot as plt
7
+ import numpy as np
8
+ import numpy.linalg as linalg
9
+
10
+
11
+ from petal_qc.utils.all_files import all_files
12
+ from petal_qc.metrology import DataFile
13
+ from petal_qc.metrology import DataFile
14
+ from petal_qc.utils.Geometry import fit_plane
15
+ from petal_qc.utils.Geometry import project_to_plane
16
+ from petal_qc.utils.Geometry import remove_outliers_indx
17
+
18
+
19
+ rgx = "serialNo =\\s+([A-Z0-9]+)"
20
+ serial_no = re.compile(rgx)
21
+
22
+ mtype = re.compile("Project Name:\\s+([A-Za-z0-9]+)_bow")
23
+
24
+
25
+ def get_array_range(A):
26
+ """Gets mean and range of given array."""
27
+ avg = np.mean(A)
28
+ imin = np.argmin(A)
29
+ vmin = A[imin]
30
+ imax = np.argmax(A)
31
+ vmax = A[imax]
32
+ stdv = np.std(A)
33
+ return avg, stdv, [vmin, vmax], [imin, imax]
34
+
35
+
36
+
37
+ def create_bow_figure(SN, mtype, pout, width) -> plt.Figure:
38
+ """Create the sensor bow figure.
39
+
40
+ Args:
41
+ options: Program options.
42
+ pout: set of points
43
+ width: the actual bow.
44
+
45
+ Returns:
46
+ plt.Figure: The bow figure.
47
+ """
48
+ fig_bow, ax = plt.subplots(subplot_kw={'projection': '3d'})
49
+ fig_bow.suptitle(r"{}_{} - Sensor bow {:.1f} $\mu$m".format(SN, mtype, width))
50
+
51
+ zplt = 1000*pout[:, 2]
52
+ # surf = ax.plot_trisurf(pout[:, 0], pout[:, 1], zplt, cmap=plt.cm.jet, edgecolor="black", linewidths=0.2)
53
+ surf = ax.scatter(pout[:, 0], pout[:, 1], zplt, c=zplt, marker="o", edgecolor='none')
54
+ ax.set_xlabel("X")
55
+ ax.set_ylabel("Y")
56
+ ax.set_zlabel("Z")
57
+ cbar = fig_bow.colorbar(surf, shrink=0.5, aspect=5, location="left")
58
+ cbar.set_label(r"Z ($\mu$m)")
59
+ return fig_bow
60
+
61
+
62
+ def module_bow(ifile):
63
+ """Compute module bow."""
64
+ SN = None
65
+ mod_type = None
66
+ print(Path(ifile).name)
67
+ with open(ifile, "r", encoding="utf-8") as fin:
68
+ ss = fin.read()
69
+ mtx = serial_no.search(ss)
70
+ if mtx:
71
+ SN = mtx.group(1)
72
+
73
+ mtp = mtype.search(ss)
74
+ if mtp:
75
+ mod_type = mtp.group(1)
76
+
77
+ if SN is None:
78
+ return None, None, None
79
+
80
+ print("{} - {}".format(SN, mod_type))
81
+
82
+ data = DataFile.read(ifile, "(Bow|Sensor)")
83
+ if len(data) == 0:
84
+ return None, None, None
85
+
86
+ # Try to remove locator points and get the plane
87
+ indx = remove_outliers_indx(data[:, 2])
88
+ M, TM, *_ = fit_plane(data[indx], use_average=False)
89
+
90
+ # project all data to the plane
91
+ Zmean = np.mean(M[:, 2])
92
+ M[:, 2] -= Zmean
93
+
94
+ mean, stdev, rng, irng = get_array_range(M[:, 2])
95
+ width = 1000*(rng[1]-rng[0])
96
+
97
+ # Check which one is closest to the center
98
+ min2center = linalg.norm(M[irng[0], 0:2])
99
+ max2center = linalg.norm(M[irng[1], 0:2])
100
+ # If center above the top, bow negative
101
+ if max2center < min2center:
102
+ width = -width
103
+
104
+ print("Sensor bow\nAverage: {:.1f} min {:.1f} max {:.1f} rng {:.1f}\n".format(
105
+ mean, 1000*rng[0], 1000*rng[1], width))
106
+
107
+ fig_bow = create_bow_figure(SN, mod_type, M, width)
108
+ fig_bow.savefig("{}-{}-bow.png".format(SN, mod_type), dpi=300)
109
+ plt.close(fig_bow)
110
+ del fig_bow
111
+ return SN, mod_type, width
112
+
113
+
114
+ def main(folder):
115
+ """Main entry"""
116
+ fout = open("module-bow.txt", "w", encoding="utf-8")
117
+ for fnam in all_files(folder, "*.txt"):
118
+ SN, mod_type, width = module_bow(fnam)
119
+ if SN:
120
+ fout.write("{}-{} : {:.3f}\n".format(SN, mod_type, width))
121
+
122
+ fout.close()
123
+
124
+ if __name__ == "__main__":
125
+ main("/Users/lacasta/Downloads/InterposerPetal")
126
+ #main("/Users/lacasta/Downloads/kkdvk")
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env python3
2
+ """Locates all raw data files."""
3
+
4
+ import os
5
+ import sys
6
+ import fnmatch
7
+ import re
8
+ import shutil
9
+ from pathlib import Path
10
+ import argparse
11
+
12
+ def all_files(root, patterns='*', single_level=False, yield_folders=False):
13
+ """A generator that reruns all files in the given folder.
14
+
15
+ Args:
16
+ ----
17
+ root (file path): The folder
18
+ patterns (str, optional): The pattern of the files. Defaults to '*'.
19
+ single_level (bool, optional): If true, do not go into sub folders. Defaults to False.
20
+ yield_folders (bool, optional): If True, return folders as well. Defaults to False.
21
+
22
+ Yields
23
+ ------
24
+ str: file path name
25
+
26
+ """
27
+ patterns = patterns.split(';')
28
+ for path, subdirs, files in os.walk(root):
29
+ if yield_folders:
30
+ files.extend(subdirs)
31
+
32
+ files.sort()
33
+ for name in files:
34
+ for pattern in patterns:
35
+ if fnmatch.fnmatch(name, pattern):
36
+ yield os.path.join(path, name)
37
+ break
38
+
39
+ if single_level:
40
+ break
41
+
42
+ def main(folder_in, folder_out):
43
+ """Locate raw data files in input folder and copies them in out folder
44
+
45
+ Args:
46
+ folder_in (Path): Input folder
47
+ folder_oyt (Path): Output folder
48
+ """
49
+ inF = Path(folder_in).expanduser().resolve()
50
+ if not inF.exists():
51
+ print("Input folder does not exist. {}".format(inF))
52
+ return
53
+
54
+ reg = re.compile(r"(PPC\.[0-9]+).*metr")
55
+
56
+ outF = Path(folder_out).expanduser().resolve()
57
+ if not outF.exists():
58
+ os.makedirs(outF.as_posix())
59
+
60
+ list_file = open("{}/raw-data-metrology-cores.txt".format(outF.as_posix()), "w", encoding="UTF-8")
61
+ for fnam in all_files(inF, "PPC*.txt", yield_folders=False):
62
+ R = reg.search(fnam)
63
+ if R is None:
64
+ continue
65
+
66
+ petal_id = R.group(1)
67
+ if "back" in fnam:
68
+ side = "{}-back".format(petal_id)
69
+ ofile = "{}-back.txt".format(petal_id)
70
+ elif "front" in fnam:
71
+ side = "{}-front".format(petal_id)
72
+ ofile = "{}-front.txt".format(petal_id)
73
+ else:
74
+ print("Invalid file {}".format(fnam))
75
+ continue
76
+
77
+ out_name = outF / ofile
78
+ list_file.write("{} {} {}\n".format(out_name.as_posix(), side, petal_id))
79
+ shutil.copy(fnam, out_name)
80
+
81
+ list_file.close()
82
+
83
+ if __name__ == "__main__":
84
+ parser = argparse.ArgumentParser()
85
+ parser.add_argument("--input-folder", dest="input", default=None, help="Input folder")
86
+ parser.add_argument("--output-folder", dest="output", help="Outout fodler", default=None)
87
+ opts = parser.parse_args()
88
+ if opts.input is None or opts.output is None:
89
+ print("I need both an input and an output folder.")
90
+ sys.exit(-1)
91
+
92
+ main(opts.input, opts.output)
@@ -1,18 +1,20 @@
1
1
  #!/usr/bin/env python3
2
2
  """Analize AVS metrology tests."""
3
+ import sys
4
+ from pathlib import Path
3
5
  import numpy as np
4
6
  import matplotlib.pyplot as plt
5
7
 
6
8
  try:
7
- import itkdb_gtk
9
+ import petal_qc
8
10
 
9
11
  except ImportError:
10
- import sys
11
- from pathlib import Path
12
12
  cwd = Path(__file__).parent.parent
13
13
  sys.path.append(cwd.as_posix())
14
14
 
15
- from itkdb_gtk import ITkDBlogin, ITkDButils
15
+ from itkdb_gtk import ITkDBlogin
16
+ import petal_qc.utils.docx_utils as docx_utils
17
+
16
18
 
17
19
 
18
20
  def get_value(results, code):
@@ -108,24 +110,40 @@ def do_weighing(results, weights):
108
110
  weights.setdefault(value["code"][ipos+1:], []).append(value["value"])
109
111
 
110
112
 
111
- def plot_metrology(M_values, Mould_values, petal_ids):
113
+ def plot_metrology(M_values, Mould_values, petal_ids, document):
112
114
  """Plot metrology values."""
115
+ fsize = np.zeros(2)
116
+
117
+ document.add_heading('Deviation from nominal positions', level=1)
113
118
  for key, values in M_values.items():
114
119
  fig, ax = plt.subplots(ncols=1, nrows=1, tight_layout=True)
115
120
  ax.hist(values, bins=15, range=(0, 0.150))
116
121
  ax.set_title(key)
117
-
122
+ ax.grid(True)
123
+ ax.set_xlabel("Distance (mm)")
124
+ fsize = fig.get_size_inches()
125
+ if key != "FIDUCIAL1":
126
+ document.add_picture(fig, True, 14, caption=key)
127
+
128
+ fsize[1] = fsize[0]/0.82
129
+ document.add_heading('Dependency with moulds', level=1)
118
130
  for obj in M_values.keys():
119
- fig, ax = plt.subplots(ncols=1, nrows=4, tight_layout=True)
131
+ fig, ax = plt.subplots(ncols=1, nrows=4, tight_layout=True, figsize=fsize)
120
132
  fig.suptitle("{} - Mould".format(obj))
121
133
  for mould, m_values in Mould_values.items():
122
134
  im = int(mould) - 1
123
135
  ax[im].hist(m_values[obj], bins=15, range=(0, 0.150), label="Mould {}".format(mould))
124
136
 
125
137
  for i in range(4):
138
+ ax[i].grid(True)
139
+ ax[i].set_xlabel("Distance (mm)")
126
140
  ax[i].set_title("Mould {}".format(i+1))
127
141
 
128
- def plot_weighing(weights, tick_labels, show_total=False):
142
+ if obj != "FIDUCIAL1":
143
+ document.add_picture(fig, True, 14, caption=obj)
144
+
145
+
146
+ def plot_weighing(weights, tick_labels, document, show_total=False):
129
147
  """Make the plot of weights."""
130
148
  labels = ["COOLINGLOOPASSEMBLY", "LOCATOR_A", "LOCATOR_B", "LOCATOR_C",
131
149
  "HONEYCOMBSET", "FACING_FRONT", "FACING_BACK",
@@ -169,13 +187,19 @@ def main(session):
169
187
  }
170
188
 
171
189
  core_list = session.get("listComponents", json=payload)
172
- core_tests = ["METROLOGY_AVS", "WEIGHING", "MANUFACTURING"]
190
+ core_tests = ["METROLOGY_AVS", "WEIGHING", "MANUFACTURING", "DELAMINATION", "GROUNDING_CHECK", "VISUAL_INSPECTION"]
173
191
 
174
192
  weights = {}
175
193
  petal_ids = []
176
194
  M_values = {}
177
195
  Mould_values = {}
178
196
  mould_id = None
197
+ i = 0
198
+ bad_cores = {}
199
+ counter = {"TOTAL":0}
200
+ for T in core_tests:
201
+ counter[T]=0
202
+
179
203
  for core in core_list:
180
204
  SN = core["serialNumber"]
181
205
  altid = core['alternativeIdentifier']
@@ -222,6 +246,7 @@ def main(session):
222
246
  if mould_id not in Mould_values:
223
247
  Mould_values[mould_id] = {}
224
248
 
249
+ counter["TOTAL"] += 1
225
250
  for ttype, T in good_tests.items():
226
251
 
227
252
  if ttype == "WEIGHING":
@@ -233,20 +258,50 @@ def main(session):
233
258
  elif ttype == "MANUFACTURING":
234
259
  continue
235
260
 
236
- else:
237
- for value in T["results"]:
238
- print("\t{} - {}".format(value["code"], value["value"]))
261
+ # else:
262
+ # if T["results"]:
263
+ # for value in T["results"]:
264
+ # print("\t{} - {}".format(value["code"], value["value"]))
239
265
 
240
266
  if not T["passed"]:
241
267
  print("## test {} FAILED".format(T["testType"]["code"]))
268
+ bad_cores.setdefault(altid, []).append({ttype: T["defects"]})
269
+
270
+ else:
271
+ try:
272
+ counter[ttype] += 1
273
+ except KeyError:
274
+ pass
242
275
 
243
276
  if len(T["defects"]):
244
277
  print("+ Defects:")
245
278
  for D in T["defects"]:
246
279
  print("\t{} - {}".format(D["name"], D["description"]))
247
280
 
248
- plot_weighing(weights, petal_ids)
249
- plot_metrology(M_values, Mould_values, petal_ids)
281
+ document = docx_utils.Document()
282
+ document.add_page_numbers()
283
+ document.styles['Normal'].font.name = "Calibri"
284
+ document.add_heading("AVS QC tests.", 0)
285
+
286
+ document.add_heading('Results', level=1)
287
+ document.add_paragraph("Number of bad cores: {}.".format(len(bad_cores)))
288
+ document.add_heading("Bad cores", level=2)
289
+ for key, lst in bad_cores.items():
290
+ p = document.add_paragraph()
291
+ bf = p.add_run("{}:".format(key))
292
+ bf.bold = True
293
+ bf.italic = True
294
+ for item in lst:
295
+ for ttype, defects in item.items():
296
+ msg = "{}:".format(ttype)
297
+ for D in defects:
298
+ msg += "\r{} - {}".format(D["name"], D["description"])
299
+ document.add_paragraph(msg, style="List Bullet")
300
+
301
+
302
+ plot_weighing(weights, petal_ids, document)
303
+ plot_metrology(M_values, Mould_values, petal_ids, document)
304
+ document.save("AVStests.docx")
250
305
  plt.show()
251
306
 
252
307
  if __name__ == "__main__":
@@ -254,10 +309,6 @@ if __name__ == "__main__":
254
309
  dlg = ITkDBlogin.ITkDBlogin()
255
310
  session = dlg.get_client()
256
311
 
257
- try:
258
- main(session)
259
-
260
- except Exception as E:
261
- print(E)
312
+ main(session)
262
313
 
263
314
  dlg.die()
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python3
2
2
  """Get a summery of Petal core TEsts."""
3
-
3
+ import json
4
4
  try:
5
5
  import itkdb_gtk
6
6
 
@@ -14,7 +14,7 @@ from itkdb_gtk import ITkDBlogin, ITkDButils
14
14
  from itkdb_gtk.dbGtkUtils import replace_in_container, DictDialog, ask_for_confirmation
15
15
 
16
16
 
17
- def main(session):
17
+ def main(session, options):
18
18
  """Main entry point."""
19
19
 
20
20
  # find all cores
@@ -24,17 +24,23 @@ def main(session):
24
24
  #"componentType": ["BT"],
25
25
  "componentType": ["CORE_PETAL"],
26
26
  "type": ["CORE_AVS"],
27
- "currentLocation": ["IFIC"],
27
+ # "currentLocation": ["IFIC"],
28
28
  },
29
29
  "sorterList": [
30
30
  {"key": "alternativeIdentifier", "descending": False }
31
31
  ],
32
32
  }
33
+ suff = "ALL"
34
+ if options.institute:
35
+ payload["filterMap"]["currentLocation"] = options.institute
36
+ suff = options.institute
37
+
33
38
  core_list = session.get("listComponents", json=payload)
34
39
  core_tests = ["PETAL_METROLOGY_FRONT", "PETAL_METROLOGY_BACK", "XRAYIMAGING", "THERMAL_EVALUATION", "BTTESTING"]
35
40
 
36
41
  do_check_stage = "AT_QC_SITE"
37
42
  #do_check_stage = None
43
+ petal_id_db = {}
38
44
 
39
45
  for core in core_list:
40
46
  SN = core["serialNumber"]
@@ -42,7 +48,7 @@ def main(session):
42
48
  if "PPC" not in altid:
43
49
  continue
44
50
 
45
-
51
+ petal_id_db[altid] = SN
46
52
  location = core["currentLocation"]['code']
47
53
  coreStage = core["currentStage"]['code']
48
54
  if do_check_stage:
@@ -73,14 +79,21 @@ def main(session):
73
79
  for D in T["defects"]:
74
80
  print("\t{} - {}".format(D["name"], D["description"]))
75
81
 
82
+ with open("petal_ID_db_{}.json".format(suff), "w", encoding="utf-8") as fOut:
83
+ json.dump(petal_id_db, fOut, indent=3)
76
84
 
77
85
  if __name__ == "__main__":
86
+ from argparse import ArgumentParser
87
+ parser = ArgumentParser()
88
+ parser.add_argument("--institute", default=None, help="The petal current location")
89
+ options = parser.parse_args()
90
+
78
91
  # ITk_PB authentication
79
92
  dlg = ITkDBlogin.ITkDBlogin()
80
93
  session = dlg.get_client()
81
94
 
82
95
  try:
83
- main(session)
96
+ main(session, options)
84
97
 
85
98
  except Exception as E:
86
99
  print(E)
@@ -1,8 +1,10 @@
1
1
  #!/usr/bin/env python3
2
2
  """Prepare raw data input files from DESY so that we can use them with this code."""
3
3
  import os
4
+ import sys
4
5
  import fnmatch
5
6
  import re
7
+ import shutil
6
8
  from pathlib import Path
7
9
  import argparse
8
10
 
@@ -51,17 +53,26 @@ def main(folder, out_folder):
51
53
  folder: the input folder where to find the original files.
52
54
  out_folder: the folder where the new fiels will be stored.
53
55
  """
56
+ inF = Path(folder).expanduser().resolve()
57
+ if not inF.exists():
58
+ print("Input folder does not exist. {}".format(inF))
59
+ return
60
+
61
+ print("Reading folder: {}".format(inF))
62
+ print("output in {}".format(out_folder))
54
63
  outF = Path(out_folder).expanduser().resolve()
55
64
  if not outF.exists():
65
+ print("creating {}".format(outF))
56
66
  os.mkdir(outF)
57
67
 
58
68
  rgx = re.compile(r"Project Name: (\w+)side_.*AlternativeID=PPC[-_](\d+)", re.MULTILINE|re.DOTALL)
59
69
  petal_cores = {}
60
- for fnam in all_files(folder, "*.txt"):
70
+ for fnam in all_files(inF, "*.txt"):
61
71
  P = Path(fnam).expanduser().resolve()
72
+ print(P.name)
62
73
  with open(fnam, "r", encoding="UTF-8") as ff:
63
74
  R = rgx.search(ff.read())
64
- if R:
75
+ if R:
65
76
  petal_id = "PPC.{}".format(R.group(2))
66
77
  side = R.group(1).lower()
67
78
  if "_2D_" in P.name:
@@ -86,7 +97,7 @@ def main(folder, out_folder):
86
97
  for data_type, fnam in values.items():
87
98
  if fnam is None:
88
99
  print("This should not happen.")
89
-
100
+
90
101
  with open(fnam, "r", encoding="UTF-8") as ifile:
91
102
  data += ifile.read()
92
103
 
@@ -94,10 +105,14 @@ def main(folder, out_folder):
94
105
  ofile.write(data)
95
106
 
96
107
  list_file.close()
97
-
108
+
98
109
  if __name__ == "__main__":
99
110
  parser = argparse.ArgumentParser()
100
- parser.add_argument("--input-folder", default=None, help="Input folder")
101
- parser.add_argument("--output-folder", help="Outout fodler", default=None)
102
-
103
- main("/Users/lacasta/Downloads/Report_QC-desy_Sep2024", "/tmp/desy")
111
+ parser.add_argument("--input-folder", dest="input", default=None, help="Input folder")
112
+ parser.add_argument("--output-folder", dest="output", help="Outout fodler", default=None)
113
+ opts = parser.parse_args()
114
+ if opts.input is None or opts.output is None:
115
+ print("I need both an input and an output folder.")
116
+ sys.exit(-1)
117
+
118
+ main(opts.input, opts.output)
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env python3
2
+ """List failing cores from JSon files."""
3
+ import sys
4
+ import argparse
5
+ from pathlib import Path
6
+ import json
7
+
8
+
9
+
10
+ def main(options):
11
+ """main entry."""
12
+ petal_cores = {}
13
+ for fnam in options.files:
14
+ ifile = Path(fnam).expanduser().resolve()
15
+ with open(ifile, "r", encoding="utf-8") as fin:
16
+ data = json.load(fin)
17
+
18
+ if not data["passed"]:
19
+ petalId = data["component"]
20
+ if petalId not in petal_cores:
21
+ petal_cores[petalId] = {"FRONT": [], "BACK": []}
22
+
23
+ side = "FRONT" if "FRONT" in data["testType"] else "BACK"
24
+ for D in data["defects"]:
25
+ petal_cores[petalId][side].append("{}: {}".format(D["name"], D["description"]))
26
+
27
+
28
+ keys = sorted(petal_cores.keys())
29
+ for petalId in keys:
30
+ print(petalId)
31
+ for side in ["FRONT","BACK"]:
32
+ if len(petal_cores[petalId][side])>0:
33
+ print("+-", side)
34
+ for D in petal_cores[petalId][side]:
35
+ print(" ", D)
36
+
37
+ print("\n")
38
+
39
+
40
+ if __name__ == "__main__":
41
+ parser = argparse.ArgumentParser()
42
+ parser.add_argument('files', nargs='*', help="Input files")
43
+ opts = parser.parse_args()
44
+
45
+ from petal_qc.utils.all_files import all_files
46
+
47
+ opts.files = []
48
+ for fnam in all_files(Path("~/tmp/petal-metrology/Production/Results").expanduser(), "*.json"):
49
+ opts.files.append(fnam)
50
+
51
+ main(opts)
@@ -39,12 +39,19 @@ def create_report(options):
39
39
 
40
40
  print("\n## {} - {}".format(options.SN, options.alias))
41
41
 
42
+ # Do the core analysis.
43
+ core = create_IR_core(options)
44
+
45
+ if options.golden is None:
46
+ return core
47
+
42
48
  goldenFile = Path(options.golden).expanduser().resolve()
43
49
  if not goldenFile.exists():
44
50
  goldenFile = utils.output_folder(options.folder, options.golden)
45
51
  goldenFile = Path(goldenFile).expanduser().resolve()
46
52
  if not goldenFile.exists():
47
53
  print("I need a golden file.")
54
+ return core
48
55
 
49
56
  with open(goldenFile, "r", encoding='utf-8') as fp:
50
57
  golden = golden_from_json(json.load(fp))
@@ -65,9 +72,6 @@ def create_report(options):
65
72
  P = document.add_paragraph("Golden: {}".format(goldenFile.name), "Subtitle")
66
73
  P.alignment = docx_utils.paragraph_align_center()
67
74
 
68
-
69
- core = create_IR_core(options)
70
-
71
75
  figures = get_IRcore_plots()
72
76
  document.add_heading('Original image', level=1)
73
77
  document.add_picture(figures["original"], True, 14, caption="Original Thermal image.")