petal-qc 0.0.14.dev1__py3-none-any.whl → 0.0.16__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.
- petal_qc/__init__.py +12 -2
- petal_qc/{test/getPetalCoreTestSummary.py → getPetalCoreTestSummary.py} +41 -6
- petal_qc/metrology/PetalMetrology.py +0 -13
- petal_qc/metrology/analyze_locking_points.py +4 -4
- petal_qc/metrology/compare_Cores.py +69 -4
- petal_qc/metrology/coreMetrology.py +0 -12
- petal_qc/metrology/do_Metrology.py +30 -16
- petal_qc/metrology/petal_flatness.py +0 -13
- petal_qc/metrology/readAVSdata.py +2 -0
- petal_qc/metrology/uploadPetalInformation.py +17 -17
- petal_qc/test/analyzeMetrologyTable.py +119 -0
- petal_qc/test/checkAVStests.py +2 -2
- petal_qc/test/createMetrologyFile.py +77 -0
- petal_qc/test/createMetrologyTable.py +87 -0
- petal_qc/test/desyModuleBow.py +126 -0
- petal_qc/test/findRawData.py +92 -0
- petal_qc/test/getAVStests.py +8 -0
- petal_qc/test/prepareDESYfiles.py +13 -2
- petal_qc/test/reportFromJSon.py +51 -0
- petal_qc/thermal/show_IR_petal.py +1 -10
- petal_qc/utils/ArgParserUtils.py +41 -0
- {petal_qc-0.0.14.dev1.dist-info → petal_qc-0.0.16.dist-info}/METADATA +4 -4
- {petal_qc-0.0.14.dev1.dist-info → petal_qc-0.0.16.dist-info}/RECORD +26 -19
- {petal_qc-0.0.14.dev1.dist-info → petal_qc-0.0.16.dist-info}/WHEEL +1 -1
- {petal_qc-0.0.14.dev1.dist-info → petal_qc-0.0.16.dist-info}/entry_points.txt +2 -0
- {petal_qc-0.0.14.dev1.dist-info → petal_qc-0.0.16.dist-info}/top_level.txt +0 -0
|
@@ -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,87 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Create table for metrology analysis."""
|
|
3
|
+
|
|
4
|
+
import sys
|
|
5
|
+
import re
|
|
6
|
+
import json
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from argparse import ArgumentParser
|
|
9
|
+
from petal_qc.utils.all_files import all_files
|
|
10
|
+
from petal_qc.utils.ArgParserUtils import RangeListAction
|
|
11
|
+
|
|
12
|
+
r_petal_id = re.compile("PPC.([0-9]*)")
|
|
13
|
+
|
|
14
|
+
db_file = Path("/Users/lacasta/cernbox/workspace/Petal-QC/PetalMould.csv")
|
|
15
|
+
|
|
16
|
+
petal_db = {}
|
|
17
|
+
with open(db_file, "r", encoding="utf-8") as fin:
|
|
18
|
+
for i, line in enumerate(fin):
|
|
19
|
+
if i==0:
|
|
20
|
+
continue
|
|
21
|
+
|
|
22
|
+
values = [x.strip() for x in line.split(",")]
|
|
23
|
+
petal_db[values[0]] = values[1:]
|
|
24
|
+
|
|
25
|
+
def main(options):
|
|
26
|
+
"""Main entry."""
|
|
27
|
+
ifolder = Path(options.input)
|
|
28
|
+
if not ifolder.exists():
|
|
29
|
+
print("Input folder does not exist.\n{}".format(ifolder))
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
has_list = len(options.cores) != 0
|
|
33
|
+
|
|
34
|
+
ofile = open(options.out, "w", encoding="utf-8")
|
|
35
|
+
ofile.write("PetalID,SN,side,mould,fd_dx,fd_dy,paralelism,R0,R1,R2,R3S0,R3S1,R4S0,R4S1,R5S0,R5S1,flatness\n")
|
|
36
|
+
|
|
37
|
+
for fnam in all_files(ifolder.as_posix(), "*.json"):
|
|
38
|
+
fstem = fnam.stem
|
|
39
|
+
if "PPC." not in fstem:
|
|
40
|
+
continue
|
|
41
|
+
|
|
42
|
+
R = r_petal_id.search(fstem)
|
|
43
|
+
if R is None:
|
|
44
|
+
continue
|
|
45
|
+
|
|
46
|
+
petal_id = R.group(0)
|
|
47
|
+
pid = int(R.group(1))
|
|
48
|
+
|
|
49
|
+
if has_list and pid not in options.cores:
|
|
50
|
+
continue
|
|
51
|
+
|
|
52
|
+
SN = petal_db[petal_id][0]
|
|
53
|
+
side = 1 if "back" in fstem else 0
|
|
54
|
+
mould = int(petal_db[petal_id][1])
|
|
55
|
+
|
|
56
|
+
data = None
|
|
57
|
+
with open(fnam, "r", encoding="utf-8") as fin:
|
|
58
|
+
data = json.load(fin)
|
|
59
|
+
|
|
60
|
+
ofile.write("{}, {}, {}, {}".format(petal_id, SN, side, mould))
|
|
61
|
+
print("data SN", data["component"])
|
|
62
|
+
D = data["results"]["METROLOGY"]["REL_POS_DELTA"]["FD01-FD02"]
|
|
63
|
+
ofile.write(",{:.5f}, {:.5f}".format(D[0], D[1]))
|
|
64
|
+
|
|
65
|
+
D = data["results"]["METROLOGY"]["PARALLELISM"]
|
|
66
|
+
ofile.write(",{:.5f}".format(D))
|
|
67
|
+
|
|
68
|
+
for x in data["results"]["METROLOGY"]["FLATNESS_LOCAL"]:
|
|
69
|
+
ofile.write(", {:.5f}".format(x))
|
|
70
|
+
|
|
71
|
+
D = data["results"]["METROLOGY"]["FLATNESS_GLOBAL"]
|
|
72
|
+
ofile.write(", {:.5f}".format(D))
|
|
73
|
+
|
|
74
|
+
ofile.write("\n")
|
|
75
|
+
|
|
76
|
+
ofile.close()
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
if __name__ == "__main__":
|
|
80
|
+
parser = ArgumentParser()
|
|
81
|
+
parser.add_argument("--input-folder", dest="input", default=".", help="Input folder")
|
|
82
|
+
parser.add_argument("--out", default="out.csv", help="Output table.")
|
|
83
|
+
parser.add_argument("--cores", dest="cores", action=RangeListAction, default=[],
|
|
84
|
+
help="Create list of cores to analyze. The list is made with numbers or ranges (ch1:ch2 or ch1:ch2:step) ")
|
|
85
|
+
|
|
86
|
+
opts = parser.parse_args()
|
|
87
|
+
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)
|
petal_qc/test/getAVStests.py
CHANGED
|
@@ -200,6 +200,7 @@ def main(session):
|
|
|
200
200
|
for T in core_tests:
|
|
201
201
|
counter[T]=0
|
|
202
202
|
|
|
203
|
+
mould_db = {}
|
|
203
204
|
for core in core_list:
|
|
204
205
|
SN = core["serialNumber"]
|
|
205
206
|
altid = core['alternativeIdentifier']
|
|
@@ -243,6 +244,7 @@ def main(session):
|
|
|
243
244
|
mould_desc = do_manufacturing(good_tests["MANUFACTURING"])
|
|
244
245
|
pos = mould_desc.rfind('.')
|
|
245
246
|
mould_id = mould_desc[pos+1:]
|
|
247
|
+
mould_db[altid] = (SN, mould_id)
|
|
246
248
|
if mould_id not in Mould_values:
|
|
247
249
|
Mould_values[mould_id] = {}
|
|
248
250
|
|
|
@@ -302,6 +304,12 @@ def main(session):
|
|
|
302
304
|
plot_weighing(weights, petal_ids, document)
|
|
303
305
|
plot_metrology(M_values, Mould_values, petal_ids, document)
|
|
304
306
|
document.save("AVStests.docx")
|
|
307
|
+
|
|
308
|
+
with open("mould_db.csv", "w", encoding="utf-8") as fout:
|
|
309
|
+
fout.write("PetalID, SerialNo, MouldID\n")
|
|
310
|
+
for key, val in mould_db.items():
|
|
311
|
+
fout.write("{}, {}, {}\n".format(key, val[0], val[1]))
|
|
312
|
+
|
|
305
313
|
plt.show()
|
|
306
314
|
|
|
307
315
|
if __name__ == "__main__":
|
|
@@ -4,6 +4,7 @@ import os
|
|
|
4
4
|
import sys
|
|
5
5
|
import fnmatch
|
|
6
6
|
import re
|
|
7
|
+
import shutil
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
import argparse
|
|
9
10
|
|
|
@@ -52,14 +53,23 @@ def main(folder, out_folder):
|
|
|
52
53
|
folder: the input folder where to find the original files.
|
|
53
54
|
out_folder: the folder where the new fiels will be stored.
|
|
54
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))
|
|
55
63
|
outF = Path(out_folder).expanduser().resolve()
|
|
56
64
|
if not outF.exists():
|
|
65
|
+
print("creating {}".format(outF))
|
|
57
66
|
os.mkdir(outF)
|
|
58
67
|
|
|
59
68
|
rgx = re.compile(r"Project Name: (\w+)side_.*AlternativeID=PPC[-_](\d+)", re.MULTILINE|re.DOTALL)
|
|
60
69
|
petal_cores = {}
|
|
61
|
-
for fnam in all_files(
|
|
70
|
+
for fnam in all_files(inF, "*.txt"):
|
|
62
71
|
P = Path(fnam).expanduser().resolve()
|
|
72
|
+
print(P.name)
|
|
63
73
|
with open(fnam, "r", encoding="UTF-8") as ff:
|
|
64
74
|
R = rgx.search(ff.read())
|
|
65
75
|
if R:
|
|
@@ -86,7 +96,8 @@ def main(folder, out_folder):
|
|
|
86
96
|
data = ""
|
|
87
97
|
for data_type, fnam in values.items():
|
|
88
98
|
if fnam is None:
|
|
89
|
-
print("
|
|
99
|
+
print("Missing file name for {} {} [{}]".format(petal_id, side, data_type))
|
|
100
|
+
continue
|
|
90
101
|
|
|
91
102
|
with open(fnam, "r", encoding="UTF-8") as ifile:
|
|
92
103
|
data += ifile.read()
|
|
@@ -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)
|
|
@@ -24,21 +24,12 @@ from petal_qc.thermal import contours
|
|
|
24
24
|
from petal_qc.thermal import IRBFile
|
|
25
25
|
from petal_qc.thermal import IRPetal
|
|
26
26
|
from petal_qc.thermal import PipeFit
|
|
27
|
-
from petal_qc.thermal.Petal_IR_Analysis import AnalysisResult
|
|
28
27
|
from petal_qc.thermal.Petal_IR_Analysis import show_2D_image
|
|
29
28
|
from petal_qc.thermal.PetalColorMaps import HighContrast
|
|
30
29
|
|
|
31
30
|
import petal_qc.utils.Progress as Progress
|
|
32
31
|
import petal_qc.utils.utils as utils
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class CommaSeparatedListAction(Action):
|
|
36
|
-
"""Create a list from the comma sepparated numbers at imput."""
|
|
37
|
-
|
|
38
|
-
def __call__(self, parser, namespace, values, option_string=None):
|
|
39
|
-
"""The actual action."""
|
|
40
|
-
setattr(namespace, self.dest, list(map(int, values.split(','))))
|
|
41
|
-
|
|
32
|
+
from petal_qc.utils.ArgParserUtils import CommaSeparatedListAction
|
|
42
33
|
|
|
43
34
|
def get_min_max(values, step=1.0):
|
|
44
35
|
"""Return min and max.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""A number of utilities for argument parser."""
|
|
3
|
+
|
|
4
|
+
from argparse import Action
|
|
5
|
+
|
|
6
|
+
class CommaSeparatedListAction(Action):
|
|
7
|
+
"""Create a list from the comma sepparated numbers at imput."""
|
|
8
|
+
|
|
9
|
+
def __call__(self, parser, namespace, values, option_string=None):
|
|
10
|
+
"""The actual action."""
|
|
11
|
+
setattr(namespace, self.dest, list(map(int, values.split(','))))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class RangeListAction(Action):
|
|
15
|
+
"""Create a list from a range expresion at input.
|
|
16
|
+
|
|
17
|
+
The list is made with numbers or ranges (ch1:ch2 or ch1:ch2:step)
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __call__(self, parser, namespace, values, option_string=None):
|
|
21
|
+
"""The actual action."""
|
|
22
|
+
value = []
|
|
23
|
+
for V in values.split(','):
|
|
24
|
+
try:
|
|
25
|
+
value.append(int(V))
|
|
26
|
+
except ValueError:
|
|
27
|
+
if ':' not in V:
|
|
28
|
+
continue
|
|
29
|
+
|
|
30
|
+
items = V.split(':')
|
|
31
|
+
if len(items)==1:
|
|
32
|
+
continue
|
|
33
|
+
|
|
34
|
+
ival = list(map(int, items))
|
|
35
|
+
ival[1] += 1
|
|
36
|
+
for x in range(*ival):
|
|
37
|
+
value.append(int(x))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
setattr(namespace, self.dest, value)
|
|
41
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: petal_qc
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.16
|
|
4
4
|
Summary: A collection of scripts for Petal CORE QC.
|
|
5
5
|
Author-email: Carlos Lacasta <carlos.lacasta@cern.ch>
|
|
6
6
|
Project-URL: Homepage, https://gitlab.cern.ch/atlas-itk/sw/db/itk-pdb-gtk-gui-utils
|
|
@@ -10,14 +10,14 @@ Classifier: Operating System :: OS Independent
|
|
|
10
10
|
Requires-Python: >=3.7
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
Requires-Dist: itkdb
|
|
13
|
-
Requires-Dist:
|
|
13
|
+
Requires-Dist: itkdb_gtk>=0.10.10
|
|
14
14
|
Requires-Dist: numpy
|
|
15
15
|
Requires-Dist: matplotlib
|
|
16
16
|
Requires-Dist: lmfit
|
|
17
17
|
Requires-Dist: openpyxl
|
|
18
18
|
Requires-Dist: pandas
|
|
19
|
-
Requires-Dist:
|
|
20
|
-
Requires-Dist:
|
|
19
|
+
Requires-Dist: python_dateutil
|
|
20
|
+
Requires-Dist: python_docx
|
|
21
21
|
Requires-Dist: scipy
|
|
22
22
|
Requires-Dist: scikit-image
|
|
23
23
|
|